当前位置:   article > 正文

STM32串口升级_(((*(__io uint32_t*)slave_application_start_addres

(((*(__io uint32_t*)slave_application_start_address) & 0x2ffe0000 )+
  • STM32升级功能分为2部分,一部分是bootloader程序,另一部分是用户应用程序组成(以STM32F103C8为例来说明 )

bootloader工程分析

启动文件的复位部分

  1. ; Reset handler
  2. Reset_Handler PROC
  3. EXPORT Reset_Handler [WEAK]
  4. IMPORT __main
  5. IMPORT SystemInit
  6. LDR R0, =SystemInit
  7. BLX R0
  8. LDR R0, =__main
  9. BX R0
  10. ENDP

系统复位后会调用SystemInit函数,此函数在system_stm32f10x.c文件中,其中有个宏决定程序flash或SRAM偏移定义的宏

  1. /*!< Uncomment the following line if you need to relocate your vector Table in
  2. Internal SRAM. */
  3. /* #define VECT_TAB_SRAM */
  4. #define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field.
  5. This value must be a multiple of 0x200. */

在SystemInit函数的最后设置这个偏移值

  1. #ifdef VECT_TAB_SRAM
  2. SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
  3. #else
  4. SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
  5. #endif

启动方试有SRAM和FLASH两种,由宏VECT_TAB_SRAM来决定,SRAM_BASE基地址和FLASH_BASE基地址定义如下

  1. #define FLASH_BASE ((uint32_t)0x08000000) /*!< FLASH base address in the alias region */
  2. #define SRAM_BASE ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */

通常bootloader程序会放在偏移为0开始的一段空间,刚好是FLASH_BASE基址与偏移值为0加起来的地址值,在keil中地址配置如下

程序SystemInit执行完后进入main函数

  1. int main(void)
  2. {
  3. FLASH_Unlock();
  4. UART_Init();
  5. BspTim2Init();
  6. Main_Menu ();
  7. if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
  8. {
  9. BspTim2Close();
  10. JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
  11. Jump_To_Application = (pFunction) JumpAddress;
  12. __set_MSP(*(__IO uint32_t*) ApplicationAddress);
  13. Jump_To_Application();
  14. }
  15. else
  16. {
  17. SerialPutString("no user Program\r\n\n");
  18. }
  19. while(1);
  20. }
  1. 首先调用FLASH_Unlock函数解锁flash操作
  2. UART_Init函数初时化,为接收升级文件操作作准备
  3. BspTim2Init函数初时化定时器,提供超时计数用
  4. Main_Menu函数升级菜单操作功能实现
  5. 测试用户app地址是不是在APPLICATION_ADDRESS位置。检测栈顶的地址,来检验app是否下载成功

    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定义如下

  1. typedef void (*pFunction)(void);
  2. pFunction Jump_To_Application;
  3. uint32_t JumpAddress;

8.  设置主函数栈指针 

 __set_MSP(*(__IO uint32_t*) ApplicationAddress);

9.调用函数,跳转到app复位地址去执行复位操作

Jump_To_Application();

写升级内容到flash,数据接收采用ymode协议进行数据接收,具体协议可找度娘了解

  1. /*******************************************************************************
  2. * @函数名称:Ymodem_Receive
  3. * @函数说明:通过 ymodem协议接收一个文件
  4. * @输入参数:buf: 首地址指针
  5. * @输出参数:无
  6. * @返回参数:文件长度
  7. * @历史记录:
  8. <作者> <时间> <修改记录>
  9. *******************************************************************************/
  10. int32_t Ymodem_Receive (uint8_t *buf)
  11. {
  12. uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
  13. int32_t i, j, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
  14. //初始化Flash地址变量
  15. FlashDestination = ApplicationAddress;
  16. for (session_done = 0, errors = 0, session_begin = 0; ;)
  17. {
  18. for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
  19. {
  20. switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
  21. {
  22. case 0:
  23. errors = 0;
  24. switch (packet_length)
  25. {
  26. //发送端终止
  27. case - 1:
  28. Send_Byte(ACK);
  29. return 0;
  30. //结束传输
  31. case 0:
  32. Send_Byte(ACK);
  33. file_done = 1;
  34. break;
  35. //正常的数据包
  36. default:
  37. if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
  38. {
  39. Send_Byte(NAK);
  40. }
  41. else
  42. {
  43. if (packets_received == 0)
  44. {
  45. //文件名数据包
  46. if (packet_data[PACKET_HEADER] != 0)
  47. {
  48. //文件名数据包有效数据区域
  49. for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
  50. {
  51. file_name[i++] = *file_ptr++;
  52. }
  53. file_name[i++] = '\0';
  54. for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
  55. {
  56. file_size[i++] = *file_ptr++;
  57. }
  58. file_size[i++] = '\0';
  59. Str2Int(file_size, &size);
  60. //测试数据包是否过大
  61. if (size > (FLASH_SIZE - 1))
  62. {
  63. //结束
  64. Send_Byte(CA);
  65. Send_Byte(CA);
  66. return -1;
  67. }
  68. //计算需要擦除Flash的页
  69. NbrOfPage = FLASH_PagesMask(size);
  70. //擦除Flash
  71. for (EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
  72. {
  73. FLASHStatus = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter));
  74. }
  75. Send_Byte(ACK);
  76. Send_Byte(CRC16);
  77. }
  78. //文件名数据包空,结束传输
  79. else
  80. {
  81. Send_Byte(ACK);
  82. file_done = 1;
  83. session_done = 1;
  84. break;
  85. }
  86. }
  87. //数据包
  88. else
  89. {
  90. memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
  91. RamSource = (uint32_t)buf;
  92. for (j = 0; (j < packet_length) && (FlashDestination < ApplicationAddress + size); j += 4)
  93. {
  94. //把接收到的数据编写到Flash中
  95. FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);
  96. if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource)
  97. {
  98. //结束
  99. Send_Byte(CA);
  100. Send_Byte(CA);
  101. return -2;
  102. }
  103. FlashDestination += 4;
  104. RamSource += 4;
  105. }
  106. Send_Byte(ACK);
  107. }
  108. packets_received ++;
  109. session_begin = 1;
  110. }
  111. }
  112. break;
  113. case 1:
  114. Send_Byte(CA);
  115. Send_Byte(CA);
  116. return -3;
  117. default:
  118. if (session_begin > 0)
  119. {
  120. errors ++;
  121. }
  122. if (errors > MAX_ERRORS)
  123. {
  124. Send_Byte(CA);
  125. Send_Byte(CA);
  126. return 0;
  127. }
  128. Send_Byte(CRC16);
  129. break;
  130. }
  131. if (file_done != 0)
  132. {
  133. break;
  134. }
  135. }
  136. if (session_done != 0)
  137. {
  138. break;
  139. }
  140. }
  141. return (int32_t)size;
  142. }

1.收到文件名及长度会计算大小然后擦除flash

  1. //计算需要擦除Flash的页
  2. NbrOfPage = FLASH_PagesMask(size);
  3. //擦除Flash
  4. for (EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
  5. {
  6. FLASHStatus = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter));
  7. }

