STM32双区IAP在线升级实现详解

张开发
2026/5/8 3:52:51 15 分钟阅读

分享文章

STM32双区IAP在线升级实现详解
1. 嵌入式系统在线升级IAP技术实现详解在工业控制、物联网终端、智能仪表等长期部署的嵌入式设备中程序更新需求日益频繁。现场更换硬件或返厂升级已无法满足快速迭代与远程维护的要求。在线升级In-Application Programming, IAP技术成为保障设备持续可用性与功能演进的核心能力。本文以STM32F103RB为硬件平台完整阐述一种基于双应用区App1 App2与BootLoader协同工作的可靠IAP方案。该方案不依赖外部调试器仅通过串口即可完成固件安全更新具备分区管理、校验保护、向量表重映射及异常回滚等工程级特性。1.1 系统设计目标与约束条件本方案面向资源受限的Cortex-M3内核MCU需在128KB片内Flash共128页每页1KB约束下达成以下目标零外部依赖升级过程不中断设备主功能无需JTAG/SWD调试接口参与断电安全升级过程中意外掉电后系统仍能从已验证的旧版本启动版本可控支持运行时识别当前固件版本并在升级失败时自动回退协议可扩展底层升级逻辑与传输协议解耦便于后续替换为Wi-Fi、BLE或LoRa等无线通道内存隔离BootLoader、App1、App2三者代码空间严格分离互不覆盖。上述目标决定了必须采用“引导程序双应用区”的经典架构而非单区覆盖式升级。其本质是将Flash划分为功能明确的物理区域通过运行时跳转与数据搬运实现新旧固件的原子切换。2. Flash存储分区规划与地址映射STM32F103RB的主Flash地址空间为0x08000000 ~ 0x0801FFFF128KB。为支撑IAP机制需对该空间进行静态划分。本方案采用三级分区策略各区域起始地址、大小及用途如下表所示分区名称起始地址大小页范围主要用途BootLoader区0x0800000020KB第0~19页存放引导程序永不更新App1区0x0800500056KB第20~75页当前运行的应用程序主区App2区0x0801400044KB第76~127页升级包暂存区备份区注20KB BootLoader预留空间已充分考虑未来功能扩展如USB DFU、加密校验等实际初始BootLoader代码仅占用约8KB。该划分遵循三项工程原则BootLoader不可覆盖性将其置于Flash起始位置Keil默认链接脚本即从0x08000000开始加载避免因配置失误导致引导代码被擦除App1与App2容量非对称设计App1作为主运行区需容纳完整业务逻辑故分配更大空间App2仅用于暂存待升级的bin文件按典型固件尺寸≤40KB预留页对齐擦除所有分区边界严格对齐1KB页边界0x08005000 20×1024确保Flash擦除操作可精确控制避免误擦相邻区域。3. BootLoader核心机制解析BootLoader是系统上电后首条执行的代码其唯一职责是决定启动哪个应用程序。本方案BootLoader流程高度精简仅包含三个确定性步骤3.1 启动判据App2区有效性标志为避免每次启动均执行冗余拷贝BootLoader需快速判断App2区是否存有有效升级包。此处采用标志位法利用App2区末尾地址0x0801FFFC即最后1个字作为状态寄存器。空闲状态Flash擦除后该地址值为0xFFFFFFFF全1有效升级包App程序在完成bin文件写入后将该地址写入特征值0xAAAAAAAA。此设计优势显著零开销检测仅一次32位读取操作耗时1μs抗干扰性强0xAAAAAAAA与擦除态0xFFFFFFFF汉明距离达16位单粒子翻转SEU极难误触发无额外存储开销复用Flash物理空间不占用RAM或独立EEPROM。3.2 固件搬运App2→App1安全拷贝当检测到0x0801FFFC 0xAAAAAAAA时BootLoader执行关键动作——将App2区全部内容复制至App1区。该过程需严格遵循Flash操作规范// 伪代码App2→App1拷贝流程 if (*(uint32_t*)0x0801FFFC 0xAAAAAAAA) { // 1. 擦除App1区全部页第20~75页 for (uint16_t page 20; page 75; page) { FLASH_ErasePage(0x08000000 page * 1024); } // 2. 逐页拷贝App2数据源地址0x08014000目标0x08005000 uint32_t src_addr 0x08014000; uint32_t dst_addr 0x08005000; uint32_t len 0x0000B000; // 44KB while (len 0) { uint32_t word *(uint32_t*)src_addr; FLASH_ProgramWord(dst_addr, word); src_addr 4; dst_addr 4; len - 4; } // 3. 清除App2有效标志防止重复拷贝 FLASH_ProgramWord(0x0801FFFC, 0xFFFFFFFF); }关键约束Flash编程必须以“字”32位为单位且目标地址需4字节对齐擦除操作以“页”为单位不可跨页部分擦除。3.3 应用跳转栈指针重置与向量表重映射拷贝完成后BootLoader需跳转至App1入口。此过程涉及两个底层硬件操作1主栈指针MSP初始化Cortex-M3复位后从地址0x08000000读取初始MSP值位于向量表首字。App1的向量表位于0x08005000故需手动加载其首字__asm void MSR_MSP(uint32_t ulAddr) { MSR MSP, r0 // 将ulAddr值载入主栈指针 BX r14 // 返回调用者 }2向量表偏移寄存器VTOR配置为使CPU从中断时能正确索引App1的向量表需设置SCB-VTOR寄存器SCB-VTOR 0x08005000; // 指向App1向量表基址3绝对跳转执行获取App1复位向量向量表第二个字地址0x08005004并执行typedef void (*pFunction)(void); pFunction JumpToApp; uint32_t jumpAddress *(uint32_t*)(0x08005004); // 复位地址 JumpToApp (pFunction)jumpAddress; MSR_MSP(*(uint32_t*)0x08005000); // 加载App1栈顶 JumpToApp(); // 跳转执行安全性校验跳转前检查复位地址高位是否为0x2000xxxxSRAM或0x0800xxxxFlash防止跳转至非法地址导致HardFault。4. App1应用程序升级逻辑实现App1作为用户业务逻辑载体在运行期间承担升级包接收与写入App2区的任务。其核心模块包括串口通信驱动、YModem协议解析、Flash编程接口及版本管理。4.1 YModem协议在嵌入式端的轻量化实现YModem是XModem的增强版支持1024字节大数据包及文件名传输非常适合固件升级场景。本方案针对资源受限MCU进行裁剪仅实现关键帧类型帧类型字节值作用说明SOH0x011024字节数据包起始标识EOT0x04文件传输结束标识ACK0x06正确接收确认NAK0x15校验失败请求重传CCC0xC0连续三次0xC0表示会话建立接收状态机设计采用有限状态机FSM管理升级流程状态定义如下TO_START等待客户端发送SOH起始帧TO_RECEIVE_DATA接收连续数据包包序号递增TO_RECEIVE_EOT2收到首个EOT后等待第二个EOTYModem要求双EOT确认TO_RECEIVE_END升级完成触发系统复位CRC16校验实现使用标准CRC-16-CCITT算法多项式0x1021对SOH帧后1024字节数据计算校验值与帧末2字节比对uint16_t CRC16_CCITT(const uint8_t *data, uint16_t len) { uint16_t crc 0xFFFF; for (uint16_t i 0; i len; i) { crc ^ data[i] 8; for (uint8_t j 0; j 8; j) { if (crc 0x8000) crc (crc 1) ^ 0x1021; else crc 1; } } return crc; }4.2 App2区Flash编程关键流程接收完一个SOH数据包后需将其有效载荷1024字节写入App2区对应地址。由于Flash编程需按“字”操作需进行数据对齐处理// 将1024字节数据写入App2区指定页偏移 void WriteFlash(uint32_t WriteAddr, uint32_t *pBuffer, uint16_t NumToWrite) { HAL_FLASH_Unlock(); // 解锁Flash __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR); for (uint16_t i 0; i NumToWrite; i 4) { uint32_t word pBuffer[i/4]; if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr i, word) ! HAL_OK) { // 编程失败处理记录错误停止升级 Error_Handler(); } } HAL_FLASH_Lock(); // 锁定Flash }关键注意事项写入前必须确保目标页已擦除本方案在接收首帧时执行Erase_page(Application_2_Addr, 40)HAL_FLASH_Program()返回HAL_OK才代表写入成功需严格检查避免在Flash编程期间响应中断可临时关闭全局中断。4.3 版本信息管理与向量表重映射App1启动后首要任务是重映射向量表否则中断服务例程ISR将指向BootLoader区导致不可预知行为// 在App1的main()函数开头执行 SCB-VTOR 0x08005000; // 强制向量表定位到App1区 __set_MSP(*(uint32_t*)0x08005000); // 初始化主栈指针版本信息通过宏定义固化在代码中编译时生成#define APP_VERSION_MAJOR 0 #define APP_VERSION_MINOR 0 #define APP_VERSION_PATCH 1 #define APP_VERSION_STR 0.0.1升级完成后App1通过串口打印当前版本供运维人员验证printf(App Version: %s\r\n, APP_VERSION_STR);5. Keil MDK工程配置要点IAP方案成功落地高度依赖正确的IDE配置。本节列出Keil v5.37环境下关键设置项5.1 BootLoader工程配置配置项值说明Target → IRAM10x20000000,20KRAM区大小满足BootLoader栈需求Target → IROM10x08000000,20KFlash起始地址与大小Output → Create HEX File✅启用生成.hex用于烧录C/C → DefineBOOTLOADER条件编译标识分散加载文件scatter file示例LR_IROM1 0x08000000 0x00005000 { ; load region size_region ER_IROM1 0x08000000 0x00005000 { ; load address execution address *.o (RESET, First) *(InRoot$$Sections) .ANY (RO) } RW_IRAM1 0x20000000 0x00005000 { .ANY (RW ZI) } }5.2 App1工程配置配置项值说明Target → IROM10x08005000,56K起始地址必须与分区规划一致Target → IRAM10x20000000,20KRAM区需容纳YModem接收缓冲区Output → Create BIN File✅启用生成.bin供YModem传输C/C → DefineAPP1区分BootLoader与App1编译环境关键链接脚本修改在App1的startup_stm32f103xb.s中将向量表起始地址修正为0x08005000; 修改前默认 ; VECT_TAB_OFFSET EQU 0x00000000 ; 修改后 VECT_TAB_OFFSET EQU 0x00005000 ; 相对于IROM1基址的偏移6. 升级流程实操验证6.1 分步烧录流程BootLoader烧录使用ST-Link Utility或J-Flash选择BootLoader.hex文件设置擦除方式为Erase Sectors地址范围0x08000000~0x08004FFF20KB烧录完成后复位通过串口1观察输出 BootLoader running... Checking App2... empty Jumping to App1...App1首次烧录打开App1工程修改APP_VERSION_STR为0.0.1编译生成App1.bin使用ST-Link Utility烧录至0x08005000擦除范围0x08005000~0x08013FFF启动后串口1输出 App Version: 0.0.1 Ready for upgrade...6.2 YModem升级操作使用Xshell连接开发板串口2升级专用通道在Xshell中执行rz -y命令需安装lrzsz工具选择App1_v0.0.2.bin文件观察串口1调试通道实时日志 Receive start... Receive data bag:128 byte Receive data bag:256 byte ... Receive end... Upgrade success! Resetting...系统复位后串口1输出变为 App Version: 0.0.26.3 断电恢复测试在YModem传输过程中强制断电再次上电后BootLoader检测到App2区未写入完整0xAAAAAAAA标志跳过拷贝直接启动App1v0.0.1确保业务连续性。7. BOM清单与硬件资源占用本方案纯软件实现无需额外硬件器件。所依赖的STM32F103RB片上资源占用情况如下资源类型占用详情备注FlashBootLoader: ≤8KB, App1: ≤56KBApp2区仅存储bin文件不占代码空间SRAM≈8KB含YModem 1024B接收缓冲区未启用堆内存全部静态分配UARTUSART1调试打印USART2YModem可复用同一串口但需时分复用GPIO无全部通过串口通信无需LED指示灯定时器SysTickHAL_Delay用于超时控制兼容性说明本方案可无缝迁移至STM32F103C8T664KB Flash、STM32F103VET6512KB Flash等同系列芯片仅需调整分区地址与页数参数。8. 方案扩展与工程优化方向本基础IAP框架具备良好可扩展性实际项目中可按需增强安全加固在App2写入前增加AES-128解密步骤BootLoader校验App1区SHA256哈希值多区冗余扩展为App1/App2/App3三区支持A/B/C滚动升级彻底消除升级窗口无线升级将YModem接收模块替换为ESP8266 AT指令解析器通过HTTP GET下载bin文件差分升级集成bsdiff算法在服务器端生成差分包终端侧执行bspatch还原降低传输流量OTA云平台对接集成MQTT协议从云端获取升级包URL及数字签名实现远程集中管控。所有扩展均不改变BootLoader核心逻辑——其职责始终是“验证→搬运→跳转”这正是嵌入式IAP设计的稳定性基石。

更多文章