参考:OTA升级-阿里云开发者社区

OTA升级(Over-The-Air Technology)是一种通过无线通信技术实现远程更新设备固件或软件的方法。这项技术广泛应用于现代物联网(IoT)设备、智能手机、汽车、嵌入式系统等领域,提供了一种无需物理连接的便捷更新方式。以下将详细解释OTA升级的各个方面,包括其工作原理、关键技术以及应用场景等:

概述

OTA升级技术通过无线网络自动、可靠、安全地从远程服务器获取和应用更新,改善设备性能、添加新功能或修复安全漏洞。这种升级方式为用户和生产企业带来了极大的便利性。

工作原理

  • 开发者将最新的固件或软件版本进行打包并上传到OTA服务器。这一过程通常包括固件的压缩、加密及添加版本信息和校验码。

  • 设备通过无线网络定期或在特定触发条件下向OTA服务器查询是否存在新的固件版本。设备发送当前固件版本信息,并从服务器接收是否有新版本可用的响应。

  • 设备从服务器下载固件包,并进行数据校验以确保数据完整性和安全性。

  • 下载完成后,设备验证固件包的完整性和真实性,确认无误后开始安装。许多设备采用双分区(A/B分区)更新机制,保证系统能回滚到先前的稳定版本。

  • 安装完成后,设备通常需要重启以应用新的固件。如果安装失败,设备则可能回滚到之前的固件版本。

关键技术

  • 将更新内容打包成固件包,并通过服务器发布,包含固件的压缩数据、校验信息和更新脚本。

  • 管理和跟踪设备固件版本,确保有序更新,防止版本冲突和升级失败。

  • 使用加密、数字签名、校验和等措施保护更新过程中的数据,防止更新包被篡改或伪造。常用的加密算法包括AES,数字签名算法如RSA。

  • 支持断点续传和恢复功能,防止网络中断或其他故障导致的更新失败。

几种常见的方案

参考:

Bootloader+升级方案_bootloader升级-CSDN博客

单区升级方案

物联网单区 OTA(Single Partition OTA)升级方案是一种精简的固件升级方式,设备仅使用一个主存储分区存放运行固件,升级时直接在该分区覆盖旧版本。这种方案设计简单、占用存储资源少,适合硬件资源有限(如低功耗 MCU、小容量 Flash 设备)的场景,但也存在一定风险。

一、单区 OTA 的核心原理与架构

1. 存储分区设计

单区 OTA 的存储结构通常包含 3 个关键部分(无冗余分区):

  • Bootloader 分区(固定大小,不可升级):负责启动引导、固件校验和升级控制;
  • 主固件分区(唯一可升级分区):存放当前运行的应用固件,升级时直接被新固件覆盖;
  • 临时缓存区(可选,小容量):用于临时存放下载的新固件片段(若设备 RAM 不足)。
+-------------------+----------------------+------------------+
| Bootloader (固定) | 主固件分区 (可升级)  | 临时缓存区 (可选) |
| (如 8KB-64KB)     | (如 128KB-1MB)       | (如 32KB-128KB)  |
+-------------------+----------------------+------------------+

2. 升级流程

单区 OTA 的核心流程是 “下载→校验→覆盖→重启”,具体步骤:

  1. 触发升级:设备通过云端指令或本地触发(如按键),启动 OTA 流程;
  2. 下载固件:从服务器下载新固件(通常带校验信息,如 CRC32、SHA256),若 RAM 足够可暂存于内存,否则先存于临时缓存区;
  3. 校验完整性:下载完成后,验证新固件的校验值是否正确,确保未被篡改或损坏;
  4. 覆盖旧固件:校验通过后,直接将新固件写入主固件分区(覆盖旧版本);
  5. 重启生效:写入完成后,设备重启,Bootloader 加载主分区的新固件运行。

二、单区 OTA 的优缺点

