# 引言 在嵌入式设备OTA升级中,固件损坏或升级中断可能导致设备变砖。STM32H7系列凭借其双Bank Flash架构和硬件级回滚机制,为开发者提供了强大的安全保障。本文深入剖析双Bank Flash的工作原理,详解如何利用硬件特性实现升级失败后的自动回滚,并给出完整的配置步骤与代码示例,帮助开发者构建高可靠的在线升级方案。 # 双Bank Flash架构原理 STM32H7系列(如STM32H743、H750)内置的Flash存储器被划分为两个独立的Bank:Bank1和Bank2,每个Bank的容量通常为1MB(或根据型号不同)。这种物理隔离的设计允许系统在运行时从一个Bank执行代码,同时对另一个Bank进行擦除和编程操作,从而实现无缝的固件更新。 关键特性包括: - **独立擦写**:每个Bank可独立擦除和编程,互不干扰。 - **硬件切换**:通过设置选项字节或系统控制寄存器,可以切换系统从哪个Bank启动。 - **自动回滚**:当新固件校验失败时,硬件可自动回退到旧Bank执行,无需软件干预。 # 硬件级回滚机制 STM32H7的硬件回滚机制依赖于以下两个核心功能: 1. **启动配置**:通过BOOT0引脚和选项字节(nBOOT1、nBOOT0)决定系统从Bank1还是Bank2启动。 2. **固件有效性标志**:在每次启动时,硬件检查当前Bank的启动标志(如`FLASH_OPTR`中的`B_BFB2`位),若发现新固件未正确设置有效标志,则自动从另一个Bank启动。 具体流程: - 升级时,将新固件写入非活动Bank(如Bank2),并设置其有效性标志。 - 重启后,硬件检查Bank2的标志,若有效则从Bank2启动;若无效(如校验失败),则自动回滚到Bank1。 # 配置步骤 ## 1. 内存布局规划 将固件分为两个版本,分别放置在Bank1和Bank2的起始地址。例如: - Bank1:0x08000000(默认启动) - Bank2:0x08100000(升级目标) ## 2. 设置选项字节 使用STM32CubeProgrammer或代码配置选项字节,确保系统支持双Bank启动。关键设置: - `nBOOT1=1`,`nBOOT0=0`(从Flash启动) - `B_BFB2=1`(允许从Bank2启动) ## 3. 编写固件升级与回滚逻辑 在应用代码中实现以下功能: - 接收新固件并写入Bank2。 - 写入完成后,设置Bank2的有效性标志(如写入特定魔数到固定地址)。 - 重启系统。 # 完整代码示例 以下示例基于STM32H743,使用HAL库实现固件写入和回滚标志设置。 ```c #include "stm32h7xx_hal.h" #define BANK2_BASE_ADDR 0x08100000 #define VALID_MAGIC 0xA5A5A5A5 #define MAGIC_ADDR (BANK2_BASE_ADDR + 0x1FF000) // 预留区域 // 擦除Bank2扇区 void Erase_Bank2(void) { FLASH_EraseInitTypeDef eraseConfig; uint32_t sectorError = 0; eraseConfig.TypeErase = FLASH_TYPEERASE_SECTORS; eraseConfig.Banks = FLASH_BANK_2; eraseConfig.Sector = 0; eraseConfig.NbSectors = 8; // 根据实际扇区数调整 eraseConfig.VoltageRange = FLASH_VOLTAGE_RANGE_3; HAL_FLASHEx_Erase(&eraseConfig, §orError); } // 写入固件数据到Bank2 void Write_Firmware(uint32_t *data, uint32_t size) { uint32_t address = BANK2_BASE_ADDR; for (uint32_t i = 0; i < size; i += 8) { HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, (uint64_t*)&data[i]); address += 8; } } // 设置有效标志 void Set_ValidFlag(void) { HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, MAGIC_ADDR, (uint64_t)VALID_MAGIC); } // 升级主函数 void OTA_Update(void) { HAL_FLASH_Unlock(); Erase_Bank2(); // 假设firmware_data和firmware_size已从外部获取 Write_Firmware(firmware_data, firmware_size); Set_ValidFlag(); HAL_FLASH_Lock(); NVIC_SystemReset(); // 重启 } // 启动时检查回滚标志 void Check_Rollback(void) { uint32_t magic = *(__IO uint32_t*)MAGIC_ADDR; if (magic != VALID_MAGIC) { // 新固件无效,硬件将自动从Bank1启动,这里可添加日志 printf("Firmware invalid, rolling back\n"); } } ``` # 注意事项 - **地址对齐**:写入数据必须按8字节对齐,否则HAL_FLASH_Program会报错。 - **扇区大小**:STM32H7的Flash扇区大小因型号而异,需查阅数据手册。 - **有效标志位置**:建议将标志放在Bank2的末尾区域,避免与代码冲突。 - **硬件回滚依赖**:确保选项字节配置正确,否则硬件不会自动切换Bank。 - **测试验证**:在实际设备上模拟升级失败(如写入错误数据),确认回滚功能正常。 # 总结 STM32H7的双Bank Flash硬件级回滚机制为OTA升级提供了强大的可靠性保障。通过合理配置选项字节和设置有效性标志,开发者可以轻松实现升级失败后的自动回滚,避免设备变砖。本文的代码示例和配置步骤可直接应用于实际项目,帮助提升嵌入式系统的健壮性。