3. 链路层基本概念:帧结构、初始化序列与链路训练
链路层在UCIe协议栈里,相当于一个“交通指挥官”。
它负责把物理层传来的比特流,组装成有意义的帧;还负责在链路刚上电时,把两边芯片拉到同一个频道上。我调试过不少UCIe板级联调,八成的问题都出在链路层初始化没对齐。
3.1 链路层帧结构
UCIe链路层的帧,说白了就是一组固定格式的数据包。每一个帧都包含三个部分:帧头(Header)、数据载荷(Payload)、以及可选的循环冗余校验(CRC)。
帧头占8字节,里面最关键的是这几项:
- 帧类型(2 bits):控制帧、数据帧、重传帧等等,我习惯在调试时先看这俩bit,能快速定位是不是帧类型匹配错了。
- 序列号(6 bits):每个数据帧都有唯一序号,接收端拿它做乱序重组和丢包检测。
- 长度字段(10 bits):指示Payload的字节数,最大能到1024字节。
数据载荷部分,长度从0到1024字节不等。注意啊,控制帧是没有Payload的,只有帧头和CRC。
CRC在帧尾,用多项式CRC-16保护整个帧。我曾经犯过一个低级错误——软件配的CRC使能跟硬件不一致,结果链路一直报CRC错误,查了两天才发现。
| 字段 | 位置 | 长度 | 说明 |
|---|---|---|---|
| 帧头 | 帧起始 | 8字节 | 含帧类型、序列号、长度、保留位 |
| 数据载荷 | 帧头之后 | 0~1024字节 | 有效数据,控制帧无此字段 |
| CRC | 帧尾 | 2字节 | CRC-16校验,覆盖帧头+载荷 |
3.2 初始化序列
链路刚上电时,两边芯片需要经历一套固定的握手流程——这就是初始化序列。我把它分成四个阶段,你想想看,很像两个人第一次见面:先打招呼、互相确认身份、约定通信规则、最后进入正常对话。
- 复位阶段:主机发送复位帧,从机接收后进入复位状态。所有内部计数器清零。
- 参数协商阶段:交换链路参数,比如最大Payload长度、CRC使能、重传缓冲区大小、时钟频率。
- 对等确认阶段:双方各自验证对方发来的参数跟自己配的有没有冲突。如果有,就发NACK重新协商。
- 初始化完成阶段:双方各自发送初始化完成帧,然后进入正常链路层工作状态。
我遇到过一个问题:某个芯片对参数协商的顺序非常敏感,必须先发长度参数再发缓冲区大小,否则就死锁。那时候没有调试日志,只能靠逻辑分析仪一点点抠时序……嗯,从那以后,我在设计中强制要求参数协商帧里的字段顺序严格按协议规范排列,不许乱动。
3.3 链路训练与状态机
链路训练是UCIe的“热身环节”,它负责把物理层的差分信号调成一致。
状态机是训练过程的核心。我把它画成了一幅流程图,你可以边看边理解。
状态机里有个关键点——“训练”到“锁定”的跳转不是一步到位的。训练阶段会持续发送特定训练序列(比如交替的0x5555和0xAAAA),接收端通过检测这些序列来确定眼图中心。如果检测到误码率过高,会跳回训练状态重新调。
我个人习惯在训练阶段抓两次逻辑分析仪:一次在训练刚开始,一次在锁定之后。对比这两个时刻的眼图宽度,能快速判断是信号质量问题还是协商参数冲突。
3.4 小结
链路层帧结构决定了你能传多快、丢包后怎么恢复。初始化序列往往是调通链路的第一道坎。状态机则是你跟踪链路健康状态的仪表盘。记住一句话:所有的链路层问题,最后都能在状态机停留的位置找到线索。