程序运行流程
正常程序运行流程
程序结构
- 正常程序从起始地址(0x08000000)开始写入
- 中断向量表(地址:0x08000004)用于存储中断处理程序向量。
- 中断处理函数(0x08000004+n)用于各种中断服务函数。
- main函数(0x08000004+N),一个死循环,存放用户处理程序
程序启动流程
- 系统复位启动,从中断向量表中取出复位中断向量
- 跳转到复位中断处理函数,执行复位中断函数完成启动,跳转到main函数入口。
- 执行main函数循环。
- 中断产生,STM32硬件强制将PC指针指向中断向量表
- 根据中断源选择相应中断处理函数向量
- 跳转到对应中断处理函数,处理中断。
- 中断函数结束,PC指针跳回main函数执行
含bootloader程序运行流程
程序结构
- 正常程序从起始地址(0x08000000)开始写入
- 中断向量表(地址:0x08000004)用于存储中断处理程序向量。
- 中断处理函数(0x08000004+n)用于各种中断服务函数。
- IAP main函数(0x08000004+N),一个死循环,存放用户处理程序
- APP 中断向量表(地址:0x08000004+N+M)用于存储中断处理程序向量。
- APP main函数(0x08000004+N+M+n),一个死循环,存放用户处理程序
含bootloader程序启动流程
- 系统复位启动,从中断向量表中取出复位中断向量
- 跳转到复位中断处理函数,执行复位中断函数完成启动,跳转到main函数入口。
- 执行bootloader main函数,此时bootloader main函数内部有APP下载程序和跳转程序,执行跳转程序后会跳转到新程序的中断向量表,得到app程序的复位中断向量。
- 跳转到APP复位中断处理函数,执行复位中断函数完成启动,跳转到APP main函数入口。
- 中断产生,STM32硬件强制将PC指针指向Bootloader中断向量表
- 程序再根据我们设置的中断向量表偏移量,得到对应中断源新的中断服务程序向量
- 跳转到对应中断处理函数,处理中断。
- 中断函数结束,PC指针跳回main函数执行
程序编程重点
存储分区
常见分区方案
无备份区升级
bootloader区 + APP code区
- 升级流程:bootloader接收升级app,校验无误后写入APP code区,随后跳转到app
- 优缺点:优点是APP code区体积大,支持较大APP升级。缺点:没有备份代码,升级过程中出错,升级失败,原有代码也会被破坏。
有备份区升级
bootloader区 + APP code区 + Updata区
- 升级流程:APP code中接受升级APP,存放至updata区,校验无误后写入标志位,复位重启进入bootloader,bootloader将updata区代码复制到app区域,随后跳转至App code区。
- 优缺点:优点:始终保持至少有一份代码可以运行,即使升级过程中程序中断,设备不会崩溃。缺点:bootloader程序执行周期长,升级比较慢。程序无法回退版本。
AB对称升级
Bootloader区 + APP code_A区 + APP code_B区
- 升级流程:AB区地位等同,A区执行时接收升级代码到B区,重启后跳转到B区执行代码,再次升级时接收升级代码到A区,复位重启后跳转到A区执行。
- 优缺点:优点:代码可回退版本,升级过程中出现意外不影响原代码执行。缺点:分区多,APP空间小,限制了代码量。
有工厂代码区升级
bootloader区 + Factory code区 + APP_A区 + APP_B区
- Factory区用于存储出厂程序,AB分区对称升级。此外APP内有回复出厂设置选项,可以恢复出厂程序。
- 常见于智能物联网设备,ESP32中有此功能
TC397 SOTA
与其他OTA不同,TC397有硬件OTA方案,TC397内部flash有六块flash,两种地址映射方式。正常地址映射编址:PF0 1 2 3 4 5 ,除此之外还有一种编制方式PF2 3 0 1 5 4 。正常代码存储在0 1存储块中,程序中可把升级代码存储到2 3块中,然后切换编制方式,下次复位运行,程序直接会从2 3 代码块执行。升级方案更简单
Bootloader
升级判断处理
程序跳转函数
此处用到了函数指针的知识,关于函数指针可以搜索一下:函数指针与指针函数区别和用法。函数指针本质上是指向函数的指针,用于调用函数。
typedef void (*iapfun)(void); //定义一个函数类型参数
iapfun jump2app; //
void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法
{
jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址
MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针
jump2app(); //跳转到APP
}
}
APP
APP程序为最终执行的用户程序。
程序存储地址
- IROM1 Start: 代码起始地址
- IROM1 Size:代码存储区大小
注意:APP code大小应小于size,一般放在bootloader后面,且地址便宜为0x200倍数。
设置程序中断向量表偏移
在SystemInit 函数中有代码如下:
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
其中VTOR寄存器存放中断向量表起始地址,默认VECT_TAB_SRAM 没有定义,所以SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET 生效。VECT_TAB_OFFSET 即为中断向量表偏移量,我们只需修改VECT_TAB_OFFSET 即可使中断向量地址偏移。例如:
SCB->VTOR = FLASH_BASE | 0x10000; //设置中断向量表偏移0x10000
|