[其他] STM32/GD32 IAP/Bootloader升级APP

[复制链接]
 楼主| 铁血丹心LLLL 发表于 2022-11-23 15:37 | 显示全部楼层
跳转前关闭中断,防止 1)已经跳转到APP了但来了一个中断并落在了Bootloader, 2)中断向量表已偏移但来了中断,就会落在错误的地方
 楼主| 铁血丹心LLLL 发表于 2022-11-23 15:37 | 显示全部楼层
需要特别注意的是,如果使能了Systick等内核级别的中断,用__disable_irq(); 之类的屏蔽中断的语句是无法关闭的,需要去停止Systick的运行。最优的是在bootloader跳转前关闭所有用到的资源以及中断,在APP中重新配置所需要的,以免在Bootloader中用到的中断在APP中没有用到,而缺少对应的中断处理导致中断死循环或HardFault。APP跳转Bootloader亦应如此。
 楼主| 铁血丹心LLLL 发表于 2022-11-23 15:38 | 显示全部楼层
Bootloader升级APP

从串口接收到hex文件的一行,校验后调用以下函数写入FLASH。以下是简单的一个写入流程
  1. @ CSDN Tyrion.Mon
  2. void UpgradeAPP(xxx)
  3. {
  4.         uint16_t i = 0;
  5.     uint16_t line_data_len = xxx;        //数据域长度
  6.     static uint32_t base_addr = 0;       
  7.     uint32_t offset_addr = 0x0000ffff & xxx;        //偏移地址
  8.     uint32_t write_addr = 0;
  9.     static uint32_t has_erase_page = 0;
  10.     uint32_t need_erase_page = 0;
  11.     static bool APP_StartAddr_OK = false;
  12.         uint8_t line_type = xxx;
  13.        
  14.     switch (line_type)        //行数据类型
  15.     {
  16.     case 4: //指定基地址
  17.         base_addr = xxx;
  18.         base_addr = (base_addr << 16) & 0xffff0000;
  19.         【解锁FLASH】
  20.         break;
  21.     case 0: //写入Flash的数据
  22.         write_addr = base_addr | offset_addr;

  23.         if (APP_StartAddr_OK == false && ((APP_LOADED_ADDR + 0x08000000) == write_addr))
  24.         {
  25.             APP_StartAddr_OK = true;    //APP Flash首地址正确
  26.         }
  27.         if (APP_StartAddr_OK == true)
  28.         {
  29.             for (i = 0; i < line_data_len; i += 4)
  30.             {
  31.                 need_erase_page = ((write_addr + i) - 0x08000000) / 2048;        //算出当前地址所在页,2K每页

  32.                 if (need_erase_page != has_erase_page)
  33.                 {
  34.                     has_erase_page = need_erase_page;
  35.                     【擦除该页】
  36.                 }
  37.                
  38.                 【向指定地址以整字方式写入FLASH,或者接收到一页的量后采用页编程方式写入】
  39.                 【读出对比】
  40.                 printf("%x, ", *((volatile uint32_t *)(write_addr + i)));
  41.             }
  42.             printf("\r\n");
  43.         }
  44.         break;
  45.         case 1: //文件结束
  46.             【FLASH上锁】
  47.         break;
  48.     default:
  49.         break;
  50.     }
  51. }
 楼主| 铁血丹心LLLL 发表于 2022-11-23 15:38 | 显示全部楼层
跳转APP后的处理
  1. /* 基地址 */
  2. #define NVIC_VECTTAB_RAM            ((uint32_t)0x20000000) /*!< RAM */
  3. #define NVIC_VECTTAB_FLASH          ((uint32_t)0x08000000) /*!< Flash */

  4. /* NVIC中断向量表偏移掩码 */
  5. #define NVIC_VECTTAB_OFFSET_MASK    ((uint32_t)0x1FFFFF80)

  6. #define USER_BOOT_EXIST                                                1                        //是否有bootloader
  7. #define VECT_TAB_OFFSET                                                0x5000                //

  8. #if (USER_BOOT_EXIST == 1)
  9.         /* APP中断向量表地址偏移 需要在Linker选项卡勾选“USE Memory Layout from Target Dialog”,并修改Target选项卡中的ROM的Start地址 */
  10.         nvic_vector_table_set(NVIC_VECTTAB_FLASH, VECT_TAB_OFFSET);
  11.         __enable_irq();        //解除中断屏蔽
  12. #endif
  13. @ CSDN Tyrion.Mon
  14. void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
  15. {
  16.     SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
  17. }
 楼主| 铁血丹心LLLL 发表于 2022-11-23 15:39 | 显示全部楼层
如果在Bootloader跳转APP前就设置了中断向量偏移,则略过。
 楼主| 铁血丹心LLLL 发表于 2022-11-23 15:39 | 显示全部楼层
NVIC_VECTTAB_OFFSET_MASK掩码为0x1FFFFF80是因为VTOR寄存器的格式
13604637dce3e86f9a.png
 楼主| 铁血丹心LLLL 发表于 2022-11-23 15:40 | 显示全部楼层
APP地址偏移不能随意,CortexM3 M4权威指南中有如下描述。且还要关注该型号单片机的Flash每页大小,因为写Flash时需要整页擦除,须避免APP和Bootloader代码在同一页。
83433637dce5e23ba9.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部