☰
从烧录事故到版本管理闭环:nrf51822 量产烧录实践指南
2026/9/26 1:36:52 网站建设 项目流程

1. 从一次“烧错版本”的量产事故聊起

去年秋天,我一个做智能硬件的朋友半夜打电话给我,声音都是抖的。他们一批 1200 套设备已经生产入库,结果在出厂抽检时发现,其中 300 套固件版本不对——运行的是两周前的测试版,而不是封版后的正式版。这意味着整批货要么全部返工,要么把这 300 套一台一台地拆机重烧。而更麻烦的是,这 300 套已经混进了成品仓,连去向都查不清。

这不是个例。我做嵌入式开发这十几年,见过太多团队在“芯片烧录”这个环节上栽跟头,而且栽的方式惊人地一致:大家普遍把烧录当成一个“体力活”,认为只要点了烧录按钮、看到进度条走完,事情就结束了。真正出事的时候,往往不是烧录工具坏了,也不是芯片坏了,而是“烧进去的固件版本跟预期不一致”——这本质上是一个程序版本管理问题,只是它以烧录事故的形式爆发出来。

所以这篇文章我想认真聊聊:为什么芯片烧录是版本管理最容易出事的环节?怎么从工程构建、工具链、产线流程多个角度,把“烧录”这件事从“不可追溯的玄学”变成“可审计、可回退、可溯源的标准操作”?文中会以 nrf51822 这颗经典蓝牙 SoC 为例,把从 Keil 点击烧录到命令行可控烧录的完整路径走一遍。适合刚接触量产的小团队、嵌入式工程师、硬件项目经理,以及所有被产线烧录问题折磨过的人。

2. 为什么烧录环节会成为版本管理的重灾区

2.1 烧录是“不可逆物理写入”,不是文件复制

很多人把烧录和“复制文件到 U 盘”类比,这个类比是错的。向 U 盘复制文件,你随时可以查看文件列表、看修改时间、看文件大小来确认内容。但芯片烧录是把你编译好的二进制映像写入 Flash,写入之后,你面对的是一个没有文件系统、没有时间戳、没有目录结构的裸 Flash 空间。

如果你烧之前没有记录“这个 hex 是怎么来的、是谁编的、对应哪个 version”,那烧进去之后,唯一的核对手段就剩下“读回 Flash 内容和源 hex 做比对”。偏偏很多团队连这一步都不做,默认“工具显示成功就是成功”。可实际上接触不良、供电抖动、Flash 锁定位错误、芯片型号选错,都可能让工具显示成功但内容并不是你想要的。

我见过一个最典型的场景:工程师在 Keil 里点了一下 LOAD,MDK 提示 “Erase Done. Programming Done. Verify Done.” 三个绿勾全打上了,但程序上电后就是不跑。后来查了半天,发现他选错了 Flash 算法——芯片本来是 nrf51822 的 256KB 版本,工程里配置的却是 128KB 版本的算法,烧录器只写了前 128KB 地址空间,后面的代码根本没进去。这就是“过程成功、结果失败”的典型。

2.2 IDE 把“编译”和“烧录”捆在一起,反而制造了版本迷雾

在 Keil、IAR 这类 IDE 里,编译和烧录通常是同一个按钮流程。这个设计对开发阶段很友好,但对版本管理来说是一个巨大的隐患:你在 IDE 里看到的“当前工程代码”和“烧进芯片的二进制”未必是同一个东西。

原因很简单:很多工程师点 LOAD 时,自以为烧的是“刚改完的最新代码”,但如果修改后忘了点击 Build,LOAD 烧进去的其实是上一次编译的旧 hex。哪怕工程里代码已经改得面目全非,烧录器却还在老老实实地写上一个编译周期的产物。这种“以为烧了新版本,实际烧了旧版本”的事故,在实践里出现的频率非常高。

