本文以STM32为例,介绍详细介绍了在线升级(IAP,在线应用编程)的项目配置方法和程序实现逻辑,可使用串口在线升级或CAN等其他通信协议实现。在讲解升级基础逻辑的同时也给出了STM32相关配置代码及KEIL 的配置方法。
IAP 操作逻辑
涉及到 FLASH 中程序代码的改动,直接更新自身代码是不安全的。一种简单的实现方法是将存储器分为两个区域,一部分存储应用程序APP,用于实现业务功能;一部分存储Bootloader,用于更新APP。
程序先进入 Bootloader ,根据配置进行程序更新或直接跳转APP。
其中涉及到的几个核心问题有跳转、程序写入、APP地址偏移,其他的抢权或配置可以根据自身应用进行设计。
跳转 APP
jump_app 函数用于实现程序跳转功能,首先对APP数据进行了简单的判断,若程序文件出现明显错误则跳入死循环,防止程序跑飞。
跳转前需使用 __disable_irq();
关闭中断,防止主程序已经跳转APP,但是Bootloader中的中断触发,导致程序发生混乱。
#define ADDR_START 0x8020000
#define ADDR_END 0x803ffff
__asm void MSR_MSP(uint32_t addr)
{
MSR MSP, r0 //set Main Stack value
BX r14
}
void jump_app(void)
{
if((((*(uint32_t*)(ADDR_START+4))&0xFF000000)==0x08000000)
&&(((*(uint32_t*)ADDR_START)&0x2FFE00000)==0x20000000))
{
__disable_irq();
jump2app=(appfun)*(uint32_t*)(ADDR_START+4);
MSR_MSP(*(uint32_t*)ADDR_START);
jump2app();
}
else
{
for(;;);
}
}
APP 设计
APP程序在FLASH中的存储位置有偏移,在 main 函数一开始的位置需加入
SCB->VTOR=FLASH_BASE|0x20000;
因为 Bootloader 中需要在跳转前关闭中断,所以在应用程序中,完成初始化工作后需要重新打开中断(如果程序中使用的中断的话)。
__enable_irq();
在 Options for Target => Target => IROM1 处根据实际 FLASH 分配情况,修改地址
APP 应用程序在线调试
完成上面步骤,Bootloader 和 APP 已经可以正常工作,但是 APP 项目无法在线调试。下面需要配置仿真器程序偏移地址,实现在线调试。
在 Options for Target => Utilities => Settings,修改起始地址。
创建一个 ini 文件,内容为
SP = _RDWORD(0x08020000);
PC = _RDWORD(0x08020004);
在 Options for Target => Debug => Initialization File 中设置为该文件
问题排查
跳转后进入 HardFault_Handler(void)
Bootloader 中跳转前需要要使用 __disable_irq(); 否则在应用程序中,初始化完成前,Bootloader的中断触发会试图跳回到 Bootloader 中,触发 HadrFault。
应用程序中无法使用中断
在 Bootloader 中关闭中断后,在应用程序中需要重新开启才能使用中断。