news 2026/9/19 7:18:36

ESP IoT Solution BLE OTA 升级方案:基于 esp_ble_conn_mgr 的分扇区固件传输协议与完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESP IoT Solution BLE OTA 升级方案:基于 esp_ble_conn_mgr 的分扇区固件传输协议与完整实践

ESP IoT Solution BLE OTA 升级方案:基于 esp_ble_conn_mgr 的分扇区固件传输协议与完整实践

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

BLE OTA(Over-The-Air 固件升级)是物联网设备量产后的核心维护能力。本篇文章围绕 ESP IoT Solution 仓库中的 BLE OTA Profile 文档,系统讲解基于esp_ble_conn_mgr实现的分扇区 BLE 固件传输协议:包括 OTA 服务(UUID0x8018)与四个特征值的定义、START/STOP 命令与固件数据包的逐字节格式、CRC16 三级校验机制,并结合 ble_ota 示例 的源码与配置文件,说明从编译烧录到 NimBLE/Bluedroid、Protocomm 安全通道、预加密 OTA 与 Delta OTA 的完整落地路径。读完本文,你将能够理解 BLE OTA 的协议细节,并能在自己的 ESP32 系列项目上复刻这套升级链路。

一、BLE OTA Profile 是什么

BLE OTA Profile 是建立在esp_ble_conn_mgr(连接管理组件)之上的一层"分扇区固件传输"协议。它解决的核心问题是:BLE 链路 MTU 有限、单包载荷小,而固件镜像通常有数百 KB 甚至更大,因此必须把固件切分为多个扇区(Sector),每个扇区再拆成多个**数据包(Packet)**顺序下发,由设备端边收边校验、边写入 flash。

根据 docs/en/bluetooth/ble_ota.rst 的定义,该 Profile 的核心特征为:

  • 使用 OTA 服务 UUID0x8018
  • 解析来自主机(Central)的 START / STOP 命令以及固件数据包;
  • 数据交付给应用层回调之前,执行严格的三重校验。

三重校验是协议可靠性的关键,也是本文后续重点展开的内容:

  1. 命令包 CRC16:命令帧必须通过 CRC 校验才会被解析执行;
  2. 扇区序号与分包序号连续性:扇区不能跳跃、包序号必须严格递增,否则立即回错误 ACK 请求重传;
  3. 扇区 CRC16:一个扇区(4KB)收满后,先校验整扇区 CRC,通过后才把该扇区数据回调给应用层(写入 OTA 分区)。

配套的服务定义见 docs/en/bluetooth/ble_ota_svc.rst:0x8018服务是传输层的,可以被不同的 OTA Profile 逻辑复用;当与ble_ota_raw配合使用时,命令和固件载荷的解析由该 Profile 完成。

二、OTA 服务与四个特征值

BLE OTA Service 在 GATT 层定义了 4 个特征值,完整说明如下:

特征值UUID权限说明
RECV_FW_CHAR0x8020Write, notify固件数据接收通道,设备端收到后回复 ACK
PROGRESS_BAR_CHAR0x8021Read, notify读取 / 上报升级进度
COMMAND_CHAR0x8022Write, notifyOTA 命令下发与命令 ACK 回复
CUSTOMER_CHAR0x8023Write, notify厂商自定义数据收发通道

从源码实现看,esp_ble_ota_raw.c 中通过esp_ble_ota_svc_init()初始化该服务,通过esp_ble_ota_notify_command_raw()0x8022发送命令 ACK、通过esp_ble_ota_notify_recv_fw_raw()0x8020发送固件 ACK,与应用层完全解耦。此外 Profile 初始化时还会同时初始化esp_ble_dis_init()(DIS 服务),对外广播软件/硬件版本信息,方便主机端识别设备固件版本。

三、协议格式详解

以下格式定义与数值均来自 examples/bluetooth/ble_ota/README.md,并被源码 esp_ble_ota_raw.c 一一印证。

3.1 命令包格式(Command Package)

命令包固定 20 字节,布局如下:

单位Command_IDPayLoadCRC16
字节Byte: 0 ~ 1Byte: 2 ~ 17Byte: 18 ~ 19

