2. 升级中断场景分析:断电中断、通信中断、存储空间不足、版本校验失败、硬件异常

做固件升级最怕什么?我最怕升级到一半,啪,断了。不管是断电还是通信断了,设备变砖的风险就在眼前。这一章咱们把五种常见的中断场景掰开揉碎了讲。你想想看,只有知道敌人长什么样,才能设计出靠谱的恢复策略。

核心观点:升级中断不是「会不会发生」的问题,而是「什么时候发生」的问题。好的恢复策略,必须覆盖每一种中断场景。

固件升级中断场景全景图 升级中断 断电中断 通信中断 存储空间不足 版本校验失败 硬件异常 关键洞察 80% 的升级失败发生在 写入阶段,而非擦除或校验阶段

2.1 断电中断

这是最要命的场景。没有之一。我在一个智能电表项目里遇到过,设备正在写 Flash 的时候突然断电,结果分区表被写了一半,整个系统再也起不来了。

断电中断的核心问题在于:写操作不是原子的。Flash 写入是按页进行的,一页通常是 256 字节或 512 字节。如果写到一半断电,这一页的数据就是残缺的。

我曾经踩过的坑:以为加个大电容就能解决所有问题。后来发现电容只能撑几十毫秒,而写一页 Flash 需要 5-10 毫秒,写一个完整固件需要几秒到几十秒。电容根本扛不住。

断电中断的典型后果:

  • 引导区损坏——设备彻底变砖,连 bootloader 都进不去
  • 固件镜像不完整——校验失败,回退机制失效
  • 文件系统损坏——如果升级涉及文件系统操作,断电可能导致整个文件系统崩溃

我的建议:至少保留两个固件分区——一个运行分区,一个备份分区。升级时先写备份分区,写完后做原子切换。这样即使断电,运行分区还是好的。

2.2 通信中断

无线升级最头疼的就是这个。信号不稳定、连接超时、数据包丢失……说白了,通信中断不是「会不会」的问题,而是「多久一次」的问题。

我记得有个项目用的是 BLE 升级,用户走到隔壁房间,信号一弱,升级就断了。更麻烦的是,通信中断后设备处于「半升级」状态——旧固件已经被擦除了,新固件只收到一半。

通信中断的几种常见形式:

中断类型 典型原因 恢复难度
连接超时 网络延迟、服务器响应慢 低——可重连续传
数据包丢失 无线干扰、信号弱 中——需要重传机制
连接断开 设备移动、网关重启 高——需要重新握手
协议栈崩溃 内存泄漏、驱动异常 极高——可能需要复位

怎么应对?我个人习惯用「断点续传」的思路。把固件分成固定大小的块,每块都带 CRC 校验。接收端记录已收到的块号,重连后从断点继续发。

// 断点续传的块管理结构
typedef struct {
    uint32_t total_blocks;      // 总块数
    uint32_t received_blocks;   // 已接收块数
    uint32_t block_size;        // 每块大小
    uint32_t crc_table[MAX_BLOCKS]; // 每块CRC
    uint8_t  bitmap[MAX_BLOCKS/8];  // 接收位图
} ResumeContext;

2.3 存储空间不足

这个场景容易被忽视。你想想看,嵌入式设备的 Flash 和 RAM 都是寸土寸金。新固件比旧固件大 10%,可能就装不下了。

我在一个物联网网关项目里遇到过:固件从 512KB 升级到 640KB,但 Flash 分区只留了 600KB 的空间。结果升级到 90% 的时候,写入失败,系统直接崩溃。

存储空间不足的三种情况:

  • Flash 空间不够——新固件太大,放不进目标分区
  • RAM 空间不够——解压或校验时需要临时缓冲区,RAM 不够用
  • 文件系统碎片——虽然总空间够,但连续空间不够

关键原则:升级前必须做空间预检。不要等到写的时候才发现空间不够。预检包括:目标分区大小、临时缓冲区大小、备份分区大小。

2.4 版本校验失败

校验失败分两种:一种是固件本身有问题,另一种是传输过程中数据被篡改。

我记得有一次,客户反馈升级后设备反复重启。查了半天,发现是固件包的 CRC 校验码在传输过程中被代理服务器修改了。设备校验通过,但实际运行的是被篡改的固件。

版本校验的完整链条:

  1. 固件包完整性校验——使用 SHA-256 或 CRC32 验证包是否完整
  2. 签名校验——使用 RSA 或 ECDSA 验证固件来源是否可信
  3. 版本号校验——新版本必须高于当前版本,防止回滚攻击
  4. 兼容性校验——新固件是否与当前硬件版本、配置兼容

我曾经犯过的错:只做了 CRC 校验,没做签名校验。结果有人伪造了固件包,设备升级后直接变砖。从那以后,我所有项目都强制要求签名校验。

2.5 硬件异常

这个场景最不可控。Flash 写入超时、看门狗复位、电源纹波过大、温度过高导致 Flash 写入失败……硬件异常的种类太多了。

硬件异常的特点是:随机性强,复现困难。你在实验室测一百次都没问题,到现场就出问题。

常见的硬件异常场景:

异常类型 表现 应对策略
Flash 写入超时 写操作卡死,无法返回 加超时机制,超时后复位重试
看门狗复位 升级过程中看门狗超时 升级期间喂狗,或暂停看门狗
电源异常 电压波动导致写入错误 加电压检测,低于阈值时暂停
温度超限 高温下 Flash 写入不可靠 温度检测,超限时延迟升级

我的经验:硬件异常很难完全避免,但可以通过「重试机制」来降低影响。比如 Flash 写入失败后,等 100ms 再重试,最多重试 3 次。大部分硬件异常都是瞬时的,重试就能过去。