更隐蔽的是:IDE 的烧录过程不产生任何标准化的日志记录。没有“谁在什么时间烧了什么文件”,没有“目标芯片的 ID 是什么”,没有“固件的 SHA256 是多少”。出了问题,你唯一能依靠的是当事人的记忆——这恰恰是最不可靠的东西。

2.3 产线环境比开发环境更容易放大版本问题

开发阶段烧错版本,最多就是 debug 多花几个小时。但产线烧错版本,后果是几何级数放大的。

产线烧录通常有这几种方式:使用离线烧录器(脱机编程器)、使用夹具配合 PC 端命令行、或者用 ISP/UART 烧录。无论哪种方式,都有一个共性——操作员不是写代码的工程师,他们不会去看代码 diff,更不会去理解“这个 hex 和那个 hex 有什么区别”。他们的工作就是“把当前工位要求的文件烧进去”。

这时候如果版本管理跟不上,比如固化到产线工位的 hex 文件路径指向了一个旧目录、或者母片(master chip)本身就被烧错了 SoftDevice、或者换线生产时操作员加载了上一个产品的烧录脚本,一整批产品就会在半小时内全部变成残次品。而且由于产线速度快,发现问题时往往已经烧了几百片。返工不仅涉及拆壳、清胶、重新烧录、重新测试,还涉及是否需要报废一部分芯片——因为有些芯片在多次擦写后可靠性会下降。

所以我说烧录是“放大器”,它放大的不是烧录本身的问题,而是源头版本管理的每一个漏洞。源头只要有一丝含糊,到了产线就会被成百上千倍地放大成事故。

3. 一套“看得见、管得住、回得来”的烧录版本管理闭环

3.1 源头治理:把版本信息做进固件内部

要管住烧录版本,第一件要做的事是:让你的固件能“自报家门”。也就是说,任意拿出一台设备,不用连调试器、不用翻生产记录,就能读出它里面的固件版本。这一点很多团队没做到,导致只能把模块拆下来用编程器读 Flash,非常被动。

常见的做法是在编译期把版本号、编译时间、Git 提交哈希注入固件。以 GCC/Keil 环境为例,可以用编译宏在代码中定义:

#define FW_VERSION_MAJOR 2 #define FW_VERSION_MINOR 5 #define FW_VERSION_PATCH 1 #define FW_VERSION_STRING "2.5.1" #define FW_BUILD_TIME __DATE__ " " __TIME__ #define FW_GIT_COMMIT "7a3f9c2e"

再把它们固化到一个固定的只读区域,应用层通过串口、BLE 广播包或者某个私有命令把它输出来。这样在产线测试工位就可以实现自动化检查:设备烧录后,测试程序通过串口读取 FW_VERSION_STRING,如果与当前计划生产的版本号不一致,直接判 NG。这是一道成本极低、但极其有效的防线——问题在源头就被拦截,而不是等到整机联调才发现。

如果项目引用了 Git,更推荐把提交哈希自动带入构建:在编译脚本里调用git rev-parse --short HEAD,然后把结果作为宏定义传给编译器。这样每个固件都能精确回溯到源码的某一个提交点,而不是仅仅靠一个手填的“版本号”自我安慰。

3.2 产出物管理:hex 文件的命名、归档与校验

第二个要做的事,是给编译产物建立档案。很多团队的 hex 文件命名是final.hex、new_final.hex、final_v2.hex、最终版_不要再改.hex……这种命名方式在单机开发时问题不大,但当固件进入产线、或者三个月后需要复现某个版本时,就完全失控了。

建议的产物命名规范是:项目名_主版本.次版本.修订号_构建日期_分支_提交短哈希.hex,例如:

ble_sensor_v2.5.1_20240915_master_7a3f9c2e.hex

同时把.hex、.bin、.elf一起归档,缺一不可。.hex是烧录用格式,.bin是纯二进制有时需要用来计算偏移,.elf里带有符号表和调试信息——没有.elf,以后想用调试器定位某个线上问题会非常困难。