Command_ID 取值(源码中以BLE_OTA_CMD_START/STOP/ACK宏定义):

  • 0x0001(START):开始 OTA。Payload bytes(2 ~ 5) 填入固件总长度(小端 32 位,源码中通过get_u32_le(&data[2])读取),其余 Payload 置 0。CRC16 计算 bytes(0 ~ 17)。
  • 0x0002(STOP):结束 OTA。剩余 Payload 全部置 0,CRC16 计算 bytes(0 ~ 17)。
  • 0x0003(ACK):命令回复。Payload bytes(2 ~ 3) 填入被回复的命令 ID,Payload bytes(4 ~ 5) 为该命令的响应结果——0x0000表示接受(ACCEPT),0x0001表示拒绝(REJECT),其余 Payload 置 0。CRC16 计算 bytes(0 ~ 17)。

一个值得注意的实现细节:START 命令的 ACK 在ack_status之后还允许携带扩展字段(仍被 bytes(0 ~ 17) 的 CRC 覆盖)——byte 6 为推荐的扇区发送窗口(Central 最多可流水线预发的扇区数),byte 7 保留。该窗口由esp_ble_ota_raw_set_sector_send_window_for_ringbuf()根据应用层环形缓冲容量动态计算:窗口 = ringbuf 容量 / 4096,下限 1、上限 64。这解释了示例中OTA_RINGBUF_SIZE = 8192时窗口为 2 的来源,可在吞吐量与内存占用之间取得平衡。

3.2 固件包格式(Firmware Package)

主机发送的固件包格式如下:

单位Sector_IndexPacket_SeqPayLoad
字节Byte: 0 ~ 1Byte: 2Byte: 3 ~ (MTU_size - 4)
  • Sector_Index:当前写入的扇区号。扇区号从 0 开始递增、不能跳跃,必须发送完 4K(BLE_OTA_SECTOR_SIZE = 4096)数据后才能进入下一个扇区,否则设备立即回复错误 ACK 请求重传。
  • Packet_Seq:扇区内包序号,从 0 递增。特殊值0xFF表示该扇区的最后一包:此时 Payload 末尾 2 字节为整个扇区 4K 数据的 CRC16,其余字节填充0x0。设备端收到末包后校验数据总长度与 CRC,通过则回复正确 ACK,主机再开始发送下一个扇区。

3.3 固件应答包格式(ACK Package)

设备回复主机的应答包格式如下:

单位Sector_IndexACK_StatusCRC16
字节Byte: 0 ~ 1Byte: 2 ~ 3Byte: 18 ~ 19

ACK_Status 取值(源码中的ble_ota_fw_ack_status_t):

  • 0x0000:成功(SUCCESS);
  • 0x0001:CRC 错误(CRC_ERR);
  • 0x0002:Sector_Index 错误(INDEX_ERR),bytes(4 ~ 5) 携带设备期望的 Sector_Index,便于主机跳转到正确扇区续传;
  • 0x0003:Payload 长度错误(LEN_ERR)。

3.4 CRC16 算法与校验流程

