前言
大家知道,STM32单片机有一块系统存储器(System Memory),存储的是芯片自带的BootLoader启动程序,可通过串口或USB口等来升级程序。但是要运行自带的BootLoader,需要设置BOOT0和BOOT1引脚的电平(有些型号是通过选项字节设置BOOT1)。之前的文章中介绍过通过硬件的方式来实现设置BOOT引脚电平和复位《STM32固件IAP程序实现》。这种电路只支持串口方式,其它接口的方式还需要自己设计硬件电路来设置BOOT引脚。
有时候受产品的外观或尺寸等限制,不允许额外的电路来实现BOOT引脚电平的设置,但又不想自己编写IAP程序,这时可以通过软件调用芯片自带BootLoader的方式来实现。
可行性
首先,STM32是支持通过软件来调用芯片自带BootLoader的,在官方提供的文档AN2606《STM32 microcontroller system memory boot mode》4.1节中有这样一段介绍:
也就是说,在跳转到芯片自带BootLoader程序之前,需要执行以下操作:
1)关闭所有外设的时钟
2) 关闭使用的PLL
3) 禁用所有中断
4) 清除所有挂起的中断标志位
以上操作执行完毕后,直接使用跳转指令,跳转到System Memory地址即可。System Memory 的地址可以在数据手册中找到,下面是F407的地址:
程序设计
跳转程序代码如下(代码参考安富莱开发板中程序),注释比较详细,直接看就行。
-
static void JumpToBootloader(void)
-
{
-
uint32_t i=
0;
-
void (*SysMemBootJump)(
void);
/* 声明一个函数指针 */
-
__IO
uint32_t BootAddr =
0x1FFF0000;
/* F407系统BootLoader地址 */
-
/* 关闭全局中断 */
-
DISABLE_INT();
-
/* 关闭滴答定时器,复位到默认值 */
-
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_INT();
-
/* 跳转到系统BootLoader,首地址是MSP,地址+4是复位中断服务程序地址 */
-
SysMemBootJump = (
void (*)(
void)) (*((
uint32_t *) (BootAddr +
4)));
-
/* 设置主堆栈指针 */
-
__set_MSP(*(
uint32_t *)BootAddr);
-
/* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
-
__set_CONTROL(
0);
-
/* 跳转到系统BootLoader */
-
SysMemBootJump();
-
/* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
-
while (
1)
-
{
-
}
-
}
另外一种方法
有些朋友可能觉得关闭外设时钟、中断等操作太复杂,可能会出错。这时也可以通过另外一种方式来实现上述操作:即软件复位。
芯片复位后,外设时钟、中断等默认都是关闭的,只需要在初始化前完成跳转即可。我们知道,stm32在运行main.c函数之前会先执行system_stm32f4xx.c 中的SystemInit 函数,在标准库中该函数的功能是初始化时钟等,因此我们需要在该函数开始时添加跳转代码。而在HAL库中,该函数只是配置了中断向量,因此可以直接在main.c函数的开始添加跳转代码。跳转代码可参考上面的程序。具体流程如下:
需要升级时,首先在flash某个地址将一个标志位置1;
产生软件复位;
判断标志位为1,需要升级,标志位清零,执行跳转程序。
标志位为0,直接运行程序。
测试
跳转成功后,使用STM32CubeProgrammer即可升级程序。选择接口,点击连接(下图已经连接成功),然后选择程序文件烧录即可。
推荐阅读:
欢迎关注公众号"嵌入式技术开发",大家可以后台给我留言沟通交流。如果觉得该公众号对你有所帮助,也欢迎推荐分享给其他人。
转载:https://blog.csdn.net/zhang062061/article/details/115744216