OTA 断电变砖——擦完旧区没备份就跳,加双备份 + 标记有效区再切
OTA 断电变砖——擦完旧区没备份就跳加双备份 标记有效区再切文章标签#嵌入式开发 #单片机 #Flash #OTA升级 #OTA #远程升级 #Bootloader #固件 #双备份摘要OTA 升级最怕中途断电——运行区只剩残包设备直接变砖。本文从真实事故切入剖析原地覆盖的真空期缺陷给出 A/B 双备份 有效标记 原子切换的防砖方案新固件先写备份区整包 CRC32 magic 校验通过后才切换启动槽断电自动回退原区。附错误/正确代码、时序图与实测对比。一、开篇那个升级到一半断电的噩梦做一款联网设备OTA 流程是收到新固件 → 直接擦掉运行区 → 写入新固件 → 跳转。一次现场升级时用户恰好在擦完旧固件、新固件才写 30%时断电。再次上电运行区是半截残包Bootloader 跳过去直接 HardFault设备变砖只能返厂烧录。复现率虽低但一旦发生就是 100% brick。如果你做 OTA 还是原地覆盖,这一讲能救你的售后。我会从双备份分区讲起给你一套断电可恢复的 A/B 升级方案并附实测对比。全文导航入门认知为什么原地升级会砖→ 进阶原理A/B 分区与有效标记机制→ 高级应用错误流程复现 正确 Bootloader 代码 实测对比。二、入门认知OTA 的本质是换座位OTAOver-The-Air升级核心是把新固件安全地放到能跑的地方再切过去。原地覆盖最大的问题是在擦旧和写新之间存在一个无可用固件的真空期此时断电必砖。类比你给行驶中的汽车换轮胎直接把旧胎拆了才发现新胎没气——车只能停路边。正确做法是备好另一条满气胎确认装好再拆旧的。如图 1 展示原地覆盖危险与 A/B 双备份安全的差异收到新固件擦运行区写新固件(中断电→变砖)跳转收到新固件写备份区B(运行区A不动)校验B完整标记B有效,切启动槽下次启动从B跑,A作备份图 1原地覆盖 vs A/B 双备份升级流程适用边界Flash 够大能容两份 App才用 A/B极小芯片可用差分外部 SPI Flash 备份折中。三、进阶原理双备份 有效标记如何防砖关键三要素双区Slot A、Slot B 各一份 App当前跑 A 时新包写 B。有效标记每个 Slot 头部存magic 版本 CRC。Bootloader 只跳magic 正确且 CRC 通过的区。原子切换用独立的一小段启动槽标志存另一页 Flash记录下次从哪启动写好新包并校验通过后再更新该标志。断电场景推演写到 B 中途断电 → B 的 magic/CRC 不完整 → 下次启动 Bootloader 检测 B 无效仍从 A 启动 → 设备照常工作可重试升级。易混淆点对比方案断电可恢复存储开销复杂度原地覆盖否(变砖)1 份低A/B 双备份是2 份中外部 SPI回滚是1.5 份高[坑] 高频翻车校验只算长度对不算 CRC残包长度凑巧对就误判有效。必须整包 CRC32 校验 magic 双保险。断电场景推演时序图FlashBootloader用户设备FlashBootloader用户设备Slot B 的 magic/CRC 不完整设备照常工作,可重试升级写入新固件到 Slot B(中途断电)重新上电启动读取启动槽标志校验 Slot B(失败)回退校验 Slot A(通过)从 Slot A 正常启动四、高级应用复现与根治错误流程演示伪代码voidota_bad(uint8_t*pkg,uint32_tlen){flash_erase(APP_ADDR,len);// 擦旧固件flash_write(APP_ADDR,pkg,len);// 这里断电 → 残包,变砖jump_to_app(APP_ADDR);}正确完整代码双备份 Bootloader 核心#defineSLOT_A0x08004000#defineSLOT_B0x08020000#defineFLAG_ADDR0x08002000// 启动槽标志页typedefstruct{uint32_tmagic;uint32_tver;uint32_tcrc;}hdr_t;#defineGOOD_MAGIC0x544F5441// TOFA/* 校验某 slot 头部 整包 CRC */intslot_valid(uint32_taddr,uint32_tlen){hdr_t*h(hdr_t*)addr;if(h-magic!GOOD_MAGIC)return0;if(crc32((uint8_t*)(addrsizeof(hdr_t)),len-sizeof(hdr_t))!h-crc)return0;return1;}/* 升级:写另一个 slot,校验通过后切标志 */voidota_good(uint8_t*pkg,uint32_tlen,uint32_tcur_slot){uint32_tdst(cur_slotSLOT_A)?SLOT_B:SLOT_A;flash_erase(dst,len);flash_write(dst,pkg,len);// 写备份区,当前区照常跑if(!slot_valid(dst,len)){report_fail();return;}// 校验不过不切flash_write_word(FLAG_ADDR,dst);// 原子切启动槽}/* Bootloader 启动:只跳有效 slot */voidboot(void){uint32_tslot*(uint32_t*)FLAG_ADDR;if(slot!SLOT_Aslot!SLOT_B)slotSLOT_A;if(!slot_valid(slot,APP_LEN))slot(slotSLOT_A)?SLOT_B:SLOT_A;// 无效回退if(slot_valid(slot,APP_LEN))jump_to_app(slot);elsehard_fault_trap();// 双区都坏,进恢复模式}Bootloader 启动决策流程否是是否是否上电启动读取启动槽标志标志指向 A 或 B?默认指向 Slot A校验目标 Slotmagic CRC 通过?跳转该 Slot 运行回退校验另一 Slot另一 Slot 有效?进入恢复模式(DFU)改前 vs 改后实测对比指标原地覆盖A/B 双备份升级中途断电100% 变砖0(回退原区)售后返厂率高趋近于 0存储占用1 份2 份[注意] 切换标志本身也要防断电可写两副本 各自 CRC读取时多数表决或先把标志写入再擦旧区保证任何时刻至少一个可用固件。五、收尾要点复盘与最佳实践核心要点① 原地覆盖有真空期断电必砖② A/B 双备份 有效标记 原子切换③ 校验必须整包 CRC不只看长度。最佳实践清单可收藏OTA 绝不原地覆盖用 A/B 或外部备份。每个固件包带 magic 版本 CRCBootloader 只跳校验通过者。切启动槽是最后一步且写前确保新包已完整校验。双区都坏要进恢复模式如 UART/USB DFU而非直接崩。升级成功建议软复位一次确认可启动见第74讲。进阶延伸可加滚动版本号 签名验签防降级攻击与固件篡改A/B 还可配合健康心跳——新固件跑满 N 秒才确认提交否则回滚。完整 OTA 升级流程总览否是是否收到新固件写入备份区(当前区不动)整包 CRC32 magic 校验校验通过?报告失败,保留原区原子切换启动槽标志软复位,从新区启动健康心跳确认?提交新固件,旧区作备份回滚到旧区

相关新闻

PR Lens 渲染器确定性设计全解析:同一份 diff 为何每次都能画出字节级一致的 SVG

PR Lens 渲染器确定性设计全解析:同一份 diff 为何每次都能画出字节级一致的 SVG

【免费下载链接】pr-lens Review code 100X faster. Lens draws every PR as animated architecture and data-flow walkthroughs, inside the pull request itself. Use it as a GitHub App, GitHub Action, CLI, or a Skill for your coding agent 项目地址: http…

2026/10/11 19:44:39 阅读更多 →
AI辅助测试用例生成实操指南:提示词设计到落地应用的完整路径

AI辅助测试用例生成实操指南:提示词设计到落地应用的完整路径

AI辅助测试用例生成实操教程:从提示词设计到落地应用的完整路径在测试行业摸爬滚打了十来年,手动写用例的日子我太熟悉了——一张Excel表摊开,需求文档翻来覆去地啃,一条一条地列前置条件、操作步骤、预期结果,一个功能…

2026/10/11 19:44:39 阅读更多 →
Dagger TypeScript SDK 中的 `float` 类型别名:在 Dagger API 中声明浮点数值的完整指南

Dagger TypeScript SDK 中的 `float` 类型别名:在 Dagger API 中声明浮点数值的完整指南

