STM32双Bank启动模式下OTA失败后自动回滚的硬件看门狗联动设计

1. 为什么需要双Bank + 看门狗联动?

传统OTA升级中,若新固件写入Flash中途断电或校验失败,设备可能无法启动,需人工干预。STM32的双Bank架构(如F7/H7系列)将Flash分为两个独立Bank,可分别存储旧版和新版固件。结合硬件看门狗(IWDG),即使新固件运行异常,看门狗超时复位后,Bootloader可检测Bank有效性并自动回滚,实现无人值守的可靠升级。

2. 双Bank启动原理

  • Bank结构:以STM32H743为例,Flash共2MB,分为Bank1(0x08000000-0x080FFFFF)和Bank2(0x08100000-0x081FFFFF),每个Bank可独立擦写。
  • 启动模式:通过选项字节nBOOT1BOOT_ADD0配置启动地址。支持BOOT_SWAP功能,可交换Bank映射,使复位后从指定Bank启动。
  • OTA流程
    1. 当前运行在Bank1(旧固件),接收新固件写入Bank2。
    2. 写入完成后,设置标志位(如备份寄存器),并触发软件复位。
    3. Bootloader检查标志,若Bank2有效则交换Bank并跳转;若无效则回滚至Bank1。

3. 硬件看门狗联动设计

3.1 看门狗作用

  • IWDG:独立于主时钟,由LSI(约32kHz)驱动,一旦启动无法停止,超时后产生复位。
  • 联动策略
    • 新固件启动后,必须在一定时间内“喂狗”(刷新计数器),否则复位。
    • 若新固件因异常死机或卡死,看门狗超时复位,系统回到Bootloader。
    • Bootloader检测到升级未完成或新固件无效,自动回滚至旧Bank。

3.2 系统状态机

typedef enum {
    STATE_BOOTLOADER = 0,
    STATE_APP_OLD,
    STATE_APP_NEW,
    STATE_UPDATE_PENDING
} SystemState;
  • 正常启动:Bootloader检查标志,决定进入旧或新App。
  • 升级中:App写入新固件后,设置UPDATE_PENDING并复位。
  • 回滚:若新App启动后未及时喂狗,复位后Bootloader清除标志并跳转旧App。

4. 配置步骤

4.1 硬件配置

  • 使用STM32CubeMX启用IWDG,设置超时时间(如1秒)。
  • 配置Flash双Bank模式(部分型号需通过选项字节设置)。

4.2 软件实现

Bootloader部分(位于Bank1起始地址)

// 检查升级标志(备份寄存器或Flash特定地址)
if (check_update_flag()) {
    // 验证Bank2固件(CRC或校验和)
    if (verify_bank2_firmware()) {
        // 交换Bank映射
        HAL_FLASHEx_OB_Program(OB_SWAP_BANK);
        // 清除标志
        clear_update_flag();
        // 跳转到Bank2的App
        jump_to_app(APP2_ADDRESS);
    } else {
        // 回滚:清除标志,启动旧App
        clear_update_flag();
        jump_to_app(APP1_ADDRESS);
    }
} else {
    // 正常启动,检查当前Bank有效性
    if (is_current_bank_valid()) {
        jump_to_app(current_app_addr);
    } else {
        // 尝试另一Bank
        jump_to_app(other_bank_addr);
    }
}

App部分(旧/新固件均需包含)

// 初始化IWDG
void IWDG_Init(void) {
    // 使能LSI,设置预分频和重装载值,超时约1秒
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    IWDG_SetPrescaler(IWDG_Prescaler_64);
    IWDG_SetReload(0xFFF); // 约1秒
    IWDG_ReloadCounter();
    IWDG_Enable();
}

// 主循环中周期性喂狗
while(1) {
    // 业务逻辑
    IWDG_ReloadCounter(); // 喂狗
}

OTA升级函数(在旧App中)

void OTA_Update(void) {
    // 接收新固件并写入Bank2
    write_firmware_to_bank2();
    // 设置升级标志
    set_update_flag();
    // 软件复位
    NVIC_SystemReset();
}

5. 完整代码示例(简化)

// Bootloader main.c
int main(void) {
    HAL_Init();
    SystemClock_Config();
    // 初始化Flash和选项字节
    
    if (check_update_flag()) {
        if (verify_bank2()) {
            // 交换Bank
            FLASH_OB_SwapBank();
            clear_update_flag();
            jump_to(APP2_ADDR);
        } else {
            clear_update_flag();
            jump_to(APP1_ADDR);
        }
    } else {
        // 正常启动,检查当前Bank有效性
        if (is_bank1_valid()) jump_to(APP1_ADDR);
        else if (is_bank2_valid()) jump_to(APP2_ADDR);
        else error_handler();
    }
}

// App中初始化看门狗
void App_Init(void) {
    IWDG_Init();
    // 其他初始化
}

// 主循环
while(1) {
    // 任务处理
    IWDG_ReloadCounter(); // 喂狗,确保系统存活
}

6. 注意事项

  • 看门狗超时时间:需大于新固件启动最长时间,避免误复位。建议2-5秒。
  • 标志位存储:使用备份寄存器(如RTC备份域)或Flash末尾扇区,注意掉电保持。
  • Bank交换操作:需在无中断环境下执行,且操作后必须复位才生效。
  • 固件验证:除CRC外,建议在App启动后自检关键外设,若失败主动喂狗超时触发回滚。
  • 调试时:可暂时禁用看门狗,但发布前必须启用。
  • 双Bank支持:仅部分型号支持,如STM32F7/H7/L4+,需查阅参考手册。

7. 总结

通过双Bank启动与硬件看门狗联动,OTA升级失败后系统能自动回滚,极大提升可靠性。本文方案适用于对稳定性要求高的工业、医疗等场景。开发者可根据具体芯片型号调整细节,建议结合STM32CubeMX快速配置,并充分测试异常场景。