归档时还要记录“构建环境”,包括编译器版本(如 ARMCC V5.06 update 7 / GCC 10.3)、SDK 版本(nRF5 SDK 15.3.0 等)、SoftDevice 版本、芯片型号。这一点特别容易被忽略:很多团队只保留 hex,却忽略了“这个 hex 是用哪个编译器编出来的”。等你过了半年想重新生成一版一模一样的东西,旧编译器早就找不到了。

此外,每个产物在归档时生成 SHA256 校验值。因为产线上烧录脚本最终应该绑定“文件哈希”,而不是绑定“文件名”——文件名可以改错,哈希改不了。下面是建议的归档元数据表结构:

字段示例值说明
产品型号BLE_SENSOR_V2硬件料号
固件版本2.5.1应用层版本号
构建时间2024-09-15 14:32:08编译机本地时间
Git 分支master源码分支
Git 提交7a3f9c2e短哈希
编译器GCC 10.3-2021.10完整的工具链标识
SDK 版本nRF5_SDK_15.3.0依赖的 SDK
SoftDevices130_nrf51_2.0.1依赖的协议栈
产物哈希sha256: 1a2...f9最终 hex 的校验值

3.3 烧录过程记录:让每块板子的“出生”可追溯

源头管好了,接下来要管“过程”。

我在推动团队规范化时,第一件事就是废掉“在 IDE 里手动点烧录”的做法,全部改成命令行烧录加日志记录。原因只有一个:IDE 不给你留证据,命令行可以。每次烧录时,脚本会自动记录时间、操作员账号、hex 文件路径、文件哈希、芯片 ID、烧录结果。

对于量产场景,芯片的唯一标识(Device ID/序列号)要与烧录日志绑定。像 nrf51822 这类芯片,J-Link 可以通过读寄存器拿到唯一的 Device ID,每一颗芯片都不同。把“芯片 ID + 固件版本哈希 + 烧录时间 + 操作员”四元组记录下来,以后任何一块板子出了问题,都能精确回答:这块板子是什么时候烧的、烧的是什么版本、由谁烧的、源文件是什么。

如果做不了数据库系统,最低配也得有一个 CSV 日志文件,但强烈建议至少进 SQLite 或者直接对接产线的 MES 系统。因为 CSV 在多人同时操作时容易写入冲突,而且没法做高效查询。别把这一步省掉,这是你将来面对客户投诉、批次追溯时唯一的救命稻草。

3.4 版本回退与稳定基线

最后一个是“回得来”,也就是版本回退机制。

软件开发过程中,版本是不断前进的,但产线必须有一个“当前稳定生产版本”的概念。不能今天开发出了 v2.5.2 测试版,就让产线立刻烧新版本。同时,一旦某个线上版本出了问题,需要能快速恢复到上一版。

具体的做法是:在产线烧录服务器上维护一个目录结构,形如:

/production_baseline/ current -> v2.5.1/ v2.5.0/ v2.5.1/ v2.5.2_test/

current是一个软链接,只有经过评审通过、QA 签字的版本才能更新这个链接。产线烧录脚本固定读取current/目录下的 hex 和哈希清单,操作员不需要也不允许手动选择文件。这样即便有人手滑,也很难烧错版本——因为脚本不给你选择的机会。

如果说得再彻底一点:产线工位上不放任何“选择”的入口。烧录脚本的参数由上位机根据当前扫描的工单自动下发,操作员只需要扫码、放板、按启动。人一参与选择,就有出错的可能。

4. 以 nrf51822 为例:从 Keil 点击烧录到命令行可控烧录

聊完管理层面的框架,下面进入实操。我相信很多读者搜“nrf51822芯片用什么烧录”是因为手上正拿着这颗芯片。先说结论:nrf51822 是老将了,但它的烧录路径很典型,理解透了,对其他 Cortex-M0/M4 芯片同样适用。

nrf51822 支持 SWD 烧录,最常见的烧录工具是 SEGGER J-Link。官方提供的命令行工具是nrfjprog,在 nRF5 的时代它是独立安装的,后来的新版本则可通过nrfutil工具链管理。如果你只是想烧个程序,用nrfjprog就够了。