优点:

  1. 资源占用少:无需冗余分区(如双区 OTA 的 A/B 分区),节省 Flash 空间(对小容量 Flash 设备至关重要,如 128KB Flash 的 MCU);
  2. 实现简单:无需复杂的分区切换逻辑和标志位管理,Bootloader 和应用程序设计简化;
  3. 兼容性好:适用于几乎所有嵌入式平台(如 STM32、ESP8266、PIC 等),尤其适合裸机系统或轻量 RTOS。

缺点:

  1. 升级风险高:若升级过程中断(如断电、网络故障),主分区固件会被破坏,设备可能变砖(无法启动);
  2. 无回滚能力:升级失败后无法恢复到旧版本,只能通过重新烧录固件(如 J-Link 物理连接)修复;
  3. 对环境要求高:需保证升级过程中电源稳定、网络可靠,否则失败概率高。

三、关键技术与优化措施

为弥补单区 OTA 的缺陷,实际应用中需加入以下保障机制:

1. 固件校验与加密

  • 完整性校验:新固件必须包含校验信息(如 CRC32、SHA256),写入前验证,避免写入损坏的固件;
  • 加密传输:通过 AES 加密固件,防止传输过程中被篡改(尤其在非加密网络中);
  • 签名验证:使用 RSA 等算法对固件签名,Bootloader 启动时验证签名,防止恶意固件刷入。

2. 断点续传

  • 若固件体积较大(超过设备 RAM),支持断点续传:将固件分块下载,每块校验后存入临时缓存区,全部下载完成后再合并写入主分区,减少单次写入中断的风险。

3. 紧急恢复机制

  • Bootloader 救援模式:若主分区固件损坏,Bootloader 检测到异常后,进入 “救援模式”(如通过特定引脚电平触发),允许重新通过串口或简易网络下载固件;
  • 最小系统备份:在主分区外预留极小区域(如 16KB),存放 “最小可启动固件”,升级失败时 Bootloader 可加载该固件进行基础修复。

4. 电源与网络保障

  • 升级前检查设备供电状态(如电池电量 > 50%),避免低电量升级;
  • 优先在稳定网络环境下触发升级(如 Wi-Fi 信号强度 > 80%),减少下载中断概率。

四、典型应用场景

单区 OTA 适合硬件资源有限、对成本敏感、升级频率低且环境可控的设备,例如:

  • 低功耗传感器(如温湿度传感器、光照传感器):固件体积小(<64KB),升级频率低;
  • 简单控制设备(如智能开关、小家电控制器):功能单一,升级需求少;
  • 工业领域的 “非关键节点” 设备:环境稳定(如工厂内网、电源可靠),可接受偶尔物理修复。

单区 OTA 是一种 “轻量、低成本” 的升级方案,核心优势是节省资源和实现简单,但需通过校验、加密、紧急恢复等机制降低风险。它适合硬件受限且升级场景可控的设备,是物联网低功耗、极简设备的常见选择。若设备对可靠性要求极高(如医疗设备、工业控制核心节点),则建议采用双区 OTA 方案。

双区升级方案

物联网双区 OTA(Dual Partition OTA,又称 A/B 分区升级)是一种高可靠性的固件升级方案,通过在设备中划分两个独立的固件分区(A 分区和 B 分区) 实现安全升级,即使新固件安装失败,设备也能回滚到旧版本,避免 “变砖” 风险。这种方案广泛应用于对可靠性要求高的物联网设备(如工业控制器、智能家居网关、车载设备等)。

一、双区 OTA 的核心架构与原理

1. 存储分区设计

双区 OTA 的存储结构通常包含 4 个关键部分:

  • Bootloader 分区(固定大小,不可升级):负责启动引导、分区选择、固件校验;
  • A 分区(主分区):存放当前正在运行的固件版本;
  • B 分区(备用分区):用于接收新固件,升级时写入此分区;
  • 参数区(小容量):存储分区状态标志(如 “当前激活分区”“升级状态”“校验结果”)。
