第4章 GTY的复位与初始化:让收发器「醒过来」的正确姿势
各位同学,欢迎来到第四章。前面我们聊了GTY的架构和时钟,但一个硬件模块光有电和时钟是不够的——你得让它「醒过来」,并且按照正确的顺序进入工作状态。
复位与初始化,说白了就是给GTY一个清晰的启动流程。我见过不少新手在这块翻车:复位时序不对,数据线死活拉不高;或者初始化顺序搞反了,误码率高得吓人。这章我们就来掰扯清楚,GTY到底该怎么正确复位和初始化。
4.1 复位信号的分类与作用
GTY的复位信号有好几根,它们各管一摊,千万别混淆。我习惯把它们分成三类:
| 复位类型 | 信号名 | 作用对象 | 作用范围 |
|---|---|---|---|
| 硬复位 | GTY_GTRESET | 整个GTY Quad | 所有通道、PLL、时钟 |
| PLL复位 | CPLLRESET / QPLLRESET | 对应PLL | 仅复位PLL本身 |
| 通道复位 | TXPCSRESET / RXPCSRESET | 单个通道的PCS逻辑 | TX或RX的数据通路 |
有人问:我直接用GTY_GTRESET把全部复位一遍不就完了吗?省事儿。嗯,我以前也这么干过,但后来发现一个问题——每次全局复位,PLL都要重新锁定,这得花好几十微秒。如果只是通道数据出了问题,复位PCS就够了,不需要动PLL。
4.2 复位序列——千万别搞反顺序
很多同学第一次看UG手册,发现复位序列列了一堆步骤,头都大了。其实记住一条主线就行:时钟域 → PLL → 数据通路。核心逻辑是——先有稳定的参考时钟和PLL输出,才能去初始化依赖它们的PCS和数据通路。这个顺序是物理决定的,不是Xilinx强加的。
推荐复位步骤(以单个GTY通道为例)
- 确保参考时钟已稳定——时钟芯片的输出要稳定,GTY的REFCLK输入不能有毛刺。
- 拉低GTY_GTRESET,保持至少10微秒——这期间内部所有状态机归零。
- 释放GTY_GTRESET——注意这里只是释放硬复位,不是马上操作通道。
- 复位并等待CPLL锁定:
- 拉高CPLLRESET,保持1微秒以上;
- 拉低CPLLRESET;
- 轮询CPLLLOCK信号,直到它为高;
- 释放TX/RX PCS复位:
- 拉低TXPCSRESET和RXPCSRESET(如果有独立信号);
- 或者通过GTY的初始化状态机,驱动TXUSERRDY和RXUSERRDY为高;
- 等待PCS初始化完成——TX侧等待TXRESETDONE,RX侧等待RXRESETDONE。
- 检查CDR锁定和RX信号质量——对于RX侧还要确认RXELECIDLE已经消失。
举个例子,下面是我某个项目里用的Verilog代码片段,只展示了核心控制逻辑:
// 复位状态机 - 简化版
// 状态:IDLE → CPLL_RESET → WAIT_CPLL → PCS_RESET → WAIT_PCS → READY
always @(posedge clk or posedge rst_i) begin
if (rst_i) begin
state <= IDLE;
gty_reset_n <= 1'b0;
cpll_reset <= 1'b1;
tx_usrrdy <= 1'b0;
rx_usrrdy <= 1'b0;
end else begin
case (state)
IDLE: begin
gty_reset_n <= 1'b1; // 释放硬复位
state <= CPLL_RESET;
end
CPLL_RESET: begin
cpll_reset <= 1'b0; // 释放CPLL复位
state <= WAIT_CPLL;
end
WAIT_CPLL: begin
if (cpll_locked) begin
tx_usrrdy <= 1'b1; // 通知通道PCS开始初始化
rx_usrrdy <= 1'b1;
state <= PCS_RESET;
end
end
PCS_RESET: begin
// 等待TXRESETDONE和RXRESETDONE
if (tx_resetdone && rx_resetdone)
state <= READY;
end
READY: begin
// 数据通路已就绪
end
endcase
end
end
4.3 复位完成信号怎么看?
复位序列走完了,怎么确认GTY真的准备好了?靠几个状态指示信号:
- CPLLLOCK / QPLLLOCK:PLL锁定的硬性指示。逻辑高表示频率锁定。
- TXRESETDONE:TX侧的PCS初始化完成。高电平表示TX数据通路已准备就绪。
- RXRESETDONE:RX侧PCS初始化完成。注意,这个信号高并不代表CDR也锁定了。
- RXELECIDLE:RX检测到线路空闲。正常工作时应该是低电平。
- RXCLKCORCNT:时钟校正计数。可以用来判断RX侧的时钟对齐是否稳定。
我个人的习惯是:在上层控制器里把这些信号都引出来,做成一个状态寄存器,方便上板调试时通过ILA观察。你想想看,如果复位完成后TXRESETDONE是低的,你还在拼命往TX FIFO里写数据——那不是白费功夫吗?
4.4 初始化阶段需要配置什么?
复位做完只是第一步,真正的「初始化」还包括通过DRP(动态重配置端口)写入通道参数。说白了,你需要在复位完成后,按顺序写寄存器:
| 配置项 | DRP地址 | 典型值 | 说明 |
|---|---|---|---|
| TX预加重 | 0x16 | 0x0001 (2.5dB) | 根据PCB走线长度调整 |
| RX均衡器 | 0x1F | 0x0003 (5dB) | 补偿高频损耗 |
| 极性控制 | 0x10 | 0x0000 | TX/RX极性翻转 |
| 输出幅度 | 0x12 | 0x0010 (800mVpp) | 幅度越大,功耗越高 |
这些配置必须在PLL锁定之后、数据通路激活之前写入。我以前踩过一个坑:先把PCS复位释放了,再去写DRP,结果写进去的值不生效,因为PCS已经在按默认值初始化了。顺序错位,白忙活一场。
4.5 常见陷阱与实践建议
最后分享几个我遇到过的真实问题,希望能帮你们少走弯路:
- CPLL复位时间不够: 手册上说CPLLRESET低电平至少保持1微秒。我见过有人只拉了100纳秒,结果CPLLLOCK一直不拉高——因为内部模拟电路根本没复位彻底。
- 多个通道共用CPLL: 如果一个CPLL给两个通道服务,复位其中一个通道时不能把CPLLRESET拉高,否则另一个通道也会掉线。用通道级的TXPCSRESET和RXPCSRESET就好。
- RXELECIDLE没消失就认为链路OK: 我曾经在调试时发现RXRESETDONE拉了,就以为数据通了,结果上板抓ILA发现RXELECIDLE还是高——链路根本没建立。需要加上检查RXELECIDLE和RX信号质量的逻辑。
- 仿真和实物表现不一致: 仿真时复位时序跑得好好的,上板就不行。为什么?因为仿真器里的PLL锁定时间和CDR锁定时间都是理想化的,实际芯片可能慢好几倍。复位时间参数一定要留余量。
- 热复位与冷重置: 如果系统运行中需要复位GTY,记得先让链路伙伴端的发送器停止发送,不然RX侧会收到一堆假信号。我建议设计一个握手协议,复位前通知对端。
嗯,关于复位与初始化,就讲这么多。记住那个核心顺序——时钟 → PLL → 数据通路,然后仔细检查每个完成信号。GTY不会自己告诉你「我还没准备好」,但如果复位序列不对,它一定会用各种奇怪的方式让你知道——数据错乱、链路断开、误码暴增。把这些基础打牢了,后面的内容就好办了。