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 掉线、串口被拔,接收端只存了半包数据。这时候如果直接开始擦写,写进去的就是垃圾。

我个人习惯把通信中断分成三个层级:

  1. 物理层中断:线缆被拔、无线信号消失。这种最干脆,MCU 通常能通过超时检测到。
  2. 协议层中断:TCP 连接超时、蓝牙 ATT 断开、CAN 总线错误。需要协议栈回调通知应用层。
  3. 数据包损坏: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 写入失败,甚至触发用户强制断电。

升级中断常见原因关系图 升级中断四大原因及关联 升级中断 电源异常 通信中断 存储故障 用户强制断电 电压不稳导致重传 低电压写入失败 进度卡死引发断电 关键洞察 电源异常是放大器——它同时影响通信稳定性和 Flash 写入可靠性 电压跌落 瞬时掉电 纹波过大 BOD 触发

2.6 如何快速定位中断原因

现场出了问题,怎么快速判断是哪种中断?我一般按这个顺序排查:

  1. 看日志:如果有 RTC 或系统滴答,先看最后一条日志的时间戳。如果日志突然中断,大概率是电源或用户断电。
  2. 检查复位原因寄存器:大部分 MCU 都有 RCC_CSR 或类似寄存器,能读出是欠压复位、外部复位还是看门狗复位。这个信息非常关键。
  3. 看 Flash 内容:读一下升级分区的 Magic Number 和 CRC。如果 Magic 对但 CRC 错,说明通信中断;如果 Magic 都不对,可能是存储故障。
  4. 问用户:别不好意思,直接问「您当时有没有拔电源或者按复位键?」用户反馈往往能省掉一半排查时间。

小技巧:我习惯在 Bootloader 里保留一个「上次升级结果」标志位,每次升级前清零,升级成功写 0x5A5A,失败写 0xA5A5。下次启动时读一下这个标志,就能知道上次升级是否正常完成。成本只有 2 字节 Flash,排查效率提升 80%。