第四章 链路层协议:帧结构、多帧、通道映射、扰码与CRC校验

链路层,说白了就是JESD204B的骨架。数据怎么打包,怎么分组,怎么搞定同步,全靠这层定规矩。我刚开始接触这个标准时,光看帧和多帧的关系就绕了半天。今天咱们把它拆开,一个一个说清楚。

4.1 帧结构:基本传输单元

JESD204B里最小的数据单元叫“帧”。一个帧包含固定数量的字节,具体多少个,由参数F决定。F可以是1、2、4,甚至更大。你在配置时选一个值,协议就把ADC的采样数据切成这么长的块。

举个例子,F=1时,一个帧只有1个字节。F=4时,一个帧有4个字节。每个字节对应一个转换器样本的某个部分。如果是多链路多转换器,还会混合多个通道的数据。

每个帧的边界由帧时钟(frame clock)标定。收发双方必须严格对齐这个边界。

关键点: 帧长度F、每帧字节数、帧时钟三者关系固定。你配置时别忘了让F×链路速率匹配ADC输出率。

4.2 多帧:更高级的分组

多帧是多帧的集合?别被字面绕晕了。一个“多帧”是多个帧组成的一个逻辑分组。数量由参数K定义,K的取值范围通常是1到32。一个多帧包含K个帧。

多帧的重要性在于——同步。链路建立阶段,接收端靠多帧边界来锁定对齐。它还会在数据流中插入特定的同步字符(/A/、/Q/、/F/等),这些字符只出现在多帧的边界上。我调试时遇到过一次对接不上,查了半天才发现是K配置不匹配。

帧与多帧参数对照
参数含义典型值
F每帧字节数1, 2, 4
K每多帧包含帧数4, 8, 16
帧时钟每秒帧数由链路速率 / (F×8) 决定

4.3 通道映射:数据怎么分配到每条线

通道映射解决一个问题:多个ADC通道的数据,如何在多条物理链路上传输?JESD204B用一套灵活的映射规则。每个转换器样本被拆成若干字节,然后按照你定义的顺序塞进不同的帧字节里。

映射规则写在寄存器里,你通过SPI或I²C配置。接收端必须用完全相同的映射才能恢复。我记得有一次把映射配反了,示波器上波形完全不对。后来打开JESD204B协议手册的附录,一行一行对,才找到毛病。所以我的建议是:画一张映射表,写进代码注释里,别偷懒。

避坑指南: 通道映射的字节序要特别注意。Converter Sample Data是先高字节还是低字节?看你的ADC手册。我遇到过一个怪问题:ADC手册写的是LSB first,但协议默认是MSB first,结果数据顺序全反了。

4.4 扰码:让信号更干净

为什么需要扰码?想象一下,你一直发相同的字节(比如全是0x00),链路上一段时间没有电平跳变。那么时钟恢复电路就很难锁定,错误率会飙升。扰码就是故意打乱数据,保证足够的跳变密度。

JESD204B用了一个多项式:x⁸ + x⁴ + x³ + x² + 1。它是个自同步扰码器,接收端不需要知道初始值,只要收到数据就能恢复。算法很简单:输出 = 输入 ⊕ 扰码器状态。状态是8位,每处理一个字节更新一次。

我在项目中习惯把扰码和校验开关设计成可配的。调试初期关掉扰码,方便用逻辑分析仪看原始数据;确认跑通后再打开。千万别忘了在生产代码里打开,否则链路可能通但不过EMI测试。

小技巧: 如果你的链路速率超过6Gbps,建议必开扰码。否则时钟抖动会让你头疼。

4.5 CRC校验:数据完整性最后一道防线

CRC校验是多帧级别加的。在每个多帧末尾,插入一个校验码。接收端重新计算,如果对不上,就报错并请求重传。JESD204B定义了两种模式:CRC-12和CRC-8。具体用哪个由链路配置决定。

CRC-12多项式:x¹² + x¹¹ + x³ + x² + x + 1。
CRC-8多项式:x⁸ + x² + x + 1。

计算方式很简单:把整个多帧(不含校验字节)的字节串当作被除数,多项式作除数,取余数。注意起始值、输出异或值在协议中有固定规定,不能随便改。我见过有人自己实现CRC时忘了处理这些细节,导致接收端永远报CRC error。

// CRC-8 计算示例(多帧长度为K×F字节,校验字节1个)
uint8_t crc8(const uint8_t *data, int len) {
    uint8_t crc = 0x00;
    for (int i = 0; i < len; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 0x80) crc = (crc << 1) ^ 0x07; // 多项式写入
            else            crc = crc << 1;
        }
    }
    return crc ^ 0x00; // 输出异或值
}

4.6 链路层协议整体流程

下面这张图把帧、多帧、扰码、CRC、通道映射之间的关系画在了一起。你一看就明白。

链路层协议核心流程 ADC 样本数据 通道映射 组帧(F字节) 成多帧(K帧) 扰码(可选) CRC 校验 串行输出链路 F=每帧字节数;K=每多帧帧数;CRC校验位于多帧尾部;扰码作用在帧数据上。

看到没?数据先从ADC样本进来,经过通道映射分配字节顺序。然后组帧,每F个字节一帧。接着成多帧,每K个帧一个组。之后可选扰码,再在每个多帧末尾加上CRC校验。最后串行化输出。

4.7 实际调试中的几个关键参数

  1. 检查F与K的乘积: 多帧总字节数 = F × K。这个值决定同步头占位。我建议先配小值(比如F=1,K=4)跑通,再逐步放大。
  2. 通道映射的字节对齐: 如果ADC是16位,每个样本占2字节。映射时要指定哪个字节走哪个帧位置。调试时打印出映射表,一次确认。
  3. 扰码的使能同步: 发送端和接收端必须同时开或同时关。我在一次协作中忘了同步这个配置,花了半天才发现。
  4. CRC错误的排查: 如果接收端频繁报CRC错误,先把扰码关掉,再看原始数据是否对。可能是串行链路误码,也可能是配置问题。
经验教训: 我曾经在某个项目中,把K配置成了0。协议规定K至少为1,结果链路一直同步失败。所以一定要看参数取值范围,别想当然。

嗯,链路层的东西说到这儿。帧、多帧、映射、扰码、CRC,每个环节都绑在一起。你配错一个参数,整个链路就不干活。不过别怕,只要掌握了这个架构,调试的时候就知道从哪里下手。