ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FPGA SFP千兆以太网实战:基于XAPP1082的从零调试与避坑指南

FPGA SFP千兆以太网实战:基于XAPP1082的从零调试与避坑指南 1. 为什么SFP光口是FPGA以太网开发的第一道坎很多刚接触FPGA的朋友在板子上跑通了流水灯、数码管甚至写了个UART收发就觉得自己已经入门了。结果一拿到带SFP光口的板子打开Vivado面对一堆GT、GTH、GTY收发器原语和时钟约束瞬间就懵了。我当初也是这样手里攥着一块黑金AX7系列板子盯着那两个SFP笼子看了整整两天不知道从哪下手。SFP光口实现千兆以太网传输本质上要解决三个层面的问题物理层的光电转换与高速串行收发、数据链路层的8b/10b编解码与帧同步、用户逻辑层的MAC帧收发与流控。这三个层面任何一环出问题现象都是链路不通或者丢包严重而FPGA开发最难受的就是——你没法像软件那样打个断点看看变量只能靠ILA抓波形一点点猜。XAPP1082这份文档之所以经典是因为它把Xilinx 7系列FPGA上用1G/2.5G Ethernet PCS/PMA IP核实现SFP千兆以太网的完整流程讲透了。但文档毕竟是文档很多文档里不会写、但你不做就通不了的细节只有真正在板子上跑过一遍才知道。这篇内容就是把我从零跑通SFP千兆以太网的全过程拆开包括IP核配置、时钟方案、约束文件、上板调试以及我踩过的那些坑。适合谁看如果你已经会基本的Vivado操作写过简单的Verilog但没碰过高速收发器那这篇就是给你准备的。如果你已经跑通过也可以看看我在调试环节总结的排查链路说不定能帮你省下几个通宵。2. 动手之前SFP链路里那些绕不开的基础概念2.1 SFP光口到底在做什么SFP是Small Form-factor Pluggable的缩写中文叫小型可插拔光模块。你可以把它理解成一个翻译官FPGA内部处理的是并行数字信号而光纤上跑的是高速串行光信号SFP模块负责把电信号转成光信号发出去同时把收到的光信号转回电信号。在千兆以太网场景下SFP模块的工作速率是1.25 Gbps注意不是1 Gbps因为8b/10b编码会带来25%的开销1.25 Gbps × 8/10 1 Gbps 有效数据速率。这个1.25 Gbps的串行信号通过板上的差分走线连接到FPGA的GT收发器引脚由GT收发器完成串并转换。这里有个容易混淆的点SFP模块分光模块和电模块两种。光模块插光纤电模块插网线也就是常说的电口SFP。两者在FPGA侧的接口完全一样都是差分对加几个低速控制信号。所以你在实验室用光模块跑通了换成电模块接普通网线也一样能通调试阶段用电模块反而更方便因为不需要配对端的光模块和光纤。2.2 8b/10b编码为什么必须要有很多新手会问为什么不能直接把8位数据发出去非要编成10位这不是白白浪费25%的带宽吗原因在于直流平衡和时钟恢复。高速串行链路上没有独立的时钟线接收端要从数据流本身恢复出时钟。如果数据里长时间出现连续的0或连续的1接收端的CDRClock Data Recovery电路就会找不到北时钟漂移导致误码。8b/10b编码保证任意5个连续bit里至少有2个1和2个0这样信号跳变足够频繁CDR就能稳定工作。同时编码后的数据长期来看0和1的数量基本相等直流分量接近零交流耦合电容才能正常工作。Xilinx的1G/2.5G Ethernet PCS/PMA IP核内部已经集成了8b/10b编解码器你不需要自己写。但理解这个原理很重要因为调试时如果看到链路不稳定很可能就是编码器配置或者收发器均衡参数的问题。2.3 GMII、RGMII、SGMII这几个接口别搞混刚接触的时候我被这几个缩写搞得头大这里用一句话说清楚接口类型位宽时钟用途GMII8位125 MHzMAC与PHY之间的标准并行接口RGMII4位125 MHz DDRGMII的简化版引脚少一半SGMII1位串行625 MHz串行版GMII走高速差分线1000BASE-X1位串行1.25 Gbps光纤上的原始千兆以太网SFP光口用的是1000BASE-X也就是1.25 Gbps串行。而FPGA内部的MAC核通常输出GMII接口。所以PCS/PMA IP核的作用就是做GMII ↔ 1000BASE-X的转换中间包含8b/10b编解码、弹性缓冲、时钟校正等模块。XAPP1082的核心思路就是用1G/2.5G Ethernet PCS/PMA IP核把GMII转成1000BASE-X直接驱动SFP的差分对。这样你就不需要外挂PHY芯片FPGA直接和SFP模块对话。3. Vivado工程搭建从IP核配置到引脚约束3.1 IP核选型与关键参数打开Vivado在IP Catalog里搜索1G/2.5G Ethernet PCS/PMA选那个带or SGMII的版本。双击打开配置界面几个关键参数必须设对Standard选择选1000BASE-X而不是SGMII。这两个的区别是SGMII带自动协商1000BASE-X是纯光纤模式。如果你用的是SFP光模块选1000BASE-X如果用电口SFP接交换机有些交换机要求SGMII协商那就选SGMII。我建议先用1000BASE-X因为逻辑简单不涉及协商状态机。Physical Interface选Device Specific Transceiver这样IP核会直接调用你FPGA里的GT收发器而不是走SelectIO。Core Configuration勾选Include Shared Logic in core还是in example design如果你的工程里只有这一个IP核用GT选in core省事如果多个IP核共享GT选in example design然后手动例化shared logic。新手建议选in core。Clock Configuration这里是最容易出错的地方。IP核需要几个时钟clk_p125 MHzGMII接口的时钟clk_gtGT收发器的参考时钟取决于你的板子晶振clk_ref200 MHz或125 MHz用于IDELAYCTRL以我用的黑金AX7为例板子上给GT的参考时钟是125 MHz差分晶振。所以clk_gt的频率要设成125 MHz然后在约束文件里把它绑定到正确的引脚。3.2 时钟方案一个容易翻车的地方SFP千兆以太网对时钟的要求非常苛刻。GMII接口的125 MHz时钟必须和收发器恢复出来的时钟同源否则弹性缓冲会溢出或下溢。IP核内部有一个弹性缓冲Elastic Buffer它的作用是吸收发送时钟和接收时钟之间的微小频差。但这个缓冲深度有限通常几十个字节如果两端时钟频差太大超过±100 ppm缓冲就会周期性溢出表现为链路时通时断。所以你的125 MHz参考时钟精度很关键。普通晶振精度大概±50 ppm勉强够用如果有条件用±20 ppm的温补晶振更稳。我一开始用板载的普通晶振链路跑几分钟就断一次换了高精度晶振后连续跑24小时没出过问题。另外Vivado的Clock Wizard生成的125 MHz时钟如果输入是100 MHz会有分数分频jitter比较大。建议直接用板上的125 MHz晶振经过BUFG驱动不要用MMCM从其他频率分频。3.3 约束文件怎么写才不出错约束文件是新手最容易忽略、也最容易出问题的地方。XAPP1082的example design里有一份参考约束但直接抄往往不通因为引脚定义和你的板子不一样。首先GT收发器的引脚约束必须和原理图完全一致。以我的板子为例# GT参考时钟 set_property PACKAGE_PIN F6 [get_ports gt_refclk_p] set_property IOSTANDARD LVDS [get_ports gt_refclk_p] # SFP发送差分对 set_property PACKAGE_PIN D4 [get_ports sfp_txp] set_property PACKAGE_PIN D3 [get_ports sfp_txn] # SFP接收差分对 set_property PACKAGE_PIN C4 [get_ports sfp_rxp] set_property PACKAGE_PIN C3 [get_ports sfp_rxn]这些引脚号必须查你板子的原理图不能照抄。我见过有人直接抄了example design的引脚结果综合报错说引脚不存在折腾半天才发现板子型号不对。其次时钟约束要写清楚create_clock -period 8.000 -name gt_refclk [get_ports gt_refclk_p] create_clock -period 8.000 -name clk_125m [get_ports clk_125m_p]8 ns周期对应125 MHz。如果你用的是200 MHz参考时钟周期就是5 ns。还有一个隐藏的坑SFP模块的TX_DISABLE和TX_FAULT信号。很多板子把这两个信号接到了FPGA的普通IO上如果你不驱动它们SFP模块可能处于关闭状态。TX_DISABLE低电平有效所以要把它拉低TX_FAULT是输入可以不管或者接到LED上做指示。assign sfp_tx_disable 1b0; // 使能SFP发送这个细节XAPP1082里提了一句但很容易被忽略。我当初就是忘了拉低TX_DISABLEILA抓波形发现GT有发送数据但光模块就是不出光查了半天才想起来。4. 用户逻辑设计从MAC帧到数据回环4.1 先跑通回环再谈协议IP核配置好、约束写对之后不要急着写复杂的MAC控制器。第一步应该是跑通回环测试把接收到的数据直接发回去看看链路能不能通。具体做法是在IP核的example design基础上改把rx_data直接接到tx_datarx_valid接到tx_valid。这样外部发什么FPGA就回什么。用两台PC通过SFP电模块对接一台ping另一台如果能ping通说明物理层和链路层都通了。这个回环测试的价值在于它把问题范围缩小到了IP核配置时钟约束这三件事上。如果回环不通你不需要怀疑MAC逻辑只需要查这三样。我当初回环跑了整整一天才通最后发现是GT参考时钟的引脚约束写错了导致收发器根本没工作。4.2 GMII接口的时序细节回环通了之后就可以接自己的MAC逻辑了。GMII接口的时序有几个细节要注意发送方向gmii_tx_clk是IP核输出的125 MHz时钟你的MAC逻辑要用这个时钟的上升沿输出gmii_txd和gmii_tx_en。注意gmii_tx_clk是从IP核出来的不是你自己生成的必须用它来同步发送数据。接收方向gmii_rx_clk是从接收数据恢复出来的时钟和gmii_tx_clk同频但可能不同相。你的接收逻辑要用gmii_rx_clk采样gmii_rxd和gmii_rx_dv。这里有个经典问题跨时钟域。发送用gmii_tx_clk接收用gmii_rx_clk如果你要在收发之间传递信息比如流控必须做跨时钟域处理。简单的方法是加一级FIFO用异步FIFO把接收数据搬到发送时钟域。4.3 一个极简MAC发送模块的写法下面这段代码是我实际用的GMII发送模块功能是把FIFO里的数据打成以太网帧发出去module mac_tx ( input wire clk_125m, input wire rst_n, input wire fifo_empty, input wire [7:0] fifo_dout, output wire fifo_rd_en, output reg [7:0] gmii_txd, output reg gmii_tx_en ); // 前导码 SFD reg [7:0] preamble [0:7]; initial begin preamble[0] 8h55; preamble[1] 8h55; preamble[2] 8h55; preamble[3] 8h55; preamble[4] 8h55; preamble[5] 8h55; preamble[6] 8h55; preamble[7] 8hD5; // SFD end reg [3:0] state; reg [2:0] pre_cnt; reg [10:0] frame_len; reg [10:0] byte_cnt; localparam IDLE 4d0; localparam PRE 4d1; localparam DATA 4d2; localparam DONE 4d3; always (posedge clk_125m or negedge rst_n) begin if (!rst_n) begin state IDLE; gmii_tx_en 1b0; gmii_txd 8h00; pre_cnt 3d0; byte_cnt 11d0; end else begin case (state) IDLE: begin gmii_tx_en 1b0; if (!fifo_empty) begin state PRE; pre_cnt 3d0; end end PRE: begin gmii_tx_en 1b1; gmii_txd preamble[pre_cnt]; if (pre_cnt 3d7) begin state DATA; byte_cnt 11d0; end else begin pre_cnt pre_cnt 1b1; end end DATA: begin gmii_tx_en 1b1; gmii_txd fifo_dout; if (byte_cnt frame_len - 1) begin state DONE; end else begin byte_cnt byte_cnt 1b1; end end DONE: begin gmii_tx_en 1b0; state IDLE; end endcase end end assign fifo_rd_en (state DATA); endmodule这段代码的核心逻辑是检测到FIFO非空后先发7个0x55前导码加1个0xD5 SFD然后连续发送数据字节最后拉低gmii_tx_en表示帧结束。实际使用中还需要加CRC校验和帧间隙IFG但作为入门示例这个框架已经能跑通最基本的UDP包发送了。4.4 接收方向的帧对齐接收比发送麻烦一点因为你要从连续的字节流里找到帧的起始位置。标准做法是状态机搜索SFD持续监测gmii_rxd当连续收到7个0x55后跟一个0xD5时认为帧开始然后开始计数接收后续字节。这里有个坑前导码可能被弹性缓冲吃掉一部分。因为弹性缓冲会插入或删除空闲字符来调整时钟频差有时候你收到的帧前面只有5个0x55而不是7个。所以状态机不能死等7个0x55应该用收到0xD5就认为帧开始的策略前面的0x55数量不固定。我在调试时用ILA抓过接收波形发现前导码数量在5到7之间跳变这就是弹性缓冲在工作。如果你的状态机写死了等7个0x55就会出现偶尔丢帧的现象而且很难查。5. 上板调试链路不通时的排查链路5.1 先看GT有没有起来链路不通第一步不是查MAC逻辑而是确认GT收发器有没有正常工作。在Vivado的Hardware Manager里找到你的GT通道看几个关键状态gt_powergood必须为1表示GT供电正常gt_pll_lock必须为1表示PLL锁定gt_rx_cdr_lock接收端CDR锁定有光信号时应该为1gt_tx_reset_done和gt_rx_reset_done复位完成如果gt_pll_lock为0说明参考时钟有问题。检查晶振有没有起振、引脚约束对不对、参考时钟频率设置是否正确。我遇到过一次gt_pll_lock死活不锁最后发现是IP核里参考时钟频率设成了125 MHz但板子上实际是200 MHz晶振。如果gt_rx_cdr_lock为0说明接收端没有收到有效信号。可能的原因光纤没插好、对端没发数据、SFP模块没使能TX_DISABLE没拉低、收发差分对接反了。差分对接反是个隐蔽的坑TX和RX如果画反了现象就是CDR永远不锁但你看原理图又觉得没问题。这时候可以试着在约束里把P和N对调一下如果通了就是画反了。5.2 ILA抓波形的正确姿势GT起来之后如果链路还是不通就要用ILA抓GMII接口的波形了。插入ILA核抓gmii_tx_clk、gmii_txd、gmii_tx_en、gmii_rx_clk、gmii_rxd、gmii_rx_dv这几组信号。触发条件设成gmii_rx_dv上升沿这样能抓到接收帧的起始。正常的接收波形应该是gmii_rx_dv拉高后gmii_rxd依次出现0x55、0x55...0xD5然后是目标MAC地址、源MAC地址、类型字段、数据、CRC。如果gmii_rx_dv一直是0说明IP核没收到有效帧。回到上一步查CDR锁定。如果gmii_rx_dv有跳变但数据全是乱码可能是8b/10b解码错误检查收发器均衡参数。ILA的采样深度要设够至少抓1024个采样点因为一个最小以太网帧也有64字节加上前导码和IFG需要几百个时钟周期。采样深度不够的话你只能看到帧头看不到帧尾。5.3 弹性缓冲溢出怎么判断弹性缓冲溢出的现象是链路能通但跑一段时间后丢包然后自动恢复周期性出现。判断方法是抓IP核的rx_elastic_buffer_overflow和rx_elastic_buffer_underflow信号如果这两个信号有脉冲就是频差太大了。解决办法有两个一是换更高精度的参考时钟晶振二是在IP核配置里把弹性缓冲深度设大一点如果有这个选项。Xilinx的IP核通常不让你改缓冲深度所以只能从时钟精度入手。我实测下来普通晶振跑千兆以太网平均几小时会出现一次弹性缓冲溢出表现为ping测试偶尔丢一个包。对于一般应用够用了但如果要做视频流传输这种对丢包敏感的场景必须用高精度晶振。5.4 收发差分对极性反了的补救前面提到差分对可能画反。如果你怀疑是这个问题不用改板子在约束文件里把P和N对调就行# 原来 set_property PACKAGE_PIN D4 [get_ports sfp_txp] set_property PACKAGE_PIN D3 [get_ports sfp_txn] # 对调后 set_property PACKAGE_PIN D3 [get_ports sfp_txp] set_property PACKAGE_PIN D4 [get_ports sfp_txn]GT收发器内部有极性反转功能所以约束对调后重新生成比特流功能就正常了。这个技巧在调试阶段非常实用能帮你快速排除是不是画反了这个怀疑。6. 从回环到实战UDP数据回传的完整实现6.1 为什么选UDP而不是TCP在FPGA上实现完整的TCP协议栈是件很痛苦的事状态机复杂、资源占用大、调试困难。对于大多数FPGA以太网应用UDP就够了。UDP无连接、无重传、头部简单只有8字节非常适合FPGA这种发出去就不管的场景。当然UDP不保证可靠传输但你可以自己在应用层加简单的应答机制。比如PC发一个请求包FPGA回一个数据包PC收到后发下一个请求。这样虽然效率低一点但逻辑简单不容易出错。6.2 UDP包格式与校验和计算一个完整的UDP/IP包结构如下层级字段长度以太网头目标MAC 源MAC 类型14字节IP头版本 长度 ID 标志 TTL 协议 校验和 源IP 目标IP20字节UDP头源端口 目标端口 长度 校验和8字节数据用户数据可变IP头的校验和计算是新手容易出错的地方。算法是把IP头按16位分组逐组相加如果有进位就回卷加到低位最后取反。Verilog实现如下function [15:0] ip_checksum; input [159:0] header; // 20字节IP头 reg [31:0] sum; integer i; begin sum 0; for (i 0; i 10; i i 1) begin sum sum {16b0, header[i*16 : 16]}; end sum (sum 32hFFFF) (sum 16); sum (sum 32hFFFF) (sum 16); ip_checksum ~sum[15:0]; end endfunctionUDP校验和是可选的在IPv4里如果校验和字段为0表示不校验。为了简化很多FPGA实现直接把UDP校验和设成0PC端也能正常接收。但有些操作系统比如某些Linux发行版会检查UDP校验和所以稳妥起见还是算一下。6.3 一个可用的UDP回传架构我的UDP回传架构是这样的接收路径GMII接收 → 帧解析状态机 → 提取目标MAC和IP → 判断是否是发给FPGA的包 → 提取UDP数据 → 写入接收FIFO用户逻辑从接收FIFO读数据 → 处理比如加1、取反、回传 → 写入发送FIFO发送路径从发送FIFO读数据 → 组装以太网头、IP头、UDP头 → 计算校验和 → GMII发送这个架构的关键是FIFO的深度。如果PC发得快、FPGA处理得慢接收FIFO会溢出。所以FIFO深度要够至少能缓存几个最大帧1500字节。我用的是2048×8的FIFO实测能扛住PC端连续发送。另外发送路径要处理帧间隙IFG。以太网标准要求两个帧之间至少间隔12个字节的时间96个bit时间。如果你的发送状态机发完一帧立刻发下一帧有些交换机会认为这是非法帧而丢弃。所以在DONE状态后要等至少12个时钟周期再回到IDLE。6.4 上板实测ping通之后做什么回环通了、UDP回传也通了之后可以用PC端的网络调试助手发UDP包测试。我常用的测试流程用ping命令测试链路层是否通需要FPGA端能响应ARP或者PC端配静态ARP用网络调试助手发UDP包看FPGA是否回传逐渐加大发送速率观察是否丢包用Wireshark抓包分析帧格式是否正确Wireshark是个好东西能看到FPGA发出来的包长什么样。如果Wireshark显示Malformed Packet说明你的帧格式有问题通常是长度字段或者校验和算错了。我当初调试时Wireshark一直报IP校验和错误查了半天发现是Verilog里16位加法没有处理进位回卷。改完之后就正常了。所以校验和计算一定要仔细这是最容易出错的地方。7. 几个让我熬夜的坑与对应的解法7.1 综合报错GT not available这个错误通常是因为你选的FPGA型号和IP核不匹配。比如你选的是Artix-7但IP核配置成了Kintex-7的GT。解决办法是在IP核配置里把Silicon Revision和Device改成和你实际芯片一致的选项。还有一种可能是GT的参考时钟引脚被其他IP占用了。检查你的Block Design里有没有其他IP也在用同一个GT Quad。如果有需要把shared logic提取出来共用。7.2 比特流生成失败Implement Design变红Implement Design变红通常是因为时序不满足。打开Timing Report看WNSWorst Negative Slack是多少。如果是负数说明有时序违例。SFP千兆以太网工程里最容易违例的是GMII接口的125 MHz路径。因为125 MHz周期只有8 ns如果逻辑级数太多很容易超。解决办法在GMII接口上加一级寄存器打拍把组合逻辑拆成流水线用set_max_delay约束放松非关键路径我当初遇到的是接收状态机的组合逻辑太长从gmii_rxd到状态机输出经过了好几级LUT。后来在状态机输入加了一级寄存器时序就过了。7.3 ILA抓不到波形ILA抓不到波形的原因很多最常见的是采样时钟选错了。ILA的采样时钟必须是被抓信号的同步时钟。如果你抓gmii_rx_clk域的信号采样时钟就要选gmii_rx_clk不能选系统时钟。另一个原因是触发条件设得太苛刻。比如你设了gmii_rx_dv 1 gmii_rxd 8hD5但实际波形里gmii_rx_dv和gmii_rxd的时序关系可能和你想的不一样。建议先用简单的触发条件比如gmii_rx_dv上升沿抓到波形后再分析。还有一种情况是ILA核的时钟域和JTAG时钟域不同步导致上传数据失败。这时候可以降低ILA的采样深度或者换用更小的ILA核。7.4 链路通但丢包严重链路能ping通但丢包严重通常是以下几个原因弹性缓冲溢出前面说过换高精度晶振FIFO溢出加大FIFO深度或者加流控帧间隙不够确保发送状态机在帧之间等待至少12个时钟周期CRC错误检查CRC计算逻辑或者直接用IP核的CRC校验功能我遇到过一次丢包率50%的情况最后发现是发送FIFO的读使能逻辑有问题偶尔会多读一个字节导致帧长度不对。用ILA抓发送波形对比Wireshark的抓包结果才定位到这个问题。8. 工程固化与上电自启动8.1 生成固化文件调试完成后需要把比特流固化到Flash里让板子上电自动加载。Vivado里生成固化文件的步骤打开Hardware Manager连接板子右键FPGA设备选Add Configuration Memory Device选择你板子上的Flash型号常见的是Micron或Winbond的SPI Flash右键选Program Configuration Memory Device选择你的.bin文件不是.bit文件注意.bit文件是JTAG加载用的.bin文件才是固化用的。在Vivado里生成.bin文件的方法是在Settings里勾选Bin File选项或者用write_cfgmem命令转换。8.2 上电自启动的注意事项固化之后板子上电应该自动加载。如果没加载检查几个地方Flash型号选对了没有板子的启动模式跳线是不是设成了SPI Flash启动.bin文件有没有生成正确我遇到过固化后不启动的情况最后发现是Flash型号选错了。板子上实际是W25Q128我选成了W25Q64容量不匹配导致加载失败。所以选Flash型号时一定要查原理图。8.3 固化后SFP链路不工作有时候JTAG加载时链路正常固化后就不通了。这通常是因为复位逻辑的问题。JTAG加载时Vivado会自动复位GT固化后上电GT的复位需要你自己控制。正确的做法是在逻辑里加一个上电复位计数器等GT参考时钟稳定后通常几毫秒再释放GT复位。Xilinx的example design里有这个逻辑直接抄过来就行。reg [19:0] reset_cnt; always (posedge clk_125m) begin if (reset_cnt ! 20hFFFFF) reset_cnt reset_cnt 1b1; end wire gt_reset (reset_cnt ! 20hFFFFF);这个计数器大概数100万个时钟周期对应8毫秒左右足够GT参考时钟稳定了。9. 从XAPP1082延伸出去还能玩什么跑通SFP千兆以太网之后这个平台可以扩展出很多应用。比如视频传输把摄像头数据通过UDP包发到PCPC端用Python或OpenCV接收显示。这个方案比HDMI采集卡便宜而且FPGA端逻辑简单。高速数据采集ADC采样数据通过SFP传到服务器做实时信号处理。千兆带宽对于大多数中低速ADC足够了。多板卡同步用SFP做板间通信实现多块FPGA的同步采集和处理。SFP的延迟比普通IO低而且抗干扰能力强。网络时间同步在FPGA里实现IEEE 1588协议做高精度时间同步。这个对时钟要求更高但原理和千兆以太网是一样的。我目前在做的是把SFP千兆以太网和DDR3缓存结合起来做一个网络数据记录仪PC通过网口发指令FPGA把采集到的数据存到DDR3然后通过网口回传。这个架构在工业数据采集场景很实用。最后分享一个调试小技巧如果你有逻辑分析仪可以把SFP的差分信号接到分析仪上直接看1.25 Gbps的串行波形。虽然分析仪可能解不出8b/10b编码但能看到信号幅度和眼图判断信号完整性。如果没有高端分析仪就用ILA抓并行侧的信号也能定位大部分问题。SFP千兆以太网这个方向入门门槛确实比流水灯高不少但一旦跑通你会发现FPGA的高速接口能力一下子打开了。XAPP1082是个很好的起点但文档里的example design只是能跑要真正用到项目里还需要根据实际需求做很多调整。希望这篇内容能帮你少走一些弯路把更多时间花在应用逻辑上而不是和底层接口死磕。
返回列表