如何从零开始手写NRF 52 RADIO相关BLE协议栈的每一个细节机制?

摘要:NRF 52 RADIO 相关机制 一、前言 这篇文章只有一个核心问题:一包数据是怎么从 RAM 飞到空气中的? 我们将以 00_phy_raw_tx 这个例程为主线,逐步拆解 nRF52 芯片的无线发送过程。在这个过程中你会遇到一些陌生的
NRF 52 RADIO 相关机制 一、前言 这篇文章只有一个核心问题:一包数据是怎么从 RAM 飞到空气中的? 我们将以 00_phy_raw_tx 这个例程为主线,逐步拆解 nRF52 芯片的无线发送过程。在这个过程中你会遇到一些陌生的名词——外设寄存器、TASK、EVENT、SHORTS、PLL、GFSK、CRC……每遇到一个新概念,我们都会先停下来把它解释清楚,再继续往下看代码。 阅读本文不需要任何 Nordic 或射频的基础,只需要你会读 C 代码。 二、外设寄存器:用内存地址控制硬件 在我们正式开始之前,需要先搞清楚一件事:如何用 C 代码控制硬件电路? 在普通的程序里,写一个变量 x = 1 只是把数字存到 RAM 里,对外界没有任何影响。但 nRF52 芯片里有一类特殊的内存地址,它们并不对应 RAM,而是直接连接到芯片内部的硬件电路。往这些地址写数据,就等于在操作硬件开关。这类地址就叫做外设寄存器(Peripheral Register)。 nRF52 芯片内部有很多个"外设"模块——无线电、时钟、定时器、GPIO……每个外设都有自己的一组寄存器,分布在固定的内存地址段。Zephyr 提供了一个指针 NRF_RADIO,它直接指向 RADIO 外设的寄存器块起始地址。因此,写 NRF_RADIO->TASKS_TXEN = 1 就是往那个特定的硬件地址写入 1,触发无线电电路启动的物理动作。 特别需要注意的是:往外设寄存器写入 1 和往普通变量写入 1 在逻辑上完全不同。 前者触发的是一个不可逆的硬件事件,而非简单的数据存储。 三、TASK / EVENT:nRF 外设的统一编程模型 理解了寄存器是什么,我们来看 nRF 系列芯片的一个核心设计理念。 nRF 的所有外设都遵循同一套"命令与应答"模式,叫做 TASK / EVENT 模型。它的规则非常简单: TASK(任务) 是你向硬件发出的命令。往某个 TASK 寄存器写 1,就等于按下一个按钮,命令外设执行对应的动作。写入后硬件立刻执行,寄存器本身没有持久意义。 EVENT(事件) 是硬件向你发出的通知。当外设完成某个动作或达到某个状态时,它会把对应的 EVENT 寄存器自动置 1,通知软件"某件事发生了"。 有一个非常重要的特性:EVENT 寄存器是"粘性"的(sticky)。硬件把它置 1 之后,它会一直保持 1,不会自动变回 0。即使硬件已经完成了那个动作、进入了下一个状态,EVENT 仍然保持 1。这意味着:软件必须手动向 EVENT 寄存器写 0 来清除它,否则下次读到的还是上次的残留 1,会造成误判。 用一张表格来总结: 类型 方向 操作 特点 TASK 软件 → 硬件 写 1 触发动作 写完即生效,无需清除 EVENT 硬件 → 软件 读 1 表示发生 粘性,必须手动写 0 清除 这套 TASK / EVENT 模型贯穿 nRF52 的全部外设设计。理解了这两个概念,就掌握了整个 nRF 外设编程的基础。 四、RADIO 状态机:射频电路不是一个简单的开关 有了 TASK / EVENT 的基础,我们来看 RADIO 外设本身。 射频发送电路并不是"按下去就发"这么简单。在发出任何数据之前,芯片内部的 PLL(锁相环)需要先"预热"——它要把 16 MHz 的参考时钟倍频到 2.4 GHz 的载波频率,这个过程需要约 40 微秒让频率稳定下来。只有频率锁定之后,真正的发送才能开始。 因此,RADIO 外设在内部维护了一个状态机,一次完整的发送要按顺序经历以下几个状态: DISABLED │ ← TASKS_TXEN(软件命令:开始预热) ↓ TXRU (TX Ramp-Up,PLL 预热阶段,约 40 µs) │ ← EVENT_READY(硬件通知:PLL 锁相完成,可以发送了) ↓ TXIDLE (等待发送指令,PLL 保持锁定) │ ← TASKS_START(软件命令:开始发射) ↓ TX (正在发射比特流:前导码 → 接入地址 → PDU → CRC) │ ← EVENT_END(硬件通知:最后一个 bit 发完了) ↓ TXIDLE (返回等待状态,射频电路仍然开着!) │ ← TASKS_DISABLE(软件命令:关闭射频) ↓ DISABLED (射频完全关闭,功耗降至最低) │ ← EVENT_DISABLED(硬件通知:已彻底关闭) 这里有一个容易踩坑的细节:发送完毕后,RADIO 会回到 TXIDLE 状态,而不是自动关闭。
阅读全文