4. Detect状态详解:Detect.Quiet与Detect.Active子状态、接收器检测机制、电气空闲退出条件
好,咱们今天来聊聊PCIe链路训练的第一个状态——Detect。很多刚接触PCIe的工程师,觉得Detect就是“检测一下有没有设备插上”,其实没那么简单。我个人习惯把Detect比作“握手前的试探”——你伸出手,先确认对方在不在,再决定要不要握上去。
Detect状态内部又分成两个子状态:Detect.Quiet 和 Detect.Active。这两个子状态交替运行,直到链路成功检测到对端设备,或者超时报错。
4.1 Detect.Quiet子状态
Detect.Quiet,说白了就是“安静地听”。
进入这个状态后,发送器会做一件很重要的事:把差分电压拉到共模电平,也就是让D+和D-两根线的电压相等。为什么要这么做?因为只有先“归零”,才能准确判断后面有没有信号变化。
我记得有一次调试一个Gen3的板卡,发现链路死活训练不过去。抓波形一看,Detect.Quiet阶段共模电压一直漂移,导致后续的接收器检测误判。嗯,这里要注意:共模电压的稳定,是Detect阶段的第一道门槛。
Detect.Quiet的持续时间,规范里写的是至少12个UI(Unit Interval)。但实际项目中,我建议你留出至少20个UI的余量,因为不同板卡的寄生参数不一样,12个UI有时候不够“安静”。
关键点:Detect.Quiet期间,发送器不发送任何数据,只维持共模电平。接收器则处于监听状态,等待可能的电气空闲退出事件。
4.2 Detect.Active子状态
Detect.Quiet结束后,链路进入Detect.Active。这个阶段,发送器开始“主动出击”——它会在差分线上施加一个小的电压阶跃,然后观察接收端的反射情况。
你想想看,如果对端有设备,这个阶跃信号会被接收器的终端电阻吸收一部分,反射回来的信号就会比较弱。如果对端是空的,信号几乎全反射回来,幅度就很大。接收器就是靠这个反射波幅度来判断有没有设备存在的。
我刚开始做PCIe验证时,总觉得这个机制很巧妙——不需要复杂的协议交互,一个脉冲就能搞定。但后来踩过坑才发现,反射波检测对PCB走线的阻抗匹配非常敏感。阻抗不连续的地方,哪怕没有设备,也会产生反射,导致误判。
避坑指南:我曾经遇到一个案例,板卡在Detect.Active阶段总是误报“检测到设备”,但实际上插槽是空的。最后定位到是过孔阻抗不连续,产生了虚假反射。解决办法是在过孔附近加回流地过孔,把阻抗控制好。
Detect.Active的持续时间,规范规定是最多2ms。如果2ms内没有检测到设备,链路会回到Detect.Quiet,重新开始。这个循环会持续进行,直到设备插入或系统复位。
4.3 接收器检测机制
接收器检测,其实就是上面说的“反射波法”。但具体实现上,有几个细节值得注意:
- 检测阈值:接收器会设定一个电压阈值,反射波幅度超过阈值就认为有设备,低于阈值就认为没有。这个阈值通常设定在50mV~100mV之间,具体取决于芯片设计。
- 去抖处理:为了防止噪声干扰,检测结果通常需要连续稳定至少4个检测周期才能确认。我习惯在验证脚本里加一个“去抖计数器”,模拟这个行为。
- 极性无关:接收器检测不关心D+和D-的极性,只关心差分幅度。所以哪怕你插反了(当然PCIe插反了也插不进去),检测结果也是一样的。
个人经验:在仿真验证中,我通常会在Detect.Active阶段注入一个“弱反射”场景,比如把对端接收器阻抗改成50Ω(标准是100Ω差分),看看DUT能不能正确识别。这种边界测试,往往能发现芯片检测逻辑的bug。
4.4 电气空闲退出条件
电气空闲(Electrical Idle)是PCIe链路中的一个重要概念。简单说,就是差分线上没有信号跳变,电压维持在共模电平。Detect.Quiet状态,本质上就是一种电气空闲。
那么,什么时候退出电气空闲?规范定义了两个条件:
- 检测到差分信号跳变:如果接收器在电气空闲期间,检测到D+和D-之间有超过175mV的差分电压变化,就认为电气空闲结束,链路应该进入下一状态。
- 超时退出:如果电气空闲持续了超过12个UI(在Detect.Quiet场景下),发送器会自动发起Detect.Active,主动产生信号跳变。
这里有个容易混淆的点:电气空闲退出不等于链路训练成功。它只是告诉链路“嘿,好像有动静了”,接下来还要经过Polling、Configuration等一系列状态,才能真正建立连接。
| 参数 | 最小值 | 典型值 | 最大值 | 说明 |
|---|---|---|---|---|
| Detect.Quiet持续时间 | 12 UI | 20 UI | 无上限(循环) | 建议留余量 |
| Detect.Active持续时间 | — | — | 2 ms | 超时回到Quiet |
| 接收器检测阈值 | 50 mV | 75 mV | 100 mV | 差分幅度 |
| 电气空闲退出阈值 | — | 175 mV | — | 差分跳变幅度 |
4.5 核心逻辑流程图
下面我用一张SVG图,把Detect状态的整体流程画出来。你可以看到Detect.Quiet和Detect.Active是如何交替工作的,以及接收器检测和电气空闲退出在其中的位置。
从这张图你可以看到,Detect.Quiet和Detect.Active形成了一个闭环。我个人觉得,理解这个闭环的关键在于:Quiet是“听”,Active是“问”。先听有没有动静,没有就问一下,问完再听。如此反复,直到对方回应。
4.6 实际调试中的常见问题
最后,我分享几个在Detect阶段踩过的坑,希望能帮你少走弯路:
- 问题1:Detect阶段一直循环,不进Polling。 大概率是接收器检测阈值设置太高,或者对端设备的终端电阻异常。我曾经遇到过一颗芯片,内部终端电阻只有80Ω(标准是100Ω),导致反射波幅度偏小,检测不到。
- 问题2:电气空闲退出误触发。 如果PCB上电源噪声耦合到差分线上,可能会让接收器误以为有信号跳变。解决办法是在电气空闲检测逻辑里加一个低通滤波器,或者提高退出阈值。
- 问题3:Detect.Quiet时间太短。 有些芯片为了加快训练速度,把Quiet时间压到刚好12个UI。但实际板卡上,共模电压建立需要时间。我建议至少留20个UI,否则后续检测容易出错。
验证小技巧:在仿真环境中,我习惯在Detect.Active阶段随机改变对端设备的阻抗(80Ω~120Ω),看看DUT的检测逻辑是否健壮。这种随机化测试,往往能发现最隐蔽的bug。
好了,Detect状态就讲到这里。记住一句话:Detect是链路训练的地基,地基不稳,后面全是白搭。下一章我们会进入Polling状态,看看链路如何从“检测”过渡到“握手”。
公众号:蓝海资料掘金营,微信deep3321