4.1 为什么要从 IDE 切换到命令行

你当然可以在 Keil 里把 nrf51822 的工程配好,点 LOAD 直接烧。开发阶段我完全支持这么做,效率高。但一旦进入多人协作、多版本并行、批量烧录或产线阶段,建议立即切到命令行。

理由有三:

  • 可记录:命令行每次执行都能重定向输出到日志文件,内容包括所用文件、操作结果、耗时等,天然具备溯源性。
  • 可重放:把一条命令固化在脚本里,任何时间执行效果完全一致。而 IDE 里“是否重新编译”“是否擦除整个芯片”“是否校验”这些选项都可能被人动过。
  • 可集成:命令行可以被 MES、测试工装、自动化脚本调用,形成完整的产线闭环。

4.2 环境准备清单

以 nrf51822 + nrfjprog 为例,环境准备包括:

  1. 安装 J-Link 驱动(SEGGER J-Link Software Pack)。nrfjprog 依赖 J-Link DLL,版本不要太旧,否则对新芯片支持不好。
  2. 安装 nrfjprog 命令行工具。旧版直接在安装 J-Link 时附带,或者从 Nordic 官网下载单独的 nrfjprog 安装包。
  3. 把 nrfjprog 的安装目录加入系统 PATH,方便命令行直接调用。
  4. 准备目标 hex 文件(我们的应用固件),以及 SoftDevice hex 文件(如果需要重烧协议栈)。

注意:nrf51822 有很多子型号,比如 nrf51822-QFAA(48 引脚,256KB Flash)、nrf51822-QCAA(48 引脚,128KB Flash)、nrf51822-CFAC(CSP 封装)等。烧录脚本必须明确目标芯片型号,否则可能出现 Flash 容量识别错误。J-Link 通常能自动识别,但在脚本里建议写死正确的 device 参数,避免换线生产时搞错型号。

4.3 烧录前必须先做的“读信息”动作

很多工程师拿到一块裸板,上来就直接烧。我的习惯是先读再烧、先看再动。对于 nrf51822,以 nrfjprog 为例:

# 列出当前连接到 PC 的所有 J-Link 识别的芯片 ID nrfjprog --ids # 读取芯片基本信息 nrfjprog --device

--ids输出的是目标设备的 ID。注意如果你板上同时接了多颗芯片或者通过转接板接了多个目标,这里会有多行。生产时一个工位如果只有一个夹具,通常只会出现一个 ID,若有多个 ID 需要立即检查排线是否漏接或者 PCB 上有其他 SWD 设备。

--device会显示芯片的具体型号。如果你手头是 nrf51822,应该能看到类似nRF51822 QFAA的信息。这一步能帮你避免“对着 128KB 的芯片烧 256KB 的固件”这种低级错误。

另外一个实战中很好用的读法是:直接读 0x00000000 开始的 Flash 内容。因为 Flash 起始处如果烧过 SoftDevice,会有固定的向量表数据。如果你怀疑目标芯片是不是全新空片:

# 读取 Flash 起始 16 个字节,看是否为全 0xFF(空片特征) nrfjprog --memrd 0x00000000 --n 16

输出如果全是ff ff ff ff,说明芯片是空白的;如果出现了一些向量值,说明里面有旧程序。在产线上这一步特别有价值:它能告诉你这块板子是不是“二次利用”的返工板,避免在旧程序之上覆盖烧录导致不可预料的残留。

4.4 标准烧录操作序列

对 nrf51822,完整烧录一个从空白芯片到可运行系统的过程,包含三个阶段:擦除、烧录 SoftDevice、烧录 Application。因为 nrf51822 上跑 BLE 必须依赖 Nordic 的 SoftDevice(协议栈),它和应用固件是分开存放的。

