1. STM32程序升级方法
1.1 ST-link / J-link下载
将编译生成的hex
文件使用ST-Link/J-Link工具直接下载进 Flash 即可。Keil中点击下载也能一键下载。下载后的代码会存放在Flash的起始地址0x0800 0000处。
简单补充一句,bin文件和hex文件的区别:
- bin文件不带地址信息,因此下载的时候需要指定下载地址。
- hex文件自带地址信息,直接点击下载自己会找到要下载到的地址(默认0x0800 0000)。
ST-LINK/J-LINK方式支持在线调试
1.2 ISP(In System Programing)
我们常见的一键下载电路就是用的这种方式。这个是利用了 STM32 自带的 Bootloader 升级程序。可以通过USB转串口,再通过ISP软件导入程序。
在用户参考手册中,可以看到下表,关于启动模式设置的。
ISP根据读取到的FLASH大小自动确定下载地址。
ST公司在系统存储器中存放了BootLoader引导程序,通过BootLoader引导程序可完成自启动,并通过向量表跳转至用户APP程序。一般可通过USART1、USART3、CAN2、USB对Flash重新编程。系统BootLoader的起始地址0x1FFF F000,进入系统自带的BootLoader后可利用STM32CubeProgrammer更新程序
不管通过何种方式,程序最后都是下载到主闪存存储器Flash里面的。
可以这么理解:芯片出厂时,系统存储器中已经存储了一段程序,这段程序的功能是将串口1(固定的)收到的数据,放到主闪存存储器(Flash)中,从0x0800 0000地址处开始。
1.3 IAP(In Application Programing)
IAP 和 ISP 其实基本上是一样的,都是通过串口接收程序,存放到FLASH中的某段地址。
ISP 是由厂商已经提供好的,因此接口固定(串口1);
IAP可以自定义使用任何接口接收应用程序。因为这一点,用户可以用多种方式更新程序。
1.3.1 正常程序运行流程
正常情况下,程序从Flash启动时的流程如下:
1. 程序从Flash启动,根据中断向量表找到复位中断处理函数的地址。(0x0800 0004处是中断向量表的起始地址,也是中断向量表的起始,记录了复位中断处理函数的地址)。
2. 执行复位中断处理函数,初始化系统环境后跳转到main函数。
3. 在main函数的死循环中运行,直到有中断发生。
4. 中断发生时,跳转到中断向量表起始处,根据中断信号源跳找到相应的中断处理函数。
5. 中断处理函数执行完后返回到main函数继续运行。
1.3.2 IAP时程序运行流程
引入IAP后的启动流程如下图所示。在Flash中存储了两套程序:
Bootloader程序:自举程序。负责接收数据(APP应用程序代码)并将其存储到Flash中。
APP应用程序:我们真正的应用程序。
- 程序从Flash启动,根据中断向量表找到复位中断处理函数的地址。
- 执行复位中断处理函数后,跳转到Bootloader的main函数。该函数检查并保存新的APP程序到Flash,然后跳转到第二套程序运行。
- 一旦进入新的APP程序,根据中断向量表找到复位中断处理函数,进入App程序的main函数运行。
- 为确保中断能正确跳转到APP程序的中断处理函数,需要在APP程序中修改中断向量表的偏移,确保中断发生时能正确执行APP程序的中断处理函数。
ISP | IAP |
---|---|
在系统存储器中存储了一套接收串口1数据的程序 | IAP是将Flash分成了两份,在第一份中存储了一套接收某个接口的程序 |
使用硬件BOOT引脚设置进行跳转 | 使用软件(直接修改PC指针)进行跳转 |
仅能使用芯片厂商设置好的接口(串口1) | 用户自定义,理论上只要能接收数据的接口都可以用 |
2. STM32 Bootloader实现
bootloader基本概念
首先贴上参考文献,这位老哥开源了自己测试的代码,大家可以直接下载,此处做个补充完善
STM32深入系列02——BootLoader分析与实现_stm32 bootloader-CSDN博客文章浏览阅读3.3k次,点赞34次,收藏96次。stm32 bootloader功能分析与实现_stm32 bootloaderhttps://blog.csdn.net/weixin_46253745/article/details/135321134先说BootLoader的思想,对于新手来讲认识的编译后的程序就是.HEX文件,常见做法就是各种下载器或者usb转串口用ISP程序进行烧录,但是企业场景不可能每个设备挨个拿串口去传输,我要远程升级怎么办?
答案就是.BIN文件和BOOTLOADER自举思路。
在 默认方式下,我们的嵌入式程序是以连续二进制的方式烧录到 STM32 的可寻址 Flash 区域上 的。如果我们用的 Flash 容量大到可以存储两个或多个的完整程序,在保证每个程序完整的情 况下,上电后的程序通过修改 MSP 的方式,就可以保证一个单片机上有多个有功能差异的嵌 入式软件,这就是我们要讲解的 IAP 的设计思路。
通常实现 IAP 功 能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目代码通过USB、USART等方式接收更新程序并执行更新,第二个项目代码执行用户真正的功能。
我们将第一个项目代码称之为 Bootloader程序,第二个项目代码称之为 APP程序,他们存放在 STM32F429 FLASH 的不同地址范围。
bootloader原理
我们知道的复位方式有三种:上电复位,硬件复位和软件复位。当产生复位,并且离开复位状态后,CM4 内核做的第一件事就是读取下列两个 32 位整数的值:
(1)从地址 0x0000 0000 处取出堆栈指针 MSP 的初始值,该值就是栈顶地址。
(2)从地址 0x0000 0004 处取出程序计数器指针 PC 的初始值,该值指向复位后执行的第 一条指令。下面用示意图表示,如图 9.1.1 所示。
上述过程中,内核是从 0x0000 0000 和 0x0000 0004 两个的地址获取堆栈指针 SP 和程序计数器指针 PC。事实上,0x0000 0000 和 0x0000 0004 两个的地址可以被重映射到其他的地址空间。
例如:我们将 0x0800 0000 映射到 0x0000 0000,即从内部 FLASH 启动,那么内核会从地址 0x0800 0000 处取出堆栈指针 MSP 的初始值,从地址 0x0800 0004 处取出程序计数器指针 PC 的初始值。CPU 会从 PC 寄存器指向的地址空间取出的第 1 条指令开始执行程序,就是开始执行复位中断服务程序 Reset_Handler。 将 0x0000 0000 和 0x0000 0004 两个的地址重映射到其他地址空间,就是启动模式选择。
理论上所有程序都是从虚拟地址0x0000 0000开始启动!!!所谓不同的启动模式就是将物理地址0x08000000/0x20000000/0x1FFFF000映射到了虚拟地址0x0000 0000!!!从而MSP取值和CP取值的地址不同!!
flash、sram等存储空间都被映射到4GB的虚拟地址上。
测试过程的碎碎念
注意,划分Flash的时候,注意App程序起始地址,根据芯片不同起始地址倍数关系也不同
STM32F1:地址必须是4的倍数,因为每次写入只能写入32位数据,即4个字节。
STM32F4:地址可以从任意地址开始,因为每次写入可以写入8位数据,每个地址就是1个字节。
STM32L4:地址必须是8的倍数,因为每次写入只能写入64位数据,即8个字节。
Stm32的flash都是从0x0800000开始的,结束地址看片子的flash大小
Stm32的sram都是从0x2000000开始的,结束地址看片子的sram大小
理论上我们只需要确保APP起始地址在Bootloader之后,并且偏移量为0X200的倍数即可(相关知识,请参考:NVIC的向量表偏移寄存器设置问题(已解决)-OpenEdv-开源电子网)
检查栈顶地址是否合法.0x20000000是sram的起始地址,也是程序的栈顶地址;
appxaddr存放的是用户程序Flash的首地址,(*(volatile u32*)appxaddr)的意思是取用户程序首地址里面的数据,这个数据就是用户代码的堆栈地址,堆栈地址指向RAM,而RAM的起始地址是0x20000000。
在保存了一个完整的 APP 到了对应的位置后,我们需要对栈顶进行检查操作,初步检查 程序设置正确再进行跳转。我们以 FlashAPP 为例,用 bin 文件查看工具(A 盘→6,软件资料 →1,软件→winhex),可以看到 bin 的内容默认为小端结构
中断向量表一个中断占4个字节,正好是一个指针的大小。