DevOpsCI/CD后端CLI云原生 【免费下载链接】dagger Automation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud 项目地址: https://gitcode.com/GitHub_Trending/da/dagger 点击查看 免费下载 本文围绕 Dagger v0.2…

2026/10/11 19:44:39 阅读更多 →

最新新闻

新浪Level2接口SDK接入实战:授权、协议解析与避坑指南

新浪Level2接口SDK接入实战:授权、协议解析与避坑指南

简介:新浪Level2接口SDK是一份面向量化开发与行情分析人员的Java工程,用于对接新浪Level2全推行情,获取股票、基金等品种的深度交易数据。相比普通免费接口,Level2数据在速度与深度上更适合机构级策略,适合有一定Java基…

2026/10/11 22:50:35 阅读更多 →
一个 Key 调用所有模型:2026 四大聚合平台价格、生态与稳定性横评

一个 Key 调用所有模型:2026 四大聚合平台价格、生态与稳定性横评

大模型 API 聚合平台的核心价值一句话就能说清:一个 Key 接入多家大模型,统一计费与访问管理,把供应商切换成本降到最低。市面上的主流玩家分三类——国际商业聚合、国内商业聚合、自托管开源方案,路线不同,取舍也不同…

2026/10/11 22:50:35 阅读更多 →
HOP上游升级SOP:pnpm upstream:update一键同步rhwp并全链路验证的完整流程

HOP上游升级SOP:pnpm upstream:update一键同步rhwp并全链路验证的完整流程

【免费下载链接】hop 项目地址: https://gitcode.com/gh_mirrors/hop22/hop 点击查看 免费下载 HOP 是一款开源的 HWP/HWPX 文档编辑器,桌面外壳由 HOP 团队维护,而文档解析与渲染引擎来自上游项目 rhwp。如何安全地跟随上游版本前进&#x…

2026/10/11 22:50:35 阅读更多 →
Android游戏逆向重构实战:从植物大战僵尸源码2到可运行工程

Android游戏逆向重构实战:从植物大战僵尸源码2到可运行工程

简介:本资源为《植物大战僵尸》Android平台开源实现的完整工程源码,面向Android游戏开发初学者与进阶者,聚焦塔防类游戏架构设计、图形渲染与状态管理等核心实践。压缩包共173个文件,含20个Java源文件(涵盖GameScene、…

2026/10/11 22:50:35 阅读更多 →
基于线性回归的PM2.5预测系统Python源码实战解析

基于线性回归的PM2.5预测系统Python源码实战解析

简介:基于线性回归的PM2.5预测系统源码,是一套面向Python学习者、机器学习入门者及大气环境数据分析场景的小型完整项目。代码以单文件Python脚本承载数据读取、特征构造、模型训练与结果预测等关键流程,配套原始训练/测试CSV表、处理后的特征…

2026/10/11 22:50:35 阅读更多 →
PgQue 监控实战:5 个必须告警的队列健康指标 + 如何揪出卡住的消费者

PgQue 监控实战:5 个必须告警的队列健康指标 + 如何揪出卡住的消费者

【免费下载链接】PgQue PgQue – Zero-bloat Postgres queue built on top of on battle-proven Skypes PgQ. One SQL file to install, pg_cron to tick https://pgque.dev 项目地址: https://gitcode.com/gh_mirrors/pg/PgQue 点击查看 免费下载 PgQue 是一个零膨…

2026/10/11 22:49:35 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →