GTY收发器复位序列:初始化流程与复位控制寄存器

各位工程师朋友,这一章咱们来聊聊GTY收发器的复位序列。说实话,这玩意儿我刚开始接触的时候也头大——复位信号多,时序要求细,稍不注意就容易出问题。但只要你把复位序列搞清楚了,后续的调试工作会顺畅很多。说白了,复位就是给收发器「按下开机键」,但这个过程比想象中要复杂得多。

为什么要设计这么复杂的复位流程?

你想想看,GTY收发器内部有PLL、有CDR、有串并转换、有FIFO缓冲,每个模块上电后都需要一定时间才能稳定工作。如果一股脑全部复位再释放,很可能某个模块还在抖动,另一个已经开始干活了,结果就是链路建立失败。我在一个40G光互联项目里就遇到过这种情况——复位顺序不对,眼图怎么调都张不开。

核心原则:GTY复位采用「分级、分步、可编程」的策略。写代码时一定要按顺序来,别想着一个复位信号搞定所有事。

复位序列的整体流程

我们先看一张总览图,把复位流程跑一遍。我个人习惯把复位分成三个阶段:初始化、PLL锁定、通道复位。

GTY收发器复位初始化流程 阶段一:初始化 GTTX_RESET / GTRX_RESET 阶段二:PLL锁定 CPLL/DPLL 锁定检测 阶段三:通道复位 TX/RX 数据通路 ⏱ 关键定时要求 每个阶段之间需要等待至少10μs ~ 100μs(具体取决于参考时钟频率) 复位控制寄存器 • GTTX_RESET • GTRX_RESET • TX_FSM_RESET • RX_FSM_RESET 状态指示信号 • TX_RESET_DONE • RX_RESET_DONE • CPLL_LOCK • DPLL_LOCK 常见复位失败源 ⛔ 参考时钟未稳定 ⛔ PLL锁定超时 ⛔ 复位时序违反 ⛔ 电源不稳定

一步一步来:详细的复位步骤

下面我把每个阶段拆开来讲。这些步骤我在《高速接口设计实战》课程里反复强调过,你最好记在笔记本上。

1. 初始化复位

先拉低GTTX_RESET和GTRX_RESET。这里有个坑——这两个信号是低电平有效。我以前带过一个新人,写了个高电平复位,结果仿真过不了,查了半天才发现是极性搞反了。

  • TX复位:assert GTTX_RESET = 1'b0,保持至少10μs
  • RX复位:assert GTRX_RESET = 1'b0,保持至少10μs
  • 释放时先释放TX再释放RX,间隔20μs以上

2. 等待PLL锁定

释放复位后,PLL开始工作。你需要轮询CPLL_LOCK或DPLL_LOCK信号。嗯,这里要注意一点——PLL锁定信号从拉高到真正稳定,中间还有个毛刺窗口期。我个人习惯是检测到锁定后再多等50μs再往下走。

经验技巧:如果用的是外部参考时钟,建议先确认参考时钟稳定后再启动PLL复位流程。我做过一个项目,参考时钟来自一个刚上电的振荡器,PLL怎么都锁不住——后来加了100ms延时才解决。

3. 通道数据通路复位

PLL锁定后,才能操作通道复位。这一步主要通过TX_FSM_RESET和RX_FSM_RESET来控制。复位时间不宜太短,我试验过,至少保持50μs才能保证内部状态机完全复位干净。

复位控制寄存器详解

咱们来看看主要的复位控制寄存器。这些寄存器都在GTY的DRP地址空间中,具体偏移地址请参考对应器件的手册。

寄存器名称 地址偏移 位域 功能描述
GTTX_RESET 0x000 [0] TX PLL及前端复位,低有效
GTRX_RESET 0x001 [0] RX PLL及前端复位,低有效
TX_FSM_RESET 0x002 [0] TX数据通路FSM复位,低有效
RX_FSM_RESET 0x003 [0] RX数据通路FSM复位,低有效
CPLL_RESET 0x004 [0] CPLL单独复位,高有效
DPLL_RESET 0x005 [0] DPLL单独复位,高有效

警告:在操作DRP寄存器时,必须等待前一次写操作完成(通过DRP_DONE信号确认)再发起下一次操作。我曾经因为连续快速写寄存器,导致复位配置没有正确加载,整个链路无法建链。

复位完成检测

复位流程走完后,需要通过状态信号来确认复位是否成功:

  • TX_RESET_DONE:TX通道复位完成标志
  • RX_RESET_DONE:RX通道复位完成标志
  • CPLL_LOCK / DPLL_LOCK:PLL锁定状态

这几个信号都拉高后,才能认为复位成功。我建议你在代码里加个超时机制——比如等待5ms还没看到所有done信号,就报个错误并重新触发复位。

典型复位代码框架(Verilog 伪代码):

// 复位序列状态机
always @(posedge clk or posedge rst) begin
  if (rst) begin
    state <= IDLE;
    gttx_reset <= 1'b0;
    gtrx_reset <= 1'b0;
  end else begin
    case (state)
      IDLE: begin
        // 初始化复位
        gttx_reset <= 1'b0;
        gtrx_reset <= 1'b0;
        state <= WAIT_PLL_LOCK;
      end
      WAIT_PLL_LOCK: begin
        // 等待PLL锁定
        if (cpll_lock) begin
          state <= RELEASE_TX_RESET;
        end
      end
      RELEASE_TX_RESET: begin
        // 释放TX复位
        gttx_reset <= 1'b1;
        state <= RELEASE_RX_RESET;
      end
      // ... 后续状态
    endcase
  end
end

避坑指南

做复位设计这么多年,我踩过的坑真不少。这里挑几个最常见的分享给你:

  • 不要同时复位TX和RX:我试过同时释放,结果两个通道的PLL互相干扰,都锁不定。分开操作,间隔100μs左右。
  • 注意参考时钟的稳定性:如果参考时钟来自板级振荡器,上电后至少等100ms再操作GTY复位。这个值不算大,但在高速板卡上很实用。
  • DRP写入后要检查done:不检查done直接写下一笔,很可能寄存器值没写进去——我当时在FPGA原型验证时抓了三天bug才发现这个问题。
  • 复位状态机一定要有超时:万一某个复位信号一直拉不高,没有超时的话整个系统就卡死了。我一般设5ms超时,到了就报错重试。

好了,GTY收发器的复位序列就讲到这里。你实际调试的时候,建议先用chipscope抓一下RESET_DONE和LOCK信号,确认时序对不对。复位如果搞不定,后面的高速链路调试更是白搭。