3、nRF DFU技术概览:nRF5 SDK与nRF Connect SDK中的DFU模块、支持的传输方式(BLE、UART、USB等)
nRF系列芯片的固件升级(DFU, Device Firmware Update)是产品从原型走向量产、从交付走向维护的关键环节。无论是修复现场设备的严重Bug、为已售出的传感器增加新算法,还是为穿戴设备推送新的UI界面,DFU都是唯一的远程运维通道。Nordic Semiconductor提供了两代主要的开发框架:面向传统nRF5系列(如nRF52832、nRF52840)的nRF5 SDK,以及面向新一代nRF53、nRF54系列和nRF91系列(蜂窝物联网)的nRF Connect SDK(NCS)。这两套SDK在DFU模块的设计理念、传输协议和配置方式上存在显著差异,理解这些差异是正确实施OTA升级的前提。
上图展示了两个SDK在DFU模块上的核心差异。nRF5 SDK的DFU更像是一个“独立功能组件”,开发者需要手动集成Bootloader、传输服务和固件处理逻辑;而NCS则将DFU深度融入Zephyr RTOS的生态中,以MCUboot为底层引导框架,配合SMP(Simple Management Protocol)或MCUmgr协议,实现了更统一、更安全的升级链路。下面我们分别深入剖析。
3.1 nRF5 SDK中的DFU模块:经典但需精细配置
nRF5 SDK(版本15.x至17.x)是过去五年nRF52系列产品的主流开发环境。其DFU方案基于Nordic私有的DFU协议,通过BLE GATT服务(通常为0000FE59-CC3A-482A-8E2C-0F5B1A1D4F0F)或UART/USB CDC-ACM进行数据传输。整个DFU流程由三个独立固件协作完成:Bootloader(负责接收新固件并写入Flash)、SoftDevice(蓝牙协议栈,负责BLE传输)、Application(用户应用,负责触发DFU并进入Bootloader模式)。
核心原理:双Bank(Dual Bank)升级机制
nRF5 SDK的DFU采用双Bank策略。Flash被划分为两个区域:Bank 0(当前运行的应用)和Bank 1(新固件暂存区)。当收到新固件时,Bootloader将其写入Bank 1,校验通过后,通过交换Bank映射关系使新固件生效。这种设计的好处是:如果新固件损坏或断电导致写入不完整,Bootloader仍可回退到Bank 0的旧固件,保证设备不“变砖”。
在nRF5 SDK中启用DFU,通常需要以下步骤:
- 配置Bootloader工程:在SDK的
examples/dfu/bootloader基础上修改,设置DFU服务UUID、传输方式(BLE/UART/USB)、Flash布局(通过pca10056.ld链接脚本定义Bank大小)。 - 生成Bootloader设置页:使用
nrfutil settings generate生成包含公钥、DFU版本等信息的设置页,并烧录到固定地址(如0x7F000)。 - 应用工程集成DFU服务:在应用代码中初始化DFU服务,并监听升级请求(例如通过Button或UART指令)。
- 生成固件包:使用
nrfutil pkg generate将应用hex文件打包成ZIP格式,包含dat(元数据)和bin(固件)文件。
| 配置项 | 典型值 | 说明 |
|---|---|---|
| DFU服务UUID | 0xFE59 | Nordic自定义服务,可修改 |
| 传输方式 | BLE / UART / USB | BLE需SoftDevice支持,UART/USB需额外驱动 |
| Bank大小 | 0x3C000 (240KB) | 取决于Flash总容量和应用大小 |
| 签名方式 | RSA 2048 / ECC P-256 | 防止固件被篡改 |
常见误区:很多开发者误以为只要烧录了Bootloader就能自动支持DFU。实际上,nRF5 SDK的Bootloader需要与应用共享SoftDevice,且Bootloader本身不包含协议栈,必须依赖应用在DFU期间保持蓝牙连接。如果应用崩溃或SoftDevice未正确初始化,DFU将无法启动。因此,建议在应用启动时先检查是否存在待升级的固件标志,再决定是否进入DFU模式。
3.2 nRF Connect SDK中的DFU:MCUboot与SMP协议
nRF Connect SDK(NCS)基于Zephyr RTOS,其DFU方案彻底重构。NCS默认使用MCUboot作为Bootloader,这是一个开源、安全的引导加载程序,支持镜像签名、加密、多镜像(如App+Net Core)以及A/B分区切换。传输层则通过MCUmgr协议实现,该协议支持BLE、UART、USB、甚至以太网和蜂窝网络,且与Zephyr的Shell、日志系统深度集成。
NCS的DFU架构与nRF5 SDK最大的不同在于:Bootloader不再依赖应用。MCUboot独立运行,在启动时检查镜像的有效性(签名、版本、CRC),并决定启动哪个镜像。这意味着即使应用完全崩溃,只要MCUboot完好,设备仍可通过DFU恢复。
关键概念:SMP(Simple Management Protocol)
SMP是MCUmgr的传输协议,定义了设备管理命令(如固件上传、下载、复位、文件系统操作)。在BLE上,SMP使用Nordic UART Service(NUS)或专门的SMP服务(UUID: 0x8D53_DC1D-1DB7-4CD3-868B-8AC4-6BF9_7452)。开发者可以使用mcumgr命令行工具或手机App(如nRF Connect)直接发送固件包。
在NCS中配置DFU,通常涉及以下工程配置(以prj.conf为例):
# 启用MCUmgr
CONFIG_MCUMGR=y
CONFIG_MCUMGR_CMD_OS_MGMT=y
CONFIG_MCUMGR_CMD_IMG_MGMT=y
# 启用BLE SMP传输
CONFIG_MCUMGR_SMP_BT=y
CONFIG_MCUMGR_SMP_BT_AUTHEN=y
# 启用UART传输(可选)
CONFIG_MCUMGR_SMP_UART=y
# 启用固件上传(通过mcumgr)
CONFIG_MCUMGR_CMD_IMG_MGMT_UPLOAD=y
# 设置Bootloader为MCUboot
CONFIG_BOOTLOADER_MCUBOOT=y
构建完成后,生成的merged.hex包含MCUboot+App,可直接烧录。升级时,使用mcumgr命令:
# 通过BLE连接设备(假设设备名为"my-device")
mcumgr --conntype ble --connstring peer_name=my-device image upload app_update.bin
# 测试新镜像(重启后运行一次)
mcumgr --conntype ble --connstring peer_name=my-device image test
# 确认并永久生效
mcumgr --conntype ble --connstring peer_name=my-device image confirm
3.3 传输方式对比与选型策略
无论是nRF5 SDK还是NCS,DFU的传输方式直接影响用户体验和升级成功率。下表对比了三种主流传输方式的特点:
| 传输方式 | 典型速率 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| BLE | ~2-5 KB/s (ATT MTU 247) | 穿戴、智能家居、医疗 | 无线、无需额外硬件、手机可直接操作 | 速率受连接间隔和MTU限制,长距离不稳定 |
| UART | 115200 bps (~11.5 KB/s) | 工厂产线、调试、网关设备 | 简单可靠、速率稳定、无需协议栈 | 需要物理连接,不适合远程 |
| USB | USB 2.0 FS (~1 MB/s) | 开发调试、大固件升级 | 速率极高、供电稳定 | 需要USB线缆,通常用于开发阶段 |
在实际产品中,BLE OTA是最常见的需求,但开发者必须注意:BLE DFU的速率瓶颈在于ATT MTU大小和连接参数。nRF5 SDK默认MTU为23字节,实际有效载荷仅20字节;若通过sd_ble_gattc_exchange_mtu_request协商到247字节,速率可提升近10倍。NCS则默认支持MTU 247,且可通过CONFIG_BT_L2CAP_TX_MTU进一步优化。
风险提示:在BLE DFU过程中,如果连接中断(如设备超出范围或手机锁屏),升级将失败。nRF5 SDK的Bootloader会保留Bank 1的未完成数据,但不会自动重连;NCS的MCUmgr支持断点续传(通过image upload -c命令),但需要应用层配合实现重连逻辑。建议在设计中加入“升级失败后自动回退并广播错误码”的机制。
3.4 实战案例:从nRF5 SDK迁移到NCS的DFU改造
某智能锁项目原基于nRF52832和nRF5 SDK 15.3,使用BLE DFU进行固件更新。产品上市后,发现两个痛点:一是升级过程中若手机来电导致蓝牙断开,锁具会卡在Bootloader模式,用户无法开锁;二是固件包未签名,存在被恶意刷写的风险。团队决定迁移到NCS,并利用MCUboot的A/B分区和镜像回滚机制解决上述问题。
初始现象与目标:原系统升级成功率约92%,失败后需返厂恢复。目标是将成功率提升至99%以上,并支持远程回滚。
关键输入数据:应用固件大小约180KB,nRF52832 Flash为512KB。原方案Bank 0/1各分配200KB,剩余112KB用于SoftDevice和Bootloader。迁移后,MCUboot要求每个镜像槽位至少能容纳最大镜像+额外元数据(约4KB),因此重新规划Flash:MCUboot占用48KB,App槽位0和1各占200KB,剩余64KB用于配置存储和日志。
分析判断过程:团队对比了nRF5 SDK的私有DFU协议与NCS的SMP协议。发现SMP支持image test命令,即先运行新镜像一次,若应用在启动后10秒内未调用image confirm,MCUboot自动回滚到旧镜像。这完美解决了“升级后无法启动”的问题。同时,MCUboot的签名验证(使用EC P-256)确保了固件来源可信。
实际操作步骤:
- 在NCS中重新实现应用,将原有业务逻辑移植到Zephyr环境。
- 配置
prj.conf启用MCUboot和SMP BLE传输,并设置CONFIG_BOOT_UPGRADE_ONLY为false以支持回滚。 - 使用
west build -b nrf52832dk_nrf52832构建,生成merged.hex。 - 编写Python脚本调用
mcumgr,在升级前先读取当前镜像版本,升级后自动执行image test并等待设备重启。 - 在应用启动代码中,调用
boot_write_img_confirmed()确认镜像,若应用初始化失败则不调用,触发自动回滚。
结果对比:迁移后,升级成功率提升至99.3%。即使升级过程中断电,MCUboot也能在下次上电时自动回滚到旧版本。固件包大小从原来的ZIP(未压缩)变为MCUboot格式(支持压缩),实际传输数据量减少了约15%。
风险与代价:迁移工作量较大,尤其是外设驱动和低功耗管理需要适配Zephyr的PM(电源管理)框架。此外,MCUboot的A/B分区需要双倍Flash空间,对于512KB的nRF52832来说,如果应用超过200KB,则无法使用A/B方案,需考虑压缩或外部Flash。
复盘经验:对于新项目,强烈建议直接使用NCS,其DFU生态更现代、更安全。对于存量nRF5 SDK项目,若产品已稳定,不必急于迁移;但必须至少增加固件签名和双Bank回滚机制,避免“裸奔”式升级。DFU不是简单的“烧录新固件”,而是一个涉及引导安全、分区管理、传输可靠性和用户交互的系统工程。