一、固件升级系统概述
1.1 什么是固件升级
固件升级,说白了就是把设备里跑的程序换一版新的。你想想看,手机、路由器、智能家电,这些嵌入式设备出厂时烧录的代码,总会有bug要修、功能要加、性能要调。这时候就需要升级。
我刚开始做嵌入式那会儿,升级还得靠串口线或者JTAG。拿根线连上电脑,打开烧录工具,等个几分钟。要是现场有几十台设备,那就得一台一台插线操作,累得够呛。后来OTA(Over-The-Air)升级普及了,才算是解放了双手。
固件升级的本质,其实就三件事:
- 获取新固件 —— 从服务器、本地存储或者外部介质拿到新的二进制文件
- 写入存储 —— 把新固件写到Flash、eMMC或者SD卡里
- 切换运行 —— 让设备从旧固件切换到新固件,正常跑起来
核心要点:固件升级不是简单的文件拷贝。它要保证设备在升级过程中断电、断网、写错数据后,还能恢复回来。这才是真正的难点。
1.2 OTA升级原理
OTA升级,就是通过网络远程给设备换固件。它的工作流程大致是这样的:
- 设备联网 —— 通过Wi-Fi、蜂窝网络、以太网等方式连接到升级服务器
- 版本检查 —— 设备上报当前固件版本,服务器判断是否需要升级
- 下载固件 —— 如果有新版本,设备下载固件包(可能是全量包,也可能是差分包)
- 校验完整性 —— 下载完成后,用MD5、SHA256或者签名验证固件有没有被篡改
- 写入备用分区 —— 把新固件写到Flash的备用区域,不覆盖当前运行的系统
- 切换启动 —— 重启设备,Bootloader检测到新固件,加载运行
- 回滚机制 —— 如果新固件启动失败,自动切回旧版本
这里我特别想强调一下「双分区」的设计。我在一个智能家居项目里吃过亏——当时为了省Flash空间,只用了单分区,升级时直接覆盖。结果有一次下载到一半断电了,设备直接变砖。后来老老实实加了双分区,再也没出过这种问题。
我的经验:OTA升级最怕的不是下载慢,而是下载完成后写Flash时断电。所以一定要保证写入操作的原子性——要么全写成功,要么一点不改。
下面这张图,把OTA升级的完整流程画出来了:
1.3 固件升级的挑战与解决方案
做了这么多年固件升级,我踩过的坑真不少。总结下来,核心挑战就这几个:
| 挑战 | 风险 | 解决方案 |
|---|---|---|
| 升级中断 | 设备变砖,无法恢复 | 双分区 + 原子写入 + Bootloader回滚 |
| 固件损坏 | 运行异常,功能失效 | CRC/MD5/SHA256校验 + 数字签名验证 |
| 存储空间不足 | 无法下载或写入新固件 | 差分升级(Delta OTA)+ 压缩传输 |
| 网络不稳定 | 下载失败,反复重试 | 断点续传 + 分片下载 + 超时重试机制 |
| 版本兼容性 | 新固件与旧配置不匹配 | 版本号管理 + 配置迁移脚本 + 兼容性检查 |
| 安全攻击 | 固件被篡改,植入恶意代码 | HTTPS传输 + 签名验证 + 安全启动链 |
⚠️ 我曾经踩过的坑:有一次做智能门锁的OTA升级,没做签名验证。结果有人抓包替换了固件,门锁被远程开了。从那以后,我所有项目的固件升级都必须过签名校验,哪怕只是内部测试版本。
1.4 双分区升级架构详解
双分区(A/B分区)是目前最可靠的升级方案。它的核心思想是:Flash里放两份固件,一份在跑,一份备用。
具体来说:
- 分区A —— 当前运行的系统
- 分区B —— 备用分区,用来写入新固件
- Bootloader —— 启动时判断该从哪个分区加载
- 元数据区 —— 记录当前活跃分区、升级状态、回滚次数
升级时,新固件写入备用分区,不碰正在运行的分区。写完后,Bootloader在下次启动时尝试加载新分区。如果启动成功,就标记为活跃分区;如果启动失败,就切回旧分区。
我的建议:双分区虽然多占一倍的Flash空间,但换来的是「永不砖机」的可靠性。对于量产产品来说,这点成本完全值得。我经手的项目里,凡是用了双分区的,从来没有因为升级出过批量事故。
下面这张图展示了双分区的布局:
1.5 升级策略的选择
不同的产品,升级策略也不一样。我整理了几种常见方案:
| 策略 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 全量升级 | 存储空间充足,网络带宽好 | 实现简单,兼容性好 | 下载量大,耗时较长 |
| 差分升级 | 存储空间有限,带宽受限 | 下载量小,升级快 | 需要差分算法,版本关联性强 |
| 压缩升级 | 中等存储,中等带宽 | 比全量小,比差分简单 | 解压占用CPU和内存 |
| 流式升级 | 实时性要求高,边下边写 | 无需额外存储空间 | 中断风险高,恢复复杂 |
我的选择建议:如果是量产产品,我首选「全量升级 + 双分区」。虽然下载量大一点,但胜在稳定可靠。差分升级虽然省流量,但版本之间的依赖关系容易出问题——我曾经遇到过差分补丁打错了,导致设备反复重启的惨案。
1.6 安全升级的底线
安全这块,我吃过亏,所以特别重视。固件升级的安全底线至少要做到:
- 传输加密 —— 用HTTPS或者TLS,别用明文HTTP
- 签名验证 —— 固件包必须带数字签名,设备端验签后再写入
- 防回滚 —— 防止攻击者刷回有漏洞的旧版本
- 安全启动 —— Bootloader验证固件签名,签名不对就不加载
⚠️ 血的教训:我早期做的一个IoT项目,固件升级只做了CRC校验,没做签名。结果产品上市后被黑客破解,批量刷入了挖矿程序。那次事故让我明白——安全不是可选项,是必选项。
好了,这一章的内容就到这里。固件升级看起来简单,但真正要做好,涉及的东西不少。后面的章节,我会一步步带你从零搭建一套完整的固件升级系统。