SerDes基础原理:串行化与解串行化、PLL与时钟恢复(CDR)、8B/10B与64B/66B编码
各位同学,今天我们来啃一块硬骨头——SerDes的基础原理。说实话,我刚入行那会儿,觉得SerDes就是个黑盒子,数据进去数据出来,没啥了不起。直到有一次项目里,板级互联死活跑不上5Gbps,我才老老实实把里面的门道摸了个遍。
SerDes,全称Serializer/Deserializer,说白了就是串行器和解串器。为什么需要它?你想想看,传统的并行总线,比如DDR,数据线动辄几十根,跑个几百兆就头疼得要命。SerDes只用一两对差分线,就能跑到几十Gbps。这背后的魔法,就是今天我们要聊的三个核心模块。
核心要点:SerDes的本质是用时间换空间——把宽位并行数据在时间轴上压扁,用高速串行链路传输,再在接收端恢复出来。
一、串行化与解串行化
串行化,就是把N位并行数据,按位依次发送出去。比如一个10位的并行总线,时钟频率是100MHz,数据率就是1Gbps。串行化之后,只需要一对差分线,时钟频率变成1GHz,数据率还是1Gbps。
我习惯把串行器想象成一个「旋转的桶」。并行数据像倒水一样灌进桶里,桶每转一格,就倒出一位数据。接收端再拿一个同步旋转的桶,把数据接住,重新拼成并行数据。
这里有个关键问题:发送端和接收端的桶,转速必须完全一致。否则数据就会错位。这就是为什么我们需要PLL和CDR。
// 串行化示意(伪代码)
// 并行数据: [D7, D6, D5, D4, D3, D2, D1, D0]
// 串行输出: D7 -> D6 -> D5 -> D4 -> D3 -> D2 -> D1 -> D0
always @(posedge clk_ser) begin
if (load)
shift_reg <= parallel_data;
else
shift_reg <= {shift_reg[6:0], 1'b0};
serial_out <= shift_reg[7];
end
个人经验:我在做10Gbps SerDes时,发现串行器的输出摆幅控制特别重要。摆幅太大,功耗高;摆幅太小,接收端误码率飙升。一般建议控制在800mV~1.2V之间,具体看你的PCB走线长度。
二、PLL与时钟恢复(CDR)
PLL(锁相环)是SerDes的心脏。它的任务很简单:产生一个高频、低抖动的时钟。发送端用这个时钟去串行化数据,接收端用这个时钟去采样数据。
但问题来了——接收端怎么知道发送端的时钟频率?这就是CDR(时钟数据恢复)的活。
CDR的原理,说白了就是「猜」。接收端先根据参考时钟,产生一个大概频率的本地时钟。然后盯着输入数据的跳变沿,不断调整本地时钟的相位和频率,直到和发送端完全同步。
我遇到过最坑的情况是什么?有一次,CDR的环路带宽设得太宽,结果数据里连续出现长串的0或1,没有跳变沿,CDR直接失锁了。嗯,这里要注意:CDR的环路带宽要和数据的「游程长度」匹配。一般建议环路带宽是数据率的1/1000左右。
避坑指南:我曾经在一个项目里,PLL的VCO控制电压纹波太大,导致输出时钟抖动超标。排查了三天,最后发现是电源去耦电容放得太远。记住:PLL的模拟电源一定要单独走线,去耦电容要放在VCO引脚1mm以内。
CDR有两种主流架构:
- 基于PLL的CDR:用鉴相器比较数据边沿和本地时钟,输出误差信号控制VCO。优点是抖动小,缺点是锁定时间长。
- 基于相位插值的CDR:用多个相位等间隔的时钟,根据数据边沿选择最佳相位采样。优点是锁定快,适合突发模式。
我个人更偏爱基于PLL的CDR,尤其是在连续数据传输的场景下。它的抖动性能更稳定,误码率更低。
三、8B/10B与64B/66B编码
好,现在数据能串行发送了,时钟也恢复了。但还有一个问题:数据里如果连续出现多个0或1,接收端的CDR就找不到跳变沿,会失锁。
解决方案就是——编码。把原始数据变换一下,保证有足够的跳变沿。
8B/10B编码,是IBM在1983年发明的老古董了。它把8位数据映射成10位码字。10位码字里,0和1的数量差不超过2,而且不会出现连续5个相同的位。
你想想看,8位数据有256种组合,10位码字有1024种组合。多出来的768种组合,一部分用作控制字符(比如K28.5用于帧对齐),一部分是无效的。
| 编码 | 输入位宽 | 输出位宽 | 编码效率 | 最大游程长度 |
|---|---|---|---|---|
| 8B/10B | 8 | 10 | 80% | 5 |
| 64B/66B | 64 | 66 | 96.97% | 66 |
| 128B/130B | 128 | 130 | 98.46% | 130 |
8B/10B的优点是实现简单,DC平衡好。但效率只有80%,意味着你跑10Gbps的线速,实际有效数据只有8Gbps。在高速场景下,这个开销有点大。
64B/66B编码就聪明多了。它只加2位同步头(01或10),剩下的64位全是有效数据。效率高达96.97%。但代价是什么?最大游程长度变成了66位——也就是说,理论上可能出现连续66个0或1。这对CDR的要求就高了。
我在做100G以太网项目时,用的就是64B/66B编码。配合高性能的CDR,完全没问题。但如果你用的是老旧的SerDes IP,建议还是老老实实用8B/10B。
选型建议:
- 速率 < 10Gbps:用8B/10B,简单可靠
- 速率 10Gbps ~ 50Gbps:用64B/66B,效率高
- 速率 > 50Gbps:考虑128B/130B或更高级的FEC编码
知识体系总览
下面这张图,是我自己画的SerDes核心逻辑图。你看一眼,就能把今天讲的内容串起来。
从这张图你能看到,SerDes的发送端和接收端是对称的。发送端先编码,再串行化,最后通过PLL产生的时钟发出去。接收端先用CDR恢复时钟,再解串行化,最后解码得到原始数据。
每一步都有坑,但每一步也都有成熟的解决方案。我做了这么多年FPGA,最大的体会就是:SerDes的设计,本质上是在「速度」、「功耗」、「面积」和「可靠性」之间找平衡。没有完美的方案,只有最适合你项目的方案。
最后一个小技巧:如果你在调试SerDes链路时遇到误码,别急着怀疑硬件。先检查一下编码是否正确,再检查CDR的锁定状态。我遇到过好几次,都是因为8B/10B编码器的极性控制位配错了,导致接收端解码出来的数据全是乱的。
好了,SerDes的基础原理就聊到这里。记住这三个核心模块,后面我们讲高速收发器的具体实现时,你会觉得豁然开朗。