+-------------------+----------------------+----------------------+------------------+
| Bootloader (固定) | A分区 (主固件)       | B分区 (备用/新固件)  | 参数区 (标志位)  |
| (如 16KB-128KB)   | (如 512KB-4MB)       | (与A分区等大)        | (如 4KB-32KB)    |
+-------------------+----------------------+----------------------+------------------+

2. 核心原理:“先写备用分区,验证通过再切换”

双区 OTA 的关键是升级过程不影响当前运行的固件,具体逻辑:

  • 设备正常运行时,Bootloader 根据参数区的 “激活标志” 加载 A 分区固件(默认状态);
  • 升级时,新固件被写入 B 分区(此时 A 分区仍在运行,不被干扰);
  • 新固件写入完成并校验通过后,参数区的 “激活标志” 被修改为 “优先启动 B 分区”;
  • 设备重启后,Bootloader 加载 B 分区的新固件;若新固件运行正常,参数区更新 “成功标志”;若运行失败(如启动卡壳),Bootloader 自动切回 A 分区,保证设备可用。

二、双区 OTA 的详细升级流程

以 “A 分区运行旧固件,升级到 B 分区新固件” 为例,步骤如下:

  • 触发升级与下载新固件

    • 设备接收云端升级指令,确认当前激活分区(如 A 分区),确定备用分区(B 分区);
    • 从服务器下载新固件(带校验信息,如 SHA256 签名),边下载边写入 B 分区(避免占用过多 RAM)。
  • 校验新固件完整性

    • 下载完成后,计算 B 分区新固件的校验值,与服务器提供的签名比对;
    • 若校验失败,丢弃 B 分区数据,升级终止(A 分区仍正常运行)。
  • 更新启动标志位

    • 校验通过后,修改参数区的 “激活标志” 为 “下次启动 B 分区”,并记录 “待验证状态”。
  • 重启并尝试启动新固件

    • 设备重启,Bootloader 读取参数区,发现 “激活标志 = B 分区”,加载 B 分区固件;
    • 新固件启动后,需在规定时间内(如 10 秒)向 Bootloader 反馈 “启动成功”(通过写参数区标志实现)。
  • 确认升级成功或回滚

    • 若新固件成功反馈 “启动正常”,参数区更新为 “B 分区激活,升级完成”,下次启动默认加载 B 分区;
    • 若新固件未按时反馈(如启动失败、崩溃),Bootloader 判定升级失败,自动将 “激活标志” 改回 “A 分区”,重启后加载旧固件,实现自动回滚。

三、双区 OTA 的核心优势

  1. 高可靠性,避免设备变砖
    升级过程中即使断电、新固件损坏,也不会影响原分区(A 分区)的旧固件,Bootloader 可自动回滚,解决单区 OTA 的致命缺陷。

  2. 无缝升级,减少停机时间
    新固件在备用分区写入和校验,不影响当前运行的固件,仅在最后一步通过重启切换,适合对 “连续运行” 要求高的设备(如工业控制器)。

  3. 支持复杂场景扩展
    可基于双区架构衍生出 “多版本回滚”(如保留多个历史版本)、“差分升级”(仅传输新旧固件差异)等高级功能。

四、关键技术与注意事项

  • 分区大小设计

    A、B 分区需大小相同,且容量需大于最大固件体积(通常预留 20%-30% 冗余,应对固件膨胀)。

  • 启动校验机制

    • Bootloader 需严格校验固件签名(如 RSA 签名),防止恶意固件写入;
    • 新固件启动后必须主动 “上报存活状态”(如通过 GPIO、参数区标志),否则 Bootloader 判定失败并回滚。
  • 参数区保护

    参数区存储关键标志位,需采用 “写保护 + 冗余存储”(如同一标志存 2 份,取多数值),防止断电导致标志位错乱。

  • Flash 磨损均衡

    若设备使用 NAND Flash(有擦写次数限制),需通过算法均衡 A、B 分区的擦写次数(如交替作为 “备用分区”),延长存储寿命。

五、典型应用场景

