IAP-Bootloader:基于STM32F407 STM32CubeMX的按钮式Bootloader程序与APP程序切换
一、前言
1.1、IAP与ISP
bootloader一般分为两种:
1、ISP – 使用ST芯片自带的bootloader程序实现APP程序的刷写,其优势是简单,可靠。
2、IAP – 自己编写一个bootlader实现APP程序的刷写,其优势是自定义,灵活性强。可以通过任意的通讯接口实现远程升级。
ISP的bootloader实战,可以参考之前我的以下文章:
bootloader | 基于STM32F407 – 使用STM32Cubeprogrammer的USB DFU进行固件烧写
bootloader | 基于STM32F407 – 使用STM32Cubeprogrammer的UART进行固件烧写
在学习IAP时,找到一些不错的资料:
【实战技能】单片机bootloader的CANFD,I2C,SPI和串口方式更新APP视频教程(2022-08-01)
BSP视频教程第17期:单片机bootloader专题,启动,跳转配置和调试下载的各种用法(2022-06-10)
【不是问题的问题】为什么STM32的Flash地址要设置到0x08000000
下面文章是初学IAP的重点,文章是基于标准库解决问题,在HAL库上原理一样,只是处理方法改一下。(HAL库没有函数NVIC_SetVectorTable)
从启动程序(BootLoader)跳转到指定地址时(APP)出现问题的解决方法
文章后见会介绍如何在HAL库上处理这个问题(system_stm32f4xx.c文件),毕竟现在使用标准库的人比较少,且ST官方也不建议使用标准库了。
IAP的难点在于Bootloader跳转APP,有如下几点需要弄明白的:
1.2、本次实验的目的
将自己编写的bootloader程序烧写进STM32芯片的FLASH地址0x08000000的起始位置,接着将APP程序烧写进STM32芯片的FLASH地址0x08010000起始的地址。

一共有两个程序,APP与BOOT(bootloader程序)。

学会bootloader与APP程序互相跳转的程序后,接着可以使用串口,CAN,SPI,I2C,网口等通讯接口升级APP程序了。
工程分享:
链接:https://pan.baidu.com/s/1ZeSxh10BbqqPjarWMkDbfQ?pwd=f2zz
提取码:f2zz
二、STM32CubeMX
STM32CubeMX配置初始的工程的步骤我就省去了,本例程只使用了简单的GPIO输出与GPIO读取,并没有复杂的外设。将百度云盘分享的工程下载下来直接查看配置即可。
三、MDK的设置
3.1、Bootloader工程
Flash起始地址: 0x8000000,其大小是0x10000(65536/1024 = 64K)
最后修改下载算法,将BOOT程序的下载地址限制在0x08000000 – 0x0800FFFF
3.2、APP工程
最后修改下载算法,将BOOT程序的下载地址限制在0x08010000 – 0x0803FFFF
四、代码
4.1、Bootloader工程
4.1.1、main.c
函数JumpToBootloader()是从安富莱那里直接拷贝过来使用的,比其他嵌入式厂家要专业。
我的APP程序是从FLASH内存的0x08010000开始,这个按照自己的内存分配修改一下即可。
4.1.2、system_stm32f4xx.c
这里非常重要!这里非常重要!这里非常重要!重要的事情说三遍!!!!!!
这个代码就是修改程序的中断向量表从内存FLASH哪里取出来,并初始化。bootloader程序的中断向量表在0x08000004里。后面会介绍为什么我知道bootloader程序的中断向量表是在内存0x08000004里边。
编译一下工程:
4.2、APP工程
4.2.1、main.c
4.2.2、system_stm32f4xx.c
编译一下工程:
五、map文件确认程序flash的位置与中断向量表的位置
Keil工程的map文件如何打开,可以参考:
Keil | 解决Keil双击工程名无法打开.map的问题
5.1、Bootloader工程的map文件
5.1.1、确认flash的位置
5.1.2、确认中断向量表的位置
5.2、APP工程
5.2.1、确认flash的位置
5.2.2、确认中断向量表的位置
从两个工程的.map文件看来,flash与中断向量表的设置都是在预期。
六、下载两个程序到板子上
直接用MDK把两个工程都烧写进去,两个工程的FLASH地址设置不一样,所以不会互相影响。
下载bootloader程序。
下载APP程序。
七、观察板子
下载完两个程序进去后,板子重新上电。
首先,LED1在闪烁,LED2与LED3都是熄灭。表示正在运行bootlader程序。接着,按下KEY1。
按下KEY1后,LED1与LED2在闪烁,LED3常亮,表示此时正在运行的是APP程序。
当我们按下KEY2后,LED1在闪烁,LED2与LED3都是熄灭的。表示此时又返回运行bootlader程序了。
至此,实验成功!!!!
八、细节补充
8.1、为什么需要修改system_stm32f4xx.c的代码?
原因是程序跳转之后,还需要另外告诉程序中断向量表也需要跳转。比如bootloader跳转APP程序后,此时的中断向量表也需要指向APP程序的中断向量表,否则无法产生中断。
bootloader程序与APP程序都有自己的中断向量表。
修改system_stm32f4xx.c就是为了达到这个目的。实际上,从system_stm32f4xx.c上看,HAL也准备好了代码给我实现中断向量表的重新设置。
看下面代码:
VECT_TAB_BASE_ADDRESS被谁调用?往下看。
VECT_TAB_BASE_ADDRESS被函数SystemInit()调用了。
OK…那谁调用了函数SystemInit()?从下图看到,从STM32F407的启动文件找到,Reset_handler中断回调调用了SyetemInit( ),接着进入main()函数开始运行。
梳理完了,大概是这样的。。
8.2、不修改system_stm32f4xx.c的代码可以吗?
当然可以啊,我们修改system_stm32f4xx.c就是为了运行这个代码:
那么,我们在main()函数写入这个代码也可以的,如下图所示:
bootloader工程:
APP工程: