做FPGA高速接口的活儿,光口迟早是要碰的。两块板子之间要传几十米、几百米甚至跨机房的数据,铜线方案受距离限制太大,SFP光模块加一根光纤基本是标准答案。但很多新手第一次拿到SFP这颗料,直接懵了:这么多引脚到底是干嘛的?光模块要不要驱动芯片?FPGA里哪来的以太网MAC?Xilinx早年针对这个场景出过一份官方应用笔记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供电。下面这张表把关键引脚的意义列清楚,这是我做板卡设计时经常对照的:
| 引脚 | 名称 | 方向 | 功能说明 |
|---|---|---|---|
| 2 | TX_FAULT | 输出(模块→FPGA) | 模块发送端故障指示,高有效 |
| 3 | TX_DISABLE | 输入(FPGA→模块) | 拉高会关断模块激光器,正常工作必须拉低 |
| 4/5 | MOD_DEF2/MOD_DEF1 | I2C | 光模块的I2C管理总线,可读取温度、电压、光功率 |
| 6 | MOD_DEF0 | 输出 | 模块在位检测,模块插入后接地 |
| 7 | RATE_SEL | 输入 | 速率选择,千兆场景一般拉低或悬空 |
| 8 | LOS | 输出(模块→FPGA) | 接收光信号丢失告警,高电平表示无光 |
| 12/13 | RD-/RD+ | 输出(模块→FPGA) | 接收差分数据对 |
| 18/19 | TD+/TD- | 输入(FPGA→模块) | 发送差分数据对 |
| 16/15 | VccT/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也有对应的IP(1G/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 <= 1'b0; tx_data <= 32'h0000_0000; end else begin tx_valid <= 1'b1; tx_data <= tx_data + 32'h0000_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 Wizard(7 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这条路就不够了。你需要换用这两颗IP:1G/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/66B,Aurora的版本也从8B/10B变成64B/66B(就是Aurora 64B66B IP);二是PCB布线要求更苛刻,差分对等长控制、阻抗连续性、过孔残桩控制都会直接影响链路能否跑起来;三是参考时钟的抖动指标要求更高,板上如果还是用普通晶振就不行了,需要专门的时钟芯片。
我个人在实际项目里做升级时,习惯先在老平台上把所有调试方法论沉淀下来,再迁移到高速平台。因为误码定位的思路永远是一样的:一层层回环,一个信号一个信号地排除。
5.4 最后分享一个实用习惯
每次在板子上调光口或任何高速接口之前,花两分钟把光模块和光纤端面用清洁笔擦一遍。这个动作看起来是小题大做,但实际能帮你省掉大量的无效排查时间。光纤头只要有一粒灰尘,就能让千兆链路丢帧丢到怀疑人生,而这些灰尘肉眼几乎看不见。
另外,建议把Aurora核的门控时钟、用户时钟、以及GT的时钟每一个都挂到信号探针上,上板实测一遍时钟频率和相位关系。高速接口调试没有捷径,但有一套"先时钟、后物理、再协议"的排查顺序,就能少走很多弯路。上面的流程如果你从头到尾走一遍,SFP光口千兆链路对你来说就不是什么神秘的东西了。