nrfutil 1.4.20安装与使用:Python 2.7环境下DFU固件升级实践
2026/9/14 15:48:42 网站建设 项目流程

简介:nrfutil 1.4.20是一份针对Nordic nRF5系列微控制器的Python库资源包,面向物联网嵌入式开发者与BLE应用工程师,主要解决固件打包、安全签名及设备固件更新(DFU)等常见需求。该版本对nRF51、nRF52系列提供稳定支持,内置命令行工具,可创建和验证DFU包、打印设备信息,适用于智能穿戴、智能家居、传感器网络等低功耗无线产品。压缩包共48个文件,以38个Python源文件为核心,辅以6个txt说明文件、2个pkg-info元数据文件及cfg配置文件,整体仅93KB,结构紧凑,便于快速部署与二次开发。目前已有138人学习使用,借助包内源码与配置,开发者可快速掌握nrfutil命令行操作、DFU包生成与验证流程,理解固件签名及安全校验机制,进而将其整合到实际IoT项目或自动化脚本中,提升固件分发效率与产品安全性。

1. nrfutil 1.4.20 是什么:一把 Python 生态里的 Nordic 刷机钥匙

nrfutil 1.4.20 是 Nordic Semiconductor 官方维护的 Python 命令行工具,负责 nRF51/nRF52 芯片构建后处理:签名密钥、DFU 升级包、bootloader 设置页都归它管。标题里的 zip 就是本地 Python 库安装源。

固件工程师最早认识它多是在 nRF5 SDK 12 时代:编译完 app.hex,跑一条 dfu genpkg 命令,把 hex 打包成带签名与 init packet 的 zip,再用串口 DFU 刷回板子。1.4.20 是这一代工具链里最常用的一组命令,老工程普遍把它钉死为固定依赖。

适合三类人:手里有老 nRF5 工程、要在新机器上复现历史构建、以及被 python 环境安装反复折腾的人。这里不深入蓝牙协议,只把 zip 变成可用工具链,讲清参数与排错边界。

2. 装对 Python 2.7 环境:nrfutil 1.4.20 的依赖边界与最小安装命令

网上 python 安装教程很多,但 nrfutil 1.4.20 这条线要单独说:它要求 Python 2.7。原因不是偷懒,而是这一代 nrfutil 的实现大量依赖 py2 的字符串与字节行为,setup.py 也只在 py2 上验证过。拿 python3 直接装会在构建阶段就报语法错或 import 失败,所以先认清依赖边界,再决定安装路径。

2.1 依赖边界:py2.7.18、pip 20.3.4 与两个核心包

Python 2 官方最后一个小版本是 2.7.18,之后没有安全更新,所以 nrfutil 1.4.20 的环境本身就是一套冻结的工具链。依赖层面,1.4.20 的核心是 ecdsa 与 intelhex:前者负责 DFU 包签名与验签,后者负责解析和生成 hex 文件。两个包在当时的 py2 环境下表现稳定,pip 会自动把它们解析出来。如果用到 BLE 回连 DFU(dfu nordic子命令),环境里还会牵扯 pc_ble_driver_py,装不上时多半是它的锅。

真正容易踩雷的是 pip 与 setuptools。2020 年底起 pip 停止支持 Python 2,如果直接在新创建的 py2.7 venv 里跑 pip install,解析器会去拉只支持 py3 的新版本,最终报出 "python setup.py egg_info" 失败。常见做法是把三个构建工具钉到 py2 生命周期内的最后可用版本:

组件可安装的最高版本说明
Python2.7.18官方 py2 最终版本,Windows/macOS 有独立安装包
pip20.3.4之后所有 pip 版本放弃 py2
setuptools44.1.144.x 是最后支持 py2 的系列
wheel0.37.1最后支持 py2 的 wheel 构建工具

这些版本号是边界而不是必须,但把三件套钉在这组组合里,可以躲掉绝大多数"装完 import 失败"的坑。Windows 上如果 VSCode 里做了 python 环境配置,记得把解释器指到 venv 里的 python.exe,别让系统里默认的 py3 解释器掺和进来。

2.2 从 nrfutil-1.4.20.zip 本地安装的三步

拿到 nrfutil-1.4.20.zip 之后,标准流程是先建 py2.7 虚拟环境,再从 zip 安装。下面的命令以 Linux/macOS 为例:

# 1. 用 virtualenv 创建 py2.7 环境;Windows 下把路径换成 python2.7.exe virtualenv -p python2.7 venv_nrf source venv_nrf/bin/activate # 2. 在 py2 环境下把三件套钉到最后一个可用版本 pip install "pip==20.3.4" "setuptools==44.1.1" "wheel==0.37.1" # 3. 从本地 zip 安装 nrfutil,pip 会自动把 ecdsa、intelhex 一起装上 pip install ./nrfutil-1.4.20.zip