# 1. 全片擦除(目标为空白芯片时非必需,但建议执行以确保干净) nrfjprog --eraseall # 2. 烧录 SoftDevice 协议栈 nrfjprog --program s130_nrf51_2.0.1_softdevice.hex --chiperase --verify # 3. 烧录应用固件 nrfjprog --program ble_sensor_v2.5.1_20240915_master_7a3f9c2e.hex --verify # 4. 复位并运行 nrfjprog --reset

命令里几个参数有必要解释一下:

  • --chiperase:烧录前先对芯片执行全片擦除。SoftDevice 和应用固件的位置关系由 Nordic 的链接配置决定,使用--chiperase可以保证 Flash 里没有残留数据干扰后续程序的运行。
  • --verify:烧录完成后立即从 Flash 读回内容并与源 hex 比对。这个选项是必须带的,不是可选项。没有它,烧录工具只负责写、不负责查,等于让你考试交卷后不检查答案就离开考场。
  • --program后面跟的文件路径要写绝对路径,或者在脚本里先切到统一目录。我踩过坑:明明当前目录有 hex,但因为脚本是从其他目录被调用的,相对路径解析到别的 hex,导致烧错。脚本开始前先cd到归档目录,或者直接用完整路径,能规避这种问题。

另外提醒一点:--eraseall会把芯片里所有内容擦掉,包括已经写进去的 SoftDevice。如果你只是更新应用层,不想动 SoftDevice,就不要用--eraseall,直接--program app.hex --verify即可。这也是烧录脚本设计里需要明确的参数化内容——产线到底执行“整片烧录”还是“仅应用烧录”,必须由产品设计决定的初始化流程明确下来。

4.5 量产场景的批量烧录与防错

单颗芯片用手动命令烧是没问题的,但产线上通常需要批量烧。常见方案有三种:

  • J-Link + 夹具 + 上位机批量脚本:每次只烧一块板,PID 控制压合,烧完自动放行。适合中小批量。
  • 离线烧录器(脱机编程器):先把固件加载到烧录器的存储器,然后拿着烧录器去板子上烧,不需要 PC。适合产线迁移、现场维护。
  • 多路烧录器:一个控制器带多个夹具并行烧录,适合大批量。

不管是哪种,防错的核心逻辑一致:烧录前检查“目标固件哈希”和“计划烧录的哈希”是否一致。最简单的方式就是在脚本中固化了当前项目要烧录的 hex 的 SHA256,每次执行时先计算出待烧文件哈希:

sha256sum ble_sensor_v2.5.1_20240915_master_7a3f9c2e.hex

印出的哈希值和归档表中记录的一致,才允许下一步。这一步可以写进脚本自动执行,防止“文件被替换、路径被改”这类意外。

5. 烧录后的最后一公里:读回校验与探针脚本

5.1 为什么“写成功”不等于“写对了”

烧录过程的最后一个环节——校验——是我最想强调的部分。

我见过一个非常典型的产线事故:操作员反映某批次板子烧录成功率 100%,但出货后客户反馈有超过 5% 的设备无法配对。分析后才发现,烧录工位用的是旧版本夹具,探针接触不良。探针与芯片 SWD 引脚之间出现间歇性接触电阻,导致烧录器写 Flash 时偶尔丢位(bit flip)。由于产线脚本没有启用 verify,烧录器报“成功”就放过了。

这个事故的根源在于:把“写入动作完成”误认为“数据正确落在 Flash 中”。Flash 写入是一个复杂的物理过程,电压、温度、接触电阻、时序都会影响最终结果。唯一可靠的确认方式,就是写入后把 Flash 的内容读出来,与源文件逐字节比对。这也是为什么--verify是烧录命令里最不能省的一个选项。

5.2 用脚本把“读回校验”变成第一道闸门

除了 nrfjprog 自带的--verify,我习惯额外用脚本做一次“烧前探针 + 烧后复核”。所谓烧前探针,是在烧录前先读取目标芯片当前的状态,确认它是不是该烧录的状态;烧后复核则是在烧录完成后,再次通过应用层协议(比如串口 AT 指令)读取设备报告的版本号,与预期版本比对。