双区 OTA 适合对可靠性要求高、升级频率中等、硬件资源较充足的设备:

  • 工业物联网设备(如 PLC、传感器网关):停机成本高,不允许升级失败;
  • 智能家居核心设备(如智能音箱、中控网关):用户对 “设备变砖” 零容忍;
  • 车载物联网设备(如车机系统、OBD 模块):需符合车规级可靠性标准。

双区 OTA 通过 “双分区冗余 + 校验 + 自动回滚” 机制,解决了单区 OTA 的可靠性痛点,是当前中高端物联网设备的主流升级方案。虽然它会占用更多存储资源且实现较复杂,但对于需要保障设备持续可用的场景(如工业、车载、智能家居),这种 “牺牲资源换可靠性” 的设计是必要的。

差分升级方案

物联网差分 OTA(Differential OTA)升级方案是一种通过传输 “新旧固件差异内容” 而非完整固件包来实现升级的技术,能显著减少升级包体积(通常可减少 50%-90%),节省网络带宽和设备存储资源,尤其适合低带宽环境(如 NB-IoT、LoRa)或硬件资源有限的设备。

一、差分 OTA 的核心原理

差分 OTA 的核心是 **“只传变化,不传全部”**,通过以下三步实现:

  1. 差分包生成(云端)
    云端对比设备当前固件版本(旧版)和目标版本(新版),通过差分算法(如 bsdiff、xdelta3、zstd)计算两者的二进制差异,生成体积远小于完整固件的差分包(delta file)

    例如:旧固件(1MB)→ 新版固件(1.2MB,仅修改了部分功能模块)→ 差分包(可能仅 100KB,包含修改部分的二进制数据)。

  2. 差分包传输(设备端)
    设备从云端下载差分包(而非完整固件),大幅减少传输数据量(尤其在 NB-IoT 等按流量计费的场景中,可降低成本)。

  3. 本地合成新固件(设备端)
    设备接收差分包后,结合本地存储的旧固件,通过与云端相同的差分算法反向合成新固件,再写入存储分区(通常配合双区 OTA 实现安全升级)。

二、差分 OTA 的关键流程(结合双区架构)

为保证可靠性,差分 OTA 通常与双区 OTA 结合使用,完整流程如下:

云端:
旧固件(V1.0) → 差分算法 → 差分包(delta.bin) → 提供下载

设备端:
1. 检测当前版本(V1.0),请求云端差分包;
2. 下载delta.bin到临时缓存区;
3. 校验差分包完整性(如CRC/SHA);
4. 以本地V1.0固件为基础,应用delta.bin合成V2.0完整固件;
5. 将合成的V2.0写入B分区(备用分区);
6. 校验B分区新固件完整性;
7. 切换启动分区,重启后运行V2.0(失败则回滚到A分区V1.0)。

三、主流差分算法对比

不同差分算法的压缩效率、计算复杂度和兼容性不同,需根据设备能力选择:

算法压缩效率计算复杂度(设备端)适用场景
bsdiff高(需较多 RAM)固件差异较大、设备资源充足(如 Linux 网关)
xdelta3中小规模固件、RTOS 设备(如 STM32)
zstd中(支持流式处理)需兼顾效率和速度的场景
简单块比对低(适合 MCU)极简设备(如 8 位 MCU),仅比对固定块差异

四、差分 OTA 的核心优势

  1. 节省网络带宽
    差分包体积远小于完整固件(如 10MB 固件→1MB 差分包),尤其适合低速率网络(如 LoRa、NB-IoT),减少传输时间和失败概率。

  2. 降低存储压力
    设备无需缓存完整新固件,只需存储差分包(通常为原固件的 10%-30%),适合小容量 Flash 设备(如 256KB Flash 的 MCU)。

  3. 减少功耗
    传输数据量减少,设备无线模块(如 Wi-Fi、蜂窝模组)的工作时间缩短,降低电池功耗(对低功耗传感器至关重要)。

