STM32 OTA升级原理分析

  • 程序运行流程
  • 正常程序运行流程
  • 程序结构
  • 程序启动流程
  • 含bootloader程序运行流程
  • 程序结构
  • 含bootloader程序启动流程
  • 程序编程重点
  • 存储分区
  • 常见分区方案
  • 无备份区升级
  • 有备份区升级
  • AB对称升级
  • 有工厂代码区升级
  • TC397 SOTA
  • Bootloader
  • 升级判断处理
  • 程序跳转函数
  • APP
  • 程序存储地址
  • 设置程序中断向量表偏移


程序运行流程

正常程序运行流程

stm32 基于Ymodem IIC升级_main函数

程序结构

  • 正常程序从起始地址(0x08000000)开始写入
  • 中断向量表(地址:0x08000004)用于存储中断处理程序向量。
  • 中断处理函数(0x08000004+n)用于各种中断服务函数。
  • main函数(0x08000004+N),一个死循环,存放用户处理程序

程序启动流程

  • 系统复位启动,从中断向量表中取出复位中断向量
  • 跳转到复位中断处理函数,执行复位中断函数完成启动,跳转到main函数入口。
  • 执行main函数循环。
  • 中断产生,STM32硬件强制将PC指针指向中断向量表
  • 根据中断源选择相应中断处理函数向量
  • 跳转到对应中断处理函数,处理中断。
  • 中断函数结束,PC指针跳回main函数执行

含bootloader程序运行流程

stm32 基于Ymodem IIC升级_main函数_02

程序结构

  • 正常程序从起始地址(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程序为最终执行的用户程序。

程序存储地址

stm32 基于Ymodem IIC升级_stm32_03

  • 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