OTA 升级断点续传与回滚:升级到一半断电设备变砖怎么办?
摘要:无线升级(OTA)固件包 200KB,传输到一半突然断电,重启后进不了程序?不是网络不稳,而是 缺少断点记录(Checkpoint)和双分区回滚(Rollback)机制。本文解析工业级 OTA 的完整实现思路。
一、反面教材(裸奔式 OTA)
场景:收到一包就直接往 Application 区写。
// 收到第一包
FLASH_Erase(APP_ADDR);
// 每收到一包
FLASH_Write(APP_ADDR + offset, data);
// 写完校验
if (CRC_OK) Set_Boot_Flag(BOOT_APP);
痛点:
-
断电变砖:写到一半断电,Flash 里是残缺固件,重启直接 HardFault。
-
无回滚:新固件有 Bug,启动失败,只能上门拆机重刷。
-
重传浪费:断了要从 0 重传,低功耗设备受不了。
二、进阶写法(双分区 + 断点 + 回滚)
核心思想:永远不在运行分区上直接写;记录进度;新固件跑不起来自动回退。
1. Flash 分区规划(铁律)
+-------------------+ 0x08000000
| Bootloader (32KB) |
+-------------------+
| App_A (Active) | <- 当前运行
+-------------------+
| App_B (Download) | <- OTA 写入区
+-------------------+
| Param / OTA_State | <- 记录版本/进度/CRC
+-------------------+
2. OTA 状态结构体(断电记忆)
typedef struct {
uint32_t magic; // 0xAA55AA55 表示有效
uint32_t total_size;
uint32_t written_offset;// 断点位置
uint32_t crc_received;
uint8_t state; // 0:空闲 1:下载中 2:校验OK 3:激活待重启
uint16_t crc_header;
} OTA_State_t;
写入策略:
-
每接收并写入 N 包(或 1KB 对齐),更新
written_offset和crc_received,回写 Flash。 -
这样断电重启后,Bootloader 可读出
written_offset,通知上位机从断点续传。
3. 断点续传流程
[设备重启]
-> Bootloader 读 OTA_State
-> 若 state == DOWNLOADING:
上报断点 offset 给上位机
上位机发送 offset 之后的数据
-> 继续写入 App_B
4. 校验与激活(原子操作)
// 全部写完
if (Calc_CRC(APP_B_ADDR, total_size) == crc_expected) {
ota_state.state = OTA_STATE_VERIFIED;
Save_OTA_State(&ota_state);
// 切换启动分区(改 Option Bytes 或 Boot Flag)
Set_Boot_Partition(BOOT_APP_B);
NVIC_SystemReset();
}
5. 回滚机制(Watchdog + 标记位)
新固件第一次启动必须"自证清白":
// App_B main()
int main(void)
{
if (Is_First_Boot()) {
// 执行关键外设自检
if (Peripheral_Self_Test_OK()) {
Clear_First_Boot_Flag();
Start_IWDG(); // 开启独立看门狗
} else {
Request_Rollback_To_App_A(); // 回滚
NVIC_SystemReset();
}
}
// ...
}
-
若新固件 没喂狗 / 启动失败 / 自检不过 → 看门狗复位或主动回滚 → Bootloader 切回 App_A。
三、进阶收益
|
维度 |
裸奔 OTA |
工业级 OTA |
|---|---|---|
|
断电安全 |
变砖 |
断点续传 |
|
新固件有 Bug |
变砖 |
自动回滚 App_A |
|
流量 |
全量重传 |
只传剩余包 |
|
量产信心 |
低 |
高 |
四、工程级最佳实践
-
Bootloader 绝不升级:
-
Bootloader 区只读,OTA 只换 App 分区,防死锁。
-
-
签名校验(可选进阶):
-
除 CRC 外,用 RSA/ECDSA 验签,防恶意固件。
-
-
版本号记录:
-
Param 区存
fw_version,便于云端追溯。
-
-
最小 OTA State 写入次数:
-
每 4KB 或每帧更新一次,避免频繁擦写 Param 区。
-
五、总结 Checklist
-
[ ] 是否采用双 App 分区(Active / Download)?
-
[ ] 是否记录了断点
written_offset可供续传? -
[ ] 新固件是否有首次启动自检 + 回滚逻辑?
-
[ ] Bootloader 是否只切换启动标志,不写 App 内容?
六、写在最后(关注我,少走弯路)
我是 gqqsherry666,一个拒绝调包、专注工程落地的嵌入式架构师。
OTA 是产品上线后的第一道鬼门关。
没有断点续传和回滚,一次升级失败就可能让你失去所有用户信任。
关注我的专栏《嵌入式系统架构实战》,系列正式完结。
原创文章,转载请注明出处。
更多推荐


所有评论(0)