五、关键挑战与解决方案

  • 设备端计算能力要求

    • 问题:合成新固件需消耗 CPU 和 RAM(如 bsdiff 合成 1MB 固件可能需 2-4MB RAM),对低配置 MCU(如 RAM<64KB)压力大。
    • 解决:选择轻量级算法(如 xdelta3),或在设备端采用 “分片合成”(分块处理差分包,降低单次内存占用)。
  • 版本依赖限制

    • 问题:差分包与旧版本强绑定(V1.0→V2.0 的差分包无法用于 V1.1→V2.0),若设备版本碎片化严重,云端需维护大量差分包。
    • 解决:采用 “基线版本” 策略(如指定 V1.0 为基线,所有旧版本先升级到基线,再用基线到 V2.0 的差分包),减少差分包数量。
  • 安全性风险

    • 问题:差分包若被篡改,合成的新固件可能存在恶意代码。
    • 解决:差分包需附加数字签名(如 RSA),设备端验证通过后才合成;合成后对新固件再次校验(与云端提供的 SHA 值比对)。
  • 兼容性问题

    • 问题:不同硬件版本(如 Flash 型号、外设配置)的固件可能不兼容,差分包可能导致升级失败。
    • 解决:差分包生成时关联硬件型号,设备请求时携带硬件信息,云端返回匹配的差分包。

六、典型应用场景

差分 OTA 适合以下场景:

  • 低带宽 / 高延迟网络:如 NB-IoT 物联网表计(水表、电表)、LoRa 传感器,通过减少数据量避免传输超时;
  • 低功耗设备:如电池供电的智能门锁、穿戴设备,降低无线传输功耗以延长续航;
  • 大容量固件设备:如搭载 Linux 的智能网关(固件体积 100MB+),差分包可节省大量流量成本。

七、与全量 OTA 的对比

维度差分 OTA全量 OTA
升级包大小小(仅差异内容)大(完整固件)
网络依赖低(适合低带宽)高(需稳定高带宽)
设备资源要求中(需合成计算)低(直接写入)
版本管理复杂(需维护多版本差分包)简单(仅需目标版本)
适用场景低带宽、低功耗、大容量固件设备高带宽、资源有限、小固件设备

总结

差分 OTA 是物联网设备升级的 “高效方案”,核心价值在于通过传输 “差异内容” 降低网络和存储成本,尤其适合资源受限或网络条件差的场景。实际应用中,常与双区 OTA 结合(差分包合成新固件后写入备用分区),在保证效率的同时提升可靠性。目前,差分 OTA 已成为中高端物联网设备的主流升级方式,被华为、阿里云、艾拉比等主流物联网平台广泛支持。

对文件系统的依赖

物联网的 OTA 是否需要文件系统支持,并非绝对必要,核心取决于 OTA 的升级对象、设备硬件资源(如存储类型)以及升级方案的设计。但在大多数复杂场景(尤其是升级应用程序、配置文件或多模块固件时),文件系统的支持能显著提升 OTA 的灵活性、可靠性和可管理性。

一、先明确:OTA 的 “升级对象” 决定是否依赖文件系统

物联网 OTA 的升级对象通常分为两类,不同对象对文件系统的需求截然不同:

升级对象核心特点是否需要文件系统?典型场景
裸机固件 /bootloader直接写入设备的 “原始存储区域”(如 Flash),无文件概念通常不需要极简嵌入式设备(如传感器、低功耗 MCU 设备)
应用程序 / 配置文件需区分 “不同文件”(如 APP 镜像、参数配置、资源包)推荐或必须依赖文件系统智能网关、工业控制器、带 UI 的智能设备

二、不需要文件系统的 OTA 场景(“裸写” 方案)

当 OTA 仅升级单一、连续的固件镜像(如裸机 MCU 的整个程序),且存储介质为 “无文件系统的原始 Flash/SRAM” 时,可直接通过 “地址映射” 方式写入,无需文件系统。

核心原理

设备将存储介质(如 Nor Flash)划分为固定的 “物理分区”(如 “Boot 分区”“固件分区 A”“固件分区 B”),OTA 过程中仅需知道 “目标分区的物理地址”,直接将固件镜像按字节写入对应地址,无需管理 “文件名称、路径、权限” 等文件系统概念。

