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),且多跳后延迟和丢包上升,必须依赖块重传和窗口机制保证完整性。

DFU 传输通道对比:从物理链路到镜像落地 BLE DFU GATT / SMP · 1M PHY UART / USB DFU MCUmgr · CDC / 串口 Matter OTA BDX · Thread/Wi-Fi Thread DFU CoAP / MCUmgr · Mesh 吞吐 / 时延 60~100 kbps 连接间隔 15 ms MTU 247 · 通知分包 吞吐 / 时延 UART 90 KB/s USB 数百 KB/s 链路稳定 · 无配对 吞吐 / 时延 Thread 20~80 kbps BDX 块传输 多跳后延迟上升 吞吐 / 时延 单跳 20~80 kbps CoAP 重传 Mesh 多跳转发 nRF Connect SDK DFU 传输抽象层 统一镜像格式 · 分包/重组 · 校验 · 状态机 · 回滚确认 镜像落地:Slot 0 / Slot 1 双区切换 校验通过 → 标记待激活 → 重启 → 确认或回滚

二、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 和 Thread 在传输大镜像时功耗明显上升,电量不足会导致中途掉线,而 DFU 中断后若没有断点续传,往往需要从头再来。

四、一个可参考的通道参数对照

通道 典型有效吞吐 关键调优参数 适用场景
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 传输方案。