2.接收到文件内容写对应的flash,从用户程序 ApplicationAddress地址开始写

uint32_t FlashDestination = ApplicationAddress;

写操作如下:

  1. memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
  2. RamSource = (uint32_t)buf;
  3. for (j = 0; (j < packet_length) && (FlashDestination < ApplicationAddress + size); j += 4)
  4. {
  5. //把接收到的数据编写到Flash中
  6. FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);
  7. if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource)
  8. {
  9. //结束
  10. Send_Byte(CA);
  11. Send_Byte(CA);
  12. return -2;
  13. }
  14. FlashDestination += 4;
  15. RamSource += 4;
  16. }
  17. Send_Byte(ACK);

写入后会读回内容,如果写入的与读回的内容不一致,则会终止升级操作

  • 应用程序部分

此部分只需注意以下几点即可

1.  起始地址设置,即bootloader跳转到用户程序的地址

2.偏移地址设置

  1. /*!< Uncomment the following line if you need to relocate your vector Table in
  2. Internal SRAM. */
  3. /* #define VECT_TAB_SRAM */
  4. #define VECT_TAB_OFFSET 0x3000 /*!< Vector Table base offset field.
  5. This value must be a multiple of 0x200. */

升级时要使用有ymode协议的串口工具才能正常升级,最后,demo下载地址:

https://download.csdn.net/download/mygod2008ok/12082368

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/223416
推荐阅读
相关标签
  

闽ICP备14008679号