典型场景:极简 MCU 设备的双分区 OTA

以低功耗 MCU(如 STM32L4、ESP8266 裸机方案)为例,常见 “双分区(A/B)升级”:

  1. 存储划分:Boot分区(固定地址0x08000000)固件A分区(0x08008000)固件B分区(0x08040000)
  2. OTA 流程:设备从服务器下载新固件 → 直接写入 “空闲的 B 分区”(通过物理地址定位) → 写入完成后修改 Boot 分区的 “启动标志位” → 重启后 Bootloader 加载 B 分区固件;
  3. 关键:整个过程仅操作 “物理地址”,无需文件系统,适合资源极度有限(如 RAM<16KB、Flash<128KB)的设备。

局限性

  • 仅支持 “单一镜像升级”,无法单独升级配置文件、资源包(如字体、图标);
  • 存储管理僵化:若需新增升级对象(如多模块固件),需重新划分物理分区,灵活性差;
  • 风险较高:若写入过程中断(如断电),可能导致分区数据损坏,需依赖 Bootloader 的校验机制(如 CRC、MD5)恢复。

三、需要文件系统的 OTA 场景(“文件化” 方案)

当 OTA 涉及多类型升级对象(如 APP、配置、资源包)、动态存储管理或复杂设备架构时,文件系统是 “高效管理存储” 的必要工具。

核心原因:文件系统解决了 3 个关键问题

  1. “多文件区分” 问题
    复杂设备(如智能网关、工业 PLC)需升级的内容可能包括:应用程序镜像(app.bin)硬件配置文件(config.json)UI资源包(res.zip)驱动模块(driver.so)。文件系统(如 FAT32、LittleFS、JFFS2)通过 “文件名 + 路径” 区分不同文件,避免不同升级对象写入同一分区导致混乱。

  2. “存储动态管理” 问题
    无文件系统时,存储分区大小固定(如固件 A 分区固定 4MB),若新固件体积超过 4MB,需重新硬件设计;而文件系统支持 “动态分配存储空间”,只要总存储剩余空间足够,即可灵活存储不同大小的升级文件,无需预划分固定分区。

  3. “可靠性与可维护性” 问题
    文件系统通常自带 “数据校验(如 CRC)、坏块管理(如 NAND Flash 的坏块处理)、断电恢复” 机制,能降低 OTA 中断导致的存储损坏风险;同时,可通过文件系统的 “删除、重命名、备份” 操作,实现升级前的配置备份、升级失败后的回滚(如删除损坏的新文件,恢复旧文件)。

典型场景:Linux/RTOS 设备的多模块 OTA

以搭载 Linux(如 OpenWRT)的智能网关为例:

  1. 存储介质(如 eMMC)采用 EXT4 文件系统,划分/boot(启动文件)、/root(根文件系统,含应用程序)、/etc(配置文件)、/tmp(临时下载目录);
  2. OTA 流程:网关从服务器下载app_v2.0.tar.gz(应用包)和config_v2.0.json(配置文件) → 存储到/tmp目录 → 解压后将app_v2.0覆盖/root/app,将config_v2.0.json备份到/etc/config/backup后替换原文件 → 重启应用生效;
  3. 关键:通过文件系统的目录结构和文件操作,实现多文件的有序管理,升级失败后可从/etc/config/backup恢复旧配置。

四、主流 OTA 方案与文件系统的关联

不同 OTA 方案对文件系统的依赖程度不同,具体对应关系如下:

OTA 方案对文件系统的需求适用设备类型
全量固件升级若升级 “单一镜像”(如裸机 MCU),无需;若升级 “多文件镜像”(如 Linux 根文件系统),需要极简 MCU 设备、复杂 Linux 设备
差分升级推荐需要:差分包生成后需存储为文件(如 delta.bin),升级时需读取旧文件、应用差分到新文件大多数 RTOS/Linux 设备
双分区(AB)升级裸机场景无需;若分区内包含多文件(如 A 分区是 EXT4 文件系统),则需要极简 MCU(无需)、智能设备(需要)
多模块升级必须需要:需通过文件系统区分不同模块的升级文件(如 sensor.bin、wifi.bin)多模块设备(如智能摄像头、工业控制器)