第一行创建虚拟环境,-p指定解释器路径。Windows 对应的激活命令是venv_nrf\Scripts\activate。如果你的机器上没有 python2.7,Windows 和 macOS 可以装官方 2.7.18 安装包;新的 Linux 发行版基本不带 py2,常见做法是直接用docker run -it --rm -v $(pwd):/work python:2.7 bash在容器里完成同样操作。第二行把构建工具钉在 py2 支持范围内,目的是让 pip 解析依赖时不至于把 nrfutil 的依赖链带到 py3-only 的包。第三行的./前缀告诉 pip 这是本地归档文件而不是包名,pip 会先解包 zip 再执行构建。

另一条等价路径是先解压目录,然后进入目录执行python setup.py install。区别在于 setup.py 方式不会解析依赖,缺 ecdsa 或 intelhex 时要手动pip install ecdsa intelhex。我一般优先用 pip 装,一次把依赖闭环解决。

2.3 验证安装:version 与 help 的输出判断

nrfutil version # 期望输出里带 1.4.20;如果显示 5.x 或 6.x,说明装错了包源 nrfutil dfu genpkg --help | grep -E "application|key-file"

nrfutil version是本阶段最重要的校验。现在从 PyPI 直接pip install nrfutil拿到的已经是 6.x 新版,命令体系完全不同,所以 1.4.20 必须从 zip 安装。dfu genpkg --help用来确认子命令存在且参数名符合预期,输出里出现--application--key-file就说明当前在 1.4.20 的命令体系内。顺手再看一眼python --version,确保是 2.7.x,尤其是 VSCode 终端里容易串解释器。

3. 三个高频命令:用 nrfutil 1.4.20 完成密钥、DFU 包与设置页

装好之后,真正天天敲的是三个命令:keys管签名、dfu genpkg管打包、settings generate管 bootloader 设置页。这三个命令对应 nRF5 DFU 方案的三个环节,顺序不能乱,参数写岔轻则包生成失败,重则升级时收到版本不匹配报错。下面按使用频率逐个拆。

3.1 keys generate:签名密钥与公钥回填

nrfutil keys generate signing.pem nrfutil keys display --key pk --key-file signing.pem

第一条生成 PEM 格式的 ECDSA P-256 私钥文件,文件名随意,但存放路径要固定,因为每次 genpkg 都要用到。第二条把公钥打印到终端,--key pk只导出公钥,不会把私钥内容暴露在日志里。DFU 方案里公钥需要预先烧进 bootloader:把 display 输出的 64 字节公钥数组填到 nRF5 SDK 的dfu_public_key.c,重新编译 bootloader。也就是说,signing.pem 一旦丢失,线上设备将永远无法接受你新打的包,因为 bootloader 里只有旧公钥。密钥文件不要进 Git,更不要放进 CI 制品。

3.2 dfu genpkg:单应用与多组件的打包参数

# 场景一:只升级应用固件 nrfutil dfu genpkg \ --application build/app.hex \ --application-version 0x0A \ --key-file signing.pem \ dist/app_only.zip # 场景二:应用 + softdevice 一起打包,用于整机恢复 nrfutil dfu genpkg \ --application build/app.hex \ --application-version 0x0A \ --softdevice build/sd.hex \ --softdevice-version 0x0C \ --key-file signing.pem \ dist/with_sd.zip

--application传入编译产物 hex,nrfutil 内部用 intelhex 解析后按页读取。--application-version是十进制或 0x 前缀的整数,会被写进 init packet;设备端 bootloader 拿它和固件里的版本配置比对,不一致就直接拒绝升级。第二个场景里的--softdevice--softdevice-version同理,但要注意:softdevice 打包只应在目标设备当前 softdevice 版本混乱或需要整机恢复时使用。日常 OTA 只打 app 即可,因为替换或降级 softdevice 有变砖风险。

参数作用常见坑
--application应用固件 hex 路径路径含空格或中文时用引号包住
--application-version应用版本号,写入 init packet必须与 SDK 配置一致
--softdevice附带打包的 softdevice hex版本号写错会收到 SD_VERSION_FAILURE
--key-file签名私钥 PEM私钥丢失后无法再生成签名包
输出 zip 路径生成的 DFU 包建议带日期或版本号,方便追溯

参数名以 1.4.20 的nrfutil dfu genpkg --help为准,不同小版本可能多出--hw-version之类的扩展项,但上面五个是核心。生成后可以解压 zip 确认固件 bin 与 init packet 两个实体都在。

3.3 settings generate:bootloader 设置页的生成时机

nrfutil settings generate \ --family NRF52 \ --application build/app.hex \ --application-version 0x0A \ --bootloader-version 0x0B \ --bl-settings-version 1 \ build/bl_settings.hex

这个命令生成 bootloader 设置页镜像,对应 flash 里单独划给 bootloader 的一块区域,记录当前 app 版本、bootloader 版本、bank 状态。--family必须写对芯片系列,NRF51 工程不要填 NRF52;--bl-settings-version在 1.4.20 时代要配合 bootloader 固件里编译进来的设置页版本,多数老工程是 1。生成的 settings.hex 需要和 bootloader hex 一起烧录:先烧 bootloader,再把 settings 写到指定地址,顺序反了 bootloader 会认为设置页无效。之后的正常 OTA 流程中,这一区域由 bootloader 自己维护,不需要每次生成。