下面是一个简化版的生产烧录脚本,它把“读芯片信息 → 擦除 → 烧 SoftDevice → 烧 App → 校验 → 复位”整体串联起来,并写日志:

#!/bin/bash # 生产烧录脚本示例(nrf51822 + J-Link) set -e TARGET_HEX="/data/production_baseline/current/ble_sensor_v2.5.1_20240915_master_7a3f9c2e.hex" SOFTDEVICE_HEX="/data/fw_archive/softdevice/s130_nrf51_2.0.1_softdevice.hex" LOG_DIR="/var/log/production_flash" TIMESTAMP=$(date +%Y%m%d_%H%M%S) LOG_FILE="${LOG_DIR}/flash_${TIMESTAMP}.log" # 0. 检查待烧文件是否存在 if [ ! -f "$TARGET_HEX" ]; then echo "[ERROR] Target hex not found: $TARGET_HEX" | tee "$LOG_FILE" exit 1 fi # 1. 记录待烧文件的 SHA256 echo "[INFO] SHA256 of target hex:" | tee -a "$LOG_FILE" sha256sum "$TARGET_HEX" | tee -a "$LOG_FILE" # 2. 检测芯片 nrfjprog --ids 2>&1 | tee -a "$LOG_FILE" # 3. 整片擦除 nrfjprog --eraseall 2>&1 | tee -a "$LOG_FILE" # 4. 烧录 SoftDevice nrfjprog --program "$SOFTDEVICE_HEX" --chiperase --verify 2>&1 | tee -a "$LOG_FILE" # 5. 烧录 Application nrfjprog --program "$TARGET_HEX" --verify 2>&1 | tee -a "$LOG_FILE" # 6. 复位 nrfjprog --reset 2>&1 | tee -a "$LOG_FILE" echo "[INFO] Flash completed. Log saved to $LOG_FILE" | tee -a "$LOG_FILE"

这段脚本虽然不是完整的生产级代码,但已经包含了记录、校验、日志三个关键要素。产线如果要接 MES,在最后一步把$LOG_FILE里的哈希值、芯片 ID 解析出来,上报到数据库即可。

5.3 用 J-Link Commander 做更精细的烧录控制

如果你需要更底层的控制,可以用 J-Link Commander(JLink.exe命令行模式)直接写烧录脚本。J-Link Commander 支持更灵活的脚本控制,比如烧录前读取某个地址的值,烧录后比较。nrf51822 的烧录本质就是 SWD 接口操作,J-Link Commander 相当于直接在 SWD 协议层工作,不受 nrfjprog 某些高层封装的限制。

一个典型的 JLink 脚本flash_nrf51.jlink示例如下:

device nRF51822_XXAA si SWD speed 4000 connect erase loadfile /data/production_baseline/current/ble_sensor_v2.5.1_20240915_master_7a3f9c2e.hex verify 0x00000000, 0x00001000 r go exit

其中verify 0x00000000, 0x00001000表示把起始地址 0x00000000 开始、长度为 0x1000 字节的区域与加载文件比对。注意这里长度要根据你的固件实际大小调整,否则可能比对不完整或是多比对了未写入区域。执行方式:

JLink.exe -CommanderScript flash_nrf51.jlink

这种方式的好处是脚本文件也可以纳入版本库,作为烧录配置的一部分管理。不过它的错误提示不如 nrfjprog 直观,产线操作员的排查门槛稍高一些,建议产线优先用 nrfjprog 方案,把 J-Link Commander 作为高级排障手段。

6. 我在生产现场反复踩过的几个坑

最后分享几个真实踩坑记录。这些都是发生在嵌入式产品团队里、几乎每个人都会遇到的版本/烧录陷阱。

6.1 SoftDevice 与 Application 版本不匹配

nrf51822 或者更广义地说,Nordic 的 nRF51 系列,应用代码和 SoftDevice(蓝牙协议栈)是分开的。Application 在编译时必须链接到特定版本的 SoftDevice 头文件。如果你烧录了不匹配的 SoftDevice,程序表现为:设备可枚举、但一调用蓝牙 API 就 HardFault 或者干脆无法启动。

