ARTICLE DETAIL

资讯详情

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

FPGA SFP光口千兆以太网设计实战:从GTX配置到UDP收发

FPGA SFP光口千兆以太网设计实战:从GTX配置到UDP收发 十几年前我第一次在FPGA上调光口拿着示波器在SFP座子上戳了半天发现高速差分信号根本没法用普通探头测后来老老实实去看了XAPP1082的参考设计才算真正把千兆以太网跑起来。这次就把这套经验整理出来从硬件引脚到GTX收发器配置再到MAC核和UDP收发逻辑手把手带你走一遍完整流程。新手照着做就能通老手也可以当个速查手册用。1. 整体设计与技术选型为什么用SFP光口做千兆以太网1.1 项目背景与应用场景先说清楚这个项目是干什么的。简单说就是用FPGA上的SFPSmall Form-factor Pluggable光模块接口实现一个1000Mbps的以太网物理链路跑UDP协议跟电脑或者其他设备通信。这套方案在工业相机采集、软件无线电、高速数据采集、视频传输这些场景里特别常见因为光纤传输距离远、抗干扰能力强而且电气隔离天然就有不用像网线那样担心共地问题和雷击浪涌。适合什么人看呢第一类是刚接触FPGA高速接口的学生或者转行者手里正好有一块带SFP座子的开发板想把它用起来但不知道从哪下手。第二类是做项目需要把FPGA采集到的数据高速传给上位机但没接触过光通信的工程师。第三类是想把官方参考设计XAPP1082吃透用来做二次开发的朋友。需要注意一点这个方案的定位是“把数据从A点搬到B点”而不是完整实现三层交换机。我们用的是UDP协议不是TCP因为UDP实现简单、实时性好、适合流式数据传输。TCP的拥塞控制、重传机制在FPGA里做起来太复杂而且很多时候我们并不需要它。1.2 光口方案vs电口方案选型背后的考量我见过很多人问FPGA上明明有RGMII接口接个PHY芯片加RJ45座子就能跑千兆以太网为什么要绕一圈用SFP光口这里面的门道其实不少。电口方案需要外接PHY芯片比如88E1111、RTL8211芯片本身贵不说Layout要求也高差分对等长、阻抗控制、时钟布线都有讲究。而且电口方案的最大传输距离也就是100米左右铜缆的重量和体积也限制了应用场景。更重要的是如果你用的是Xilinx的FPGA特别是Artix-7、Kintex-7这些中高端型号芯片本身就集成了GTX高速收发器不用白不用直接接光模块能省掉一个PHY芯片的成本。光口方案的优势就很明显了传输距离从100米扩展到几公里甚至几十公里取决于光模块类型多模几百米单模可以到几十公里电气隔离好不存在共地噪声问题特别适合工业环境光纤线缆轻、细、柔韧性好布线方便省掉PHY芯片直接用FPGA的GTX收发器做物理层如果以后要升级到10G甚至25G光口的硬件架构不用变换模块换约束就行当然光口方案也有它的门槛最核心的就是那套GTX收发器的配置包括参考时钟、线速率、8B/10B编码、Comma对齐等等这些概念对新手来说确实有点绕。XAPP1082的价值就在于它把这些配置都已经调好了你只需要照着搭就行。1.3 千兆以太网技术路线GMII、SGMII与1000BASE-X怎么选在FPGA里实现千兆以太网有几种不同的物理层方案很多人容易搞混我先梳理一下方案接口类型线速率编码方式典型用途GMII并行接口125MHz×8bit1Gbps无编码直接8bit并行MAC芯片与PHY芯片之间的并行接口RGMII并行接口125MHz×4bit×DDR1Gbps无编码4bit DDR同上引脚减半SGMII串行接口1.25Gbps8B/10BMAC芯片与PHY芯片之间的串行接口1000BASE-X串行接口1.25Gbps8B/10BMAC芯片直接驱动光模块或背板注意看1000BASE-X和SGMII的线速率都是1.25Gbps不是1Gbps因为8B/10B编码付出了20%的带宽开销有效数据率才是1Gbps。区别在于SGMII是为了连接外部PHY芯片设计的MAC端和PHY端之间有自协商和时钟从恢复机制而1000BASE-X是光口直连方案不经过额外PHY直接用串行收发器驱动光模块。在我们的设计里选的是1000BASE-X模式。Xilinx的1G/2.5G Ethernet PCS/PMA or SGMII IP核可以配置成这种模式内部把8B/10B编码、Comma检测、时钟数据恢复CDR这些功能都包进去了。这个IP核就是XAPP1082的核心你可以理解为它把整个物理层拆成了两部分GTX收发器负责高速串行信号的收发PCS层负责编码解码和链路管理。还有一个细节如果你以后想不用光模块直接让两个FPGA通过PCB走线连接背板互联也可以用这个IP跑1000BASE-X或SGMII模式都行。这种应用在ATCA、MicroTCA这些通信板卡标准里很常见所以这套方案的生命力很长不是学完就扔的东西。2. 硬件基础SFP接口引脚与光模块工作原理2.1 SFP座子引脚定义详细说明动手写代码之前先把硬件这块搞明白否则后面很多东西你会看不懂。SFP座子通常是20个引脚2×10排列引脚间距是0.8mm的缩距封装常见的型号有AMP的1367562-1、Molex的74741-0010等等。不同厂家引脚定义基本是标准化的因为SFP MSAMulti-Source Agreement协议就是干这个的。SFP的引脚大致可以分为几类高速差分数据线、低速管理信号、电源地线、以及I2C管理接口。高速信号部分最关键的是一对发送差分线TD和TD-和一对接收差分线RD和RD-它们都是CML电平标准的直接连接到FPGA的GTX收发器。注意差分对的极性和方向都不能接反TD就是发送FPGA到光模块RD就是接收光模块到FPGA这个跟你想的“从FPGA视角看收发”是一致的。低速管理信号主要有这么几个TX_FAULT引脚2光模块发送故障指示低电平有效正常工作时要拉高TX_DISABLE引脚3光模块发送禁用高电平有效接逻辑0就能正常发送LOS引脚8信号丢失指示光模块接收不到光信号时输出高电平可以接到FPGA做链路状态判断MOD_DEF0引脚4模块在位检测光模块插上后默认接地FPGA可以通过检测这个引脚的电平判断光模块是否插入MOD_DEF1引脚5和MOD_DEF2引脚6这两根线其实是SDA和SCL也就是I2C接口用来读取光模块的内部数字诊断信息DDM比如光功率、温度、偏置电流等等。地址是A0h8位地址格式7位地址是0x50我手头的一个SFP座的引脚表大概长这样引脚号名称方向功能说明1VEET-发送部分地2TX_FAULT输出发送故障指示低有效3TX_DISABLE输入发送禁用控制高有效4MOD_DEF0输出模块在位检测5MOD_DEF1(SCL)输入/输出I2C时钟6MOD_DEF2(SDA)输入/输出I2C数据7RATE_SELECT输入速率选择一般不用可悬空8LOS输出接收信号丢失指示高有效9VEER-接收部分地10VEER-接收部分地11VEER-接收部分地12RD-输出接收差分信号负端到FPGA13RD输出接收差分信号正端到FPGA14VEER-接收部分地15VCCR-接收部分电源一般3.3V16VCCT-发送部分电源一般3.3V17VEFT-发送部分地18TD输入发送差分信号正端来自FPGA19TD-输入发送差分信号负端来自FPGA20VEFT-发送部分地记住了电源引脚最好做好滤波VCCR和VCCT各放几个0.1uF的陶瓷电容到地高频特性好的MLCC是首选。如果板子空间允许再加个10uF的钽电容做低频去耦对光模块的稳定性很有帮助。2.2 光模块类型与光纤选择多模还是单模光模块选型这块很多新手容易翻车因为看着参数就头晕。其实只要抓住几个要点就行。波长和距离是关键。多模光模块一般是850nm波长配OM3或者OM4多模光纤传输距离在300米内。单模光模块是1310nm或者1550nm波长配单模光纤传输距离从2公里到几十公里都有。千兆以太网场景下如果只是实验室链接或者换机柜内部多模块就够了便宜而且光纤跳线也好买。如果是跨楼传输或者园区组网那就得上单模。FPGA开发板上做设计一般用的是SFP或者SFP座子兼容两种模块。千兆以太网项目选千兆光模块1000BASE-SX或者1000BASE-LX10G的项目选万兆模块10GBASE-SR或者10GBASE-LR。这里有个常见坑万兆光模块不能直接配千兆线速率用虽然外观一样但内部驱动芯片和光器件的偏置点不一样硬用的话可能出现光功率异常、误码率高的问题。反过来千兆模块插到只支持10G的板子上也点不亮。还有一个注意事项多模光缆一般是橙色或者水绿色的护套单模光缆是黄色的光纤跳线的接口都是LC的SFP模块的接口也是LC。买的时候记得让商家给你配套的光纤跳线两头都是LC的才行。有些老设备是SC接口跟SFP不匹配别买错了。最后说一句DDM诊断功能也就是SFP模块的I2C接口。通过这个接口能读到模块的温度、VCC、偏置电流、发送光功率和接收光功率。调试的时候这个功能特别有用比如链路不通你先通过DDM看接收光功率是多少。如果是-40dBm基本就是光纤没插好或者模块坏了如果接收光功率正常但link还是不上那就是FPGA或者IP核配置的问题了。调试SFP光口DDM信息是一个很好的分水岭。2.3 GTX收发器基础概念参考时钟、线速率、CDR与8B/10B编码光模块直接对接的就是FPGA内部的GTX高速收发器这一步是很多新手卡住的地方。我不打算讲太深但最基本的几个概念必须要懂否则XAPP1082里的配置你看不明白。GTX收发器本质上是模拟电路它的采样时钟不是从外部时钟直接得到的而是从一个参考时钟REFCLK经过内部的PLL倍频得到的。参考时钟一般是125MHz或者156.25MHz125MHz是千兆以太网的标准选择因为乘以10就得到1.25Gbps的线速率8B/10B编码后的速率乘一个固定的分频倍率刚好等于线速率。接收端的工作流程是这样的进来的串行信号先经过CDR时钟数据恢复模块从信号边沿中提取出采样时钟。这个过程依赖于Comma字符。在8B/10B编码中定义了一些特殊的控制字符比如K28.5即0xBC这些字符被用来做字节对齐。GTX收发器会持续在数据流里寻找Comma找到之后就把字节边界对齐到这里然后才能正确解码出数据。Xilinx的PCS/PMA IP核里有个叫做“comma alignment”的配置就是这个作用。关于GTX的复位时序新手几乎都会在这里踩坑。GTX收发器的复位是分层次的从PLL复位到TX复位再到RX复位必须按顺序来。Xilinx提供了一个参考代码 gtwizard_rst.v在Vivado安装目录下能找到或者直接用Transceiver Wizard IP生成时勾选“Include CDR”相关的复位逻辑。XAPP1082里的例子也包含了专门的复位模块我强烈建议新手在开始阶段就把它例化成独立模块不要自己手搓复位时序因为GTX的复位时序有点反直觉——不是所有复位信号同步拉高拉低就行而是要等某些状态标志位如TX_RESETDONE、RX_RESETDONE拉高之后才能解除。另外GTX的TX和RX是独立的TX那边是并行数据通过PISO并转串变成高速串行RX那边是串行进来经过CDR恢复时钟、串转并、8B/10B解码变成并行数据。单看一条链路收发两端各自独立但以太网协议要求收发的时钟是同一个参考时钟否则容易出问题。在XAPP1082里参考时钟是125MHz由板上的晶振产生这个时钟精度要求是±100ppm以内普通的50ppm有源晶振就够用了。3. 核心逻辑拆解XAPP1082架构与IP核配置3.1 XAPP1082参考设计整体架构XAPP1082是Xilinx官方发布的用于SGMII和1000BASE-X应用的参考设计下载链接在Xilinx官网文档区能搜到。它能省你大量时间因为里面已经把GTX收发器的配置、物理层管理、时钟模块都做好了。整个参考设计的层次大概是这样的顶层xapp1082_top下面挂了三个主要模块clk_wiz模块负责把板上的输入时钟可能是125MHz或者200MHz转换成各个模块需要的时钟比如GTX的参考时钟、MAC核接口时钟、用户逻辑时钟tri_mode_ethernet_mac_0Xilinx的Tri-Mode Ethernet MAC核支持10/100/1000Mbps我们可以配置成1000Mbps的GMII接口模式跟PCS/PMA核对接。注意这里的GMII是MAC核和PCS/PMA核之间的内部接口不是对外的。eth_gtx_reset模块负责GTX收发器的复位管理再往下就是这个自研的小IP——gig_ethernet_pcs_pma它其实就是1G/2.5G Ethernet PCS/PMA or SGMII IP核的实例化配成了1000BASE-X模式。这个IP核包含两个部分GTX wrapper和PCS/PMA逻辑。GTX wrapper是Xilinx自动生成的里面例化了GTXE2_CHANNEL原语PCS/PMA逻辑包含8B/10B编解码、Comma检测、时钟修正和链路状态机auto-negotiation功能在1000BASE-X模式下其实是简化处理的不对接标准PHY只是链路同步。数据通路的走向是用户逻辑UDP或者自定义协议→ Tri-Mode Ethernet MAC核 → GMII接口 → PCS/PMA IP核 → GTX高速串行 → SFP模块 → 光纤。如果你看XAPP1082里的原理图还有一个细节MAC核的接收用户接口和发送用户接口用的时钟分别是RXUSRCLK和TXUSRCLK这两个时钟都来自PCS/PMA核的输出频率都是125MHz。也就是说用户逻辑工作在125MHz时钟下每个时钟周期处理8bit数据得到1Gbps的吞吐量。3.2 Tri-Mode Ethernet MAC IP核配置要点Tri-Mode Ethernet MAC IP核就是大家常说的TEMAC它是Xilinx的三速以太网MAC核。虽然名字叫三速支持10/100/1000Mbps在光口方案里我们只关心它的千兆模式。在Vivado里添加这个IP的时候有几个配置项需要特别注意第一是接口模式。MAC核对外可以配置成GMII或者RGMII接口我们跟PCS/PMA核对接选GMII。接口时钟125MHz数据位宽8bit。第二是使能管理接口。MAC核内部有一个MDIO接口用来管理物理层芯片但1000BASE-X模式下PCS/PMA核的MDIO管理通道是连到GTX的所以要让能和PCS/PMA核的MDIO信号对接上。在Vivado的IP配置界面里勾选“Enable Management Interface”把MDIO的输入输出使能信号都引出来。第三是接收端流量控制Flow Control和广播帧过滤这些功能根据你的需求配置。如果只是做UDP传输建议把硬件流控关掉简化逻辑。第四是地址过滤。MAC核可以配置成只接收特定目的MAC地址的帧也可以配置成混杂模式接收所有帧。这在调试阶段特别有用因为有时候上位机发过来的帧目的MAC不是你的板卡地址但你想看看到底收到没有。把配置文件里默认的MAC地址改成你板卡的地址如果忘了改收到的帧目的MAC匹配不上MAC核会把这些帧丢掉然后你就在Wireshark里看到数据发出来了但FPGA这边毛都没收到。在XAPP1082的参考代码里地址过滤默认是关闭的所有收到的帧都会送到用户逻辑。可以把这当做一个调试选项先开放接收全部帧确认链路没问题之后再根据需要过滤。3.3 时钟架构与复位逻辑GTX收发器稳定运行的先决条件GTX收发器要稳定工作时钟和复位这关必须过这是XAPP1082里最核心的两个部分新手卡住十有八九是在这里。先说时钟。GTX收发器需要两类时钟一个是参考时钟GTREFCLK另一个是用户时钟TXUSRCLK/RXUSRCLK。参考时钟从板上的时钟输入引脚送进来经过IBUFDS_GTE2原语这是GTX的专用时钟缓冲器之后直接接到GTX的参考时钟引脚。这里有个规矩参考时钟的引脚位置不是随便分配的必须是FPGA的专用时钟引脚而且跟你使用的GTX通道要满足一定的象限关系。在Vivado里如果你用Transceiver Wizard配置GTX它会帮你检查这个关系如果不对会报错到时候看错误信息改引脚约束就行。用户时钟是GTX内部产生的。TXUSRCLK由GTX的TXOUTCLK分频得到RX路径也一样。为了方便XAPP1082里直接用GTX的TXOUTCLK作为TXUSRCLK频率是125MHz数据位宽8bit然后RXUSRCLK直接用RXOUTCLK。这样做的好处是接口时序简单都是同源时钟域。再说复位。GTX的复位有个参考代码叫gtwizard_rst.v可以从Vivado安装目录下的.../data/ip/xilinx/transceiver_ug476/找到。这个模块主要做两件事第一个是PLL复位和锁定检测第二个是TX和RX路径复位和复位完成检测。核心套路是这样的系统上电后先把PLL复位等PLL锁定gt_rxresetdone和gt_txresetdone状态位变高之后再释放TX和RX的复位。TX的复位释放之后要等TX的复位完成信号tx_resetdone置位RX的复位还要等CDR的复位完成。这个顺序不能乱否则GTX会处在一种半死不活的亚稳态状态看起来好像没有明显故障但实际链路不同步。我还遇到过这种情况明明复位时序看起来没问题GTX的复位完成信号也等了但MAC核就是不link up。后来发现是PCS/PMA核的内部复位问题。因为PCS/PMA核在GTX复位期间必须保持复位等GTX完成之后才能释放。XAPP1082里的复位模块是同时处理这两个核的复位关系的你要是自己写复位逻辑一定要仔细研究参考代码里reset_sync和reset_done之间的逻辑关系。3.4 1000BASE-X链路建立过程与状态寄存器解读链路是怎么建立的这个搞清楚之后排查问题就没那么痛苦了。1000BASE-X的链路建立过程大致是这样的发送端一直在发送/ D code / 编码的空闲序列里面带有Comma字符K28.5接收端在数据流里找Comma找到之后做字节对齐这部分是PCS/PMA核里的CDR和Comma检测模块完成的对齐之后接收端开始从同步状态机SYNC的状态里恢复帧然后进入链路同步状态同步建立之后本来还应该有一个Auto-Negotiation自协商过程交换双方的流控能力、工作模式。1000BASE-X的自协商相对简单因为它不需要像电口那样协商网线线序和速度它只要确认双方都是1000BASE-X模式就好了自协商完成之后链路就是UP状态这时MAC核才能正常收发帧PCS/PMA核的状态寄存器能看到这个过程的各个状态。所以调试的时候不要上来就看用户数据先看看PCS/PMA核的状态输出比如sync_status、link_timer、rx_recclk这些信号的电平。如果sync_status一直为低说明接收端没有找到Comma对齐后面的一切分析都是空谈。还有一个很常见的坑就是误以为“光纤插上了链路有了”。实际上光纤插上了只能说明光路通物理链路还要经过上面那些步骤才能建立。而且自协商在有些跨厂商的设备对接时可能出幺蛾子比如某些交换机的端口模式是强制的1000BASE-X全双工跟你的自协商模式不匹配就会一直起不来链路。解决办法是看PCS/PMA核的配置里有没有“Isolate”和“Unidirectional”之类的选项或者在交换机的端口上把自协商关掉强制成1000M全双工。4. 实例代码与实现步骤从IP核配置到UDP收发4.1 Vivado工程创建与IP核例化流程我们直接讲实操。新建一个Vivado工程目标芯片按你板子上的FPGA型号选我用的是Artix-7系列的XC7A35T但用其他型号差异不大因为IP核配置自己会适配芯片系列。在IP Catalog里搜索并添加以下几个IP1G/2.5G Ethernet PCS/PMA or SGMII有的版本叫“Ethernet 1G/2.5G Base-X PCS/PMA or SGMII”配置成1000BASE-X模式注意选择正确的GT参考时钟一般是125MHz线速率设为1.25GbpsTri-Mode Ethernet MAC配置成GMII接口兼容三速但把最高速度设为1GClocking Wizard把板上输入时钟转成125MHz作为GT参考时钟和用户逻辑时钟具体到IP核参数的详细配置我用表格列一下关键项方便你对着检查配置项推荐值说明PCS/PMA IPPhysical InterfaceSGMII或者1000BASE-X跟设计一致线速率Line Rate1.25Gbps千兆以太网是1.25G不是1GGT参考时钟频率125MHz必须是精确的125MHz±100ppm以内参考时钟源单端或差分依板载晶振用IBUFDS_GTE2转成差分MAC IP接口标准GMII跟PCS/PMA核对接管理接口使能MDIO这样PCS/PMA和MAC核能互相管理MAC地址配置按需配置调试阶段建议先允许混杂模式IP核添加完之后接下来是自动化连接。Xilinx的IP设计里有“Run Connection Automation”功能能自动帮你把MAC核和PCS/PMA核之间的信号接起来包括GMII接口、MDIO、时钟和复位。我建议先用这个功能它能保证接口名匹配然后你再去手动添加用户逻辑。手动连接也没问题但要看仔细GMII_TX_CLK、GMII_TX_EN、GMII_TXD[7:0]这些信号别接漏了。最后把PCS/PMA核的GT引脚和SFP座子对应起来在XDC文件里写引脚约束。这一步不能随便编得查你板子的原理图看SFP的TX/TX-接到FPGA的哪个引脚对应的GTX通道是哪个。通常板子的原理图会标注“SFP_TXP1”“SFP_TXN1”这样的网络名你在原语例化里找到对应的引脚就行。4.2 关键代码GTX收发器例化与时钟连接这部分把GTX收发器的连接代码展示出来。XAPP1082里的GTX wrapper是你最省心的选择因为它把GTXE2_CHANNEL原语的所有参数都配好了你只需要把它当成黑盒来用。我这里给你看的是它的顶层接口代码片段这样你能理解引脚连接。// GTX wrapper例化示例简化 gtx_wrapper #( .WRAPPER_SIM_MODE (FAST), .WRAPPER_SIM_GTXRESET_SPEEDUP (1) ) u_gtx_wrapper ( .gtx_clk_i (refclk_bufg), // 125MHz参考时钟 .gtx_rst_i (gtx_rst), // 复位 .tx_clk_out (tx_clk_out), // 125MHz发送时钟 .rx_clk_out (rx_clk_out), // 125MHz接收时钟 .tx_data_i (gmii_txd_from_mac), // 来自MAC核的并行数据 .tx_en_i (gmii_tx_en_from_mac), .tx_er_i (1b0), .rx_data_o (gmii_rxd_to_mac), // 送到MAC核的并行数据 .rx_en_o (gmii_rx_dv_to_mac), .rx_er_o (gmii_rx_er_to_mac), .reset_done_o (reset_done), .txn_o (sfp_txn), // 发送差分负端到SFP .txp_o (sfp_txp), // 发送差分正端到SFP .rxn_i (sfp_rxn), // 接收差分负端来自SFP .rxp_i (sfp_rxp) // 接收差分正端来自SFP );注意几个细节。tx_data_i和rx_data_o都是8bit的并行数据接口时钟是tx_clk_out和rx_clk_out频率都是125MHz。这两个时钟不需要做BUFG直接用就行因为它们本身就是从GTX的时钟缓冲器出来的低抖动时钟。GTX的复位信号要用前面提到的gtwizard_rst模块生成不要直接拿外部的按键信号给它否则很容易遇到第一次复位后链路起不来的情况。参考时钟的做法是这样的板上的125MHz时钟进来之后先用IBUFDS_GTE2原语转成差分信号然后接给GTX的GTREFCLK。注意IBUFDS_GTE2的输出是两个引脚Q和QB其中Q接GTX主时钟QB接地或者接GTX从时钟具体看你IP核生成的wrapper代码里的例子。IBUFDS_GTE2 #( .CLKCM_CFG (TRUE), .CLKRCV_TRST (TRUE) ) u_ibufds_gte2 ( .O (gtrefclk), .ODIV2 (gtrefclk_div2), .I (refclk_p), .IB (refclk_n) );生成出来的gtrefclk直接给PCS/PMA核的GT_REF_CLK引脚。4.3 简易UDP收发逻辑FPGA和上位机通信的最小实现链路通了之后用户逻辑该怎么封装数据这里我提供一个最简单的UDP发送和接收框架它不做ARP、不做ICMP就光是UDP的裸协议。,再强调一遍这个代码是让你理解数据通路用的不是让你直接商用的。商用最起码要加ARP响应否则上位机的ARP缓存里找不到FPGA板卡的MAC地址数据根本发不到网卡驱动这一层。先看发送部分。你需要构造一个完整的以太网帧目的MAC6字节 源MAC6字节 以太网类型2字节UDP是0x0800 IP头20字节 UDP头8字节 用户数据 FCS4字节由MAC核自动计算。IP头里关键字段版本和头长度固定为0x45服务类型可以是0总长度等于IP头加UDP头加数据长度标识字段可以随便设标志和片偏移为0TTL设为64协议字段是17UDP源IP和目的IP按你的网络环境填头部校验和也是必须算的。UDP头里源端口、目的端口、长度UDP头加数据、校验和IPv4里可以设为0但建议还是算了因为有些设备会丢校验和为0的UDP包。Xilinx的TEMAC核提供了一个简单的发送接口我描述的发送状态机大概是这样的// 发送状态机伪代码 localparam IDLE0, SEND_PREAMBLE1, SEND_MAC2, SEND_IP3, SEND_UDP4, SEND_DATA5, SEND_FCS6;你需要在SEND_MAC状态把48bit的目的MAC和源MAC按顺序发送SEND_IP状态发IP头SEND_UDP状态发UDP头SEND_DATA状态发用户数据。每个状态都是8bit输出使能信号拉高一个时钟周期表示一个字节有效。接收部分更简单MAC核出来的是去掉前导码和FCS的完整以太网帧你只需要在接收接口上判断目的MAC是不是广播地址或者本机地址如果是混杂模式就不用判断然后看以太网类型是不是0x0800再解析IP头里的协议字段和UDP头里的端口号最后取出数据。为了方便调试我建议在用户逻辑里加一个自检回环把接收到的UDP数据原封不动地发回去。这样你在电脑上用网络调试助手发什么就能收到什么链路通了没有一目了然。,顺便说一句用网络调试助手之前记得把电脑的IP设置成和FPGA板卡同一网段比如FPGA设成192.168.1.10电脑的网卡IP就设成192.168.1.100子网掩码255.255.255.0。如果跨网段了ARP那关就过不了你会在Wireshark里看到大量ARP请求但没人响应。4.4 引脚约束与综合布局要点数据和控制逻辑写完之后XDC约束文件是最后一道坎。除了SFP的TXP/TXN/RXP/RXN引脚约束之外还有GTX的参考时钟引脚、复位按键引脚、状态指示LED引脚都需要在XDC里声明。SFP高速差分对在XDC里的写法是这样的set_property PACKAGE_PIN M4 [get_ports sfp_txp] set_property IOSTANDARD LVCMOS33 [get_ports sfp_txp]等等这里我要特别提醒GTX的高速差分引脚不要用普通的IOSTANDARD约束去限制它。正确的做法是只给PACKAGE_PIN约束然后在PCS/PMA核的GTX属性里配置好电平标准和终端电阻因为GTX收发器的电平标准是固定的CML不是从XDC里配置的。如果你在XDC里写IOSTANDARD反而可能把GTX的正常工作搞乱。更规范的做法是在PCS/PMA核的配置界面里有一栏“Select the TX and RX pins”把GTX的TXP/TXN/RXP/RXN手动绑定到指定的FPGA引脚上这个引脚配置会在生成的wrapper代码里体现。你只需要在XDC里给顶层端口加set_property PACKAGE_PIN {pin_name} [get_ports {gt_txp_0}]这样一句以及给对应的GT参考时钟引脚加PACKAGE_PIN约束。还有一个容易忽视的GTX的复位信号和状态LED引脚它们的IOSTANDARD要看板子设计可能是LVCMOS33、LVCMOS18或者LVCMOS15这个别照抄别人的一定要看你板子的原理图。综合布局之后跑Implementation之前可以做一个IO规划检查确认引脚冲突的话会报错。跑完Implementation之后用Vivado的Report Utilization看下GTX资源占用确认GTXE2_CHANNEL被正确实例化而不是被优化掉了。还有一个常用技巧在Vivado的“Open Implemented Design → Schematic”里搜一下你的GTX模块能直观看到数据通路的连接是否跟你预期一致。5. 上板调试与常见问题排查5.1 光模块与光纤链路自检流程代码烧到板子上之后第一步不是去ping而是用一套有顺序的排查流程能帮你快速定位到是硬件问题、光路问题还是逻辑问题。第一步检查光模块供电和寄存器的DDM信息。用I2C读取光模块的温度、供电电压、发送光功率。如果读不到要么是SFP座子虚焊要么是I2C地址搞错了。常见的SFP是地址A0h但有些模块会在A2h寄存器组里才有DDM数据7位地址分别是0x50和0x51要注意别搞混。第二步光纤回环测试。拿一根光纤跳线把光模块的TX和RX直接短接也就是光纤的A端插到TXB端插到RX。这种情况下FPGA发出去的光信号立刻被自己的接收端收到。如果设计正确PCS/PMA核的sync_status会变成高电平link_timer开始计时然后链路up。注意光纤回环测试不能用一根跳线自己插自己要分成两根或者用回环适配器因为一根单芯光纤只能单向传。第三步DDM读接收光功率。回环状态下接收光功率应该在-5dBm左右具体看模块的指标。如果读到的接收光功率比发送光功率低10个dB以上先怀疑光纤跳线质量或者连接器脏了用光纤清洁笔擦一下。第四步如果回环测试能up但对接交换机或网卡不能up那问题多半出在自协商或者速率匹配上。试试把交换机的端口强制成1000M全双工看能不能起来。有些交换机的自适应能力差FPGA这边的自协商老是失败这时候强制模式是最后的办法。我调试时习惯让板子上的LED指示link状态把PCS/PMA核的sync_status引到LED上方便肉眼判断。再配合ILA核抓MAC核的接收信号比如GMII_RX_DV的波形能很清楚看到链路起来后是否真的有数据帧进来。5.2 常见问题速查表与处理方案这里把我在各种项目里以及和同行交流时遇到的高频问题整理成一张速查表强烈建议收藏。问题现象可能原因解决方案link一直up不起来sync_status为低光纤未正确对接光模块损坏GTX参考时钟没有接对先用光纤回环测试排查光路检查GT_REF_CLK引脚和频率link能up但收不到/发不出数据MAC核地址过滤配置不当帧格式错误UDP校验和不对配置混杂模式先测试用Wireshark抓包对比帧结构数据偶发丢帧CRC错误GTX复位时序不对时钟抖动过大光模块性能下降检查gtwizard_rst模块复位时序用DDM看光功率是否在正常范围第一次上电正常复位后link起不来GTX复位没有等CDR完成PCS/PMA核复位和GTX复位冲突严格按XAPP1082的复位模块做复位释放必须等tx/rx_resetdone只发不收或者只收不发TX/RX差分对接反SFP座的RX和TX搞混检查原理图网络名确保光模块的TX接到FPGA的RX端IP核对端设备自协商失败速率不匹配对方端口配置了强制模式把对端端口改为自适应或强制1000M全双工GTX参考时钟报错引脚约束错误使用非专用时钟引脚查FPGA的GTX参考时钟引脚表用IBUFDS_GTE2原语板上同时有多个GTX参考时钟互相干扰共用参考时钟源PCB布局走线串扰尽量用独立参考时钟检查时钟树的分配还有一个特别隐蔽的问题光模块的TX_DISABLE引脚悬空了。SFP模块的TX_DISABLE是内部上拉的悬空等于逻辑高电平等于把发送关掉了。我见过好几个人在这上面卡了一晚上发光功率总为0最后发现是SFP座子上的TX_DISABLE引脚没接下拉电阻。正确做法是把这个引脚直接接地或者在板子上留个0欧电阻方便断开。5.3 调试心得从ILA波形到上位机联调ILAIntegrated Logic Analyzer是调试FPGA高速接口的神器。我在调千兆以太网时的习惯是抓如下几个信号第一个是PCS/PMA核的状态输出信号包括reset_done、sync_status、link_timer还有rx_byte_is_aligned。这几个信号能判断链路底层是否同步。第二个是MAC核的GMII接口信号包括GMII_RX_CLK、GMII_RX_DV、GMII_RXD。这里能看到完整的以太网帧进来的时候DV信号会拉高一整段RXD上有前导码、MAC地址、IP头、UDP头、数据。第三个是用户逻辑里的状态机当前状态值。很多问题其实是状态机写错了比如SEND_IP状态里长度字段算错了或者IP头校验和写反了字节序这些用ILA一眼就能看出来。用ILA触发条件很重要比如你想抓链路握手那一瞬间的波形触发条件就设成sync_status从0变1。想抓数据帧触发条件就设GMII_RX_DV拉高这种有明确边沿的信号ILA抓起来非常准。跟我做上位机联调时还有个小技巧先在电脑上用Wireshark抓包看FPGA发上来的帧格式对不对。比如目的MAC对不对、IP头校验和算得对不对、UDP校验和填了没有。Wireshark对格式错误的帧有明显的提示比如“TCP checksum offload”或者“IP checksum incorrect”见到这些提示就好排查了。反过来如果FPGA收不到电脑发的数据先在Wireshark里看电脑是不是一直在发ARP请求如果是那就是ARP响应逻辑没做要回到UDP逻辑部分补一个ARP响应的状态机。ARP响应其实不复杂核心就是收到一个ARP请求包解析出对方的IP和MAC然后回一个ARP应答告诉对方“这个IP对应的MAC是什么”。因为在TCP/IP协议栈里上层软件比如网络调试助手发UDP包给一个IP之前系统会先查ARP缓存如果没有记录就会发ARP请求询问这个IP的MAC地址。没有ARP响应你的板子在局域网上就是一个“不存在”的节点。这也是为什么很多新手拿着UDP代码去ping板卡总是ping不通的原因——不是UDP没发出去是根本到不了UDP那一步。6. 经验总结与扩展建议6.1 从千兆到万兆这套方案的扩展路径如果你已经跑通了千兆以太网光口方案那恭喜你FPGA高速接口这条路你已经进了门。下一步可以考虑往两个方向扩展。第一个方向是速率升级。把PCS/PMA核从1G模式改成10G模式对应的IP核是10G/25G High Speed Ethernet PCS/PMA or RS-FECGTY收发器线速率从1.25Gbps变成10.3125Gbps。参考时钟可以从125MHz变成156.25MHz。架构上10G方案需要用64bit的数据位宽时钟变成了156.25MHz用户逻辑整体从125MHz换到156.25MHz时钟域状态机的时序要求要高很多。但好消息是你在千兆项目里学到的GTX复位管理、PCS状态机、MAC核管理、ILA调试方法这些底层思路是完全相通的。第二个方向是通信协议升级。把裸UDP升级成带重传机制的可靠UDP或者干脆移植轻量级的TCP/IP协议栈比如lwIP到FPGA上。这块的工作量大一些但如果应用场景有线速要求可以考虑用CPU软核配合DMA来做协议栈FPGA只负责高速数据通路和DMA搬运协议处理交给CPU去跑。xilinx的Zynq系列就是这么干的PS端跑Linux或者裸机协议栈PL端做高速数据通路两边用AXI-DMA对接。6.2 个人实操中的关键体会最后说几句实在话。这套方案虽然叫“新手必看”但真正调通的过程中我踩过的坑比想象中多得多挑几个印象最深的说说。第一个体会是GTX的设计和调试不能用“先跑通再说”的心态一定要按层次来。底层的GTX和PCS/PMA没调通之前别急着往上传MAC核和UDP逻辑。我见过有的同学一口气把所有模块都例化上去最后出问题都不知道是GTX的问题还是MAC的问题调试时间成倍增加。健康的节奏是先配GTX用回环测试确认串行链路通再挂PCS/PMA确认sync_status和link状态正常再挂MAC核用ILA确认帧能被正确转发最后才加自己的UDP逻辑。第二个体会是光模块和光纤的质量永远值得检查一遍。有一次我调了两天所有寄存器都是正常的、波形也都对后来发现是那根光纤跳线有一芯衰减太大。换了根光纤一切问题都消失了。所以调不通的时候先拿光功率计或者DDM读一下接收光功率这个数据在几分钟内就能告诉你是不是硬件层面出了问题省下后面排查逻辑的大把时间。第三个体会是调试工具的使用决定了你效率的上限。ILA的触发条件设置、采样深度配置以及Wireshark抓包分析这三个工具用熟了基本能覆盖大部分问题。平时多花点时间把ILA的触发、条件捕获和查看窗口这些功能搞清楚比上来就堆代码要划算得多。真正做高速接口调试的时候“看到波形”比“猜原因”靠谱一万倍。6.3 最后的建议这篇文章覆盖了从SFP引脚定义到GTX配置再到UDP收发的完整流程但篇幅再长也不可能覆盖所有细节。我的建议是有问题首选查XAPP1082的原始应用笔记以及Xilinx的PG0471G/2.5G Ethernet PCS/PMA或SGMII IP产品指南和UG4767 Series FPGAs Transceivers Wizard用户指南。这三份文档我到现在还在查每次都有新收获。对着数据手册比对波形和寄存器也是工程师的基本功。动手是最好的学习方式。找一块带SFP座子的开发板按本文的步骤搭工程、跑回环、抓波形真正把这条路走通一次你在FPGA高速接口领域就算真正入门了。
返回列表