干了这么多年FPGA,要说哪个接口最让人又爱又恨,SGMII绝对排得上号。说它简单吧,原理上不就是串行数据吗,7根线的事;可真上了板子,IP核配错一个选项、复位时序差那么一点、时钟频率偏了那么几个ppm,整条链路就是死活link不上,或者link上了数据全是错的。我这些年帮人排查过不少SGMII的问题,大部分根因翻来覆去就那么几个,但架不住每个项目都要重新踩一遍。这篇就把从IP核配置到板级调试的完整流程,按我实际工程里的操作顺序捋一遍,该给的代码给代码,该列的检查清单列清楚,争取让你照着做一遍就能把这条链路跑通。
1. 为什么是SGMII:三种常见PHY接口的本质对比
在做FPGA网络接口之前,先得把SGMII放在整个接口体系里看明白。以太网MAC和PHY之间的接口,工程里最常见的就是GMII、RGMII和SGMII这三种,它们的取舍关系其实是引脚数量和时钟频率之间的博弈。
GMII是最原始的并行接口,数据线8bit,发送和接收各一组,加上控制信号,加起来有20多根线。工作在千兆时时钟125MHz,这个频率在PCB上不算高,但20多根线摆在一起,布线面积和干扰问题都够喝一壶的。RGMII是它的降引脚版本,把时钟变成双沿采样,数据线降到4bit,一共12根线左右,代价是时序预算变得非常紧,源同步接口在PCB上得认真做等长。SGMII则完全是另一条路线,数据变成串行差分对,一对发送一对接收,加一个参考时钟,总共也就7根线,速率固定跑1.25Gbps,PCB布线难度直线下降。
SGMII为什么选1.25Gbps这个速率?因为千兆以太网的数据位宽是8bit、时钟125MHz,串行化之后线速率等于125MHz乘以10。多出来的2bit开销就是8b/10b编码。这个编码机制把每8bit数据映射成10bit码字,保证串行数据流里有足够的跳变沿供接收端恢复时钟,同时维持直流平衡。你可以把它想象成发快递——8bit数据是包裹里的货,2bit额外码字是包装材料和面单,货必须装上包装才能上路,收件端再把包装拆掉取出货物。8b/10b编码里有个叫运行不一致(Running Disparity,RD)的机制,就是为了保证10bit码字中0和1的数量尽量均衡,避免长时间直流偏置导致接收端判决错误。
SGMII的收发引脚各自独立,FPGA的GTX/GTH收发器通过CDR(时钟数据恢复)从接收数据流中提取时钟,所以SGMII接口没有像RGMII那样把接收时钟单独引出来给MAC。这意味着什么?意味着接收侧天然是一个从数据里恢复出来的时钟域,必须靠IP核内部的弹性缓冲和时钟转换逻辑来处理,你用户逻辑拿到的是IP核已经处理好、同步到本地时钟域的GMII接口。很多第一次做SGMII的人会下意识想"串行数据不就解个串嘛",实际上IP核帮你把CDR、8b/10b解码、时钟域转换、自协商状态机全都做完了,你真正要面对的是一堆配置选项和复位信号。
表:三种接口关键参数对照
| 接口类型 | 数据位宽 | 时钟频率(千兆模式) | 引脚数量 | 编码方式 | 传输方式 |
|---|---|---|---|---|---|
| GMII | 8bit | 125MHz | 20+ | 无(直接并转串) | 并行 |
| RGMII | 4bit(双沿) | 125MHz | 约12 | 无 | 并行 |
| SGMII | 1bit(差分) | 1.25Gbps | 7 | 8b/10b | 串行 |
2. IP核配置前必须搞懂的MAC模式与PHY模式
SGMII这个词本身指的就是MAC和PHY之间的接口协议。FPGA里做SGMII,本质上是让你的FPGA扮演MAC的角色,通过SGMII接口连接一颗外部的以太网PHY芯片,由PHY芯片去驱动网线(或者光纤)上的信号。在这个架构下,FPGA里的SGMII IP核必须配置成MAC模式,这是一个看似基础但影响全局的关键点,我见过太多人在这一步栽跟头。
以Xilinx 7系列为例,用的IP核是1G/2.5G Ethernet PCS/PMA or SGMII。这个IP核有两种主要使用模式:SGMII模式和1000BASE-X模式。当FPGA外接的是PHY芯片(比如88E1512、RTL8211这类),两侧要对接的是SGMII接口,此时必须选择SGMII模式,IP核作为MAC端。当FPGA不接PHY、直接接光模块SFP的时候,FPGA实际上是在充当PHY,对外是1000BASE-X光口协议,这时候IP核要选1000BASE-X模式,同时内部自己完成8b/10b编解码和自协商。选错模式最典型的症状就是link怎么都起不来,或者PHY芯片自协商完成但IP核这边永远报错,因为两边期望的协议帧格式根本对不上。
配置界面的其他关键选项也值得逐一说清楚。Line Rate选1.25Gbps,对应的就是千兆。用户数据接口选GMII,出来是8bit并行总线,时钟125MHz;也可以选XGMII,但那种8bit变10bit的接口实际用得不多,多数人还是走GMII。还有一个容易含糊的选项是内部时钟逻辑是Shared Logic还是Independent Logic,我一般建议把include shared logic in example design这个选项勾掉,改用Independent Logic,也就是把共享逻辑放到example design里去实例化。这样做的目的是让参考时钟缓冲、复位同步这些底层的东西先在示例工程里验证一遍,知道自己要哪些信号,再搬到自己的工程里,后续如果出了reset或时钟问题,排查范围会小很多。
速度协商这块,如果你只需要千兆,配置成Force 1000 Mbps就省事;如果你希望支持10/100/1000速率自适应,那就要开自协商并保留SGMII的speed negotiation逻辑。注意SGMII的自协商机制和1000BASE-X并不完全一样,SGMII的自协商是PHY芯片通过配置寄存器把链路速度反馈给MAC侧的,IP核会根据对端的速度自动调整GMII接口的时钟频率(千兆125MHz、百兆25MHz、十兆2.5MHz)。这个特性很实用,但前提是用户逻辑得能适配这个变化的时钟,如果只固定跑千兆,建议直接锁速率,少一堆麻烦事。
表:SGMII IP核常见配置项速查
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| Line Rate | 1.25Gbps | 千兆SGMII固定值 |
| Interface | GMII | 用户侧数据接口,8bit |
| PCS/PMA mode | SGMII | 外接PHY芯片时选此模式 |
| 1000BASE-X mode | 不勾选 | 直连光模块时才需要 |
| Shared Logic | Independent | 便于问题定位 |
| Speed Negotiation | 按需 | 固定千兆更省事 |
| Tx/Rx Inband FS | 按需 | 多用于自协商场景 |
3. 从GMII到用户逻辑:接口转接模块的写法与关键细节
IP核配置完,用户逻辑面对的就是一组GMII接口信号。GMII接口看起来相当直白:发送侧是tx_clk、tx_en、tx_er、txd[7:0],接收侧是rx_clk、rx_dv、rx_er、rxd[7:0]。但直接从IP核出来的GMII和最终接入用户MAC逻辑之间,隔着一层很少被文档明确写透的细节:IP核的GMII接口在以太网帧的数据通路里,到底负责到哪一层。
以发送方向为例,IP核默认并不帮你生成前导码和帧起始定界符(SFD),你需要自己构造完整的以太网帧格式:先发7字节的前导码0x55,然后1字节的SFD 0xD5,接着是6字节目的MAC地址、6字节源MAC地址、2字节长度/类型字段,然后是46到1500字节的负载,最后是4字节的FCS帧校验。如果待发送的数据不足46字节,还要补零到最小帧长64字节。也就是说,FPGA内部的发送逻辑需要自己完成MAC层的组帧工作,IP核只负责把这8bit并行数据进一步8b/10b编码后变成串行码流送给PHY。这是新手最容易漏掉的地方,以为往txd上放数据、拉高tx_en就能发出去,结果抓出来的波形完全不是以太网帧结构。
接收方向同理,IP核解出来的rxd[7:0]是包含前导码在内的原始GMII数据,rx_dv从检测到前导码时就会拉高。如果你只需要提取MAC帧净荷,就要自己做一个状态机,等待前导码和SFD之后才开始缓存数据,并且按帧长把CRC校验结果确认一下。Xilinx这个IP核在接收方向有一个rx_er信号,它不仅能反映物理层的错误码,也能把CRC校验失败、8b/10b解码错误等状态汇总成错误标志,具体含义要看status_vector和datasheet里的错误指示定义,但调试时盯着rx_er是一个快速判断链路是否健康的好习惯。
帧间隙IFG也是GMII转接时必须考虑的。以太网标准要求两帧之间至少间隔96ns,换算成GMII的125MHz时钟就是12个时钟周期。发送逻辑在上一帧发完后,至少让tx_en保持低电平12拍,才能开始下一帧。有些PHY和MACIP对这12拍要求比较严格,时序紧张的时候少几拍就会导致对端把帧丢弃。
还有一个我实战中经常被问到的点:用户逻辑的时钟和IP核的GMII接口时钟是否必须同源。最稳妥的方案是用户逻辑直接使用IP核提供的gmii_tx_clk和gmii_rx_clk(这两个通常同频),让所有MAC层逻辑都跑在这个时钟域里。如果用户逻辑需要跨时钟域,比如要接一个工作在125MHz的独立用户时钟,那必须在数据通路中间插入异步FIFO做缓冲,绝不能直接把两个不同时钟域的信号接在一起。SGMII接收侧的时钟原本就是从数据流中恢复出来的,哪怕PPM偏差再小,长时间运行也可能导致FIFO溢出或读空,所以IP核内部本身就有弹性缓冲来处理这个问题,用户逻辑侧就不要再人为制造第二个跨时钟域风险点了。
下面给一个最简单的GMII发送参考代码框架,实现的是在用户请求到来时发送一帧固定内容的数据帧,包含前导码、SFD、MAC地址、长度和负载:
module gmii_tx_if #( parameter MAC_TARGET = 48'h00_1A_2B_3C_4D_5E, parameter MAC_SOURCE = 48'h00_1A_2B_3C_4D_5F )( input wire clk125, input wire rst_n, input wire tx_start, input wire [7:0] tx_data_in, input wire tx_data_valid, output reg tx_en, output reg tx_er, output reg [7:0] txd ); localparam IDLE = 3'd0; localparam PRE = 3'd1; localparam SFD = 3'd2; localparam DA = 3'd3; localparam SA = 3'd4; localparam TYPE = 3'd5; localparam PAY = 3'd6; localparam IFG = 3'd7; reg [2:0] state; reg [2:0] cnt; // 前导码计数 0~6 reg [3:0] ifg_cnt; // 帧间隙计数 reg [2:0] byte_cnt; // 地址/负载字节计数 reg [15:0] payload; // 用于生成测试payload的计数器,实际使用中替换为fifo数据 always @(posedge clk125 or negedge rst_n) begin if (!rst_n) begin state <= IDLE; tx_en <= 1'b0; tx_er <= 1'b0; txd <= 8'h00; end else begin case (state) IDLE: begin tx_en <= 1'b0; if (tx_start) begin state <= PRE; cnt <= 3'd0; end end PRE: begin tx_en <= 1'b1; txd <= 8'h55; // 前导码 if (cnt == 3'd6) state <= SFD; else cnt <= cnt + 1'b1; end SFD: begin txd <= 8'hD5; // 帧起始定界符 state <= DA; byte_cnt <= 3'd0; end DA: begin txd <= MAC_TARGET[47 - byte_cnt*8 -: 8]; if (byte_cnt == 3'd5) begin state <= SA; byte_cnt <= 3'd0; end else byte_cnt <= byte_cnt + 1'b1; end SA: begin txd <= MAC_SOURCE[47 - byte_cnt*8 -: 8]; if (byte_cnt == 3'd5) begin state <= TYPE; byte_cnt <= 3'd0; payload <= 16'h0000; end else byte_cnt <= byte_cnt + 1'b1; end TYPE: begin txd <= 16'h0800 >> 8; // 类型字段高字节,按需改 state <= PAY; byte_cnt <= 3'd0; end PAY: begin txd <= tx_data_in; if (!tx_data_valid) begin state <= IFG; ifg_cnt <= 4'd0; end end IFG: begin tx_en <= 1'b0; if (ifg_cnt == 4'd11) state <= IDLE; // 12拍帧间隙 else ifg_cnt <= ifg_cnt + 1'b1; end default: state <= IDLE; endcase end end endmodule这个代码只是骨架,没处理CRC插入,实际工程建议把CRC计算放在发送数据写入FIFO时同步算好,或者调用FPGA厂商的CRC硬核。接收侧的状态机逻辑类似,只是反着来,等待rx_dv拉高之后识别前导码和SFD,然后按帧缓存数据并做CRC校验。
4. Clk与复位:最容易让板级调试卡壳的两个"元凶"
SGMII接口的板级调试,十个问题里至少有五个出在时钟和复位上。这两个东西看起来不起眼,但它们一旦不对,整个链路就处于一种"什么现象都有可能出现"的薛定谔状态,排查起来极其消耗耐心。
先看参考时钟。SGMII链路的两端必须保证频率足够接近,标准要求PPM偏差在一定范围内,FPGA侧的GT参考时钟一般从板载晶振获取,最简单是125MHz,也可以从PHY芯片反馈一个125MHz时钟。这里有一个高频踩坑点:GT参考时钟必须接到FPGA的专用参考时钟引脚(比如7系列的GTREFCLK引脚),并且采用AC耦合差分输入,Xilinx的IP核示例工程里会用IBUFDS_GTE2原语把差分时钟缓冲进来。有些人图省事,把参考时钟接到一个普通IO引脚上,那GT是无论如何都锁不住的,现象就是IP核的tx/rx_resetdone一直不拉高,因为GT的参考时钟根本没进到收发器里。
再来说userclk。IP核会在内部根据链路速率生成给GMII接口使用的时钟,千兆时是125MHz。如果开了速率自适应,这个时钟会随协商结果变化。这也就意味着,如果你在用户逻辑里用了一个固定125MHz时钟去采GMII信号,而PHY协商到了百兆甚至十兆,你的逻辑必然采错。所以如果做自适应速率,用户侧时钟也要跟着切换,通常用一个MMCM/PLL动态重配来实现。如果不是必须支持多速率,我倾向于在IP核里直接固定千兆,把这个问题直接消灭在配置阶段。
复位域是另一个问题渊薮。Xilinx SGMII IP核的复位信号有gt_reset、gt_tx_reset、gt_rx_reset、mac_tx_reset等,它们之间的时序关系是有要求的,不能一股脑拉高再拉低草草了事。example design里有专门的复位同步和扩展逻辑,它会把外部复位信号同步到对应时钟域并拉长到足够时间。很多人喜欢自己写复位逻辑,结果gt_reset的释放时序不满足GT收发器的要求,导致复位完成后GT的PLL锁定状态和resetdone信号一直不对。我自己调试时的习惯是:先原封不动跑通IP核的example design,确认简单的回环能通,再把自己的逻辑挪进来,这样如果出问题,至少能确定不是复位本身的锅。
gt_reset还要注意一个亚稳态问题。FPGA内部如果直接用异步复位信号去复位跨时钟域的模块,很容易出现亚稳态,表现就是链路偶发起不来或者跑一段时间掉链子。稳妥做法是把外部复位先打两拍同步到目标时钟域再使用,example design里的reset_sync模块干的就是这个事。
我在项目里一般会给复位信号做成可手动控制的,比如把gt_reset接到一个按键上。调试的时候按一下复位看链路能不能重新建立,比反复重新加载比特流快得多。这个习惯让我省了非常多折腾的时间。芯片重新配置一次要几十秒,按个键一秒都不需要。
时钟问题还有一个容易忽略的地方:复位释放和时钟稳定的顺序。GT参考时钟要由外部晶振先稳定输出,FPGA配置完成之前它就应该存在,不能出现"上电后时钟还没起振、FPGA已经开始跑GT复位流程"的情况。另外,如果板子上PHY芯片的主时钟和FPGA的GT参考时钟不是同一个源,两边的PPM偏差可能超标,尤其当PHY用的晶振精度不高时,长时间跑了之后偶尔出现CRC错误或者link闪断,就要往时钟精度这个方向查。
下面是示例工程中复位同步和一个简单超时检测的使用思路:
// 复位同步:把外部复位同步到clk125域 reg [1:0] rst_sync; wire rst_n_sync = rst_sync[1]; always @(posedge clk125) begin rst_sync[0] <= ~ext_rst_n; rst_sync[1] <= rst_sync[0]; end // 超时检测:如果GT复位后一段时间resetdone还没有拉高,给出提示 reg [31:0] timeout_cnt; reg timeout_flag; always @(posedge clk125 or negedge rst_n_sync) begin if (!rst_n_sync) begin timeout_cnt <= 32'd0; timeout_flag <= 1'b0; end else if (resetdone) begin timeout_cnt <= 32'd0; timeout_flag <= 1'b0; end else if (timeout_cnt == 32'd125_000_000) begin timeout_flag <= 1'b1; // 1秒未完成复位,标志位置位 end else begin timeout_cnt <= timeout_cnt + 1'b1; end end这只是一个简单的监测逻辑,但它能帮你在板级调试时快速判断是"复位没完成"还是"链路其他部分有问题",不用老盯着signaltap猜。
5. 板级调试的完整链路:从光口回环到上下行数据打流
板级调试这个环节最忌讳的就是"一上来就把两个板子对接,然后发现问题"——两个板子同时出问题的可能性太大,你根本不知道是发送端坏了、接收端坏了、还是两边的配置打架。我自己的调试顺序永远是逐层隔离、逐个确认,串行链路尤其适合这种打法。
上电之后第一件事,是静态检查。原理图上的FPGA GT参考时钟引脚是否正确连接、PHY芯片的复位引脚和配置引脚是否接对、SGMII差分对是否连到了正确的BANK、AC耦合电容是否在链路上、PHY芯片的MDIO/MDC管理接口有没有上拉电阻。这些问题在PCB阶段就该确认,但实际做板子总有疏漏,调试前花10分钟过一遍,能省下不少无用功。
第二步,用IBERT来验证GTX/GTH收发器的物理通道。IBERT是Xilinx提供的一个专用测试IP,不需要任何外部PHY逻辑,直接在GT收发器内部产生PRBS码流并自己接收比对。它能验证FPGA内部的串行数据通路是否正常、GT参考时钟是否锁住、信号质量和眼图如何、误码率大概在什么量级。如果IBERT误码率都很高,那就别指望SGMII IP核能跑通了,问题大概率在硬件或者参考时钟;如果IBERT完全正常,恭喜你,物理层是通的,问题可以锁定在IP核配置或逻辑正确性上。这一步的价值怎么强调都不过分,它是把物理层问题与应用层问题一刀切开的最高效手段。
第三步,在IP核内部做回环。Xilinx的SGMII IP核在PCS层提供回环配置,通常是内部把发送数据环回到接收路径,这样不经过外部物理链路就能验证IP核本身的数据通路。跑通这一级,说明IP核配置、复位、时钟、GMII接口都是正常的。虽然IP核的example design本身一般会包含这种回环机制,但手动触发一次回环并抓一下GMII侧信号,更有助于确认你的用户逻辑和IP核之间的接口对接正确。
第四步,才是外部的物理回环。如果用的是PHY芯片,先把PHY配置成数字回环模式,就可以在不依赖外部网线对端的情况下,让PHY把接收的数据直接回发给发送端,FPGA侧发多少,接收侧就应该收到多少。这里的PHY配置通常靠MDIO接口读写PHY寄存器实现。如果这一步也通了,那整个FPGA加PHY的数据通路就都验证过了。如果你的板子上是SFP光模块,就用一根光纤把TX和RX短接,或者用光口测试仪做一个外部回环。
上述步骤都通过之后,才到双板对接。双板对接时千万不要又费劲烧一堆逻辑去写发包程序,最简单的是一个板子固定发特定的测试图案,比如连续0x5A交替或者伪随机数,另一个板子接收并计数,配合ILA在线抓取接收数据。如果接收数据里有错,先看ILA抓到的rx_er有没有被拉高,再看rx_dv与rxd的对齐关系;如果rx_er一直是0但数据内容不对,考虑是不是两边的字节序、FCS或者CRC处理标准不同。
在数据打流环节,我还想多提一句"别迷信网络测速软件"。很多人调通了之后会用PC上的iperf或者打流仪灌数据,如果跑了一段时间掉速或者丢包,就不知道如何定位。这时候一定要回到最小系统逐段排查:先确认FPGA到PHY之间的GMII接口有没有反压,也就是FIFO有没有溢出;再确认PHY到对端的协商速率是不是你预期的那一档;最后再查FPGA内部MAC和用户逻辑之间是不是存在数据吞吐瓶颈。很多掉速问题其实是用户侧DDR带宽不够或者FIFO深度不足导致的,这个锅不该SGMII接口来背。
我给你一个我常用的排查顺序表,贴在调试笔记里,顺手就能翻:
| 现象 | 排查步骤 | 常见根因 |
|---|---|---|
| GT参考时钟未锁定 | 检查专用引脚约束、AC耦合 | 参考时钟接入普通IO |
| 完全无Link | resetdone、PHY寄存器配置 | 复位时序不足、模式配错 |
| Link有但数据全错 | 回环测试、ILA抓rxd | 字节序/CRC不一致 |
| 偶发CRC错误 | 查电源纹波、PPM偏差 | 参考时钟精度不足 |
| 速率只有百兆 | 查PHY寄存器自协商结果 | 速率协商配置错误 |
| 长时间运行掉线 | 查温度、电源 | 散热不足/接触不良 |
6. 常见问题速查:把别人踩过的坑变成你的检查清单
最后这部分,我把各种SGMII相关项目里反复出现的问题做一个集中梳理,每一条都是实际遇到过、并且花过不少时间解决的,不是从文档里抄来的。
第一个高频坑:IP核配置成了1000BASE-X模式,但外接的是PHY芯片,然后发现link死活建立不起来。原因前面已经说过,SGMII模式下的自协商帧结构和1000BASE-X是不同的,两种模式不能混着对接。解决方案就是回到IP核配置界面,把模式改成SGMII,重新生成IP。这个问题往往要查一天才能想到,因为两边看起来都"能出波形",但协议层面就是不通。
第二个坑:复位信号只用了芯片手册上的最小脉宽,实际跑起来偶发失败。教训是,复位信号要多打几拍、拉长到足够时间、并且尽量做成按键可控。我遇到过一个问题,板子上电后偶尔能link,偶尔不能,最后发现是gt_reset释放太早,GT收发器的PLL还没来得及完成锁定。这种偶发问题在实验室里最难排查,因为复现率不稳定。所以复位相关的设计,宁可冗余,不要抠门。
第三个坑:ETH PHY芯片的MDIO接口没有正确处理让PHY工作在错误的自协商状态。很多PHY芯片的上电默认状态要依赖硬件引脚配置(strap pin),比如SGMII模式配置、Master/Slave模式、自协商使能等。如果原理图上strap引脚上下拉电阻不对,PHY可能工作在错误模式,外部怎么调都没用。这个属于"看起来是FPGA问题,实际是硬件问题"的典型。调试时建议首先用MDIO把PHY寄存器值读出来确认当前的工作状态,与期望值对比,再决定后面怎么调。
第四个坑:忽略AC耦合电容导致收发数据质量差。SGMII标准要求串行链路上必须串接AC耦合电容,一般取值0.1uF或者0.01uF。如果PCB上忘加了,或者只在一端加了,高速串行信号会因为共模电压不匹配导致误码,而且误码率会随温度和电压波动而改变,很难稳定复现。这个在原理图评审阶段就该盯住。
第五个坑:FPGA引脚约束里漏了DIFF_TERM。7系列GT引脚通常需要设置为差分端接模式,如果约束里没有加DIFF_TERM或者误设成LVDS的普通IO,高速信号质量会受影响。检查XDC约束,确保SGMII的收发差分对都绑到了GT专用的MGT引脚,并且设置了正确电平标准和端接。
第六个坑:速率自适应打开后,用户逻辑时钟没有跟着切换。这个前面时钟部分详细说过,这里再强调一遍。如果你用了IP核的速率自适应功能,而你用户逻辑里的FIFO读写时钟、状态机时钟始终固定在125MHz,一旦PHY协商到百兆,GMII接口的实际速度会降到25MHz,你的逻辑要么采不到数、要么采样错误。稳妥的处理方式是在IP核配置时把速率锁定到1000Mbps,或者认真处理多速率时钟切换。
第七个坑:仿真时一切正常,上板就挂。仿真环境里通常没有真实PHY芯片的模型,IP核的行为仿真模型和真实硅片之间风格差异很大,特别是复位时序、自协商过程这些。别太依赖IP核的仿真结果来推断板上行为,仿真只适合验证用户逻辑的状态机和时序逻辑,链路的最终判定必须以板级实测为准。
为了避免这些坑反复踩,我建议每一位新项目里使用SGMII的同事,都按下面的顺序做一遍:原理图评审重点关注GT参考时钟和PHY strap电阻;拿到板子上电先量所有电源轨和参考时钟频率;加载IBERT验证物理通道;加载IP核example design跑通内部回环;然后才接入自己的用户逻辑。每一步的结果都记录下来,这样到后续真正排查问题时,你手里握着的是一张逐步确认过的"健康地图",任何异常都能快速锁定到具体层级上。
另外我还想强调一下PCB板级设计与FPGA工程的配合。SGMII差分对在PCB上要求100Ω差分阻抗控制,尽量保持短距离走线,如果必须走长线,留意保持等长差分对的匹配性。在FPGA和PHY之间如果串入了连接器或者排线,信号质量会明显下降,出问题时先考虑这一点,有可能误码率就是从这里来的。FPGA工程师和PCB工程师在这个环节要多沟通,这恰恰是很多项目里被忽视的断层。
最后聊两句我自己的习惯
调试SGMII的时候,我自己还有两个小习惯,一个是在工程里留一个统计CRC错误帧或rx_er拉高的计数器,用ILA或者串口随时可以读出来,这样长时间跑稳定性测试时不用一直盯着屏幕看波形。另一个是给GT复位做两个可选触发源,一个是自动上电复位,一个是外部按键手动复位。自动复位用于正常使用,手动复位用于调试排查,反复按几下就能快速定位到底是不是复位时序带来的问题,比重新加载比特流快太多。这些习惯不值什么钱,但是真的能省时间,愿你少熬几个夜。