3. 链路训练状态机(LTSSM):状态定义与转换
搞 USB 3.0 协议,最绕不开的就是 LTSSM 。全称 Link Training and Status State Machine。
你想想看,一条 USB 3.0 链路从物理连接到真正能传数据,中间要干多少事?
- 先判断对面有没有设备
- 然后对齐位、做握手
- 接着协商速度、通道数目
- 再调均衡参数
- 最后才能进入正常工作模式
这些步骤不是瞎来的。LTSSM 就是把这些流程串起来的状态机。我个人习惯把 LTSSM 理解为“链路的生命轨迹”。它规定了每条差分对在什么时刻该干什么。你在示波器上看到的那些电平跳变、低频周期性信令(LFPS)、训练序列……背后全是 LTSSM 在驱动。
3.1 状态概览
USB 3.0 规范把 LTSSM 分成十多个状态,但常用的核心状态就那么几个。我画了个简化的状态转换图,方便你建立整体印象。
从上图可以看到,链路从 Rx.Detect 开始,经过 Polling、Configuration 到达 U0,这是正常工作的主路径。一旦链路上出现错误或者对方请求进入低功耗,就会迁移到 Recovery 或 U1/U2/U3。
3.2 每个状态是干什么的?
下面我按顺序拆开讲。每个状态都有明确的目的,别搞混了。
3.2.1 Rx.Detect —— 探测对面是否有接收端
这是物理链路通电后干的第一件事。主机端口会输出一个短的 DC 电平,依靠接收端端接电阻产生的反射来判断。
- 条件:端口上电后,如果没有检测到终端,就一直刷 Rx.Detect。
- 成功转换:检测到接收端 →
Polling - 失败处理:超时后重试,如果连续失败就进入
SS.Disabled。
3.2.2 Polling —— 位锁定与链路训练
一旦确认对面有人,马上发训练序列(TS1/TS2)。目的是让接收端的 CDR(时钟数据恢复)锁定频率和相位,同时让双方知道对方的存在。
Polling 里有两个子状态:Polling.Active 和 Polling.Passive。你别被名字吓到,其实就是谁主导发序列的问题。
| 子状态 | 行为 | 我遇上过的坑 |
|---|---|---|
| Polling.Active | 主动发送 TS1 序列,期待收到对方响应 | 信号质量差时,接收方 CDR 无法锁定,一直超时重试 |
| Polling.Passive | 只接收不发送,等待对方先完成锁定 | 链路两端的相位差太大,被动方容易收不到有效序列 |
3.2.3 Configuration —— 均衡与宽度协商
这是链路训练中最关键的一步。在这里双方要交换均衡参数(TxEQ Preset)、协商通道宽度(x1/x2/x4)、并做电源模式协商。
我记得有一次客户报告 USB 3.0 偶尔掉盘,抓 log 发现总是卡在 Configuration 状态。后来我打开示波器看训练序列,发现 Preset 值从主机发过去,设备回了一个不支持的 Preset 值。主机不认可,就一直重发。
3.2.4 U0 —— 正常工作状态
走到这一步,恭喜你,链路通了。U0 状态里,数据可以随时双向传输。但别以为万事大吉。
U0 状态下链路仍然需要监视信号完整性。一旦误码率超过阈值(通常是 10⁻¹²),就会触发 Recovery 状态。
3.2.5 Recovery —— 链路修复与重新训练
Recovery 不是错误状态,它更像“临时刹车”。用来快速重训练,尝试恢复链路而不必回到 Polling 重新来一遍。
Recovery 里也有子状态:Recovery.Active、Recovery.Configuration 等。具体怎么做我不细说,你记住两点就够了:
- 如果 Recovery 成功,回到 U0。
- 如果 Recovery 失败(比如超时或收到错误序列),跳回 Polling 甚至 Rx.Detect。
我曾经在 EM 测试中发现机壳接地不良时,Recovery 反复失败。每隔几秒链路上就出现一次幅度波动,跟着就掉到 Polling。折腾了一个星期才找到是接地螺丝松了。
3.2.6 U1/U2/U3 —— 低功耗状态
USB 3.0 支持多种省电模式。U1、U2、U3 的功耗依次降低,退出延迟也依次增大。这里我不展开,你只需要知道退出低功耗状态时需要走 Recovery 而不是直接回到 U0。
3.3 状态转换的关键判断条件
为了让你调试时更有方向,我整理了一张表,列出最常见的转换触发条件。
| 当前状态 | 转换条件 | 目标状态 |
|---|---|---|
| Rx.Detect | 检测到接收端终端 | Polling |
| Polling | 完成 TS1/TS2 交换,位锁定 | Configuration |
| Configuration | 均衡参数协商完成,进入 U0 | U0 |
| U0 | 链路错误或超时 | Recovery |
| U0 | 空闲进入低功耗 | U1/U2/U3 |
| Recovery | 训练成功 | U0 |
| Recovery | 失败超时 | Polling / Rx.Detect |
| U1/U2/U3 | 退出低功耗 | Recovery |
3.4 避坑指南
最后聊几个我踩过的坑,希望你别再碰。
- Rx.Detect 假检测:有些端口对噪声敏感,会把终端检测搞成误触。我建议在硬件设计上给 Rx.Detect 加个去抖定时器,软件里也可以多读两次状态确认。
- Polling 阶段 CDR 锁不住:很多情况是时钟抖动太大。检查 PLL 环路带宽,适当降低参考时钟的抖动指标。
- Configuration 阶段 Preset 不匹配:设备芯片和主机芯片可能来自不同厂家,支持的 Preset 集合不一样。如果协商失败,尝试手动固定 Preset(比如都用 Preset 0),排除兼容性问题。
- Recovery 频繁触发:这通常是电源噪声或者信号完整性下降的早期信号。不要只盯着状态机,去量一下供电纹波和信号眼图。
嗯,LTSSM 的状态定义和转换说完了。你给我一张图(上面那张),再对照表格和流程,基本就能看懂大部分链路训练行为。下一段我们真正上手实操,看看怎么用逻辑分析仪抓 TS1/TS2 序列,以及怎么通过调整均衡参数推动链路通过 Configuration。先消化这些基础状态吧。