源码中的校验算法为CRC16-CCITT(多项式0x1021,初值0x0000,与 BLE OTA 主机工具保持兼容。设备端完整的接收校验流水线(对应文档所述"三重校验")如下:

  1. 命令包到达后先检查长度是否为固定 20 字节,再以 bytes(0 ~ 17) 计算 CRC 并与 bytes(18 ~ 19) 比对,不通过直接回 REJECT;
  2. 固件包到达后先比对Sector_Index是否等于当前期望扇区,不匹配回0x0002
  3. 非末包(Packet_Seq != 0xFF)还要比对包序号是否连续,乱序回0x0003
  4. 末包拆出尾部 2 字节 CRC,与设备端对整扇区累计数据的 CRC 计算结果比对,不一致回0x0001并清空该扇区接收状态等待重传;
  5. 全部通过后,通过esp_ble_ota_raw_recv_fw_data_callback()注册的recv_fw回调把整扇区数据交给应用层,同时累计recv_total_len与 START 命令声明的固件总长度比对,防止超长数据。

四、示例工程实战:从编译到 OTA 完成

官方示例位于 examples/bluetooth/ble_ota,其工作流程为:通过 BLE 接收固件,以扇区为单位依次写入 flash,直至升级完成。

4.1 分区表

升级依赖 OTA 分区,示例的 partitions.csv 需保证有足够的 app0 / app1 双 OTA 分区;设备当前固件运行在某个 OTA 分区,新固件写入另一个,esp_ota_set_boot_partition()切换启动分区后重启生效。

4.2 应用层数据流与源码佐证

从 app_main.c 可以看到一条完整的"BLE 数据 → 环形缓冲 → OTA 写入"流水线:

  • ble_ota_ringbuf_init(OTA_RINGBUF_SIZE)创建 8KB 字节型 RingBuffer;
  • Profile 的固件接收回调ota_recv_fw_cb()把每个通过校验的 4K 扇区写入 RingBuffer;
  • 独立任务ota_task()通过xRingbufferReceive()阻塞取出数据,调用esp_ota_write()(普通 OTA)或esp_delta_ota_feed_patch()(Delta OTA)写入目标分区;
  • 当累计写入长度达到esp_ble_ota_get_fw_length()(即 START 命令声明的固件长度)后,执行esp_ota_end()esp_ota_set_boot_partition()esp_restart()重启到新固件。

该任务栈大小OTA_TASK_SIZE = 8192,优先级 5;notify_sem计数信号量用于控制读写速率,避免环形缓冲溢出。

4.3 编译与配置(通用)

示例提供两套主机栈配置:

  • Bluedroid(双模)sdkconfig.ci.bluedroid
  • NimBLE(BLE only)sdkconfig.ci.nimble

默认配置见 sdkconfig.defaults。标准构建命令为:

idf.py set-target esp32h2 idf.py menuconfig idf.py build flash monitor

4.4 主机侧 APP

协议设计为通用 BLE OTA 主机服务,示例配套的主机端 APP 由 Espressif 官方提供(esp-ble-ota-android)。使用 Bluedroid 且需与该 APP 兼容时,若选择Bluedroid - Dual-mode,需按以下步骤关闭 BLE 5.0 特性:

  1. Component config>Bluetooth>Bluedroid Options,取消勾选Enable BLE 5.0 features
  2. Component config>Bluetooth>Controller Options,取消勾选Enable BLE 5 feature

4.5 ESP32-H2 使用注意

构建 ESP32-H2 的 BLE OTA 示例需使用ESP-IDF 5.0 或更高版本。另外需保证通过 BLE 传输的固件镜像与示例设置的FLASHSIZE(4MB)一致,即确认ESPTOOLPY_FLASHSIZE_4MB已被设置,否则会出现镜像尺寸与 flash 布局不匹配的问题。

五、进阶升级模式

示例在基础"裸传输"之上还支持三种进阶模式,均可通过idf.py menuconfigExample Configuration → Type of OTA中选择:

5.1 NimBLE 高吞吐配置

若主机栈选择 NimBLE,为获得最大吞吐:

  • Component config → Bluetooth → Bluetooth → Host → NimBLE - BLE only
  • Component config → Bluetooth → NimBLE Options → Preferred MTU size in octets设为517(更大 MTU 意味着单个固件包可携带更多载荷,扇区切包次数更少)。

5.2 Protocomm 安全通道 OTA

利用 protocomm 层做安全握手与加密传输:

  • Example Configuration → Type of OTA → Use protocomm layer for security
  • Component config → OTA Manager → Type of OTA → Enable protocomm level security

该模式下 app_main.c 走esp_ble_ota_init()/esp_ble_ota_start()流程,支持 Security 1(PoP 口令)与 Security 2(salt/verifier 认证)两种安全等级,示例中通过CONFIG_EXAMPLE_OTA_SECURITY_VERSION_1/2切换。

5.3 预加密 OTA(Pre-Encrypted OTA)

固件在产线/发布侧先用 rsa_key/private.pem 私钥加密,设备端用内置公钥解密后写入:

  • 若使用 ESP32-S3,需将Component config → Bluetooth → Bluetooth → NimBLE Options → NimBLE Host task stack size设为8192
  • Example Configuration → Type of OTA → Use Pre-Encrypted OTA
  • Component config → OTA Manager → Type of OTA → Enable pre encrypted OTA

源码中通过esp_encrypted_img_decrypt_start()创建解密句柄,再以esp_ble_ota_recv_fw_data_callback(cb, decrypt_handle)将解密流程挂入固件接收回调链。

5.4 Delta OTA(差分升级)

Delta OTA 只传输新旧固件之间的差异补丁,可显著减小 BLE 传输量:

  • NimBLE:选择Use Delta OTA;若目标芯片为 ESP32-H2 / ESP32-C6,还需在 NimBLE Options 中取消Enable BLE 5 feature,并在Example Configuration取消Enable Extended Adv
  • Bluedroid:选择Use Delta OTA,并取消Enable BLE 5.0 featureEnable BLE 4.2 feature

补丁生成工具位于 tools/esp_delta_ota_patch_gen.py,先安装依赖:

pip install -r tools/requirements.txt

生成补丁(必须使用设备上当前运行的固件作为base_binary,请务必保留设备内固件的备份):

python esp_delta_ota_patch_gen.py create_patch --chip <target> --base_binary <base_binary> --new_binary <new_binary> --patch_file_name <patch_file_name>

校验补丁正确性:

python esp_delta_ota_patch_gen.py verify_patch --chip <target> --base_binary <base_binary> --new_binary <new_binary> --patch_file_name <patch_file_name>

生成的补丁文件部署到 OTA 更新服务器后,设备端在 app_main.c 中通过verify_patch_header()(校验补丁魔数0xfccdde10与当前固件 SHA-256 摘要)和verify_chip_id()(校验 chip_id 与CONFIG_IDF_FIRMWARE_CHIP_ID一致)双重把关,再经esp_delta_ota_feed_patch()边接收边还原新固件,最终由esp_delta_ota_finalize()完成落盘。

六、与其他 BLE Profile 的协作与复用

本文所述的 OTA Service(0x8018)是传输层服务,与 Profile 逻辑解耦:同样的四个特征值可以承载不同的 OTA Profile 实现;而ble_ota_raw这类 Profile 只负责命令/固件载荷的解析与校验,最终数据通过应用回调交付。这种分层设计让开发者既可以按本文协议直接复用,也可以基于esp_ble_ota_svc自行实现更贴近业务的安全校验、续传或分包策略。仓库中 ble_profiles 文档 对该组件族的整体结构有更全面的说明,可作为扩展阅读。

七、关键文件索引

  • Profile 文档:docs/en/bluetooth/ble_ota.rst(中文版)
  • 服务文档:docs/en/bluetooth/ble_ota_svc.rst
  • Profile 实现:components/bluetooth/ble_profiles/esp/ble_ota_raw/src/esp_ble_ota_raw.c 与 esp_ble_ota_raw.h
  • 示例工程:examples/bluetooth/ble_ota(主程序 app_main.c、分区表 partitions.csv、示例说明 README.md)

结语

BLE OTA 的关键在于"小管道传大文件":通过 4KB 扇区切分、20 字节命令帧、CRC16-CCITT 三级校验,把不可靠的无线链路变成可控的可靠传输。本文从 Profile 协议定义、GATT 特征值、逐字节帧格式到源码级校验流程,再到 Bluedroid/NimBLE、Protocomm、预加密与 Delta OTA 的完整配置路径,均可在当前仓库中逐文件验证。开发者可直接基于 examples/bluetooth/ble_ota 起步,按需裁剪出适合自己产品形态的 BLE 升级方案。

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 7:17:54

多机器人任务分配核心算法:市场机制与群体智能实战解析

简介&#xff1a;这份PPT围绕多机器人系统的任务分配技术展开&#xff0c;适合智能机器人、人工智能方向的初学者及研究参考。内容从多机器人系统概述出发&#xff0c;梳理集中式、分布式与混合式三种结构&#xff0c;并系统解析任务分配的分类维度&#xff0c;如静态/动态、同…

作者头像 李华
网站建设 2026/9/19 7:15:24

N_m3u8DL-RE 完整上手指南:M3U8/MPD 下载、解密与直播录制实战

N_m3u8DL-RE 完整上手指南&#xff1a;M3U8/MPD 下载、解密与直播录制实战 【免费下载链接】N_m3u8DL-RE Cross-Platform, modern and powerful stream downloader for MPD/M3U8/ISM. English/简体中文/繁體中文. 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3u8…

作者头像 李华
网站建设 2026/9/19 7:14:38

新国标下移动电源SoC与锂电保护链路设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 7:14:28

Atlas 300V 24G推理卡详解:从环境搭建到YOLO部署全流程实战

上周群里又有人甩过来一张截图&#xff0c;问Atlas 300V 24G是不是运算加速卡&#xff0c;能不能用来部署YOLO。这个问题其实挺典型&#xff0c;卡的名字里带个V&#xff0c;长得很像显卡&#xff0c;但它的定位和游戏显卡、训练卡完全不是一回事。我拿这块卡实跑了一轮YOLOv5和…

作者头像 李华
网站建设 2026/9/19 7:14:11

隧道裂缝检测实战:YOLOv5s结合BiFPN的优化方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华