2. 升级中断的常见原因
做固件升级这么多年,我见过最多的翻车现场,说白了就四种情况:电源异常、通信中断、存储故障、用户强制断电。你想想看,升级过程中芯片正在擦写 Flash,突然来这么一下,轻则升级失败,重则变砖。咱们一个一个拆开聊。
核心观点:升级中断的本质是「写操作被非正常终止」。Flash 擦写需要完整的时间窗口,任何打断都可能留下半残的数据。
2.1 电源异常
这是最常见、也是最难防的。我早期做一款智能插座产品时,用户插拔电源适配器导致升级中断,返修率一度冲到 3%。后来我们加了掉电检测电路才压下来。
电源异常分几种情况:
- 电压跌落:电池供电设备电量不足,升级到一半电压掉到 MCU 最低工作电压以下。我记得有一次测试,锂电池从 3.7V 掉到 3.0V,Flash 写入直接卡死。
- 瞬时掉电:插头松动、电源开关误触,几毫秒内电压归零。这时候 MCU 连保存现场的时间都没有。
- 电源纹波过大:开关电源老化或负载突变,纹波超过 200mV 时,Flash 写入可能产生位错误。嗯,这个比较隐蔽,一般排查不到。
| 异常类型 | 典型场景 | 影响范围 | 检测手段 |
|---|---|---|---|
| 电压跌落 | 电池供电、USB 供电不足 | 写入中断、数据损坏 | ADC 监测 VDD |
| 瞬时掉电 | 插头松动、电源开关误触 | 固件分区损坏 | BOD 欠压复位 |
| 纹波过大 | 电源老化、负载突变 | Flash 位错误 | 示波器测量 |
避坑指南:我曾经遇到一个案子,产品在实验室升级 100 次都没问题,一上量就频繁变砖。查了两个月才发现是产线电源适配器批次纹波超标。从那以后,我要求所有升级流程必须做「电源最差工况测试」——用最低输入电压 + 最大负载跑升级。
2.2 通信中断
通信中断在 OTA 升级里尤其要命。你想想看,固件包传了一半,蓝牙断连、Wi-Fi 掉线、串口被拔,接收端只存了半包数据。这时候如果直接开始擦写,写进去的就是垃圾。
我个人习惯把通信中断分成三个层级:
- 物理层中断:线缆被拔、无线信号消失。这种最干脆,MCU 通常能通过超时检测到。
- 协议层中断:TCP 连接超时、蓝牙 ATT 断开、CAN 总线错误。需要协议栈回调通知应用层。
- 数据包损坏:CRC 校验失败、重传超限。这种最坑,因为连接还在,但数据已经不对了。
经验之谈:我建议在升级协议里加一个「心跳 + 超时重传」机制。比如每 100ms 发一次心跳,连续 3 次收不到回复就判定通信中断,立即回滚到旧固件。别等应用层超时,那太慢了。
2.3 存储故障
存储故障分硬件和软件两方面。硬件上,Flash 是有寿命的——Nor Flash 一般 10 万次擦写,Nand Flash 只有几千次。升级频繁的产品,比如电表、水表,用几年就可能遇到坏块。
软件上更常见:
- 分区表损坏:升级过程中分区表被意外改写,MCU 找不到启动入口。
- 文件系统崩溃:如果用了 LittleFS 或 SPIFFS,突然断电可能导致元数据不一致。
- 地址越界:固件包大小超过分区容量,写入到隔壁分区。我见过一个案例,Bootloader 被覆盖,直接变砖。
关键数据:Flash 写入时如果电压低于 2.7V,位错误率会上升 10 倍以上。所以很多 MCU 的 Flash 控制器内置了「电压检测」——电压不够直接拒绝写入。
2.4 用户强制断电
这个最让人头疼。你无法控制用户的行为——升级进度条走到 80%,用户觉得太慢,直接拔电。或者看到「升级中请勿断电」的提示,偏偏想试试会怎样。
我做过一个用户行为统计:
| 用户行为 | 占比 | 后果 |
|---|---|---|
| 看到提示后故意断电 | 12% | 固件损坏,需强制恢复 |
| 误触电源开关 | 45% | 升级中断,可自动恢复 |
| 电池耗尽 | 30% | 写入中断,数据损坏 |
| 其他 | 13% | 视情况而定 |
避坑指南:我曾经做一个消费级产品,用户强制断电率高达 8%。后来我们在 UI 上做了两件事:一是进度条改成「剩余时间」而不是「百分比」,减少用户焦虑;二是在升级开始前弹窗确认「升级期间请勿操作电源,预计耗时 2 分钟」。强制断电率降到了 2% 以下。
2.5 四种原因的关系图
下面这张图展示了四种中断原因之间的关联和典型触发路径。你看,电源异常往往是其他问题的放大器——电压不稳会导致通信重传、Flash 写入失败,甚至触发用户强制断电。
2.6 如何快速定位中断原因
现场出了问题,怎么快速判断是哪种中断?我一般按这个顺序排查:
- 看日志:如果有 RTC 或系统滴答,先看最后一条日志的时间戳。如果日志突然中断,大概率是电源或用户断电。
- 检查复位原因寄存器:大部分 MCU 都有 RCC_CSR 或类似寄存器,能读出是欠压复位、外部复位还是看门狗复位。这个信息非常关键。
- 看 Flash 内容:读一下升级分区的 Magic Number 和 CRC。如果 Magic 对但 CRC 错,说明通信中断;如果 Magic 都不对,可能是存储故障。
- 问用户:别不好意思,直接问「您当时有没有拔电源或者按复位键?」用户反馈往往能省掉一半排查时间。
小技巧:我习惯在 Bootloader 里保留一个「上次升级结果」标志位,每次升级前清零,升级成功写 0x5A5A,失败写 0xA5A5。下次启动时读一下这个标志,就能知道上次升级是否正常完成。成本只有 2 字节 Flash,排查效率提升 80%。