赞
踩
启动文件的复位部分
- ; Reset handler
- Reset_Handler PROC
- EXPORT Reset_Handler [WEAK]
- IMPORT __main
- IMPORT SystemInit
- LDR R0, =SystemInit
- BLX R0
- LDR R0, =__main
- BX R0
- ENDP
系统复位后会调用SystemInit函数,此函数在system_stm32f10x.c文件中,其中有个宏决定程序flash或SRAM偏移定义的宏
- /*!< Uncomment the following line if you need to relocate your vector Table in
- Internal SRAM. */
- /* #define VECT_TAB_SRAM */
- #define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field.
- This value must be a multiple of 0x200. */
在SystemInit函数的最后设置这个偏移值
- #ifdef VECT_TAB_SRAM
- SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
- #else
- SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
- #endif
启动方试有SRAM和FLASH两种,由宏VECT_TAB_SRAM来决定,SRAM_BASE基地址和FLASH_BASE基地址定义如下
- #define FLASH_BASE ((uint32_t)0x08000000) /*!< FLASH base address in the alias region */
- #define SRAM_BASE ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */
通常bootloader程序会放在偏移为0开始的一段空间,刚好是FLASH_BASE基址与偏移值为0加起来的地址值,在keil中地址配置如下
程序SystemInit执行完后进入main函数
- int main(void)
- {
-
- FLASH_Unlock();
- UART_Init();
- BspTim2Init();
- Main_Menu ();
-
- if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
- {
-
- BspTim2Close();
- JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
- Jump_To_Application = (pFunction) JumpAddress;
-
- __set_MSP(*(__IO uint32_t*) ApplicationAddress);
- Jump_To_Application();
- }
- else
- {
- SerialPutString("no user Program\r\n\n");
- }
-
- while(1);
- }
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000){}
其中ApplicationAddress为用户应用程序起始地址,假如从0x8003000开始,则定义如下
#define ApplicationAddress 0x8003000
6. APPLICATION_ADDRESS + 4对应的是app中断向量表的第二项,复位地址
JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
7.把地址强转为函数指针
Jump_To_Application = (pFunction) JumpAddress;
JumpAddress 和Jump_To_Application定义如下
- typedef void (*pFunction)(void);
- pFunction Jump_To_Application;
- uint32_t JumpAddress;
8. 设置主函数栈指针
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
9.调用函数,跳转到app复位地址去执行复位操作
Jump_To_Application();
- /*******************************************************************************
- * @函数名称:Ymodem_Receive
- * @函数说明:通过 ymodem协议接收一个文件
- * @输入参数:buf: 首地址指针
- * @输出参数:无
- * @返回参数:文件长度
- * @历史记录:
- <作者> <时间> <修改记录>
- *******************************************************************************/
- int32_t Ymodem_Receive (uint8_t *buf)
- {
- uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
- int32_t i, j, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
-
- //初始化Flash地址变量
- FlashDestination = ApplicationAddress;
-
- for (session_done = 0, errors = 0, session_begin = 0; ;)
- {
- for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
- {
- switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
- {
- case 0:
- errors = 0;
- switch (packet_length)
- {
- //发送端终止
- case - 1:
- Send_Byte(ACK);
- return 0;
- //结束传输
- case 0:
- Send_Byte(ACK);
- file_done = 1;
- break;
- //正常的数据包
- default:
- if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
- {
- Send_Byte(NAK);
- }
- else
- {
- if (packets_received == 0)
- {
- //文件名数据包
- if (packet_data[PACKET_HEADER] != 0)
- {
- //文件名数据包有效数据区域
- for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
- {
- file_name[i++] = *file_ptr++;
- }
- file_name[i++] = '\0';
- for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
- {
- file_size[i++] = *file_ptr++;
- }
- file_size[i++] = '\0';
- Str2Int(file_size, &size);
-
- //测试数据包是否过大
- if (size > (FLASH_SIZE - 1))
- {
- //结束
- Send_Byte(CA);
- Send_Byte(CA);
- return -1;
- }
-
- //计算需要擦除Flash的页
- NbrOfPage = FLASH_PagesMask(size);
-
- //擦除Flash
- for (EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
- {
- FLASHStatus = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter));
- }
- Send_Byte(ACK);
- Send_Byte(CRC16);
- }
- //文件名数据包空,结束传输
- else
- {
- Send_Byte(ACK);
- file_done = 1;
- session_done = 1;
- break;
- }
- }
- //数据包
- else
- {
- memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
- RamSource = (uint32_t)buf;
- for (j = 0; (j < packet_length) && (FlashDestination < ApplicationAddress + size); j += 4)
- {
- //把接收到的数据编写到Flash中
- FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);
-
- if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource)
- {
- //结束
- Send_Byte(CA);
- Send_Byte(CA);
- return -2;
- }
- FlashDestination += 4;
- RamSource += 4;
- }
- Send_Byte(ACK);
- }
- packets_received ++;
- session_begin = 1;
- }
- }
- break;
- case 1:
- Send_Byte(CA);
- Send_Byte(CA);
- return -3;
- default:
- if (session_begin > 0)
- {
- errors ++;
- }
- if (errors > MAX_ERRORS)
- {
- Send_Byte(CA);
- Send_Byte(CA);
- return 0;
- }
- Send_Byte(CRC16);
- break;
- }
- if (file_done != 0)
- {
- break;
- }
- }
- if (session_done != 0)
- {
- break;
- }
- }
- return (int32_t)size;
- }
1.收到文件名及长度会计算大小然后擦除flash
- //计算需要擦除Flash的页
- NbrOfPage = FLASH_PagesMask(size);
-
- //擦除Flash
- for (EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
- {
- FLASHStatus = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter));
- }
2.接收到文件内容写对应的flash,从用户程序 ApplicationAddress地址开始写
uint32_t FlashDestination = ApplicationAddress;
写操作如下:
- memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
- RamSource = (uint32_t)buf;
- for (j = 0; (j < packet_length) && (FlashDestination < ApplicationAddress + size); j += 4)
- {
- //把接收到的数据编写到Flash中
- FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);
-
- if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource)
- {
- //结束
- Send_Byte(CA);
- Send_Byte(CA);
- return -2;
- }
- FlashDestination += 4;
- RamSource += 4;
- }
- Send_Byte(ACK);
写入后会读回内容,如果写入的与读回的内容不一致,则会终止升级操作
此部分只需注意以下几点即可
1. 起始地址设置,即bootloader跳转到用户程序的地址
2.偏移地址设置
- /*!< Uncomment the following line if you need to relocate your vector Table in
- Internal SRAM. */
- /* #define VECT_TAB_SRAM */
- #define VECT_TAB_OFFSET 0x3000 /*!< Vector Table base offset field.
- This value must be a multiple of 0x200. */
升级时要使用有ymode协议的串口工具才能正常升级,最后,demo下载地址:
https://download.csdn.net/download/mygod2008ok/12082368
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。