首先要先明白几个知识点:
- STM32 的 Flash 存储为小端模式,即低位在前高位在后;
- STM32 的 Flash 地址是以 0x08000000 为起始位置,以字节为单位,依次递增;
- STM32 写 Flash 的库函数中最小的写长度是半字(2 字节),即当需要连续地址写入时,写一次,地址加 2 ;
IAP 的组成框架
- 上位机:即可以存储新版固件并与主板通信的一端,通常为移动端或 PC 端软件;
- 下位机:即我们设计的主板;
- APP:即下位机的主要应用程序,实现所有设计的功能;
- Bootloader:即下位机中用于升级 APP 的应用程序,通常放在 Flash 的起始位置。
IAP 的大致流程
我采用的大致方案是:
- APP 收到上位机发来的升级指令后,将升级标志写入 Flash ,然后调用软件重启函数,进行重启;
- 重启后,STM32 先进入 Bootloader ,Bootloader 检查升级标志是否置位,如果未置位,则跳转到 APP 中,相反,则停留在 Bootloader 中;
- Bootloader 初始化后发送准备完毕命令至上位机,上位机受到后将固件数据拆分成数据帧,依次发送给 STM32 ,每发送一帧需要等待 STM32 应答无误后,继续发送下一帧;
- STM32 收到数据帧时,先保存在数组中,然后发送应答给上位机,待接收的数据长度为一页或多页时,将数据一起写入Flash ;
- 上位机发送完所有数据后,发送结束命令,STM32 收到后,将所有未写入的数据全部写完,将固件版本号写入 Flash 中,复位升级标志,检查 APP 程序区起始数据无误后,发送升级完毕应答给上位机,接着调用软件重启函数,重进 Bootloader ;
- 重进 Bootloader 后,Bootloader 检查升级标志为复位状态时,跳转到 APP 中执行 APP 程序,至此,所有升级过程全部结束。
IAP 中 Bootloader 和 APP 的相互跳转
一般方案都是利用程序地址直接跳转执行,
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
#define ApplicationAddress 0x08005000
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
{
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}
但是这样有风险,只要你还有中断可以进行,那么你的跳转将会导致 HardFault ,几经波折之后,我想到了一个新思路:软件重启 。
利用 STM32 官方库中的函数
NVIC_SystemReset()
直接重启重进 Bootloader 。如果你没在 core_cm3.h 中找到这个函数,那么说明你的库太旧了,去 ST 官网下载最新的库吧。
本文为原创文章,转载请注明出处: https://www.liuguogy.com/archives/stm32-iap.html