我遇到过一个项目,应用是用 SoftDevice s130 2.0.1 编译的,但产线母片里烧的是 s110 版本。当时测试人员一直反馈蓝牙起不来,排查了好久才发现是烧录脚本更新 SoftDevice 时选的固件版本不对。解决方案就是在烧录脚本里对 SoftDevice 的哈希做强校验,不允许人工选择。

6.2 Keil 里“下载成功”的假象

有个工程师在开发阶段反复遇到“明明烧不进去,但 Keil 显示成功”的情况。后来定位到原因:在 Keil Options → Debug → Flash Download 里勾选了 “Erase Sectors”,但芯片被设置了 Read Out Protection(读保护)。在这种情况下,调试器可以连接,但不能正常写入。Keil 提示成功是因为它对空镜像的写入“没问题”——它根本没实际写进去任何数据。

这类问题的关键在于:不要相信集成开发环境的“成功”提示。在烧录完成后,断开调试器、重新上电,看程序行为是否符合预期,或者用外部工具读一次 Flash 内容去核对。

6.3 产线换线不换脚本

这是个让人哭笑不得的坑:A 产品生产完成,产线切换做 B 产品,操作员把板子换上了,但工位 PC 上的烧录脚本还是 A 产品的。生产主管口头交代“注意改成 B 的脚本”,但没有人真的去改。结果烧了半小时,发现整批板子烧成了 A 产品固件。

我的建议是:产线工位引导界面必须绑定当前生产工单,操作员扫码时就直接加载对应的脚本和文件。如果工单扫描结果与当前脚本不匹配,软件故意禁止烧录。这一点属于“系统流程兜底”,不能只靠人的自觉。

6.4 只归档 hex,不归档环境

很多团队的固件归档里只有.hex文件,没有记录“这个 hex 用什么编译器编的、用什么 SDK 版本、哪个 SoftDevice 版本”。半年后客户投诉某个老版本有 bug,需要复现当时的构建,结果发现编译器早就升版了,工程文件也改动过大无法编译。最后只能翻 Git 历史,再搭一个半年前的编译环境重新编译,折腾了好几天。

正确的归档是一整套:hex/bin/elf + SDK 版本号 + SoftDevice 版本 + 编译器版本 + 完整 git 提交号。这组信息放在一个文本文件里,或直接塞进 hex 文件名。这花不了多少功夫,但能实实在在节省未来的排查时间。

6.5 上线烧录前没有备份当前 Flash

如果要做 FOTA(固件空中升级)相关开发,烧录前一定要先把板子上的当前固件备份出来。因为 FOTA 调试中经常需要往复烧写多个版本,而旧版本如果没有原始工程里的完整环境,可能已经无法重新生成。用nrfjprog --readcode backup.hex就能把整个 Flash dump 出来,这算是我的一个习惯。

具体到 nrf51822,写 Flash 的完整备份命令:

nrfjprog --readcode full_backup.hex

它会读出整个片上 Flash 的全部内容并保存为 hex 文件,下次如果要回退就能用--program full_backup.hex --verify完整恢复。如果你的代码里有校准参数存在固定 Flash 区域,这招也很有用——整体备份整体恢复,比部分区域读写难度低很多。

回过头来想,那次半夜接到朋友电话时,我最深的感受不是“烧录工具要换”,而是“版本管理闭环要补”。工具只能帮你执行,不能替你决策。而版本管理的核心就是让每一个烧录动作都具备明确、可追溯、可验证这三个属性。只要把开头讲的那四件事做扎实了——版本号进固件、产物档案全、日志绑定芯片、产线不给选择——烧录事故率几乎可以降到零。最后再分享一个小技巧:在产线工位上,烧录脚本启动时先打印三行字——目标文件路径、版本号、文件哈希;操作员扫完码瞄一眼,权限就交给系统,“人只管放板,板子才知道自己该烧什么”。

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

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

立即咨询