感谢关注!
本期话题
现在越来越多的嵌入式设备支持远程自动升级,不需要再借助下载器。这样对于设备的维护非常方便。
当然若使设备支持远程升级,需要编写支持升级的程序代码,可以称之为 BootLoader。
也就是说,将设备的程序代码分为两部分:BootLoader 和 APP。
BootLoader 负责升级 APP 以及引导APP运行。APP 负责实现设备的业务处理功能,也就是设备的核心功能代码。
对于Cortex-M 系列的单片机来说,若要实现 BootLoader 安全跳转到 APP,需要进行一些配置。
本文就以 STM32 单片机为例,来聊一聊实现 BootLoader 跳转的关键配置步骤。
聊一聊
在程序开发设计阶段,要根据具体应用情况,对程序存储的 Flash 进行分区。
即,BootLoader 存储的位置以及需要分配的空间大小,以及 APP 的存储的位置和大小。这个存储位置直接关系到程序的执行和跳转。
最简单的一种升级方案是:一个 BootLoader 和 一个 APP ,BootLoader 实现跳转和升级APP 的功能。本文以这个升级方案为例进行介绍。
对于 STM32 单片机来说,程序启动的映射地址为 0x8000000。
可以将 BootLoader 存储在 0x8000000 地址,分配的空间可以根据芯片具体的Flash大小进行调整。比如 0x10000,64K 字节。
APP 存储的地址,安排在 BootLoader 后边,即存储地址为 0x8010000,Flash 剩余的空间都可以分配给APP。
BootLoader 工程配置
BootLoader 的工程需要进行一些配置,以MDK为例,如下图所示,BootLoader 程序存放的 FLASH 地址为 0x8000000,大小为 0x10000。
在跳转APP的程序代码需要注意以下几点:
- 检查栈顶地址是否合法,也就是 APP 存放的起始地址是否合法,
if(((*(__IO uint32_t *)APP_FLASH_ADDR) & 0x2FFE0000) == 0x20000000)
- 屏蔽总中断,防止在程序跳转过程中,中断干扰出现异常
- 获取APP程序起始地址,代码区第二个字(起始地址+4 Flash 位置存储的数据)
- 初始化堆栈指针(用户代码区的第一个字用于存放栈顶地址)
- 利用 APP 起始地址,转化为函数指针类型,执行跳转
其具体的跳转代码如下:
/* 定义类型 */ typedef void (*pFunction)(void); /* APP flash address */ #define APP_FLASH_ADDR (0x8010000) void jump_to_app(void) { uint32_t JumpAddress; pFunction Jump_To_Application; /* 检查栈顶地址是否合法 */ if(((*(__IO uint32_t *)APP_FLASH_ADDR) & 0x2FFE0000) == 0x20000000) { /* 屏蔽所有中断,防止在跳转过程中,中断干扰出现异常 */ __disable_irq(); /* 用户代码区第二个 字 为程序开始地址(复位地址) */ JumpAddress = *(__IO uint32_t *) (APP_FLASH_ADDR + 4); /* Initialize user application's Stack Pointer */ /* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */ __set_MSP(*(__IO uint32_t *) APP_FLASH_ADDR); /* 类型转换 */ Jump_To_Application = (pFunction) JumpAddress; /* 跳转到 APP */ Jump_To_Application(); } }
APP 工程配置
APP 的工程需要进行一些配置,以MDK为例,如下图所示,APP 程序存放的 FLASH 地址为 0x8010000,大小为 0x30000。
APP程序代码需要进行如下配置:
- 修改APP 内部 Flash 向量表重定位
SCB->VTOR
- APP运行后,初始化函数中,开启中断,否则程序会运行异常
正常来说,在启动文件中执行调用 SystemInit()
函数,这个函数会配置 Flash 的接口信息。 SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET
。
修改宏定义 VECT_TAB_OFFSET
的值为 0x10000。
APP程序启动之后,需要先使能全局中断,可将下边的代码放在初始化的地方:
/* 使能中断 */
__enable_irq();
最后
设备运行期间,APP 在运行处理业务功能。如果要升级 APP ,需要从 APP 切换到 BootLoader 中。
那么如何实现 APP 跳转到 BootLoader 呢?有两种方法:
- 硬件方式,设备断电重启或复位按键
- 软件方式,通过软件控制复位MCU
软件方式,可以在APP代码中添加控制指令,当APP接收到跳转指令(或者升级指令)后,复位 MCU。如下代码可以复位MCU:
/* 复位芯片 */
HAL_NVIC_SystemReset();
好了,就这些内容。欢迎探讨交流。
感谢阅读,加油~