五、总结:是否需要文件系统?关键看 “设备复杂度”

  • 无需文件系统:仅升级单一固件、资源极度有限(Flash<256KB、RAM<32KB)的裸机 MCU 设备(如低功耗传感器、简单控制器),追求 “极简、低成本”;
  • 需要文件系统:升级多类型文件(APP、配置、资源)、存储介质较大(Flash>1MB)、追求 “灵活、可靠” 的 RTOS/Linux 设备(如智能网关、工业 PLC、消费级 IoT 设备),是当前中高端物联网设备的主流选择。

综上,文件系统并非 OTA 的 “必需品”,但却是复杂物联网设备实现灵活、可靠 OTA 的 “优选方案”。随着物联网设备功能的多样化(如多模块、多配置),依赖文件系统的 OTA 方案正成为主流。

双分区OTA过程示例

双分区(A/B 分区)升级中,分区的跳转执行主要通过Bootloader 引导程序分区状态标志实现,核心逻辑是 “启动时根据标志位选择加载的分区,运行中通过修改标志位实现下次启动的分区切换”。以下是具体实现方式:

一、核心依赖:分区状态标志与 Bootloader 决策

双分区跳转的关键是用一个独立的 “参数区” 存储分区状态,并由 Bootloader 在设备启动时读取该状态,决定加载 A 分区还是 B 分区。

1. 参数区设计

参数区(通常是 Flash 中的一小块独立区域,不可被固件升级覆盖)需存储以下关键标志:

  • 激活分区标志:记录当前应启动的分区(如0x01表示 A 分区,0x02表示 B 分区);
  • 升级状态标志:记录是否处于升级过程中(如0x00表示正常,0x01表示待验证新分区);
  • 固件校验结果:存储 A/B 分区固件的校验值(如 CRC32、SHA256),用于 Bootloader 验证固件完整性。

示例参数区结构(简化):

struct partition_flag {
    uint8_t active_part;    // 0x01=A分区, 0x02=B分区
    uint8_t upgrade_state;  // 0x00=正常, 0x01=新分区待验证
    uint32_t crc_a;         // A分区固件CRC
    uint32_t crc_b;         // B分区固件CRC
};

2. Bootloader 的启动流程(核心跳转逻辑)

Bootloader 是设备上电后第一个运行的程序,负责分区选择和引导,流程如下:

  1. 读取参数区标志:上电后,Bootloader 首先读取active_partupgrade_state
  2. 验证目标分区固件:根据active_part,读取对应分区(A 或 B)的固件,计算 CRC 并与参数区的crc_a/crc_b比对,确认固件完整;
  3. 检查升级状态
    • upgrade_state0x00(正常状态):直接加载active_part对应的分区固件,跳转执行;
    • upgrade_state0x01(新分区待验证):加载新分区固件,但需等待固件运行后反馈 “启动成功”;
  4. 失败回滚机制:若新分区固件验证失败,或运行后未在规定时间内反馈成功,Bootloader 自动将active_part切回旧分区,重启后加载旧固件。

二、分区切换的触发时机与实现

分区跳转(从 A 到 B 或反之)通常在新固件升级完成并验证通过后触发,由应用程序或 Bootloader 修改参数区标志实现。

1. 升级过程中切换标志(应用程序层)

以 “A 分区运行旧固件,升级到 B 分区新固件” 为例:

  1. 设备下载新固件并写入 B 分区,完成后计算 B 分区 CRC,更新参数区的crc_b
  2. 应用程序修改参数区:将active_part设为0x02(B 分区),upgrade_state设为0x01(待验证);
  3. 设备重启,Bootloader 读取标志,加载 B 分区固件。

