OTA项目回顾(一)

📅 2026/7/5 3:49:58
OTA项目回顾(一)
一、项目介绍该项目是一个基于 ESP32-C3 的 BLE OTA 桥接器。它的核心作用是让手机或上位机通过 BLE 连接 ESP32-C3再由 ESP32-C3 通过 UART 与下游 MCU 通信从而完成控制指令转发、日志透传以及 ESP32-C3 自身或下游 MCU 的固件升级。二、项目背景在很多嵌入式产品中主控 MCU 本身可能没有无线能力或者现场调试时不方便频繁连接串口、拆机烧录。所以该项目的设计目标就是在主控 MCU 旁边增加一个 ESP32-C3让它承担无线入口的角色手机通过 BLE 发现并连接设备。手机向 BLE characteristic 写入控制命令或 OTA 数据。ESP32-C3 把 BLE 数据转换成 UART 协议帧转发给下游 MCU。下游 MCU 的日志、状态或响应也可以通过 UART 回传给 ESP32-C3。ESP32-C3 再通过 BLE notify 把数据返回给手机。这样一来用户不需要直接接触下游 MCU 的串口也可以进行无线调试和升级。三、项目的大致流程初始化函数作用board_init()初始化 NVS用来存放 BLE 地址、产品信息等非易失数据com_uart_init()初始化 UART1建立 ESP32-C3 与下游 MCU 的通信链路bt_main_init()初始化 BLE controller、Bluedroid 协议栈和 GATT 服务esp_log_set_vprintf()重定向日志输出让日志可以通过 BLE trace 服务发送runloop_init()创建一个 FreeRTOS Queue Task 的轻量事件循环application_init()注册 ctrl、trace、ota 三个业务 profile 的回调这里的初始化顺序并不是随意的BLE 服务需要依赖 NVS 和蓝牙协议栈业务 profile 又依赖 BLE service 已经创建完成UART 也要尽早初始化因为后续控制命令和 DFU 都依赖它。四、BLE服务划分项目定义了三个主要 BLE GATT 服务。服务UUID作用CTRL0x3A10设备控制例如名称、查找、杂项命令TRACE0x3A20日志输出、shell 命令、内部日志OTA0x3AF0固件升级数据传输和升级控制每个服务下面又有多个 characteristic。例如 OTA 服务CharacteristicUUID方向作用version0x3AF1Read读取 OTA 服务版本data0x3AF2Write Without Response Notify传输 OTA 数据包ctrl0x3AF3Write Without Response Notify发送应用升级、重启等控制命令这里要理解一个 BLE 关键点BLE GATT 并不是“直接发字节流”而是围绕 service 和 characteristic 组织数据。手机端写入某个 characteristic本质上是在告诉设备“我要对这个功能点发送数据。”设备端再根据 characteristic 的 handle 或 UUID 分发到不同业务逻辑。五、UART自定义协议ESP32-C3 与下游 MCU 之间使用自定义 UART 帧格式| magic | channel | length | data | crc16 | | 0xaa | 1 byte | 2 byte | n | 2 byte |其中channel用来区分数据要交给谁处理Channel作用CHANNEL_ESP给 ESP32-C3 自己处理的控制命令CHANNEL_BLE需要转发回 BLE characteristic 的数据CHANNEL_BT/WIFI/ETH预留通道这个协议的意义是把 UART 上的一条字节流变成可校验、可路由的数据帧。如果没有magic接收端很难在异常数据后重新找到帧头如果没有length接收端不知道该读多少数据如果没有crc16接收端无法判断数据是否在传输过程中损坏如果没有channel所有业务都混在一起扩展会很困难。六、OTA设计主线项目最核心的能力是 OTA。它支持两类升级目标类型作用OTA_TYPE_ESP升级 ESP32-C3 自己的 app 分区OTA_TYPE_FW_APP把下游 MCU 固件写入 ESP32-C3 的fw_app分区再通过 UART DFU 写入下游 MCU分区表中可以看到ota_0 app ota_0 1536K ota_1 app ota_1 1536K fw_app 0x40 0x00 512K这说明项目采用了两级升级思路手机 / 上位机 | | BLE OTA v ESP32-C3 Flash |-- ota_0 / ota_1ESP32-C3 自身固件 |-- fw_app下游 MCU 固件缓存区 | | UART DFU v 下游 MCU FlashOTA 协议不是简单地连续写数据而是一个状态机IDLE | | START: type, size, crc32 v DATA | | 分包传输单包 CRC16整包 CRC32 v FINISH | | 设置启动分区或触发 DFU v IDLE这种设计的优点是可以避免 BLE 传输中丢包后整包失败。可以通过 offset 和 size 精确请求下一段数据。单包使用 CRC16 快速发现局部错误。整包使用 CRC32 保证最终固件完整性。超时和重试机制可以提升弱连接环境下的可靠性。七、 FreeRTOS 在项目中的角色这个项目不是裸机 while 循环而是典型的 RTOS 事件驱动结构。主要用到了FreeRTOS 机制在项目中的用途TaskUART 接收任务、BLE notify 任务、OTA 处理任务Queue跨任务传递 BLE notify、OTA 消息、runloop 任务Semaphore等待 BLE service 创建完成、控制 UART 接收暂停TimerOTA 超时、升级完成后延迟重启这里有一个很重要的嵌入式设计思想不要在 BLE 回调或串口接收流程里做复杂耗时逻辑。BLE GATT write 回调收到数据后项目通常只是把数据复制到队列里然后由专门的 OTA task 处理。这样可以避免阻塞蓝牙协议栈也能让业务逻辑更清晰。这篇文章主要是对项目整体框架进行一个大致的梳理在后续文章我们会进行更加详细的回顾与介绍。