从零实现BLE协议栈(4-4)实验:04_phy_connection
4-4 动手实验:编译运行 04_phy_connection
本篇是第 4 章的配套实验,将 4-1 ~ 4-4 中讲解的首锚点计算、锚点递推与 CSA#1 跳频完整跑通。
一、概述
04_phy_connection 在收到 CONNECT_IND 后:
- 计算首锚点 A0:6 步流程将 T0 + winOffset 转换为精确的 RTC tick + 皮秒余量
- 进入连接事件循环:每 connInterval 递推锚点、CSA#1 跳频、SN/NESN 流控,直到 supervision timeout
本 Demo 没有 Window Widening 补偿,因此连接只能维持约 3 秒(~16 个事件后锚点漂移超出接收窗口)。第 5 章的 Demo 05 将引入 WW 解决此问题。
二、编译与烧录
west build -b nrf52dk/nrf52832 .\write-BLE-stack-from-scratch\04_phy_connection\ -p
west flash
编译产物:
Memory region Used Size Region Size %age Used
FLASH: 100172 B 512 KB 19.11%
RAM: 18944 B 64 KB 28.91%
三、运行测试
.\write-BLE-stack-from-scratch\tools\venv\Scripts\python.exe `
.\write-BLE-stack-from-scratch\tools\bumble_connect.py `
--transport usb:2FE3:000B `
--target 66:55:44:33:22:11 `
--duration 20
Bumble 侧:连接建立后约 2.75 秒超时断开(无 WW 补偿,锚点漂移导致 RX 丢包无法恢复)。
四、串口日志
连接事件循环
[CONN] #1 ch=11 OK | rtc=456053 | rx=1/1 miss=0
[CONN] #2 ch=22 OK | rtc=457692 | rx=2/2 miss=0
[CONN] #3 ch=33 OK | rtc=459330 | rx=3/3 miss=0
[CONN] #4 ch=7 OK | rtc=460969 | rx=4/4 miss=0
[CONN] #5 ch=18 OK | rtc=462607 | rx=5/5 miss=0
[CONN] #6 ch=29 OK | rtc=464245 | rx=6/6 miss=0
[CONN] #7 ch=3 OK | rtc=465884 | rx=7/7 miss=0
[CONN] #8 ch=14 OK | rtc=467522 | rx=8/8 miss=0
[CONN] #9 ch=25 OK | rtc=469161 | rx=9/9 miss=0
[CONN] #10 ch=36 OK | rtc=470799 | rx=10/10 miss=0
...
[CONN] #20 ch=35 MISS | rtc=487183 | rx=16/20 miss=4
[CONN] #21 ch=9 MISS | rtc=488821 | rx=16/21 miss=5
...
[CONN] Supervision timeout! no RX for 2000000 us
连接总结
========== Connection Summary ==========
Total events: 56
RX OK: 16
RX timeout: 40
RX CRC error: 0
Anchor updates: 16
锚点计算详情(连接结束后打印)
===== Anchor Point Calculation =====
[Step 1] T0: CONNECT_IND end time
connect_end_rtc = 456016 (RTC0 ticks, 32768 Hz)
T0 = 456016 x 30.52us = ~13916503 us
[Step 2] Calculate first anchor offset
BLE Spec formula:
A0 = T0 + winOffset*1.25ms + transmitWindowDelay
Implementation adds margins:
conn_offset_us = winOffset*1250 + WIN_DELAY(1250)
- TICKER_RES_MARGIN(31)
- EVENT_JITTER(16)
- rx_ready_delay(41)
- ww_periodic(5)
= 0*1250 + 1250 - 31 - 16 - 41 - 5
= 1157 us
[Step 3] Convert to RTC ticks + remainder
RTC runs at 32768 Hz, 1 tick = 30.517578125 us
offset_ticks = 37
offset_remainder = 27849609 ps (sub-tick precision)
[Step 4] First anchor point (absolute RTC tick)
initial_anchor = connect_end_rtc + offset_ticks
= 456016 + 37 = 456053
[Step 5] connInterval in RTC ticks
interval = 50000 us
interval_ticks = 1638
interval_remainder = 12207031 ps
(remainder accumulates each event, carries +1 tick
when >= 1 tick period, preventing drift)
[Step 6] Window Widening parameters
Master SCA: 50 ppm
Local SCA: 50 ppm
Combined: 100 ppm
WW periodic = ceil(100 * 50000 / 1000000) = 5 us/event
===== Anchor Sequence Preview =====
A0 (first) : RTC tick 456053
A1 (A0+intv) : RTC tick 457691 (delta=1638 ticks)
A2 (A1+intv) : RTC tick 459329 (delta=1638 ticks)
(remainder carry may add +1 tick per event)
=====================================
五、日志解读
跳频序列
ch=11, 22, 33, 7, 18, 29, 3, 14, 25, 36... 是 CSA#1 跳频序列(hop increment=11):
Event# unmappedChannel mappedChannel
0 11 11
1 22 22
2 33 33
3 44 mod 37 = 7 7
4 18 18
5 29 29
6 40 mod 37 = 3 3
7 14 14
...
unmappedChannel = (lastUnmapped + hopIncrement) mod 37
如果 unmappedChannel 落在 Channel Map 的禁用位上,则 remap 到已启用通道列表。
RX 成功率衰减(无 WW 时)
前 10~16 个事件 RX 成功,之后因为没有 Window Widening 补偿,锚点漂移超出接收窗口导致持续 MISS:
RX OK ─────────┐
│ ← 锚点漂移累积超过接收窗口
RX MISS ────────┼──────────────────────────►
│
~Event #16 Event #56
(Supervision Timeout)
56 个事件中只有 16 个收到包(28.6%)——这恰好说明了为什么 Demo 05 需要引入 WW。
锚点计算公式分解
A0 = T0 + winOffset × 1.25ms + transmitWindowDelay - margins
其中 margins = TICKER_RES_MARGIN (31µs) ← RTC 分辨率补偿
+ EVENT_JITTER (16µs) ← ISR 延迟裕量
+ rx_ready_delay (41µs) ← RADIO RXRU 预热
+ ww_periodic (5µs) ← 首事件的最小 WW
RTC tick 与 remainder 协作
connInterval = 50000 µs
50000 ÷ 30.517578125 = 1638.4 ticks
→ interval_ticks = 1638
→ interval_remainder = 0.4 × 30517578.125 ps ≈ 12207031 ps
每个事件累加 remainder:
Event 0: remainder = 12207031 ps
Event 1: remainder = 24414062 ps
Event 2: remainder = 36621093 ps > 30517578 ps!
→ carry +1 tick, remainder -= 30517578
→ 实际 interval = 1639 ticks(补偿 0.4 的累积)
本系列教程同款硬件:👇
芯片: nRF 52832 开发板
工具: nRF 52840 BLE Dongle 蓝牙嗅探器
工具: 逻辑分析仪
工具: BPA low energy 蓝牙分析仪
本文版权归作者:ixbwer所有,转载请注明原文链接:https://www.cnblogs.com/ixbwer/p/19809848,否则保留追究法律责任的权利。

浙公网安备 33010602011771号