OTA 升级框架
本页面介绍 AW33N BLE SDK 中的 OTA(Over-The-Air)固件升级框架,涵盖升级核心、双区(dual-bank)更新、RCSP/Testbox/UART 等多种升级通道、Loader 下载、配置与示例代码,说明各模块的职责、协作关系与整体升级流程。
目的与范围
本页覆盖内容
- 升级框架的整体架构与模块划分(
apps/app/bsp/common/update/与apps/include_lib/update/) - 升级核心:
update.c/update.h以及code_v2版本的升级库(update_lib.a、update.ld) - 双区更新机制:
dual_update_demo.c、dual_update_crc_cal.c - 多种升级通道:RCSP 升级(
rcsp_user_update.c)、Testbox 升级(testbox_update.c、testbox_uart_update.c)、UART 升级(uart_update.h)、Loader 下载(update_loader_download.h) - 升级配置(
lib_update_config.c)与示例(ota_dg_central.c、ble_fmy_ota.c、app_custom_db_update.c) - 构建产物(
ota.bin/ota_debug.bin)
不在本页范围
- RCSP(Jieli 私有协议)本身的服务端/客户端协议细节,属于 RCSP 协议相关页面
- findmy、dongle transfer 等具体应用功能的完整实现,仅在本页引用其 OTA 相关示例
- 蓝牙控制器内部消息机制的全貌,仅引用与 OTA 相关的消息枚举
说明:受源码探索预算限制,本页对文件路径、模块划分与消息枚举均基于实际读取到的仓库信息;具体函数签名与内部算法细节以各头文件/源文件为准,文中对未验证处已明确标注。
概述
OTA(Over-The-Air,空中升级)是嵌入式 BLE 设备最关键的运维能力之一:设备通过 BLE、UART 等通道接收新固件数据,写入 Flash,在校验通过后切换到新固件运行。AW33N BLE SDK 将这一能力组织为一套分层升级框架:
- 触发与传输层:各种升级入口(RCSP、Testbox、UART、Loader 下载)负责接收固件数据并把数据交给升级核心。
- 升级核心层:
apps/app/bsp/common/update/update.c(源码实现)与apps/include_lib/update/code_v2/(预编译库update_lib.a+ 链接脚本update.ld)提供升级主流程与 Flash 读写管理。 - 双区更新层:
dual_update_demo.c与dual_update_crc_cal.c实现双分区方案(当前固件区 + 待升级区 + CRC 校验),支持失败回滚。 - 配置与示例层:
lib_update_config.c控制升级库的启用与参数;ota_dg_central.c、ble_fmy_ota.c、app_custom_db_update.c给出可参考的接入方式。
框架同时以两种形态存在:源码形态(common/update/update.c)和 库形态(apps/include_lib/liba/bd57/flash/update_lib.a 预编译静态库 + code_v2 头文件),后者面向 bd57 平台的 Flash 方案,通过 update.ld 链接脚本控制升级相关段的内存布局。构建时,apps/app/post_build/bd57/ 目录下会生成 ota.bin 与 ota_debug.bin 两种升级固件镜像(调试版与正式版)。
架构
flowchart TD
subgraph sg_Trigger["触发与传输层 (Trigger / Transport)"]
RCSP["rcsp_user_update.c<br/>(RCSP 升级通道)"]
TBOX["testbox_update.c<br/>testbox_uart_update.c<br/>(Testbox 升级通道)"]
UART["uart_update.h<br/>(UART 升级)"]
LOADER["update_loader_download.h<br/>(Loader 固件下载)"]
end
subgraph sg_Core["升级核心 (Update Core)"]
CORE["update.c / update.h<br/>(升级主流程)"]
COREV2["code_v2/update.h + update_lib.a<br/>(bd57 预编译升级库)"]
DUAL["dual_update_demo.c<br/>dual_update_crc_cal.c<br/>(双区更新与 CRC)"]
end
subgraph sg_Cfg["配置与示例 (Config & Examples)"]
CFG["lib_update_config.c<br/>(升级库配置)"]
EX1["ota_dg_central.c<br/>(dongle 中心设备 OTA)"]
EX2["ble_fmy_ota.c<br/>(findmy 应用 OTA)"]
EX3["app_custom_db_update.c<br/>(自定义数据库升级)"]
end
subgraph sg_Out["构建产物 (Build Output)"]
BIN["ota.bin / ota_debug.bin<br/>(升级固件镜像)"]
end
RCSP --> CORE
TBOX --> CORE
UART --> CORE
LOADER --> CORE
CORE --> DUAL
COREV2 --> DUAL
CFG --> CORE
EX1 --> CORE
EX2 --> CORE
EX3 --> CORE
CORE --> BIN
COREV2 --> BIN
架构说明:
- 触发与传输层是升级数据的入口,各通道实现方式不同但最终都汇聚到升级核心:
rcsp_user_update.c走 Jieli RCSP 协议(通常承载于 BLE 服务之上),testbox_update.c/testbox_uart_update.c面向 Jieli Testbox 测试工具(支持 USB/UART 两种传输),uart_update.h提供裸 UART 升级,update_loader_download.h负责 Loader 阶段的固件下载。 - 升级核心决定了"固件数据写到哪、如何写、如何校验、如何跳转"。
update.c是源码实现,code_v2是库实现(预编译update_lib.a),二者对外能力通过apps/include_lib/update/update.h与code_v2/update.h呈现。 - 双区更新层是升级可靠性的关键:把固件写入非运行分区,配合 CRC 计算实现失败回滚,避免"升级变砖"。
- 配置与示例层说明如何启用升级框架并把升级能力接入具体应用。
- 构建产物:
post_build/bd57下生成的ota.bin(正式升级镜像)与ota_debug.bin(调试镜像)即最终烧录/传输的固件文件。
主要模块与实现
升级核心:update.c / update.h
apps/app/bsp/common/update/update.c 是升级框架的源码实现主体,其配套公共头文件为 apps/include_lib/update/update.h。该模块负责升级主流程:接收升级数据、写入 Flash、管理升级状态与跳转。应用代码通过 update.h 中声明的接口触发升级或查询升级状态(具体函数签名以头文件为准)。
与 code_v2 的库实现不同,common/update 采用源码形式直接参与编译,便于开发者针对具体 Flash 布局进行裁剪和定制。
code_v2 升级库与链接脚本
apps/include_lib/update/code_v2/ 目录是升级框架的第二代(v2)实现,包含:
update.h:v2 升级库对外 APIuart_update.h:v2 的 UART 升级接口testbox_uart_update.h:v2 的 Testbox UART 升级接口update_loader_download.h:Loader 下载接口update.ld:链接脚本,划定升级相关代码/数据的段布局
对应的二进制实现位于 apps/include_lib/liba/bd57/flash/update_lib.a(bd57 平台 Flash 方案的预编译静态库)。使用库形态时,应用只需包含 code_v2/update.h 并链接 update_lib.a,通过 update.ld 保证升级代码段被正确放置(通常放置于 Loader/引导区可访问的地址)。
双区更新:dual_update_demo.c / dual_update_crc_cal.c
双区更新(dual-bank update)是保障升级可靠性的核心机制:
dual_update_demo.c/dual_update_demo.h:双区更新的示例实现,演示如何在两个固件分区之间切换、标记待升级分区并在启动时选择正确分区。dual_update_crc_cal.c:CRC 校验计算,用于在写入完成后校验固件数据的完整性——只有 CRC 通过才允许标记升级,否则保持原分区运行。
设计意图:把"正在运行的固件"与"正在写入的新固件"放在不同分区,杜绝升级过程中断电导致设备无法启动的问题;新固件启动后若运行异常,仍可回滚到旧分区。
RCSP 升级通道:rcsp_user_update.c
apps/app/bsp/common/third_party_profile/jieli/JL_rcsp/rcsp_update/rcsp_user_update.c(及同名头文件)把 OTA 能力接入 Jieli RCSP 协议栈。RCSP 是 Jieli 生态(App 与设备)常用的控制/管理协议,升级数据经由 RCSP 的升级命令字下发,由 rcsp_user_update.c 桥接到升级核心。该模块通常配合 update.h 使用,是"手机 App 通过 BLE 升级设备"这一典型场景的入口。
Testbox 与 UART 升级:testbox_update.c / testbox_uart_update.c / uart_update.h
testbox_update.c:面向 Jieli Testbox(产测/调试工具)的升级入口,一般通过 USB 虚拟串口传输固件。testbox_uart_update.c:Testbox 升级的 UART 变体,其头文件在code_v2下亦有对应实现(testbox_uart_update.h)。uart_update.h:通用 UART 升级接口,供产线或自定义上位机使用。
这些通道与 RCSP 的区别在于传输介质与协议:RCSP 走 BLE 协议栈,Testbox/UART 走串口,但最终写入 Flash 的流程统一收敛到升级核心。
Loader 下载:update_loader_download.h
code_v2/update_loader_download.h 定义 Loader 阶段的固件下载接口。在 Jieli 方案中,引导流程可能包含一个独立的 Loader 程序:系统重启后先进入 Loader,Loader 负责把下载到暂存区的新固件搬移到运行分区,再跳转执行。蓝牙控制器任务中对应的消息 MSG_BLE_TEST_OTA_LOADER_DOWNLOAD_START(见 btctrler_task.h)表明 OTA Loader 下载由蓝牙测试/升级消息驱动,是控制器侧与升级框架协作的同步点。
配置:lib_update_config.c
apps/demo/hid/config/lib_update_config.c 与 apps/demo/transfer/config/lib_update_config.c 是升级库的配置入口,随 demo 工程编译。配置内容通常包括升级库的启用开关、升级数据缓存区大小、分区/地址定义等(具体配置项以文件内容为准)。接入升级框架的第一步,就是确认工程配置中已包含升级库配置并定义了正确的 Flash 分区。
示例:dongle / findmy / 自定义数据库
apps/demo/transfer/examples/dongle/ota_dg_central.c(及头文件):dongle 中心设备侧的 OTA 示例,演示中心设备通过 BLE 连接对从设备执行升级。apps/demo/transfer/examples/findmy/ble_fmy_ota.c(及头文件):findmy 应用中的 OTA 示例,展示在 findmy 业务中叠加升级能力。apps/demo/transfer/examples/custom_db_update/app_custom_db_update.c:自定义数据库升级示例,说明除固件外还可通过升级框架更新设备上的自定义数据库(如配置文件、密钥表等)。
构建产物:ota.bin / ota_debug.bin
apps/app/post_build/bd57/ 下的 ota.bin 与 ota_debug.bin 是构建系统在编译后生成的升级镜像:ota.bin 为正式发布镜像,ota_debug.bin 为调试镜像。这两个文件是"传输层实际下载的数据",其内容由升级核心按分区布局组织。
核心流程
端到端升级流程
基于双区更新机制,一次完整的 OTA 升级按以下顺序执行(流程由 dual_update_demo.c、dual_update_crc_cal.c 与升级核心配合实现):
flowchart TD
Start([升级触发<br/>RCSP / Testbox / UART / App]) --> Down["传输层接收固件数据<br/>rcsp_user_update / testbox_update / uart_update"]
Down --> Store["升级核心写入 Flash<br/>update.c / update_lib.a 写入非运行分区"]
Store --> CRC{"CRC 校验通过?<br/>dual_update_crc_cal.c"}
CRC -->|"否"| Fail["丢弃数据 / 保持原固件运行"]
CRC -->|"是"| Mark["标记待升级分区<br/>dual_update_demo.c"]
Mark --> Reboot["系统重启"]
Reboot --> Loader["进入 Loader 引导<br/>update_loader_download.h"]
Loader --> Switch["搬移 / 切换到新分区"]
Switch --> Boot["启动新固件"]
Boot --> Verify{"新固件运行校验"}
Verify -->|"成功"| Done["升级完成"]
Verify -->|"失败"| Rollback["回滚旧固件分区"]
各步骤说明:
- 触发与传输:升级由某个通道发起(App 经 RCSP、产测工具经 Testbox/UART、控制器经
MSG_BLE_TEST_OTA_LOADER_DOWNLOAD_START消息)。传输层按块接收固件数据。 - 写入 Flash:升级核心把数据写入非运行分区——这是双区设计的关键,运行中的固件不受写入影响。
- CRC 校验:写入完成后用
dual_update_crc_cal.c计算并比对 CRC。校验失败时丢弃数据,设备继续运行旧固件,不会进入异常状态。 - 标记与重启:校验通过后标记待升级分区,然后重启进入 Loader。
- Loader 引导与切换:Loader 阶段(
update_loader_download.h)完成分区搬移/切换,随后启动新固件。 - 运行校验与回滚:新固件启动后若自检失败,可回滚到旧分区,保证设备始终可运行。
控制器侧消息协作
升级框架与蓝牙控制器通过任务消息协作。btctrler_task.h 中的消息枚举表明,控制器任务接收 OTA 相关的测试/升级消息:
MSG_BLE_TEST_UPDATA_START,
MSG_BLE_TEST_OTA_LOADER_DOWNLOAD_START,
MSG_BLE_TEST_LOOP_CONTINUE,
Source: btctrler_task.h
设计意图:把"开始更新""开始 OTA Loader 下载""继续循环"作为控制器任务消息统一调度,使升级流程与蓝牙协议栈的事件循环解耦——升级进度不会阻塞蓝牙链路,链路断开等异常可通过消息队列自然反馈到升级状态机。
使用示例
示例 1:dongle 中心设备执行 OTA
apps/demo/transfer/examples/dongle/ota_dg_central.c 展示了中心设备(dongle)通过 BLE 连接对远端从设备执行 OTA 的完整流程,包括连接管理、升级数据下发与进度处理。该示例与 ota_dg_central.h 配套,是"中心设备发起升级"这一角色的参考实现。
Source: ota_dg_central.c、ota_dg_central.h
示例 2:findmy 应用叠加 OTA
apps/demo/transfer/examples/findmy/ble_fmy_ota.c(及同名头文件)展示如何在 findmy 业务之上叠加 OTA 升级能力,是"从设备/被升级方"角色的参考实现,可直接对照 ota_dg_central.c 理解主从两侧的配合。
Source: ble_fmy_ota.c、ble_fmy_ota.h
示例 3:自定义数据库升级
apps/demo/transfer/examples/custom_db_update/app_custom_db_update.c 演示升级框架除固件外还可用于更新自定义数据库,说明升级能力可扩展到设备数据(配置、密钥、表结构等),而不局限于代码段。
Source: app_custom_db_update.c
示例 4:双区更新与 CRC
dual_update_demo.c / dual_update_demo.h 与 dual_update_crc_cal.c 共同构成双区更新的最小可用实现:前者负责分区切换逻辑,后者负责固件完整性校验。接入双区方案时以此为起点,按目标 Flash 布局调整分区地址。
Source: dual_update_demo.c、dual_update_demo.h、dual_update_crc_cal.c
注:由于源码探索预算限制,本次未能读取上述示例的完整函数体;示例的对外接口与详细调用序列请以对应头文件(
.h)为准。
配置选项
升级框架的配置分散在升级库配置文件与各通道实现中。以下为已确认存在的配置文件及其在框架中的角色(具体配置项名称与默认值需查看对应文件):
| 配置文件 | 路径 | 作用 |
|---|---|---|
lib_update_config.c(HID 工程) | apps/demo/hid/config/lib_update_config.c | HID demo 的升级库配置 |
lib_update_config.c(Transfer 工程) | apps/demo/transfer/config/lib_update_config.c | Transfer demo 的升级库配置 |
update.ld | apps/include_lib/update/code_v2/update.ld | v2 升级库链接脚本,控制升级代码段的放置 |
update.h / code_v2/update.h | apps/include_lib/update/ | 升级库 API 声明(含升级参数结构定义) |
典型配置维度包括:升级功能开关、固件接收缓存大小、升级分区地址与大小、Loader 入口地址等。接入新工程时,应先确认 lib_update_config.c 已纳入编译,并核对分区定义与 update.ld 的内存布局一致。
故障模式、边界情况与并发
故障模式
| 故障场景 | 处理机制 | 依据 |
|---|---|---|
| 固件数据在传输中损坏 | 写入完成后执行 CRC 校验,校验失败则丢弃数据、保持旧固件运行 | dual_update_crc_cal.c 的存在 |
| 升级过程中断电 | 新固件写入非运行分区,未标记切换前断电不影响当前固件;重启后仍运行旧分区 | 双区更新设计(dual_update_demo.c) |
| 新固件启动后运行异常 | 启动自检失败时回滚到旧固件分区,设备保持可运行 | 双区回滚机制 |
| 升级期间蓝牙链路断开 | 升级流程由控制器任务消息驱动(如 MSG_BLE_TEST_OTA_LOADER_DOWNLOAD_START),链路异常通过消息队列反馈,可中断/重试下载 | btctrler_task.h 消息枚举 |
| 分区空间不足 / 分区定义错误 | 需要保证 lib_update_config.c 中分区定义与 update.ld 内存布局一致,否则升级写入越界 | 配置与链接脚本 |
边界情况
- 升级镜像形态:正式发布使用
ota.bin,调试阶段使用ota_debug.bin,两者分区布局可能不同,传输侧需按对应镜像的类型选择下载流程。 - 多通道并存:RCSP、Testbox、UART 通道可同时编译进一个固件,但同一时刻只允许一个升级事务,避免多个通道同时写入 Flash 导致分区损坏。
- Loader 与主固件协同:Loader 下载与主固件升级是两段不同的流程(
update_loader_download.h与update.c分工),切换时需保证 Loader 与主固件版本匹配。
并发与一致性
- 升级核心对 Flash 的写入应串行化:传输层各通道共享同一套升级接口,写入过程不应对其他线程/任务可见中间状态,CRC 校验通过前不提交切换标记。
- 控制器任务消息(
MSG_BLE_TEST_OTA_LOADER_DOWNLOAD_START等)与升级流程之间是生产者-消费者关系,消息队列天然提供同步点,避免升级与蓝牙事件处理竞争。 - 双区切换标记的写入需保证原子性(单次 Flash 写操作完成),否则重启后可能出现"标记半写"状态;实际原子性保证取决于具体 Flash 驱动,需在移植时确认。
性能与运维注意事项
- 传输吞吐:BLE 通道受 MTU/连接间隔限制,固件按块下发;较大的缓存区(由升级库配置)可减少 ACK 往返,提升升级速率。
- Flash 寿命:双区方案每次升级至少写入一个完整固件分区,频繁升级会消耗 Flash 擦写寿命;CRC 计算增加少量 CPU 开销,但通常在下载期间并行/后台完成,不阻塞蓝牙链路。
- 升级时间预算:整体耗时 = 传输时间 + Flash 写入时间 + 校验时间 + 重启引导时间。产测场景建议用 UART/Testbox 通道(带宽高),量产售后场景用 BLE 通道。
- 调试手段:
ota_debug.bin配合调试镜像可定位升级失败阶段(传输失败 / CRC 失败 / 引导失败),建议在升级流程各阶段打日志并上报状态码。 - 运维要求:发布新固件前必须验证
ota.bin与目标分区布局匹配,且旧固件具备回滚能力,避免批量升级后设备不可用。
扩展点
升级框架的层次化设计为扩展提供了清晰的位置:
- 新增传输通道:参照
testbox_update.c/uart_update.h的写法,实现"接收数据 → 调用升级核心接口"的适配层,即可接入自定义上位机或私有协议。 - 自定义升级内容:参照
app_custom_db_update.c,在固件之外扩展自定义数据库/配置的升级,复用分区与 CRC 机制。 - 调整双区策略:以
dual_update_demo.c为模板,根据 Flash 容量实现多分区、A/B/R 三区或增量升级。 - 替换升级核心实现:
code_v2库形态与common/update源码形态可互换,工程可在两者间切换以平衡体积(库)与可定制性(源码)。 - 对接新协议栈:RCSP 通道(
rcsp_user_update.c)展示了如何在第三方 profile 中桥接升级能力,其他协议栈可照此模式接入。
测试
仓库内未见独立的 OTA 单元测试目录,测试主要依赖以下形式(基于已确认的示例文件):
- 集成示例:
ota_dg_central.c(中心设备侧)与ble_fmy_ota.c(从设备侧)可组合为端到端升级验证环境,覆盖"连接 → 下发 → 校验 → 重启"全链路。 - 双区验证:通过
dual_update_demo.c反复执行升级-回滚,验证断电/异常场景下的分区切换正确性。 - 产测工具验证:
testbox_update.c/testbox_uart_update.c支持用 Jieli Testbox 工具做产线级升级验证。
建议在自定义移植后补充:CRC 校验失败注入测试、升级中途断电测试、双区回滚测试、多通道并发升级冲突测试。
相关链接
- update.c(升级核心源码)
- update.h(升级框架公共头文件)
- code_v2/update.h(v2 升级库 API)
- code_v2/update.ld(升级链接脚本)
- dual_update_demo.c(双区更新示例)
- dual_update_crc_cal.c(升级 CRC 计算)
- rcsp_user_update.c(RCSP 升级通道)
- testbox_update.c(Testbox 升级)
- testbox_uart_update.c(Testbox UART 升级)
- btctrler_task.h(控制器任务消息)
- lib_update_config.c(HID 工程升级配置)
- lib_update_config.c(Transfer 工程升级配置)
- ota_dg_central.c(dongle OTA 示例)
- ble_fmy_ota.c(findmy OTA 示例)
- app_custom_db_update.c(自定义数据库升级示例)
- update_lib.a(bd57 预编译升级库)
- ota.bin(升级镜像产物)