BLE广播从零起步,如何实现疑问?
摘要:Hello World:BLE 广播 前提知识 阅读本文需要具备以下基础: 1-1 的 TASKEVENT 模型:本文的所有硬件操作(启动晶振、触发发送、等待完成)都基于往 TASK 寄存器写 1 触发动作、读 EVENT 寄存器确认完成
Hello World:BLE 广播
前提知识
阅读本文需要具备以下基础:
1-1 的 TASK/EVENT 模型:本文的所有硬件操作(启动晶振、触发发送、等待完成)都基于往 TASK 寄存器写 1 触发动作、读 EVENT 寄存器确认完成的模式
1-1 的 SHORTS 机制:本文的 send_on_channel() 直接使用 READY→START 和 END→DISABLE 两条硬件捷径驱动发送,不理解 SHORTS 就无法理解为什么 CPU 只需要写一个寄存器就能完成整个发送流程
HEX 与二进制表示:需要读懂字节级的数据结构和位域定义
不需要提前了解 BLE 广播规范的细节——本文会从头解释每一个字段的含义和设计原因。
一、空气中发生了什么
在手机上打开 nRF Connect App 点击扫描。屏幕上会跳出一列设备,每条记录后面跟着一个随时间变动的 RSSI 值(如 -52 dBm)。这个数字反映的是接收信号强度:距离越近数字越大,越远越小。
这些设备之所以能被扫到,是因为它们在持续地向四周广播数据包,大约每 100 ms 发一次(广播间隔可以在 20 ms 到 10.24 s 之间配置)。BLE 规范为了对抗 2.4 GHz 频段的拥堵,把广播固定在三个信道上轮流发送,而不是随机选一个频率乱发:
Channel 37 — 2402 MHz:紧贴 Wi-Fi 信道 1 的左侧边缘
Channel 38 — 2426 MHz:Wi-Fi 信道 1 与信道 6 之间的空隙
Channel 39 — 2480 MHz:Wi-Fi 信道 11/13 的右侧边缘
这三个位置经过精心选择,尽可能地绕开最常用的 Wi-Fi 信道。每次广播事件,设备依次在 37、38、39 上各发一帧,遭遇干扰时对方至少能在另外两个频道收到信号。
二、广播包的结构
物理层看到的空中数据只是一串比特流。BLE 规范规定了这串比特流在逻辑上的分层结构。一个完整的空中帧由硬件自动补全的首尾字段和软件负责填写的 PDU 组成:
Preamble(前同步码) 是固定序列 0xAA,让接收端的时钟恢复电路锁定比特率,由 RADIO 硬件自动发送。
Access Address(接入地址) 是 BLE 广播信道的"通行密码",固定值 0x8E89BED6。所有 BLE 设备在广播信道上都用同一个接入地址,这样手机的射频芯片才知道哪段信号是 BLE 包而不是其他 2.4 GHz 设备的干扰。
PDU(协议数据单元) 分为两层:
Header 占 2 字节,包含 PDU 类型(4 bit)、发送方地址类型(1 bit)、接收方地址类型(1 bit)和 Payload 长度(8 bit)等
Payload 以 6 字节的设备 MAC 地址(AdvA)开头,后面跟最多 31 字节的广播数据(AdvData)
CRC 是 24 位循环冗余校验,由 RADIO 硬件在发送最后一字节后自动计算并附加。接收端也由硬件自动核验,结果反映在 RADIO->CRCSTATUS 寄存器中。
三、在内存中构建 PDU
理解了逻辑结构之后,我们来看软件如何把数据写进内存,再交给 RADIO 的 DMA 引擎。
3.1 AdvData 数组
我们的广播数据包含两个 AD 结构体:一个 Flags,一个设备名称。
static const uint8_t adv_data[] = {
/* AD 结构体 1:Flags */
0x02, /* Length = 2:Type 1B + Value 1B */
0x01, /* Type = 0x01:Flags */
0x06, /* Value:LE General Discoverable | BR/EDR Not Supported */
/* AD 结构体 2:Complete Local Name */
0x0A, /* Length = 10:Type 1B + 9 字符名称 */
0x09, /* Type = 0x09:Complete Local Name */
'Z', 'e', 'p', 'h', 'y', 'r', 'R', 'a', 'w'
};
Flags 占 3 字节(Length + Type + Value),名称占 11 字节(Length + Type + 9 字符),共 14 字节。
3.2 组装完整 PDU
Zephyr BLE Controller 源码提供了 struct pdu_adv 来精确映射广播 PDU 的内存布局。