4. 设备端传输:nrfutil 1.4.20 串口 DFU 参数与报错对照

包打好了,最终要落进设备。1.4.20 支持两种传输:dfu serial走串口,dfu nordic走 BLE 回连。BLE 方式依赖外设地址与链路时序,这里以串口为主展开。串口 DFU 是最容易复现的方案,也是排查问题的首选路径。

4.1 串口 DFU 最小命令与端口选择

nrfutil dfu serial \ -pkg dist/app_only.zip \ -p /dev/ttyACM0 \ -b 115200

设备需要先进入 DFU bootloader 模式,此时会枚举出一个 USB CDC ACM 串口。Linux 下通常是 /dev/ttyACM0,Windows 下是设备管理器里的 COM 口。-b指定波特率,默认 115200,必须与 bootloader 编译配置一致;不一致的典型症状是连接能建立但进度条长时间不动。执行前用ls /dev/ttyACM*或 Windows 设备管理器确认端口号。如果插上板子没有新串口出现,先确认板子是否真的跑在 bootloader,而不是应用状态——应用固件可能把同一路 UART 配置成了别的用途。传输过程中 nrfutil 会滚动输出进度,结束时退出码为 0 即为成功。

4.2 DFU 过程常见报错与排查

DFU 失败时,1.4.20 会把设备端返回的 extended error code 以数字形式打出来,常见值如下:

返回码含义排查方向
0x03INIT_COMMAND_INVALIDinit packet 解析失败,检查 zip 是否损坏
0x04FW_VERSION_FAILURE应用版本不匹配,核对 --application-version
0x05HW_VERSION_FAILURE硬件版本不匹配,先查 --family
0x06SD_VERSION_FAILUREsoftdevice 版本不匹配
0x0BVERIFICATION_FAILED数据校验失败,hex 路径错或固件被截断
0x0CINSUFFICIENT_SPACE双 bank 空间不足,减固件体积或清掉旧 bank

这些码来自 nRF5 协议栈的 dfu_types.h,1.4.20 没有把它翻成可读字符串,所以对照表要常备。终端里出现乱码或 CRC 类问题时,先看两件事:波特率和 USB 转串口芯片。老型号 PL2303 在 115200 下偶发丢字节很常见,换 CP210x 的线通常能解决;bootloader 端波特率固定时,就得查线序和供电。

4.3 与新版 nrfutil 的命令差异

用途1.4.20 写法6.x 写法
生成密钥nrfutil keys generatenrfutil key generate
打 DFU 包nrfutil dfu genpkgnrfutil pkg generate
串口升级nrfutil dfu serialnrfutil dfu serial
导出公钥nrfutil keys displaynrfutil key display

这张对比表提醒一件事:网上搜到的教程如果写的是pkg generatekey generate,那是 6.x 语法,不能直接套到 1.4.20 上。老工程建议锁死 1.4.20,因为新版生成的 init packet 布局与 bootloader 协议版本不同,混用会出现工具生成成功、设备端协议不兼容。真要升级,连同 bootloader 和 SDK 一起换,不要只换工具。

5. 进阶技巧:把 nrfutil 1.4.20 构建参数收敛成回归脚本

5.1 脚本设计与验证点

手动敲 genpkg 很容易在某次发版时漏掉版本号更新。我习惯把从密钥到打包的整个流程收敛成一个 bash 脚本,每次发版只改一个 VER 变量:

#!/usr/bin/env bash set -euo pipefail NRFUTIL="$HOME/venvs/nrf_py2/bin/nrfutil" KEY=signing.pem APP=build/app.hex SD=build/sd.hex VER=0x0A PKG="dist/ota_$(date +%Y%m%d_%H%M).zip" # 密钥只在缺失时生成,避免发版时误换签名密钥 [ -f "$KEY" ] || "$NRFUTIL" keys generate "$KEY" "$NRFUTIL" dfu genpkg \ --application "$APP" \ --application-version "$VER" \ --softdevice "$SD" \ --softdevice-version 0x0C \ --key-file "$KEY" \ "$PKG" # 输出公钥与哈希,用于和 bootloader 里的公钥做比对 "$NRFUTIL" keys display --key pk --key-file "$KEY" sha256sum "$PKG"

set -euo pipefail让脚本在任一命令失败时立刻退出,避免拿到半成品包;[ -f "$KEY" ] || ...保证密钥只在首次生成,防止脚本跑歪把线上签名密钥换掉;最后的 sha256sum 同时输出到终端和 CI 日志,macOS 上对应shasum -a 256

验证时看两处:第一是脚本退出码为 0,第二是把 sha256 记录进制品库一并归档。下次回归只要对比哈希,就能确认这次刷的是不是同一个包。脚本要接 CI 的话,可以把 NRFUTIL 换成容器方式:docker run --rm -v $PWD:/work -w /work python:2.7 /work/release.sh,这样宿主机 Python 环境不会漂移。到这里 nrfutil 1.4.20 从 zip 到 DFU 包的完整流程已经闭环,剩下的就是每次发版前把 VER 改对、把哈希归档。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询