物联网设备OTA升级设计分享

举报
Jack20 发表于 2025/11/24 11:55:52 2025/11/24
【摘要】 核心原则一个稳健的 OTA 升级机制,必须保证在以下任何情况下都不会让设备变砖:升级包传输中断升级过程中突然断电升级包本身损坏或不兼容核心思想是:在设备成功运行新固件之前,永远不要丢弃旧的、可工作的固件。方案一:单分区 + 备份元数据 + 回滚机制 (最轻量)这是最节省资源的方案,只需要一个应用分区,但需要在 Flash 的某个角落(比如单独的配置区或应用分区的末尾)预留一小块空间来存储 “...

核心原则

一个稳健的 OTA 升级机制,必须保证在以下任何情况下都不会让设备变砖:
  1. 升级包传输中断
  2. 升级过程中突然断电
  3. 升级包本身损坏或不兼容
核心思想是:在设备成功运行新固件之前,永远不要丢弃旧的、可工作的固件。

方案一:单分区 + 备份元数据 + 回滚机制 (最轻量)

这是最节省资源的方案,只需要一个应用分区,但需要在 Flash 的某个角落(比如单独的配置区或应用分区的末尾)预留一小块空间来存储 “升级状态” 和 “备份固件信息”。

设计思路:

  1. Flash 分区布局:
    • Bootloader 区: 负责引导程序,检查升级状态,决定启动哪个固件。
    • Application 区: 存放当前正在运行的固件。
    • Metadata 区: (很小,比如 4KB) 存放升级状态标志、新固件的 CRC 校验值、新固件版本号等。
  2. 升级流程:
    • 步骤 1: 下载与校验: 设备通过 Wi-Fi 下载新固件到 RAM 或者临时存储区(如果 Flash 有多余空间)。下载完成后,首先校验升级包的完整性(比如 MD5/SHA)。
    • 步骤 2: 标记升级状态: Bootloader 在 Metadata 区写入状态 UPGRADE_IN_PROGRESS,并记录新固件的 CRC。
    • 步骤 3: 写入新固件: 将新固件覆盖写入 Application 区。
    • 步骤 4: 验证与切换: 写入完成后,Bootloader 读取 Application 区的固件并计算其 CRC,与 Metadata 区记录的 CRC 进行比对。
      • 如果校验成功: 在 Metadata 区将状态修改为 UPGRADE_SUCCESSFUL,然后重启设备。
      • 如果校验失败: 说明写入过程中出了问题,保持状态为 UPGRADE_IN_PROGRESS 或标记为 UPGRADE_FAILED,然后重启设备。
  3. Bootloader 的关键逻辑:
  1. 上电后,Bootloader 首先读取 Metadata 区的状态:
    • 状态为 UPGRADE_SUCCESSFULIDLE: 正常启动 Application 区的固件。
    • 状态为 UPGRADE_IN_PROGRESSUPGRADE_FAILED: 说明上一次升级失败。此时,Bootloader 需要有能力恢复固件

恢复机制 (核心):

  • 方法 A (推荐): 预留备份区域: 在 Application 区的末尾或者另一个单独的小分区里,预先存放一个 “黄金固件”(Golden Firmware),这是一个已知可用的版本。当检测到升级失败时,Bootloader 自动将这个 “黄金固件” 拷贝回 Application 区的起始位置,然后重启。
    • 优点: 恢复过程简单可靠。
    • 缺点: 占用少量额外的 Flash 空间。
  • 方法 B (有风险): 双镜像单分区: 将 Application 区划分为两部分,A 和 B。每次升级只写其中一部分,并在 Metadata 区记录哪个是当前有效的。但这需要 Bootloader 支持从分区的任意位置启动,实现稍复杂,且空间利用率不高,接近 A/B 分区了。

优点:

  • 资源占用最少,只有一个主要应用分区。
  • 实现简单。

缺点:

  • 升级过程中如果断电,旧固件已经被覆盖,必须依赖一个可靠的 “黄金固件” 备份来恢复。
  • “黄金固件” 的更新也是一个问题。

