前言
大家知道,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即可升级程序。选择接口,点击连接(下图已经连接成功),然后选择程序文件烧录即可。
暂无评论