在嵌入式系统开发中,固件升级是一个永恒的话题。传统方式需要拆解设备、连接调试器,既耗时又容易损坏产品。基于STM32G431的Bootloader结合串口IAP(In-Application Programming)方案,让设备在出厂后仍能通过串口轻松完成固件更新,这在工业控制、智能家居等领域具有广泛的应用价值。
STM32G431作为STMicroelectronics推出的主流Cortex-M4内核微控制器,内置了丰富的硬件资源。其双Bank Flash架构特别适合IAP应用,可以在不中断当前运行程序的情况下完成新固件的写入。本方案通过精心设计的Bootloader程序,配合简单的上位机工具,就能实现稳定可靠的远程升级功能。
在产品生命周期中,固件升级是不可避免的需求。传统JTAG/SWD烧录方式需要专业设备和操作人员,而IAP方案通过设备已有的通信接口(如串口、USB、CAN等)就能完成升级,大幅降低了维护成本。特别是在以下场景中优势明显:
STM32G431系列具有几个关键特性使其特别适合IAP应用:
这些特性使得在应用编程更加安全可靠,我们可以在一个Bank运行程序的同时擦写另一个Bank,完成后只需简单切换Bank即可完成升级。
一个完整的IAP系统通常包含三部分:
具体工作流程如下:
code复制[上电]
→ 运行Bootloader
→ 检查升级标志位
→ 有升级:进入接收模式
→ 无升级:跳转到应用程序
→ 应用程序运行中收到升级指令
→ 设置标志位并复位
→ 重新进入Bootloader升级流程
合理的存储器规划是稳定运行的基础。以STM32G431CBU6(128KB Flash)为例:
| 区域 | 起始地址 | 大小 | 用途 |
|---|---|---|---|
| Bootloader | 0x08000000 | 16KB | 升级程序 |
| App Vector | 0x08004000 | 0x200 | 应用程序中断向量表 |
| App Code | 0x08004200 | 110KB | 用户程序 |
| Config Data | 0x0801F800 | 2KB | 系统配置参数 |
注意:应用程序需要将中断向量表偏移量设置为0x4000,可通过SCB->VTOR寄存器配置。
采用简单可靠的帧协议格式:
code复制[HEADER][LEN][CMD][DATA][CRC]
常用命令字定义:
安全跳转到应用程序需要几个关键步骤:
c复制void JumpToApplication(uint32_t appAddress)
{
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t stack_pointer = *(volatile uint32_t*)appAddress;
uint32_t reset_handler = *(volatile uint32_t*)(appAddress + 4);
__disable_irq();
HAL_RCC_DeInit();
HAL_DeInit();
__set_MSP(stack_pointer);
Jump_To_Application = (pFunction)reset_handler;
Jump_To_Application();
}
STM32G431的Flash操作有几个易错点:
c复制HAL_FLASH_Unlock();
c复制FLASH_EraseInitTypeDef erase;
erase.TypeErase = FLASH_TYPEERASE_PAGES;
erase.Page = 16; // 要擦除的扇区号
erase.NbPages = 1;
uint32_t error;
HAL_FLASHEx_Erase(&erase, &error);
c复制HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, data);
为确保固件完整性,采用双重校验:
c复制uint32_t Calculate_CRC(uint32_t start, uint32_t end)
{
uint32_t crc = 0xFFFFFFFF;
CRC->CR |= CRC_CR_RESET;
for(uint32_t i=start; i<end; i+=4) {
CRC->DR = *(__IO uint32_t*)i;
}
crc = CRC->DR;
return crc;
}
上位机需要将HEX或BIN文件转换为适合串口传输的格式:
可靠传输的关键策略:
可能原因及排查:
优化建议:
典型错误处理:
c复制HAL_FLASH_Unlock();
在STM32G431-Nucleo开发板上的测试结果:
| 固件大小 | 波特率 | 传输时间 | 写入时间 |
|---|---|---|---|
| 64KB | 115200 | 5.8s | 2.1s |
| 64KB | 460800 | 1.5s | 2.1s |
| 64KB | 921600 | 0.8s | 2.1s |
注意:写入时间主要取决于Flash擦除和编程时间,与波特率无关。
基于此方案可进一步实现:
我在实际项目中发现,良好的Bootloader设计可以显著延长产品生命周期。一个建议是预留足够的扩展接口,比如未来可能需要的安全认证功能,可以在初期设计时就考虑进去。另外,务必在Bootloader中实现完善的错误处理机制,避免因升级失败导致设备变砖。