Detect 状态:链路训练的第一声问候

Detect 状态,说人话就是——你的 PCIe 设备在问:「嘿,对面有人吗?」

它是 LTSSM 的起点,也是整个链路训练的第一步。如果你在做板级调试时发现链路始终起不来,十有八九是卡在了这个状态。我遇到过好几次这种问题,每次排查到最后,原因往往简单到让人哭笑不得。

好,我们直接进入正题。

Detect 状态在干啥?

Detect 的核心任务听上去很简单:检测对端是否存在。但 PCIe 是个高速串行总线,收发是分开的,所以检测也得分开做——发送端和接收端各玩各的。

具体来说,Detect 要完成三件事:

  • 发送端检测:TX 发出一个低电平脉冲,看 RX 端有没有反射回来
  • 接收端检测:RX 侦测链路上是否有交流耦合电容,判断对端是否接入
  • 阻抗匹配检查:确保终端电阻(通常是 50Ω)已经就位,否则信号反射会乱套

你想想看,如果这两端都不知道对方在不在,后面的 Polling、Configuration 根本没法谈。

Detect 的子状态机

Detect 内部还有三个小子状态,我习惯把它们叫做「三步走」:

子状态 行为 典型时间 退出条件
Detect.Quiet 静默等待,让链路上的电荷泄放干净 ≥ 12ms 定时器超时
Detect.Active 发送检测脉冲,判断对端是否存在 几个 μs 检测完成
Detect.Waiting 等待对端进入 Detect 状态 ≤ 12ms 接收端检测到信号
调试小贴士: 如果你用逻辑分析仪抓 LTSSM 状态,发现设备反复在 Detect.Quiet 和 Detect.Active 之间跳,始终进不到 Waiting——大概率是电气接触不良,或者链路中间有断线。我曾经被一块软排线坑了整整两天,信号就是过不去。

物理层到底怎么「检测」的?

这部分有点底层,但我还是想讲讲,因为理解透了才能做调试。

PCIe 的物理层有两种检测机制,我分别说一下:

1. 接收检测(Receiver Detection)

这是在 TX 侧做的。TX 发出一个低幅度的脉冲(区别于正常工作时的差分信号),然后观察反射回来的信号。如果对端有接收器且终端电阻已经接上,反射回来的信号幅度和相位会不同。说白了,就是发出一个「探测声纳」,看回声是撞到墙(有设备)还是掉进黑洞(没设备)。

我记得有次在实验室,一个新手同事死活调不通链路,抓波形发现反射一直不对。我过去看了一眼,发现他的 SMA 线缆没接终端电阻——接收端是开路的,反射全回来了,逻辑分析仪以为对面有个设备,其实啥也没有。

2. 带内检测(In-Band Detection)

这是 RX 侧做的事。接收器在自己的引脚上检查是否有直流电压偏移——如果有交流耦合电容,说明对端是有源设备;如果什么都没有,那就是空载。带内检测的好处是不需要额外的管脚,省了成本,但也带来一个问题:检测阈值非常敏感。

PCIe 规范规定,接收检测的阈值电压是 50mV ~ 175mV。低于 50mV 会被认为没设备,高于 175mV 才会认为有设备。中间有个死区,这区间的信号是不确定的。

避坑指南: 我曾经碰到一块板子,链路上用了较长的 PCB 走线,寄生电容太大,导致带内检测脉冲被衰减到 40mV 左右。结果就是——明明对端有设备,但接收端一直报「未检测到」,最终卡死在 Detect 状态。解决办法是调整 Tx 驱动强度,把脉冲幅度拉上去。

电气参数表(参考 PCIe Base 5.0)

有些参数在调试时经常需要查,我整理了一个精简版:

参数 最小值 典型值 最大值 单位
检测脉冲幅度 0.5 0.6 1.2 V
接收检测阈值 50 100 175 mV
交流耦合电容 75 100 200 nF
终端电阻 40 50 60 Ω
Detect.Quiet 等待时间 12 - - ms

表格里的数据要记住几个关键的:电容值 100nF 左右,电阻 50Ω,等待时间至少 12ms。这些是硬件设计时的硬约束,错一个链路就起不来。

Detect 状态机的完整流程图

下面我用一张 SVG 图把整个 Detect 的流转逻辑画出来,方便你对照调试:

Detect 状态机流程图 进入 Detect 状态 Detect.Quiet 等待 12ms,放电完毕 定时器 超时否? 否 是 Detect.Active 发送检测脉冲,判断链路状态 检测到对端? 否 重试 是 Detect.Waiting 注意 进入 Polling 状态 需要两端同时确认 链路训练开始

这张图把整个 Detect 的流程串起来了。你可以看到,从进入 Detect 开始,经过 Quiet 的等待期,到 Active 的检测期,再根据结果决定是回到起点重试,还是进入 Waiting 等待下一步。

很多工程师拿到测试报告,看到「卡在 Detect」就直接慌了。其实你先对照这张图,看看是卡在哪个子状态——如果一直卡在 Quiet,说明前一个状态(可能是 Polling 或 Configuration 失败退回)没有正常完成,链路有脏状态没清干净。如果卡在 Active,那大概率是物理层的问题,眼图没张开呗。

常见调试误区

说几个我在项目里踩过的坑:

误区一: 觉得 Detect 状态不重要,反正只占链路训练的一小段。错!Detect 是「门神」,你连门都进不去,后面的状态学得再好也白搭。我见过太多团队花几周去调 Polling 的均衡参数,结果问题出在 Detect 的检测阈上。
误区二: 盲目相信「链路正常启动一次过,那就不用管 Detect」。我曾经有一个项目,设备冷启动时一切正常,热复位后链路就起不来。最后定位到 Detect 状态在热复位后没有完全放电,电容上残留了电荷,导致检测结果不准。解决方法是把 Detect.Quiet 的等待时间从 12ms 加到 18ms,问题解决。
误区三: 直接用示波器看 Detect 阶段的波形。其实 Detect 阶段的脉冲幅度很低(0.5V 左右),而且持续时间极短,普通示波器根本抓不到。我推荐用协议分析仪来抓 LTSSM 状态机跳变,或者直接用 PCIe IP 自带的状态寄存器去读,省时省力。

最后的叮嘱

Detect 状态是整个链路训练中「最简单但也最容易被忽略」的一个环节。它不涉及复杂的均衡算法,也没有烦人的链路宽度协商,但它决定了链路能否走下去。

我个人习惯,拿到一块新板子做调试时,第一件事就是去读 PCIe 控制器的 LTSSM 状态寄存器,确认是否正常走出了 Detect。如果连续几次都卡在 Detect,我不会急着去调后面的参数,而是先拿万用表测一下链路的两端电阻、用示波器确认交流耦合电容的值——这些物理层的东西对了,Detect 自然就过了。

下一个状态是 Polling,那才是真正开始「握手」的地方。先把基础打牢,调试起来才能得心应手。