4、Detect状态详解:如何检测对端链路存在
Detect 阶段,说白了就是链路的「第一声招呼」。
你的 PCIe 设备上电之后,并不知道对面有没有东西等着握手。它得先发射一个信号出去,看看能不能收到回音。这个「回音」的检测,就是 Detect 状态要干的事。
我记得刚接触 PCIe 时,总觉得 Detect 就是简单地量量电压。后来踩了坑才发现,这里头藏着不少小把戏。
4.1 电气检测的基本原理
PCIe 的物理层工作时,发送端和接收端之间有一对交流耦合电容。这个电容通常在哪?在发送端附近。信号经过这个电容之后,直流分量就被隔掉了。那么问题来了——你怎么知道对端有没有接一个接收器?
答案是:看直流偏置会不会被拉低。
简单说说过程。发送端在 Detect 状态会做两件事:
- 先把自己的 TX 引脚置为高阻态(Hi-Z),不驱动任何电平
- 然后拉一个很小的电流源到 TX 引脚上,大概几十微安的量级
如果对面接了接收端,那么接收端内部的 50Ω 下拉电阻会把 TX 引脚上的电压拉低到接近 0V。如果对面是空的,TX 引脚上的电压会被电流源推上去,接近电源电压。检测这个电压的高低,就能知道对端是否存在。
关键点:Detect 状态不是靠看数据信号有没有收到,而是靠检测直流负载的存在。这就有点像你去敲门——听不到声音没关系,但门有没有挡着手,你立刻能感觉到。
4.2 接收器端接检测
讲完了基本原理,咱们再深入一点。PCIe Gen1/Gen2 用的是 50Ω 单端阻抗(差分对各 50Ω 对地)。Gen3 之后改成了共模端接,但 Detect 的原理没变——还是看负载。
接收器内部的 RC 端接网络长什么样?我画了个简化图:
TX 芯片 RX 芯片
┌─────────┐ 交流耦合电容 ┌─────────┐
│ ├─────||──────────┤ │
│ 电流源 │ │ 50Ω │
│ (几十μA)│ │ 下拉到GND│
│ │ │ │
└─────────┘ └─────────┘
电流源拉了大约 20μA 的电流出来(不同厂家有差异)。如果对端有 50Ω 落地,那电压 = 20μA × 50Ω = 1mV。嗯,非常低,接近 0V。如果对端什么都没接,那电流源没有回路,电压被拉到 VDD 附近。
但这里有个陷阱——交流耦合电容的存在。在直流下,这个电容是开路的。所以实际上 Detect 检测的不是整个接收链路,而是电容之后的那段 TX 引脚被 RX 的直流端接拉低的过程。你想想看,电容把直流隔断了,电流怎么流过去的?
其实,Detect 阶段电流源工作时的频率很低(本质上就是直流偏置),电容对直流来说等于断路。这时候电流源的路径是这样的:
- 从 TX 芯片流出 → TX 引脚
- 经过 PCB 走线 → 耦合电容的一端
- 电容的另一端对直流是开路,但这时候 RX 的端接网络会通过寄生反向过来的微弱电流
- 更准确的说法是:PCIe 的 PHY 在 Detect 时会把 TX 和 RX 引脚内部短暂短接,形成一个反射波测试
我再说清楚点。现在的 PCIe PHY 很少用纯直流电流源来检测了。大多数用的是「反射法」:
PHY 发一个很窄的脉冲到 TX 引脚上。如果引脚另一端接了接收器(50Ω 到地),阻抗匹配,信号被吸收,反射电压很小。如果引脚空载,信号全反射回来,PHY 会看到一个大信号。通过比较发射和反射的能量,就能确定对端是否存在。
个人习惯:做板级调试时,如果 Detect 一直过不去,我喜欢先用示波器看 TX 引脚的直流电平。如果引脚电压在 300mV 以下,多半是接收端端接没问题;如果引脚电压接近电源轨(1.8V 或 3.3V),接收端可能没上电、或者焊错了电阻。我踩过一次坑——板子回来说链路不通,查了半天发现是接收端的 50Ω 电阻虚焊了。
4.3 检测超时与状态转换
Detect 不会无限等下去。PCIe 协议规定了一个超时机制:
| 参数 | 典型值 | 说明 |
|---|---|---|
| Detect 等待超时 | 12 ms | 最长等待对端响应的时间 |
| 电气检测脉冲宽度 | 几十 ns ~ 几百 ns | 反射法使用的探测脉冲 |
| 检测成功判定 | 连续 2~4 次检测到负载 | 防止毛刺误判 |
| 超时后的重试次数 | 无限制(连续重试) | 直到检测到对端或复位 |
超时后 PCIe 不会报错,不会宕机。它会做什么?它会重新回到 Detect 状态,再来一次。说白了就是一遍遍敲门,直到有人应答。
具体流程是这样的:
- 进入 Detect——上电或从其他状态回退后,PHY 进入 Detect.Quiet 子状态,等待一段时间(约 12ms),开始检测。
- 发射探测脉冲——PHY 在 TX 引脚上发射几个短脉冲,然后快速采样 TX 引脚上的反射波形。
- 判决——如果反射回来的能量很低(负载存在),进入等待状态,确认检测结果。多次确认后,进入 Polling 状态。
- 超时处理——如果没有检测到负载,经过 12ms 后复位 Detect 状态机,重新从步骤 1 开始。
这个超时循环会一直持续,直到链路另一端插上设备。我曾经调试过一块开发板,Slot 上没插卡,启动时看 PCIe 的调试寄存器,发现状态一直在 Detect 里循环——这很安全,不会引起任何异常。
警告:有些 FPGA 实现的 PCIe PHY 在 Detect 超时后会触发链路禁用(Link Disable)机制,这在普通 ASIC 里不常见,属于实现 bug。如果你在 FPGA 上遇到过 Detect 始终不跳出的情况,建议先检查 PHY 的 LTSSM 寄存器,看是不是被强制跳到了 Disable 状态。
4.4 Detect 状态机详解
PCIe 的 LTSSM(链路训练状态机)把 Detect 分成了两个子状态:
- Detect.Quiet——等待所有 TX 引脚保持静默 12ms,确保链路上没有残留信号。这个状态也叫「清理期」。
- Detect.Active——执行前面说的电气检测,发射探测脉冲并分析反射信号。
从 Detect.Active 出来后,如果检测成功,就跳转到 Polling.Active;如果失败,回到 Detect.Quiet 重新等 12ms。
让我给你一张完整的流程图,把整个 Detect 的逻辑串起来:
图上的逻辑很清楚。Detect 状态本身不会卡死,它会自动循环。这也是为什么 PCIe 支持热插拔——你任何时候插上一块卡,链路马上会从 Detect 推进到 Polling,不需要复位。
4.5 实战中的陷阱
做了这么多年硬件,我在 Detect 阶段碰到过三个比较典型的问题:
陷阱一:直流耦合卡在 Detect
PCIe 规定链路必须是交流耦合的。但有些工程板为了省电容,直接用了直流耦合。结果呢?Detect 状态永远检测不到负载。为什么?直流情况下传输线阻抗完全变了,反射波形跟预期对不上,PHY 误判为「没有检测到接收端」。我踩过这个坑——当时为了省两个电容,结果折腾了两天才发现问题。
陷阱二:板级阻抗不匹配导致 Detect 误判
PCB 的差分阻抗应该是 100Ω(单端 50Ω)。如果板厂加工出了问题,阻抗偏到 70Ω 或者 130Ω,反射回来的能量大小就变了。PHY 可能把有负载的情况判断成空载,然后一直在 Detect 里循环。我曾经用 TDR(时域反射计)测过一块出问题的板子,发现走线阻抗在连接器附近剧烈抖动——就是那里造成了误判。
陷阱三:超时时间被修改
有些 BIOS 或者 FPGA 代码会把 12ms 的超时改成更短的值,想加快训练速度。但 PCIe 规范强烈不建议这样做。12ms 这个时间是考虑了电源稳定时间、时钟稳定时间和寄生电容充放电时间算出来的。缩短它,在你插拔设备或电源噪声大的时候,极易出现训练失败。
避坑指南:调试 Detect 不过的问题时,我建议先量 TX 引脚直流电平,再测交流耦合电容的焊接情况,最后用上位机读 LTSSM 状态寄存器。大多数时候问题出在前两步。不要一上来就怀疑芯片坏了——PCIe PHY 的 Detect 模块非常鲁棒,几乎不会坏。
好,Detect 状态就讲到这里。说实话,它是个不怎么出彩的状态,但恰恰是这个不起眼的阶段,决定了你的设备能不能迈出链路训练的第一步。接下去,Polling 状态会开始交换真正的训练序列,那是另一场有意思的戏了。