2. 新固件验证通过后确认切换(新固件层)

新固件(B 分区)启动后,需主动 “确认存活” 以完成最终切换:

  1. 新固件运行后,初始化关键模块(如网络、外设),若正常启动,向参数区写入 “成功标志”:将upgrade_state改回0x00(正常状态);
  2. 若新固件启动失败(如卡壳、崩溃),未在规定时间(如 10 秒)内更新upgrade_state,Bootloader 判定升级失败,下次启动时自动切回 A 分区。

三、硬件与代码层面的具体实现

1. 存储地址映射(以 MCU 为例)

需在链接脚本(如 STM32 的.ld文件)中固定各分区地址,确保 Bootloader 能正确定位:

// 示例:STM32 Flash分区地址定义
#define BOOTLOADER_ADDR   0x08000000  // Bootloader起始地址
#define PARTITION_A_ADDR  0x08008000  // A分区起始地址
#define PARTITION_B_ADDR  0x08048000  // B分区起始地址(与A分区等大)
#define PARAM_ADDR        0x08088000  // 参数区起始地址

2. Bootloader 跳转代码(关键片段)

Bootloader 验证分区后,通过函数指针跳转到目标分区的固件入口(通常是复位向量表的首地址):

// 从参数区读取激活分区
uint8_t active_part = read_param(PARAM_ADDR, offsetof(struct partition_flag, active_part));

// 确定目标分区地址
uint32_t target_addr = (active_part == 0x01) ? PARTITION_A_ADDR : PARTITION_B_ADDR;

// 验证目标分区固件CRC(简化逻辑)
if (verify_crc(target_addr, active_part) != 0) {
    // 校验失败,切回旧分区
    active_part = (active_part == 0x01) ? 0x02 : 0x01;
    target_addr = (active_part == 0x01) ? PARTITION_A_ADDR : PARTITION_B_ADDR;
}

// 跳转至目标分区固件(关键步骤)
typedef void (*boot_func)(void);
boot_func jump_to_app = (boot_func)(*(uint32_t *)(target_addr + 4));  // 固件入口地址(复位向量表第二项)

// 关闭中断,设置栈顶指针(固件复位向量表第一项是栈顶地址)
__set_MSP(*(uint32_t *)target_addr);
jump_to_app();  // 跳转执行新固件

3. 应用程序修改参数区(切换标志)

应用程序升级完成后,通过 Flash 写入函数修改参数区标志:

// 升级完成后,设置下次启动B分区
struct partition_flag flag;
read_param_block(PARAM_ADDR, &flag, sizeof(flag));

flag.active_part = 0x02;          // 激活B分区
flag.upgrade_state = 0x01;        // 标记为待验证
flag.crc_b = calculate_crc(B_ADDR, B_SIZE);  // 更新B分区CRC

write_param_block(PARAM_ADDR, &flag, sizeof(flag));  // 写入参数区
NVIC_SystemReset();  // 重启生效

四、关键注意事项

  1. 参数区保护:参数区是分区跳转的 “核心大脑”,需防止意外篡改(如加写保护、冗余存储多份标志,取多数值);
  2. 固件入口地址:各分区固件的链接地址必须与分区物理地址一致(通过链接脚本保证),否则跳转后会运行异常;
  3. 中断向量表重映射:部分 MCU(如 STM32)的中断向量表默认在 0 地址,跳转至新分区后需通过寄存器将向量表重映射到当前分区地址,否则中断会失效;
  4. 原子操作:修改参数区标志时需用 “原子操作”(如先擦除再写入,避免断电导致标志位错乱),必要时分两步写入(先写临时标志,确认后再写正式标志)。

总结

双分区的跳转执行本质是 **“Bootloader 根据参数区标志选择启动分区,应用程序通过修改标志控制下次启动的分区”**,核心依赖三个要素:独立的参数区存储状态、Bootloader 的校验与决策逻辑、固件运行后的存活确认机制。这种设计确保了升级失败时能自动回滚,是双分区方案可靠性的关键。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