方案二:双 Bootloader 设计 (轻量且可靠)

这个方案不增加应用分区,而是增加一个小的、极简的 “备用 Bootloader”。

设计思路:

  1. Flash 分区布局:
    • Primary Bootloader (主 Bootloader): 功能完善,负责 OTA 升级、校验、引导应用。
    • Secondary Bootloader (备用 Bootloader): 极其简单和健壮,只做一件事 —— 检查主 Bootloader 和 Application 是否完好,如果发现损坏,则尝试从某个备份区域恢复它们,或者直接启动一个备份的应用固件。
    • Application 区: 存放当前固件。
    • Backup 区: (可选) 存放 “黄金固件” 或主 Bootloader 的备份。
  2. 工作流程:
    • 正常情况下,Primary Bootloader 运行,负责所有工作。
    • 如果 Primary Bootloader 本身在升级或运行中损坏,设备上电后,硬件的复位向量会指向 Secondary Bootloader
    • Secondary Bootloader 启动后,执行其预设的恢复逻辑,例如:
      • 检查 Application 区固件的 CRC,如果不正确,则从 Backup 区恢复。
      • 检查 Primary Bootloader 区的 CRC,如果不正确,则从 Backup 区恢复主 Bootloader。
      • 恢复完成后,跳转到 Primary Bootloader 或直接启动 Application

优点:

  • 安全性非常高,即使主引导程序损坏,设备也能自救。
  • 相比 A/B 分区,对 Flash 空间的增加较少(只多了一个小的备用 Bootloader)。

缺点:

  • Bootloader 的开发和维护复杂度增加。
  • 需要确保 Secondary Bootloader 绝对可靠,通常会将其设置为只读或写保护。

方案三:增量升级 (减少风险窗口)

增量升级本身不直接防止变砖,但它能显著降低变砖的概率,并与上述任一方案结合使用。

设计思路:

  • 不传输完整的固件镜像,只传输 “差分补丁”(Delta Patch)。这个补丁包通常比完整固件小一个数量级。
  • 设备收到补丁后,在本地将其与当前运行的旧固件合并,生成新的完整固件。
  • 合并完成后,再执行刷写和校验流程。

优点:

  • 传输时间短: 大大缩短了设备处于 “等待升级” 状态的时间窗口,从而降低了在此期间断电的风险。
  • 节省流量: 对用户和服务器都更友好。

缺点:

  • 增加了设备端的计算量: 需要在设备上运行差分合并算法(如 bsdiff/bspatch)。
  • 对旧固件版本有依赖: 补丁是针对特定版本生成的,如果设备固件版本混乱,会增加管理复杂度。

与方案一结合:

  1. 设备下载增量补丁。
  2. 在 RAM 或临时区域,将补丁与当前固件合并,生成新固件。
  3. 校验新固件的完整性。
  4. 后续流程同方案一:标记状态 -> 写入 -> 校验 -> 重启。

总结一下下

  1. 强烈推荐 “方案一 (单分区 + 备份) + 增量升级”:
    • 增量升级 减少了升级过程的时间和网络传输风险。
    • 单分区 + 备份元数据 提供了最后一道防线,确保即使在写入新固件时断电,设备也能通过 “黄金固件” 恢复。
  2. Bootloader 是关键:
    • Bootloader 代码必须极其健壮和简洁。
    • 尽量避免在 Bootloader 中使用复杂的协议栈(如 Wi-Fi),将复杂的下载逻辑放在应用程序中完成。Bootloader 只负责校验和引导。
    • 对 Bootloader 区域实施写保护,防止其被意外擦除或损坏。
  3. 使用成熟的库:
    • 对于差分升级,可以使用成熟的 bsdiff/bspatch 库的嵌入式版本。
    • 对于固件校验,使用标准的 CRC32, SHA-256 等算法。
  4. 充分测试:
    • 必须进行大量的 “破坏性测试”,比如在升级过程的不同阶段人为断电,验证设备是否能正确回滚和恢复。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。