nucleo-f411re学习记录-14,OTA 固件升级-bootloader与app分区实现
2026/4/30 17:39:36 网站建设 项目流程

代码仓库
当设备需要升级时,若每次都需通过有线连接ST-Link烧录固件会非常不便。为解决这一问题,可引入类似手机系统升级的OTA技术。

OTA(Over-The-Air,空中下载)是通过无线网络(蓝牙/WiFi/4G等)远程更新设备软件的技术,无需拆机或接线即可完成固件升级。

由于程序运行时无法擦写自身所在的Flash区域,因此需要采用bootloader-app分区:

  • bootloader,因其位于首地址0x8000000,设备启动时首先运行,负责擦写app区域,完成擦写后跳转至app

  • app,实现所需功能,也负责接收升级数据包,然后将数据写入指定存储区域

完整的 OTA 升级流程

1.App 运行中 ↓ 收到升级包2.App 将新固件存入外部 Flash 或预留分区 ↓ 设置标志位,软复位3.Bootloader 启动 ↓ 检测到升级标志4.Bootloader 将新固件写入 App 区域 ↓ 校验文件,清除标志5.Bootloader 跳转到新 App ↓6.升级完成!

已完成bootloader与app的基础功能实现:当bootloader检测到app起始地址非0xFFFFFFFF数据时,即可执行跳转操作。

bootloader实现

起始地址设置,存放第0扇区,大小16KB,目前一个扇区大小即可。第1扇区留着后续实现更多功能在打开,app起始位置在第2扇区。

跳转函数。

// 函数指针类型定义typedefvoid(*pFunction)(void);// App 起始地址#defineAPP_START_ADDR0x8008000voidJumpToApp(void){// 1. 检查栈顶地址是否合法(防止跳转到空地址)if((*(__IOuint32_t*)APP_START_ADDR)==0xFFFFFFFF){// 地址为空,不跳转return;}// 2. 关闭所有外设中断__disable_irq();// 3. 关闭 SysTick 中断,清零计数器SysTick->CTRL=0;SysTick->LOAD=0;SysTick->VAL=0;// 4. 复位所有外设时钟,如串口之类// 注意:不要复位调试相关的外设,否则 ST-LINK 会断连// 5. 设置主堆栈指针 (MSP) 为 App 的第一个字__set_MSP(*(__IOuint32_t*)APP_START_ADDR);// 6. 获取 App 的复位向量地址(App 起始地址 + 4 字节偏移)uint32_tjumpAddr=*(__IOuint32_t*)(APP_START_ADDR+4);pFunction JumpToApplication=(pFunction)jumpAddr;// 7. 重新使能中断__enable_irq();// 8. 跳转到 AppJumpToApplication();// 9. 理论上不会执行到这里while(1);}intmain(void){/* SysTick end of count event each 10ms */RCC_GetClocksFreq(&RCC_Clocks);SysTick_Config(RCC_Clocks.HCLK_Frequency/100);/* Add your application code here *//* Insert 50 ms delay */Delay(5);JumpToApp();/* Infinite loop */while(1);}

app实现

起始地址设置,存放在第2扇区,大小规划为第2+3+4扇区即16+16+64 = 128KB。

app的代码按照之前实现的即可,在main()中小小修改即可。

#defineAPP_START_ADDR0x8008000intmain(void){// 设置中断向量表偏移到 App 起始地址SCB->VTOR=APP_START_ADDR;// 设置优先级分组为2NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 配置蓝牙串口中断优先级NVIC_BT_Configuration();// 配置WIFI串口中断优先级NVIC_WIFI_Configuration();// 所有外设初始化All_Peripherals_Init();// 创建任务All_Task_Create();// 启动调度器vTaskStartScheduler();/* Infinite loop */while(1);}

如果没有SCB->VTOR = APP_START_ADDR;也能跳转到app,只是会一直重启。原因就是中断发生时,CPU 仍去 0x8000000 找中断向量,而那里是 Bootloader 的向量表,导致程序跑飞重启,若是app中不使用中断,就不会重启。但是用FreeRTOS不可避免使用#define xPortSysTickHandler SysTick_Handler,得使用滴答定时中断。

建议使用STM32CubeProgrammer官方工具进行固件烧录。该工具功能强大,支持指定地址擦除和烧录操作,能够精准烧录bootloader和app固件。若将bootloader与app固件合并为单一文件,则可实现一次性烧录。
官方工具地址

根据所需下载,注意需要个账号

工具配置,使用ST-Link,SWD

点击Connect之后,就可以对扇区进行擦除,与下载了。

尝试对扇区进行擦除

读取扇区数据,可以看到已经擦除成功,存储数据全为0xFF。

1,分别对bootloader与app烧录
单下载boot
查看地址数据,与bin文件数据一样。

单下载app,因为是烧录boot之后再烧录app,发现程序已经跑起来了,哪怕没有勾选Run after programming

串口打印数据正常,没有重启

Serial communication is normal Free heap before any task:0bytes After Key_Task:40584bytes After Feeddog_Task:40352bytes

2,若是对bootloader与app合并后下载就需要借助合并工具先合并。使用binJoin.exe工具

binJoin.exe boot.bin0x8000000app.bin0x8008000boot_app.bin

之后对boot_app.bin在地址0x8000000出烧录即可。

因为没有勾选Run after programming,需要手动按下复位键启动。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询