3. 训练序列结构:帧格式、同步码与训练码、收发时序
好,咱们接着聊训练序列的结构。这部分内容,说白了就是搞清楚训练序列长什么样、怎么发、怎么收。我刚开始接触链路训练时,总觉得这东西很玄乎,后来亲手抓了几次波形,才明白——嗯,其实就是一套约定好的握手流程。
3.1 训练序列的帧格式
先看帧格式。训练序列不是乱发的,它有固定的结构。我个人习惯把它拆成三个部分:前导、同步码、训练码。你想想看,就像寄快递,得有收件人地址(同步)、包裹内容(训练)、还有签收确认(响应)。
典型的训练帧格式如下:
| 前导 (Preamble) | 同步码 (Sync Code) | 训练码 (Training Code) | 校验 (CRC) |
| 8 UI | 16 UI | 64 UI | 8 UI |
这里UI是Unit Interval,也就是一个比特的时间宽度。前导部分我一般用来做信号检测,告诉接收端“嘿,我要开始发训练序列了”。同步码负责对齐时钟和数据,训练码才是真正用来调整均衡器、时钟恢复这些参数的。
关键点:帧格式的长度不是固定的。不同协议(比如PCIe、MIPI、HDMI)会有差异。但核心思想一致——先同步,再训练。
3.2 同步码与训练码
同步码和训练码,这两个容易搞混。我简单说说区别。
同步码,目的是让接收端找到数据的边界。它通常是一串有特殊自相关特性的序列,比如巴克码(Barker Code)或者伪随机序列(PRBS)。我在项目中遇到过一个问题:同步码选得太短,抗干扰能力差;选得太长,又浪费带宽。后来我建议用16位的巴克码,效果还不错。
训练码,目的是让接收端调整自己的参数。比如均衡器的抽头系数、时钟恢复的相位。训练码一般是已知的固定序列,接收端收到后跟自己期望的值做对比,算出误差,然后调整。
| 类型 | 作用 | 典型长度 | 常用序列 |
|---|---|---|---|
| 同步码 | 帧边界检测、时钟对齐 | 8~32 UI | 巴克码、PRBS7 |
| 训练码 | 均衡器训练、信道估计 | 32~256 UI | PRBS9、PRBS15 |
小技巧:我曾经在调试MIPI D-PHY时,发现同步码总是检测失败。后来抓波形一看,原来是前导部分的电平没稳定。加了个简单的延迟电路,问题就解决了。所以啊,同步码之前的前导部分,一定要留够稳定时间。
3.3 训练序列的发送与接收时序
时序这块,是很多工程师容易踩坑的地方。我画个简单的时序图,你感受一下:
发送端:
|--- 前导 ---||--- 同步码 ---||--- 训练码 ---||--- 等待 ---|
| 8 UI | 16 UI | 64 UI | 8 UI |
接收端:
|--- 检测 ---||--- 对齐 ---||--- 训练 ---||--- 响应 ---|
| 检测到信号 | 同步完成 | 参数更新 | 发送ACK |
这里要注意几个时间点:
- 前导检测时间:接收端需要在前导期间完成信号检测。如果前导太短,检测没完成,后面的同步码就收不到了。
- 同步对齐时间:同步码发送期间,接收端要完成比特对齐。我建议同步码至少重复发送两次,防止单次误码。
- 训练时间:训练码发送期间,接收端要完成参数调整。如果训练码长度不够,参数可能还没收敛,链路质量就差了。
避坑指南:我曾经遇到一个案例,训练序列的发送时序和接收时序没对齐。发送端发完训练码后立刻发数据,但接收端还在调整参数。结果前几个数据包全丢了。解决方案很简单——在训练码后面加一段保护间隔(Guard Interval),给接收端留足处理时间。
收发时序的另一个关键点是握手。训练不是单向的,接收端训练完成后,要发一个确认信号(ACK)给发送端。发送端收到ACK后,才能开始发正常数据。如果ACK丢失,发送端会重发训练序列。这个重传机制,说白了就是保证链路训练的可靠性。
嗯,这里我再补充一句。实际项目中,训练序列的时序参数(比如前导长度、同步码重复次数)通常可以在芯片的寄存器里配置。我建议你在调试阶段把这些参数都开放出来,方便抓波形分析。等链路稳定了,再固化到代码里。
好了,训练序列的结构就聊到这儿。下一节咱们讲链路训练的状态机,那个更有意思。