铁血丹心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。以下是简单的一个写入流程
@ CSDN Tyrion.Mon
void UpgradeAPP(xxx)
{
        uint16_t i = 0;
    uint16_t line_data_len = xxx;        //数据域长度
    static uint32_t base_addr = 0;       
    uint32_t offset_addr = 0x0000ffff & xxx;        //偏移地址
    uint32_t write_addr = 0;
    static uint32_t has_erase_page = 0;
    uint32_t need_erase_page = 0;
    static bool APP_StartAddr_OK = false;
        uint8_t line_type = xxx;
       
    switch (line_type)        //行数据类型
    {
    case 4: //指定基地址
      base_addr = xxx;
      base_addr = (base_addr << 16) & 0xffff0000;
      【解锁FLASH】
      break;
    case 0: //写入Flash的数据
      write_addr = base_addr | offset_addr;

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

                if (need_erase_page != has_erase_page)
                {
                  has_erase_page = need_erase_page;
                  【擦除该页】
                }
               
                【向指定地址以整字方式写入FLASH,或者接收到一页的量后采用页编程方式写入】
                【读出对比】
                printf("%x, ", *((volatile uint32_t *)(write_addr + i)));
            }
            printf("\r\n");
      }
      break;
      case 1: //文件结束
            【FLASH上锁】
      break;
    default:
      break;
    }
}

铁血丹心LLLL 发表于 2022-11-23 15:38

跳转APP后的处理
/* 基地址 */
#define NVIC_VECTTAB_RAM            ((uint32_t)0x20000000) /*!< RAM */
#define NVIC_VECTTAB_FLASH          ((uint32_t)0x08000000) /*!< Flash */

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

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

#if (USER_BOOT_EXIST == 1)
        /* APP中断向量表地址偏移 需要在Linker选项卡勾选“USE Memory Layout from Target Dialog”,并修改Target选项卡中的ROM的Start地址 */
        nvic_vector_table_set(NVIC_VECTTAB_FLASH, VECT_TAB_OFFSET);
        __enable_irq();        //解除中断屏蔽
#endif
@ CSDN Tyrion.Mon
void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
{
    SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
}

铁血丹心LLLL 发表于 2022-11-23 15:39

如果在Bootloader跳转APP前就设置了中断向量偏移,则略过。

铁血丹心LLLL 发表于 2022-11-23 15:39

NVIC_VECTTAB_OFFSET_MASK掩码为0x1FFFFF80是因为VTOR寄存器的格式

铁血丹心LLLL 发表于 2022-11-23 15:40

APP地址偏移不能随意,CortexM3 M4权威指南中有如下描述。且还要关注该型号单片机的Flash每页大小,因为写Flash时需要整页擦除,须避免APP和Bootloader代码在同一页。
页: 1 [2]
查看完整版本: STM32/GD32 IAP/Bootloader升级APP