2. nRF设备启动与固件存储布局

nRF5系列芯片(如nRF52832、nRF52840)的固件升级体系,本质上是一套围绕内部Flash地址空间展开的“分区协作”机制。理解这套机制的关键,不是记住某个具体地址,而是理解四个角色——SoftDevice、Bootloader、Application、Bootloader Settings——各自占据哪段Flash、谁先运行、谁负责搬运、谁负责校验,以及链接脚本如何把这些约定固化到编译产物中。

一、Flash分区的基本模型

nRF5芯片的Flash从0x00000000开始编址,容量依型号不同(nRF52832为512KB,nRF52840为1MB)。Nordic的升级体系把这整块Flash划分为若干连续区域,每个区域有明确的起始地址和大小。典型布局如下:

  • SoftDevice区:从0x00000000开始,包含协议栈和底层驱动,由Nordic以二进制形式提供,不可修改。
  • Application区:紧接SoftDevice之后,存放用户应用固件。
  • Bootloader区:位于Application之后,负责接收新固件、校验、搬运和跳转。
  • Bootloader Settings区:位于Bootloader之后,保存当前有效固件信息、CRC校验值、升级标志等元数据。
  • MBR区:在启用SoftDevice时,MBR(Master Boot Record)占据0x00000000起始的一小段,负责中断向量转发和启动调度。

这些区域的边界不是随意设定的,而是由SoftDevice的规格、Bootloader的链接脚本、Application的链接脚本三者共同约定。任何一方的地址偏移写错,都会导致启动失败或升级后无法跳转。

nRF52832 Flash 分区布局(512KB,示例配置) MBR SoftDevice Application Bootloader Settings 0x00000 0x01000 0x26000 0x66000 0x7E000 0x80000 4KB 148KB 256KB 96KB 8KB 启动流程与跳转关系 上电复位 MBR 调度 Bootloader 运行 检查 Settings 跳转 Application DFU 升级模式 向量转发 跳转 读取 有效固件 升级标志 判断

二、链接脚本如何固化分区约定

在nRF5 SDK中,Application的链接脚本(通常是 flash_placement.xml 或 .ld 文件)通过 FLASH_ORIGIN 和 FLASH_SIZE 两个宏来指定Application的起始地址和可用空间。这两个值必须与SoftDevice的结束地址对齐,且不能侵入Bootloader区域。

以nRF52832 + S132 SoftDevice为例,S132 v7.0.1的结束地址为0x26000,Bootloader起始地址通常配置为0x66000。因此Application的链接脚本应设置为:

FLASH_ORIGIN = 0x26000;
FLASH_SIZE   = 0x40000;  /* 0x66000 - 0x26000 = 0x40000,即256KB */

Bootloader的链接脚本则独立配置,其起始地址由 BOOTLOADER_START_ADDR 宏定义,通常与Application的结束地址对齐。Bootloader Settings区的起始地址由 BOOTLOADER_SETTINGS_ADDR 指定,一般紧接Bootloader之后。

这里有一个容易出错的细节:SoftDevice的结束地址不是固定值,不同版本、不同协议栈(S132、S140、S112)的结束地址不同。例如S140 v7.2.0的结束地址为0x27000,比S132多出4KB。如果Application的链接脚本仍按0x26000配置,就会与SoftDevice区域重叠,导致启动时HardFault。

三、Bootloader Settings区的数据结构

Bootloader Settings区保存的是升级体系的核心元数据,其结构体 bootloader_settings_t 包含以下关键字段:

字段含义典型值/说明
bank_0当前有效固件信息包含固件长度、CRC校验值
bank_1待升级固件信息DFU过程中写入
bootloader_sizeBootloader自身大小用于校验Bootloader完整性
app_sizeApplication大小用于校验Application完整性
crcSettings区自身CRC防止Settings被篡改

每次DFU升级完成后,Bootloader会更新Settings区中的bank_0信息,将新固件的CRC和长度写入,然后跳转到新的Application。如果Settings区的CRC校验失败,Bootloader会认为当前固件无效,进入DFU模式等待重新升级。

四、地址规划的实际操作步骤

在实际项目中,地址规划通常按以下顺序进行:

  1. 确定SoftDevice型号和版本,查阅Nordic官方文档获取其结束地址。例如S132 v7.0.1的结束地址为0x26000。
  2. 确定Bootloader的起始地址。通常取Application结束地址向上对齐到4KB边界。例如Application结束于0x66000,则Bootloader起始于0x66000。
  3. 确定Bootloader Settings区的起始地址。通常取Bootloader结束地址向上对齐到4KB边界。例如Bootloader结束于0x7E000,则Settings起始于0x7E000。
  4. 将上述地址写入Application和Bootloader的链接脚本,并确保两者不重叠。
  5. 编译后使用 nrfutil 或 nrfjprog 烧录,观察设备是否能正常启动并跳转到Application。
在开发阶段,可以通过 nrfjprog --memrd 命令读取Flash特定地址的内容,验证分区边界是否正确。例如读取0x26000处的前16字节,如果看到的是Application的中断向量表(栈顶指针和复位向量),说明Application确实从该地址开始存放。

五、常见地址规划错误与排查

地址规划错误通常表现为三类现象:设备上电后无响应、DFU升级后无法跳转、或运行一段时间后HardFault。排查时可按以下顺序检查:

  • 检查链接脚本中的FLASH_ORIGIN是否与SoftDevice结束地址一致。不一致会导致向量表错位,设备无法启动。
  • 检查Application的FLASH_SIZE是否侵入了Bootloader区域。如果Application编译后的大小超过了FLASH_SIZE,链接器会报错,但有时会静默截断,导致运行时异常。
  • 检查Bootloader Settings区的地址是否与Bootloader重叠。重叠会导致Settings被Bootloader代码覆盖,升级后无法读取有效固件信息。
  • 检查MBR是否被正确烧录。MBR是启动调度的第一环,如果MBR缺失或损坏,设备会直接卡在复位状态。
修改SoftDevice版本后,必须同步更新Application和Bootloader的链接脚本地址。不同版本的SoftDevice结束地址可能相差数KB,忽略这一点是现场升级失败的高频原因。

总结来说,nRF设备的Flash分区是一套由SoftDevice规格、链接脚本、Bootloader Settings三者共同约束的地址契约。理解每个区域的起始地址、大小和职责,并在链接脚本中精确固化这些约定,是固件升级体系能够稳定运行的基础。地址规划不是一次性的配置工作,而是每次更换SoftDevice版本或调整Bootloader功能时都需要重新核对的环节。