3. DFU协议栈与传输通道
DFU(Device Firmware Update)在工程上从来不是“把固件推给设备”这么简单。它是一条从镜像生成、分包传输、校验、暂存、触发切换到回滚确认的完整链路。nRF54 系列支持 BLE、UART/USB、Matter OTA、Thread 等多种传输通道,但真正决定工程实现难度的,是这些通道在协议栈中的位置、吞吐能力、可靠性机制以及它们如何被 nRF Connect SDK 的 DFU 传输抽象层统一起来。
一、四种传输通道的本质差异
BLE DFU 依赖 Nordic 的 Secure DFU 服务,通常以 SMP(Simple Management Protocol)或 Legacy DFU 形式暴露 GATT 特征。它的优势是无需额外物理接口,适合已量产、外壳封闭的设备;代价是吞吐受连接间隔、MTU 和 PHY 限制。以 1M PHY、连接间隔 15 ms、ATT MTU 247 为例,单次通知有效载荷约 244 字节,理论吞吐约 130 kbps,实际受协议栈调度影响通常落在 60~100 kbps。一个 512 KB 的镜像,纯传输时间约 40~70 秒,若加上校验和切换,整体在 1~2 分钟量级。
UART/USB DFU 走的是串行或 USB CDC 通道,通常配合 MCUmgr 或 Nordic 的串行 DFU 协议。UART 在 921600 bps 下有效吞吐约 90 KB/s,USB CDC 则可达数百 KB/s 甚至更高。它们的共同点是链路稳定、无需配对,适合产线烧录、开发调试和带调试口的设备;缺点是要求物理接入,现场升级不便。
Matter OTA 与 Thread DFU 属于 IP 类通道。Matter OTA 由 Matter 规范定义,固件以 OTA Requestor/Provider 角色分发,通常通过 Thread 或 Wi-Fi 承载,依赖 BDX(Bulk Data Transfer)协议做块传输。Thread DFU 则更贴近 Nordic 自身实现,可基于 CoAP 或 MCUmgr over Thread 传输。这类通道的优势是天然支持多跳 Mesh 和 IP 寻址,适合智能家居、楼宇等场景;挑战在于 Thread 网络本身带宽有限(单跳有效吞吐常在 20~80 kbps),且多跳后延迟和丢包上升,必须依赖块重传和窗口机制保证完整性。
二、nRF Connect SDK 中的 DFU 传输抽象层
nRF Connect SDK 的 DFU 实现围绕 MCUmgr 和 SMP 构建,但真正让多通道共存的是传输抽象层。它把“镜像如何被切块、如何被确认、如何被写入 Flash”与“块通过什么物理链路传输”解耦。上层是镜像管理(image manager)和 DFU 状态机,下层是各传输后端:BLE 的 GATT 服务、UART 的串口驱动、USB CDC 的端点、Thread 的 CoAP 端点。抽象层暴露统一的 smp_transport 接口,每个后端只需实现发送、接收和 MTU 查询。
以 MCUmgr 的镜像上传为例,客户端把固件按 MTU 切成若干块,每块带偏移量和 CRC。服务端收到块后写入暂存区,返回当前偏移量作为确认。若某块 CRC 不匹配,服务端不推进偏移量,客户端重发该块。这个“偏移量即确认”的机制在 BLE 上表现为 SMP 响应,在 UART 上表现为帧应答,在 Thread 上表现为 CoAP 响应。抽象层保证无论底层是什么,上层看到的都是同一套偏移量推进逻辑。
三、通道选择与工程判断
选择通道时,先看设备是否可物理接入。产线和研发阶段优先 UART/USB,因为吞吐高、调试信息完整、失败可立即重试。已部署设备若带 BLE,优先 BLE DFU,但要把连接参数调优:把连接间隔从默认的 30~50 ms 降到 15 ms,请求 2M PHY,协商更大的 ATT MTU,能显著缩短升级时间。若设备属于 Matter 生态,则走 Matter OTA,由 Matter 控制器统一调度,但要注意 OTA Provider 的存储和 BDX 窗口大小。
Thread DFU 适合已经组网、且没有 BLE 或串口可达的节点。它的关键参数是 CoAP 块大小和重传次数。Thread 单跳 MTU 约 1280 字节,但实际 CoAP 块常取 512 或 1024 字节,避免分片。多跳场景下,建议把块大小降到 256~512 字节,并增大重传窗口,否则丢包会导致整体升级时间成倍增加。
四、一个可参考的通道参数对照
| 通道 | 典型有效吞吐 | 关键调优参数 | 适用场景 |
|---|---|---|---|
| BLE DFU | 60~100 kbps | 连接间隔 15 ms、MTU 247、2M PHY | 已部署、无物理接口 |
| UART DFU | 约 90 KB/s @921600 | 波特率、流控、帧间隔 | 产线、研发调试 |
| USB DFU | 数百 KB/s | CDC 端点缓冲、包大小 | 带 USB 的设备、快速烧录 |
| Matter OTA | 20~80 kbps(Thread) | BDX 块大小、窗口、Provider 存储 | Matter 生态、统一管理 |
| Thread DFU | 20~80 kbps(单跳) | CoAP 块大小、重传次数、跳数 | Thread Mesh、无 BLE 节点 |
五、抽象层带来的实际收益
抽象层最直接的价值是让同一份固件镜像可以走不同通道。镜像本身带版本、哈希和签名,传输层只负责搬运。这意味着产线可以用 UART 快速烧录,现场可以用 BLE 增量升级,Matter 生态里又可以由控制器统一推送。对开发者而言,切换通道往往只需改配置和初始化对应的 transport 后端,而不需要重写 DFU 状态机。
但抽象层不是万能的。不同通道的 MTU、重传策略和超时行为差异很大,如果上层不感知这些差异,容易出现“BLE 上正常、Thread 上频繁超时”的问题。因此在实际工程中,仍需要针对通道设置合理的块大小、重传次数和超时时间。抽象层统一的是接口和状态机,不是性能特征。
// 示例:MCUmgr 传输后端注册的简化结构(示意)
static struct smp_transport ble_transport = {
.name = "ble",
.mtu = 247,
.send = ble_smp_send,
.recv = ble_smp_recv,
};
static struct smp_transport uart_transport = {
.name = "uart",
.mtu = 512,
.send = uart_smp_send,
.recv = uart_smp_recv,
};
// 上层镜像管理只依赖 smp_transport 接口
int dfu_upload(struct smp_transport *t, const uint8_t *img, size_t len);
理解这层抽象之后,再看 BLE DFU、UART/USB DFU、Matter OTA 和 Thread DFU,就不会把它们当成四套互不相干的机制,而是同一套 DFU 状态机在不同物理链路上的四种落地方式。通道决定吞吐、时延和可靠性边界,抽象层决定代码复用和工程可维护性,两者配合才是完整的 DFU 传输方案。