STM32的在线升级(IAP)实现方法:BOOT+APP原理详解

0 工具准备

Keil uVision5

Cortex M3权威指南(中文)

STM32参考手册

1 在线升级(IAP)设计思路

为了实现STM32的在线升级(IAP)功能,通常会将STM32的FLASH划分为BOOT和APP两个部分,BOOT就是引导APP的引导程序,当我们需要在线升级时就可以通过BOOT来实现。BOOT和APP在FLASH中的分布如下:

原理分析:

(1)当STM32复位后会跳转到FLASH首地址,也就是0x08000000 的位置,读取1-4Byte获取主堆栈指针初始值(栈顶值)并设置,然后读取5-8Byte获取复位中断服务函数入口地址并执行,进入BOOT程序

(2)BOOT程序根据用户选择升级APP或者跳转到APP

(2.1)如果用户选择升级APP则擦除APP所在扇区,按照一定协议将APP程序复制到FLASH的APP扇区

(2.2)如果用户选择跳转到APP,首先关闭全局中断及清除中断挂起标志,设置主堆栈指针,跳转到APP的复位中断服务函数**(相当于做了(1)中内核干的事情)**

2 BOOT设计

这里介绍一下BOOT跳转到APP函数的设计思路:

c 复制代码
void Jump_to_APP(void)
{
		uint32_t i=0;
		void (*SysMemBootJump)(void);

		/* 关闭全局中断 */
		__disable_irq();
		

		/* 关闭滴答定时器,复位到默认值 */
		SysTick->CTRL = 0;
		SysTick->LOAD = 0;
		SysTick->VAL = 0;

		/* 设置所有时钟到默认状态,使用HSI时钟 */
		RCC_DeInit();

		/* 关闭所有中断,清除所有中断挂起标志 */
		for (i = 0; i < 8; i++)
		{
				NVIC->ICER[i]=0xFFFFFFFF;
				NVIC->ICPR[i]=0xFFFFFFFF;
		}

		/* 使能全局中断 */
		__enable_irq();

		/* 跳转到系统BootLoader,首地址是MSP,地址+4是复位中断服务程序地址 */
		SysMemBootJump = (void (*)(void)) (*((uint32_t *) (FLASH_APP_ADDR + 4)));

		/* 设置主堆栈指针 */
		__set_MSP(*(uint32_t *)FLASH_APP_ADDR);

		
		/* 跳转到APP */
		SysMemBootJump();

		/* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
		while (1)
		{
			
		}
}

相关知识:

(1)涉及到的NVIC寄存器

(1.1)NVIC->ICER,中断失能寄存器,写入1失能中断

(1.2)NVIC->ICPR,中断挂起清除寄存器,写入1清除中断挂起

(2)APP二进制文件含义
bin文件:

Byte1-4:0x20014168

Byte5-8:0x080101A1

Byte9-12:0x08012D75

Byte13-16:0x08012851
map文件:

__initial_sp 0x20014168 Data 0 startup_stm32f40xx.o(STACK)

Reset_Handler 0x080101a1 Thumb Code 8 startup_stm32f40xx.o(.text)

NMI_Handler 0x08012d75 Thumb Code 2 stm32f4xx_it.o(i.NMI_Handler)

HardFault_Handler 0x08012851 Thumb Code 8 stm32f4xx_it.o(i.HardFault_Handler)
可以看到,APP工程的bin文件含义如下:

Byte1-4:0x20014168 主堆栈指针初始值(栈顶值)

Byte5-8:0x080101A1 复位中断服务函数地址

Byte9-12:0x08012D75 NMI中断服务函数地址

Byte13-16:0x08012851 HardFault中断服务函数地址

该部分的定义在STM32的参考手册上也可以看到:

其实,我们只需要关注主堆栈指针初始值(栈顶值)和复位中断服务函数地址即可。如果想要了解APP前几个byte的全部内容,可以参看STM32参考手册的"STM32F405xx/07xx 和 STM32F415xx/17xx 的向量表"。

弄清楚了上述的寄存器使用方法和APP的bin文件内容后,接下来BOOT中跳转到APP的操作原理就一目了然了:

(1)关闭全局中断,避免被打断

(2)关闭滴答定时器,复位到默认值,为后面的APP营造一个纯净的环境

(3)设置所有时钟到默认状态,为后面APP营造一个纯净的环境

(4)关闭所有中断同时清除所有中断挂起标志,避免APP使能中断后异常触发等情况

(5)使能全局中断,避免APP部分没有打开全局中断

(6)函数指针指向APP的复位中断服务函数(也就是APP的第5-8Byte)

(7)设置主堆栈指针(也就是APP的前4Byte)

(8)跳转到APP

以上有2个地方需要特别注意:

(1)APP的复位中断服务函数地址是APP的第5-8Byte

(2)APP的主堆栈指针初始值(栈顶值)是APP的前4Byte

3 APP设计

APP设计时只需要修改工程的flash起始地址以及中断向量偏移地址寄存器即可。

(1)修改FLASH起始地址

如果我们的APP存放在FLASH的0x8010000开始的位置,则将FLASHA的起始地址修改为0x8010000即可。

(2)修改中断向量偏移地址

BOOT下我们的中断向量偏移地址为0x08000000和默认值一样无须特别设置,APP下由于FLASH起始地址被修改到0x8010000,因此需要将中断向量偏移地址设置为0x1000:

c 复制代码
#define VECT_TAB_OFFSET  0x10000

相关寄存器如下:

当STM32发生了中断需要响应时,内核会根据向量表偏移量寄存器的值在相应的FLASH空间找到异常服务函数入口地址(中断服务函数入口地址保存工作由编译器完成 )。上电后的向量表如下:

假设我们设置的VTOR的值为0x8010000,在发生了硬错误时,会跳转到0x8010000+0x0000000C的位置找到硬错误中断服务函数地址并执行。这也是我们为什么需要在APP中设置VTOR的原因(BOOT里已经默认设置为0x0x8000000),保证我们的中断能够正确执行。

4 总结

(1)APP程序需要修改FLASH起始地址和向量表偏移量寄存器,以便内核能够在中断发生时进入正确的中断服务函数

(2)BOOT程序跳转到APP的过程实际上就是模拟内核的操作

(3)BOOT跳转到APP之前一定要失能所有中断、清除所有中断挂起标志,营造一个纯净的环境

相关推荐
Lay_鑫辰6 小时前
西门子诊断-状态和错误位(“轴”工艺对象 V1...3)
服务器·网络·单片机·嵌入式硬件·自动化
无垠的广袤9 小时前
【工业树莓派 CM0 NANO 单板计算机】本地部署 EMQX
linux·python·嵌入式硬件·物联网·树莓派·emqx·工业物联网
雲烟11 小时前
嵌入式设备EMC安规检测参考
网络·单片机·嵌入式硬件
泽虞11 小时前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
田甲11 小时前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
up向上up12 小时前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
纳祥科技21 小时前
Switch快充方案,内置GaN,集成了多个独立芯片
单片机
单片机日志1 天前
【单片机毕业设计】【mcugc-mcu826】基于单片机的智能风扇系统设计
stm32·单片机·嵌入式硬件·毕业设计·智能家居·课程设计·电子信息
松涛和鸣1 天前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法
小曹要微笑1 天前
STM32F7 时钟树简讲(快速入门)
c语言·stm32·单片机·嵌入式硬件·算法