在蓝牙低功耗(BLE)协议栈中,T_IFS(Inter Frame Space)指的是两个连续的蓝牙数据包之间的最小时间间隔。这个时间间隔对于确保蓝牙设备之间的通信不会相互干扰非常重要。T_IFS 的值设置为150微秒(150us)的原因如下:1. **避

摘要:150 µs 的物理账单:T_IFS 与帧间精确计时 本章示例代码:https:github.comixbwerwrite-BLE-stack-from-scratchtreemaster02_act
150 µs 的物理账单:T_IFS 与帧间精确计时 本章示例代码:https://github.com/ixbwer/write-BLE-stack-from-scratch/tree/master/02_active_scan 前提知识 阅读本文需要具备以下基础: 理解 BLE 广播与主动扫描流程(1-2 篇和 2-1 篇有详细讲解):T_IFS 适用于所有有"问答"结构的 BLE 帧间交互——ADV_IND→SCAN_REQ→SCAN_RSP 是最直观的场景。理解三包握手才能直观感受"为什么必须在 150 µs 内回包"。 理解 RADIO 状态机(1-1 有详细讲解):T_IFS 的本质是从 RX 切换到 TX(或反向)所需时间的上界。不理解 TXRU / RXRU(Ramp-Up)阶段就无法理解 40 µs 补偿数字的来源。 不需要提前了解 PPI 或 TIMER 外设——T_IFS 的概念本身与具体实现方式无关。具体实现(HW TIFS 和 SW TIFS)在 2-3 篇展开。 一、T_IFS:有"问答"的地方就有这条规则 BLE 的物理层是半双工的——一根天线不能同时发送和接收。当甲刚发完一帧,乙还没开始回应的这段空白时间,就叫做帧间间隔。 你可能会想:帧间间隔越短越好,节省空口时间。BLE 规范的答案是:是的,但不能无限短。存在一张硬件账单需要先付清,这个账单的金额就是 150 µs。 BLE Core Spec(Vol 6, Part B, Section 4.2.1)对这张账单给出了精准定义: 在任何需要"应答"的链路层交互中,回包方必须在上一帧最后一个 bit 结束后,恰好 150 µs ±2 µs 内发出回包的第一个 bit。 这条规则叫做 T_IFS(Inter-Frame Space,帧间间隔),适用于 BLE 链路层所有的应答式交互场景: 扫描器收完 ADV_IND → 150 µs 后发出 SCAN_REQ 第一个 bit 广播者收完 SCAN_REQ → 150 µs 后发出 SCAN_RSP 第一个 bit 连接中主设备发完数据包 → 从设备 150 µs 后发出应答包 连接中从设备发完数据包 → 主设备 150 µs 后发出应答包 "恰好"这两个字很关键。 T_IFS 不是"不超过 150 µs",而是精确等于 150 µs ±2 µs。太早不行,太晚也不行——接收方是在预设位置开了一扇宽度只有 2 µs 的窗户在等,早了还没开,晚了已经关了。 二、±2 µs:为什么窗口这么窄? 2 µs 的容忍范围是这样算出来的。 BLE 1M PHY 的空口数据速率是 1 Mbps,意味着每 1 µs 正好传输 1 bit。如果回包的第一个 bit 比预期晚了 3 µs,接收方的同步检测逻辑里就会有 3 个 bit 的错位——前导码(Preamble)的同步窗口就此失效,整包数据无法被正确解码,彻底丢失。 从接收方的角度倒推:它只能把等待窗口开得稍微宽一丁点(各允许 ±1 µs),因为再宽一点,偶发的空口噪声就可能被误认为是合法回包的开头,误判率急剧上升。出于信噪比的权衡,±2 µs(即各自向前向后各 1 µs)是 BLE 规范选定的折中点。 这个容忍范围意味着:回包方的计时精度必须优于 2 µs 的误差。换算成等效采样频率,至少需要 500 kHz 量级的精度——每 2 µs 最多只能差一个 tick。 三、150 µs 是一张硬件账单 150 µs 不是工程师拍脑袋定的。从收到上一帧的最后一个 bit,到发出回帧的第一个 bit,芯片内部有一系列硬件阶段必须依次完成。下面的分解展示的是各阶段的最大耗时预算,而非实际执行的先后顺序——真实芯片在实现层面会重排和流水线化这些步骤(具体执行时序见 2-3 篇)。 状态切换时序分解(以nRF52为例): t = 0 µs 上一帧最后一个 bit 到达(RADIO EVENTS_END 触发) ↓ t < 5 µs 射频前端切换:天线路径从 RX 通道倒换到 TX 通道 ↓ t < 20 µs 基带处理: - 完成 CRC 校验(循环冗余校验,判断收包是否有效) - 解白化(Dewhitening) - 确认 PDU 类型合法性 ↓ t ≈ 40 µs PLL 重新锁定(TX Ramp-Up): 射频发送频率与接收频率虽然在同一信道, 但 PLL 需要从"收"模式重新切换到"发"模式, 锁相环需要重新稳定到目标频率,约需 40 µs ↓ t = 150 µs TX 第一个 bit 出现在天线口 其中最耗时的是 PLL 重新锁定。PLL(Phase-Locked Loop,锁相环)是将 16 MHz 参考晶振倍频到 2.4 GHz 射频载频的电路。每次射频模式切换,PLL 都要重新"咬住"目标频率——nRF52 芯片规格书(nRF52832 PS, Section 6.20.15.7)标注的 TX Ramp-Up 时间约为 40 µs。 把这些阶段加在一起,nRF52 的硬件流水线大约需要 ~65 µs。但 150 µs 是 BLE 规范选定的值,它必须覆盖所有合规芯片——不同厂商的 PLL 锁定时间差异很大(有些可达 80~100 µs),还需要为固件处理(地址校验、缓冲区切换)预留余量: 不能是 100 µs:部分芯片的 PLL 锁定时间接近 80~100 µs,加上固件处理开销会超时,不具备跨厂商通用性。 不需要 200 µs:没有物理约束要求等这么久,多等只会浪费空口时间,同时给接收方带来更长的噪声等待窗口。 150 µs 就是覆盖所有合规芯片的硬件约束后,刚好能支付的"最低账单金额"。 四、朴素方案的失败:CPU 根本无法守时 在解释如何正确实现 T_IFS 之前,先来看最直觉的方法——用 CPU 计时——为什么根本行不通。 设想你刚收完 SCAN_REQ,想在 150 µs 后回一个 SCAN_RSP: /* 方案 A:CPU 软件计时(有根本缺陷) */ while (NRF_RADIO->EVENTS_END == 0) {} /* 等待 SCAN_REQ 接收完毕 */ NRF_RADIO->EVENTS_END = 0; /* 检查 CRC,判断 SCAN_REQ 是否发给自己 */ if (radio_crc_is_valid() && AdvA_matches_me(rx_buf)) { radio_pkt_tx_set(&pdu_scan_rsp); } k_busy_wait(110); /* 等 110 µs,让后续 TX Ramp-Up 凑足 150 µs? */ NRF_RADIO->TASKS_TXEN = 1; /* 触发 TX 预热 */ while (NRF_RADIO->EVENTS_READY == 0) {} /* 再等 PLL 锁定(~40 µs) */ NRF_RADIO->TASKS_START = 1; /* 开始发送 */ 这段代码有三处根本性缺陷: 缺陷一:k_busy_wait(110) 的精度从一开始就不够用。 k_busy_wait 的底层是 CPU 自旋循环。实际延迟取决于 CPU 主频(64 MHz)、指令缓存命中率、流水线饱和程度——三者共同决定了每次循环消耗多少个时钟周期。即使在最理想的条件下,这套机制的计时抖动也在 ±5~10 µs 量级,是 ±2 µs 容忍范围的 2.5~5 倍。 缺陷二:从 EVENTS_END 触发到 TASKS_TXEN 写入之间的代码路径长度不固定。 radio_crc_is_valid() 需要读寄存器;AdvA_matches_me() 需要对比 6 字节地址,最坏情况要循环 6 次。两次调用消耗的指令数并不相同,每次执行时间略有差异。你无法保证从 EVENTS_END 触发到 k_busy_wait 开始的这段时间每次恒定——计时基准从一开始就已经漂移。 缺陷三:任何中断都会让计时彻底失控。 Zephyr 的系统滴答中断每 1 ms 触发一次。如果它恰好落在 k_busy_wait 的执行期间,CPU 会立即离开去服务中断处理程序,等回来时 150 µs 已然过去,SCAN_RSP 无论如何都会迟到。 这不是小概率事件:在 150 µs 的等待窗口里,概率约为 15%(150 / 1000)——平均每 6~7 次交互就有 1 次被系统滴答打断。实际系统里还有其他中断来源(DMA、GPIO 等),实际失败率更高。 这三个缺陷指向同一个结论:150 µs ±2 µs 的计时要求,不能、也不应该由 CPU 承担。 五、计时必须下沉到硬件 从 EVENTS_END 触发到 TASKS_TXEN(或 TASKS_RXEN)写入,这中间需要等待 110 µs——而不是 150 µs。 为什么是 110 µs?因为触发 TASKS_TXEN 之后,PLL 还需要约 40 µs 完成 TX Ramp-Up,才能让第一个 bit 真正出现在天线上。所以: 触发 TASKS_TXEN 的时机 = T_IFS - TX Ramp-Up = 150 µs - 40 µs = 110 µs 这 110 µs 的等待,必须交给不受 CPU 调度影响的硬件电路来守住。硬件计时的精度可以做到纳秒量级,完全不受中断、指令路径差异或系统负载的影响。 nRF52 提供了两套硬件方案来实现这件事: HW TIFS:RADIO 外设内置了 TIFS 寄存器,写入 150 后,RADIO 硬件电路自己负责在 END 后 110 µs 触发下一次 Ramp-Up,CPU 全程不参与计时。 SW TIFS:用外部 TIMER1 外设配合 PPI(可编程外设互联)实现——Timer 计到 110 µs 时,PPI 直接触发 TASKS_TXEN/TASKS_RXEN,同样完全绕过 CPU 路径。 这两套方案的内部工作原理在 2-3 篇详细展开。 小结 知识点 结论 T_IFS 定义 BLE 链路层规范要求的帧间间隔:上一帧最后一 bit 结束后,恰好 150 µs ±2 µs 内发出回包第一个 bit(Core Spec Vol 6, Part B, 4.2.1) ±2 µs 来源 1M PHY 下每 1 µs 传 1 bit;超出 ±1 µs 则前导码同步失效,整包丢失 150 µs 的构成 天线切换(<5 µs)+ CRC 及基带处理(<20 µs)+ PLL TX Ramp-Up(~40 µs)≈ 65 µs(nRF52);150 µs 是覆盖所有合规芯片的跨厂商安全上界 40 µs 的来源 nRF52 PLL 从 RX 切换到 TX 后重新锁频所需稳定时间,来自 nRF52832 PS Section 6.20.15.7 110 µs 的来历 150 µs(T_IFS)- 40 µs(Ramp-Up)= 110 µs,是从 RX END 触发到写入 TASKS_TXEN 的实际等待时间 CPU 计时缺陷一 k_busy_wait 抖动 ±5~10 µs,本身就超出 ±2 µs 容忍范围 CPU 计时缺陷二 END 到 TASKS_TXEN 之间的代码路径长度不固定,每次执行有差异 CPU 计时缺陷三 系统滴答(1 ms)及其他中断随时打断 150 µs 窗口,概率约 15% 以上 正确方向 计时必须下沉到硬件:nRF52 提供 HW TIFS(RADIO 内置)和 SW TIFS(TIMER1 + PPI)两套方案,详见 2-3 篇