STM32+Bootloader 通过射频\串口进行程序的远程升级 in-application programming (IAP)
程序可通过外部boot0,boot1引脚指定运行起始地址是sram或flash,以下为通用的flash起始运行( Vector Table Relocation in Internal FLASH)
设计:1、程序复位后从app开始运行;2、接收并存储升级文件;3、跳转至bootloader运行,处理升级文件;4、软件或硬件复位
设计也可将bootloader放在app前,每次重启后先运行bootloader去检测是否有升级文件,若有则升级,若没有则跳转到app区域运行。在app若收到升级文件,完成存储校验后重启设备即可到bootloader进行升级。
1、内部flash区域规划
/* (0x800 0000 ~ 0x800 efff) 60k */
#define AppAddress (FLASH_BASE) /* 0x8000000 */
#define AppCodePageSize (0x1e) /* 用户代码APP区域 */
#define AppCodeSize (AppCodePageSize * FLASH_PAGE_SIZE)
/* (0x800 f000 ~ 0x801 2fff) 16k */
#define BootAddress (AppAddress + AppCodeSize)
#define BootPageSize (0x08) /* 8页的空间来存放Boot (16k) */
#define BootSize (BootPageSize * FLASH_PAGE_SIZE)
/* (0x801 3000 ~ 0x802 23ff) 62k */
#define AppImageAddress (BootAddress + BootSize)
#define AppImagePageSize (0x1f) /* 镜像区 存放远程升级文件 */
#define AppImageSize (AppImagePageSize * FLASH_PAGE_SIZE)
#define AppImageStartAddress (AppImageAddress + FLASH_PAGE_SIZE) /* 升级文件除去标志后存放的具体位置 */
程序需在指定的flash地址运行,stm32起始地址0x08000000+VECT_TAB_OFFSET(SCB->VTOR),这就需考虑flash的规划问题,简单地说,就是把片内flash进行分区域,每个区域规划存储什么数据的过程。以上app的SCB->VTOR = 0;bootloader的SCB->VTOR = 0xF000(0x1e * 2k = 60k);即app程序最大设计为60k,bootloader最大设计为16k,接收的升级文件最大也为60k。
图:bootloader向量表偏移设置
图:iar调试烧写设置
程序复位时,运行地址-->0x08000000
2、通过射频或串口接收升级文件保存至flash规划的AppImageAddress地址下。
3、接收完成后条用跳转至bootloader。
void System_JumpToBootLoader(void)
{
Bsp_DeInit();
uint32_t JumpAddress = 0;
pFunction Jump_To_BootLoader;
/* Test if user code is programmed starting from address "BOOTLOADER_ADDRESS" */
if(((*(__IO uint32_t*)BootAddress) & 0x2FFE0000) == 0x20000000) // DCD sfe(CSTACK) ; AppAddress
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (BootAddress + 4);
Jump_To_BootLoader = (pFunction) JumpAddress; // DCD Reset_Handler ; AppAddress + 4
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) BootAddress);
Jump_To_BootLoader();
}
}
在bootloader中处理校验
void UD_CheckAndUpdata(void)
{
if(!UD_CheckHead()) // 检测flash内是否有升级文件,一些标志,文件大小验证
{
return;
}
UD_EraseUserApp(); // 以上验证通过,开始擦除app应用数据,擦除AppAddress共60k
UD_UpDataUserApp();// 将升级文件写入至app地址,从AppImageStartAddress开始搬移数据至AppAddress
UD_EraseImageApp(); // 擦除升级文件AppImageAddress
}
4、重启设备,程序再次运行-->0x08000000,即运行升级后的程序。
升级过程遇到的问题:
1、bootloader没有进行喂狗,导致操作flash过程中出现异常死机
2、跳转bootloader之前,内部时钟,中断标志等没有清除,跳转到bootloader后,跳到了中断中,导致程序死机。
3、跳转之前,在没有先关闭时钟的情况下,关闭了外部高速晶振,导致异常死机