
做FPGA高速接口的活儿光口迟早是要碰的。两块板子之间要传几十米、几百米甚至跨机房的数据铜线方案受距离限制太大SFP光模块加一根光纤基本是标准答案。但很多新手第一次拿到SFP这颗料直接懵了这么多引脚到底是干嘛的光模块要不要驱动芯片FPGA里哪来的以太网MACXilinx早年针对这个场景出过一份官方应用笔记XAPP1082专门讲怎么用Spartan-6的GTP高速收发器连接SFP光模块实现点对点的千兆链路传输配套的RTL工程可以直接拿去跑。虽然这份资料年代有点久但整条链路的思路——从高速收发器到光模块、从8B/10B编码到链路初始化——放到今天的Artix-7、Kintex-7上依然完全通用。这篇文章我会从硬件引脚一路拆到代码仿真和上板调试照着做你也能把这套光口千兆传输跑通。1. 先把概念捋清楚SFP光口到底在传什么1.1 光口千兆以太网的速率魔术千兆以太网大家平时听得多但千兆到底是多少物理速率很多人没细算过。MAC层数据速率是1Gbps但物理层不能把这1Gb裸数据直接扔到光纤上——那会带来两个问题一是直流平衡没法保证连续长串的0或1会导致接收端无法恢复时钟二是没有足够的跳变边沿供时钟数据恢复电路CDR锁定。解决办法就是8B/10B编码每8位数据变成10位符号再发送有效带宽从1G变成1.25G。所以你在Xilinx系列IP里看到的1.25G line rate就是千兆以太网物理层的真实速率。SFP光模块本身没有协议处理能力它只负责把高速串行差分信号转成光信号是一根光纤上的SerDes管道。所有的编码、解码、时钟恢复、链路握手都得靠FPGA内部的高速收发器GTP/GTX以及后来的GTH/GTY来做。理解了这个你就明白为什么FPGA玩光口离不开高速收发器。FPGA的普通IO最多跑几百兆LVDS而SFP光模块的差分接口是CML电平速率动辄上G必须走专用收发器引脚。这也是新手最容易卡住的地方——把LPGA的LVDS引脚直接连到SFP的TD/TD-上结果怎么都不工作因为根本没走对的物理通道。1.2 SFP接口引脚详解20个引脚里真正有用的没几个SFP座子的20个引脚新手一看就觉得头大。其实用得上信号的就那么几组一对发送差分TD/TD-、一对接收差分RD/RD-、四个管理/监控信号、两组3.3V供电。下面这张表把关键引脚的意义列清楚这是我做板卡设计时经常对照的引脚名称方向功能说明2TX_FAULT输出模块→FPGA模块发送端故障指示高有效3TX_DISABLE输入FPGA→模块拉高会关断模块激光器正常工作必须拉低4/5MOD_DEF2/MOD_DEF1I2C光模块的I2C管理总线可读取温度、电压、光功率6MOD_DEF0输出模块在位检测模块插入后接地7RATE_SEL输入速率选择千兆场景一般拉低或悬空8LOS输出模块→FPGA接收光信号丢失告警高电平表示无光12/13RD-/RD输出模块→FPGA接收差分数据对18/19TD/TD-输入FPGA→模块发送差分数据对16/15VccT/VccR电源发送/接收电路3.3V供电这里有几个设计细节直接影响能不能跑通。第一TX_DISABLE这个脚很多新手板子上要么忘了接要么引到FPGA GPIO后上电默认状态是高电平结果光模块激光器一直被关着永远没有光输出。第二LOS信号最好接到FPGA调试时可以用逻辑分析仪观察有没有光比拿眼神盯着光纤判断靠谱得多。第三MOD_DEF0在模块插进去之后会被模块内部拉低到地可以通过这个脚的状态判断模块是不是插好了。还有一个真相要提前说SFP光模块的差分输入输出是CML电平而FPGA高速收发器引脚内部自带50欧姆匹配和共模电压设置直接连接即可中间不需要额外的终端电阻但需要串接AC耦合电容一般用0.1uF走差分对时注意电容封装和布局。1.3 光模块选型850nm还是1310nm光模块类型按波长和工作距离分最常见的是千兆SX和千兆LX两种。850nm多模模块配多模光纤OM1/OM2/OM3波长是橙色的适合100米到550米以内的短距离场景模块便宜多模光纤跳线也便宜。1310nm单模模块配单模光纤OS1/OS2波长是无色的能跑10公里甚至更远单模模块和跳线成本都高一些。面这个问题上我踩过明显教训有测试现场拿了一根单模跳线去接850nm的SX模块结果怎么调误码率都压不下去。不是因为模块坏了而是850nm的光在单模纤芯里激发出了高阶模经过长距离传输后色散严重接收端光功率明明在灵敏度范围内但信号质量一塌糊涂。所以选模块之前先确认手上跳线是多模还是单模别混着用。2. XAPP1082参考设计的核心原理Aurora协议与GTX收发器2.1 XAPP1082到底给了你什么XAPP1082是Xilinx官方应用笔记题目就是围绕SFP光模块和高速收发器做点对点千兆通信。它提供的RTL工程里包含了高速收发器配置、链路层协议核、以及配套的码流发生器和错误计数器。说白了这份设计解决的核心问题只有一个让两个FPGA之间通过SFP光口可靠地传数据并且给你一个可以验证链路好坏的办法。这个工程在当年的Spartan-6上是用ISE做的到了Vivado时代你完全可以用同样的思路替换组件用Aurora 8B/10B IP配合GT Wizard再加上自己写的帧发生器/帧检测器效果一模一样。下面我讲的工程搭建流程就是以XAPP1082的设计思想为骨架在Vivado上重新搭一遍的完整步骤。2.2 为什么用Aurora协议而不是直接上以太网MAC这是新手问得最多的问题既然是千兆以太网传输为什么参考设计用的是Aurora而不是正经的Ethernet IP原因在于应用场景不同。XAPP1082设计的是两个FPGA之间的点对点直连传输这是板间互联最典型的场景。Aurora 8B/10B就是Xilinx为这种场景定制的轻量链路层协议它只管初始化通道、维持链路、以流式方式搬运用户数据不涉及MAC地址、IP地址、ARP这些网络概念逻辑资源占用极小延迟也低。而真正的千兆以太网要跟交换机、路由器、电脑网卡互通就必须走完整的以太网协议栈MAC层、PCS/PMA层、自动协商、流控这些Xilinx也有对应的IP1G/2.5G Ethernet PCS/PMA配合三速MAC但复杂度和资源开销完全不同。说白了Aurora像是两台机器之间的专线以太网像是公共网络。如果你的场景是自己板子之间传数据Aurora是最省事的如果你要跟PC网卡直连上网才需要考虑正经以太网协议。刚开始做实验用Aurora把链路打通、把光路走通是最快建立信心的路径之后再换以太网MAC也不迟。2.3 8B/10B编码与链路初始化的工程视角8B/10B编码的道理不复杂工程上你只需要理解三个关键词直流平衡、特殊字符K码、逗号对齐。发射侧编码器把8位数据加一个K码标志位变成10位符号输出。其中K码如K28.5编码为0011111010或1100000101专门用来做字节对齐和链路控制。接收侧GTX收发器的CDR从数据流里恢复出采样时钟后通过搜索K28.5的独特位模式实现字节对齐把串行比特流正确地切成10位符号再解码回8位数据。Aurora协议的通道初始化也是靠K码实现的发送端不断发送初始化序列接收端通过K码识别并确认通道对齐然后进入通道就绪状态。你会在Aurora核的顶层看到channel_up这个信号它由两个lane_up信号组合而成channel_up拉高才说明链路已经建好可以开始传数据了。调试时第一步永远是看这个信号拉没拉高而不是急着看数据对不对。2.4 参考设计的代码结构长什么样XAPP1082工程的顶层例化了几个核心模块GTX/GTP收发器、Aurora链路层核、帧发生器frame generator、帧检测器frame checker、时钟管理模块。数据通路是单向的帧发生器产生递增的32位计数序列打包成Aurora帧发给对端对端的帧检测器解析收到的数据如果和预期计数不一致就把出错计数器加一。这个计数器比错的思路简单而有效是调试串行链路的基本功。帧发生器的核心代码逻辑大概是这样的// 简单的32位递增帧发生器伪代码 always (posedge user_clk) begin if (!channel_up) begin tx_valid 1b0; tx_data 32h0000_0000; end else begin tx_valid 1b1; tx_data tx_data 32h0000_0001; end end帧检测器则在接收侧比对每个收到的数据是否等于本地计数器预期值不等就报错。实际工程里帧发生器会把数据组织成帧结构帧头用特定的K码标记帧尾做CRC校验但底层思想就是上面这段代码的样子。3. 环境准备与工程搭建从零到出码流3.1 硬件清单做这个实验到底需要什么动手之前先把硬件备齐缺一样都跑不通带SFP座子的FPGA开发板注意板上必须有时钟振荡器接到FPGA高速收发器的参考时钟引脚MGTREFCLK这是光口链路工作的前提。部分开发板SFP接口是设计给SGMII用的要确认参考时钟频率是125MHz。两个SFP光模块建议同一型号同批次850nm SX模块配多模跳线是最经济的组合。一根LC-LC双工光纤跳线多模OM3或者OM2都行不宜过长测试阶段一两米足够。两块板子如果只有一块板子那就买一根LC双工回环跳线——注意这种回环线把TX连到了本端RX专门用来做单板自测。另外强烈建议准备一个光功率计。虽然可以用LOS信号判断有没有光但光功率计可以直接读到接收端光功率的绝对值判断光路有没有衰减异常。几十块钱的入门光功率计就够用。3.2 Vivado工程里如何搭出XAPP1082同款设计假如你用的是7系列FPGA在Vivado里从头搭这套工程的步骤大致如下新建工程选好FPGA型号。添加Aurora 8B/10B IP核。这是整套设计的核心配置页面里有几个关键选项需要理解Line Rate填1.25Gbps这正好是千兆以太网的线路速率。GT Refclk填125MHz收发器内部通过锁相环把125MHz倍频到1.25Gbps。通道数量Lanes选1先跑通单通道再考虑多通道捆绑。流控方式选Native Flow Control或No Flow Control测试场景选None最简单。添加**GT Wizard7 Series FPGAs Transceivers Wizard**生成收发器初始化模块按Aurora核的要求设置好环路模式。这里注意Aurora 8B/10B IP内部会例化GT所以配置时只要把参考时钟和线路速率设对GT的PMA参数会由Aurora核自动推导。编写顶层模块例化Aurora核和帧发生器/帧检测器把时钟和复位信号接好。综合、布线、生成比特流。具体到Aurora核的AXI4-Stream用户接口发送侧有s_axi_tx_tdata、s_axi_tx_tvalid、s_axi_tx_tready这几个信号接收侧对应m_axi_rx_tdata、m_axi_rx_tvalid。帧发生器就是往s_axi_tx_tdata上持续送计数数据帧检测器从m_axi_rx_tdata收数据比对。3.3 时钟和复位最容易翻车的基础设施这套设计里有两个时钟域一个是收发器内部的并行时钟user_clk由GT恢复或参考时钟分频产生1.25Gbps线速下单通道user_clk通常是62.5MHz或125MHz另一个是逻辑侧业务时钟帧发生器可以用user_clk直接跑。复位逻辑这块尤其要注意高速收发器对复位时序有严格的要求上电后要先给GTP/GTX的复位信号一段稳定的低电平时间然后释放复位再等收发器的时钟锁定txresetdone/rxresetdone信号拉高最后等Aurora核的channel_up拉高。很多新手把FPGA的全局复位直接接到收发器复位上一复位就把还没有稳定锁定的收发器又打断了链路永远建不起来。正确做法是参考Aurora核复位逻辑文档做一个可重触发的脉冲复位确保收发器有足够时间完成初始化。这里顺便提一句板上的时钟如果用的是普通晶振而不是可编程振荡器频率偏差会导致误码累积。千兆以太网对时钟精度要求一般是±100ppm以内普通晶振够用。但如果你做更高精度的应用就要考虑用压控晶振配合时钟恢复逻辑。3.4 用仿真先验一把写个简单的testbench上板之前强烈建议先仿真。跑通仿真只需要模拟三个东西给参考时钟、给复位、给Aurora核连一个回环。把发送侧的TX数据直接连到自身接收侧的RX输入这是最简单的验证手段。实际仿真中Aurora核不依赖真实光模块只要链路初始化成功你就可以看到帧发生器的数据被帧检测器正确接收错误计数器保持零。这里有个小技巧仿真时设变量把GT的复位时间精确控制好一般上电后至少延迟1ms再释放复位给收发器内部状态机足够时间。如果复位释放太早仿真的channel_up信号只会一直拉不起来跑多久都没用。4. 上板调试全记录从灯不亮到链路稳定4.1 第一轮排查为什么光模块一点动静都没有把比特流下载进FPGA之后第一步不是看数据对不对而是先确认光路活了没。我一般按这个顺序查先看模块的LOS信号。如果LOS为高说明模块没收到光问题在发送端或者光纤上。接着查TX_DISABLE如果这个信号被误置高模块激光器根本不会发光用肉眼可以看出来——SX模块发的是可见的红色光在暗环境下能从LC头侧面看到微弱的红光但别直视。如果看不到光用万用表量一下模块电源引脚有没有3.3V再量TX_DISABLE的电平。然后是参考时钟。用示波器探一下板上的振荡器输出确认频率是否为125MHz幅度是否满足收发器的输入要求。有些开发板上SFP的参考时钟和PCIe或其他接口共用需要跳线选择忘了插跳线是常见坑。还有一个非常典型的坑SFP座子的安装方向。少数座子设计成模块从反面锁进去你插的方向反了模块电极接触不上所有信号都是悬空的。这种情况用万用表量模块电源引脚就能发现。4.2 回环测试三层递进发出问题出在哪一环回环测试是串行链路调试的黄金方法思路就是每回环一层就能排除掉这一层后面的所有问题第一层近端PMA回环。在GT Wizard里把RX回环设置成Near-End PMA Loopback模式信号从FPGA发送链路直接绕回接收链路不发到光模块去。这一层回环通过说明GTX收发器本身、参考时钟、8B/10B编解码逻辑都是好的。第二层远端PMA回环。把对端板卡的回环打开让光信号从本端发出去经过光纤到对端再在对端绕回来原路返回到本端接收口。这一层通过说明光纤和两边的光模块都没问题。第三层应用层回环。不做硬件回环让帧发生器往线上发帧检测器在本端收对端发过来的数据完整性比对通过就说明整条链路彻底通了。实际测试时如果只有一块板子和一个光模块可以用LC双工回环跳线把模块的TX直接绕回本端RX这属于外部的模块级回环能验证光纤和模块接口的连接。无论哪种回环调通了再往下走。4.3 ILA抓信号别盲猜看波形说话判断链路状态最直观的手段就是把关键信号挂到ILA集成逻辑分析仪上。我最常抓的是这几个channel_up、lane_up信号、Aurora核的错误输出hard_err、soft_err、帧检测器的err_cnt计数器、以及用户接口的tvalid/tready时序。正常情况下的波形应当是复位后一小段时间内channel_up从0跳变到1然后保持为高帧检测器的err_cnt一直为0用户接口tvalid和tready持续拉高数据在稳定地流动。如果channel_up一直为0把触发条件设成channel_up下降沿或者一直为0再去和收发器的txresetdone/rxresetdone信号对照。我遇到过一次比较隐蔽的问题rxresetdone在拉高后又瞬间掉下来后来发现是对端板卡根本没上电对端收发器一直处于复位状态本端的RX自然无法完成通道初始化。串行链路是双向的任何一端异常都会导致双方都建不起来链路。如果channel_up已经拉高但err_cnt不断累加说明物理层基本通了问题大概率在信号质量或时钟精度上。这时优先看接收端的误码统计或者把收发器的采样点微调试试。多数情况下是光纤没插紧、跳线污染、或者模块不配套导致的。4.4 常见问题快速定位表调试过程里遇到的问题五花八门把最常见的几种整理成一张速查表调试时对照着排查效率高很多现象可能原因处理办法模块完全不发光TX_DISABLE为高测量并拉低TX_DISABLE发射端有光LOS仍为高光纤接反或对端未上电检查TX/RX是否交叉连接channel_up反复跳变光纤头脏污或损耗过大用光纤清洁笔清洁端面误码但偶发、不成大量电源纹波或模块温漂检查SFP座子旁的滤波电容长时间运行后丢链路时钟源ppm偏差过大换上高精度晶振或压控晶振只剩一块板无法验证缺回环手段用LC双工回环跳线自测5. 踩过的坑和这条路的后续延伸5.1 几个真实的翻车现场2019年在做一个图像采集卡项目时调试SFP接口死活跑不通千兆。所有信号都查了一遍最后发现是SFP座子的引脚28就是那个在位的检测脚被板卡设计当作普通IO接到了FPGA上但PCB上漏画了往模块方向的下拉。模块明明插着FPGA端读到的却一直是在位状态。这种基础性错误在原理图评审阶段最容易被忽略提醒做板的朋友们SFP座子这些看起来无关紧要的检测脚一定要对照座子的datasheet逐一确认电平关系。另一个印象深刻的问题是AC耦合电容选型。收发器和SFP模块之间的交流耦合电容如果不匹配会在高频部分形成额外的谐振点导致眼图闭合。有次用了封装很大的陶瓷电容根本不是高频特性好的型号1.25G的链路跑起来误码率非常高换成了高频特性好的0.1uF 0402封装电容问题立刻消失。高速信号的被动元器件真不是随便焊个电容上去就行的。还有一次是在客户现场做联调两边的板子来自不同团队。结果发现一边用了Aurora协议另一边用的是原厂简单透传模式链路初始化序列对不上channel_up永远起不来。协议理解不一致是板间联调最常见的坑所以在设计开始前就要把链路层协议、加扰方式、流控配置都拉通对齐。5.2 想真正接入以太网怎么改如果你最终的目标是让FPGA的SFP口能直接插到交换机上跟PC网卡互通那Aurora这条路就不够了。你需要换用这两颗IP1G/2.5G Ethernet PCS/PMA or SGMII负责物理编码子层再配一个三速以太网MAC或者自己写一个简单的RGMII转MAC逻辑。配置PCS/PMA IP时要选择1000BASE-X模式该模式就是为光模块直连设计的在GT收发器上跑1.25Gbps内部包含8B/10B编码、自动协商和链路状态机。然后把MAC的GMII接口有时是RGMII接进来就能对外像一个标准千兆网口一样工作。后面接AXI Ethernet Subsystem的话甚至可以上LWIP协议栈跑TCP/IP那就是真正的网络设备了。5.3 从1G到10G原理相通难度翻倍把这套1.25Gbps链路跑通之后你会发现自己已经掌握了高速收发器的核心操作参考时钟配置、CDR与链路初始化、误码定位、回环调试。这套方法论完全适用于10G甚至25G。升到10G之后变化在哪里一是线路速率从1.25G变成10.3125G编码从8B/10B变成64B/66BAurora的版本也从8B/10B变成64B/66B就是Aurora 64B66B IP二是PCB布线要求更苛刻差分对等长控制、阻抗连续性、过孔残桩控制都会直接影响链路能否跑起来三是参考时钟的抖动指标要求更高板上如果还是用普通晶振就不行了需要专门的时钟芯片。我个人在实际项目里做升级时习惯先在老平台上把所有调试方法论沉淀下来再迁移到高速平台。因为误码定位的思路永远是一样的一层层回环一个信号一个信号地排除。5.4 最后分享一个实用习惯每次在板子上调光口或任何高速接口之前花两分钟把光模块和光纤端面用清洁笔擦一遍。这个动作看起来是小题大做但实际能帮你省掉大量的无效排查时间。光纤头只要有一粒灰尘就能让千兆链路丢帧丢到怀疑人生而这些灰尘肉眼几乎看不见。另外建议把Aurora核的门控时钟、用户时钟、以及GT的时钟每一个都挂到信号探针上上板实测一遍时钟频率和相位关系。高速接口调试没有捷径但有一套先时钟、后物理、再协议的排查顺序就能少走很多弯路。上面的流程如果你从头到尾走一遍SFP光口千兆链路对你来说就不是什么神秘的东西了。