ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

100G光口测试全解析:FPGA、QSFP28与SerDes调试实战

100G光口测试全解析:FPGA、QSFP28与SerDes调试实战 开篇先交代一个背景我最近在调试一块基于UltraScale的FPGA测试板业务要求是对接100G光模块把线上真实的100GE流量收进来做报文处理再发出去。板子回来第一次上电光模块link不亮查了一圈发现不是硬件问题而是FPGA侧PCS的复位时序没给够这让我意识到做100G光口测试真正考验人的不只是光模块本身而是从光模块寄存器、线缆、SerDes眼图到FPGA硬核整个链路是否对齐。这篇文章就把这次测试的完整过程写出来从系统构成、光模块控制、FPGA侧工程到误码测试和踩坑记录全部按实际执行顺序展开适合正在做100G光口开发、或者刚接触FPGA高速SerDes的工程师参考。1. 100G光口测试到底在测什么链路组成与测试边界1.1 一条完整的100G链路从物理层到MAC层要经历什么很多人第一次接触100G光口以为就是买一个QSFP28模块插到板上FPGA里开一个IP核然后就能通。实际上100G光口是一条非常严格的分层链路任何一个环节掉链子表现出来都是link不亮、误码率高、丢包严重但定位起来特别费劲。先看这条链路的物理组成。QSFP28模块本身是4发4收也就是4条收发通道。如果走的是100GBASE-LR4模块内部已经把4路25G信号波分复用成1路通过单模光纤传输如果是100GBASE-SR4那就是4路25G信号直接在多模光纤上并联传输。无论哪种FPGA和模块之间走的是CAUI-4接口也就是4条25.78125Gbps的高速差分线。FPGA侧需要有一个硬核或者软核来实现100GE MAC和PCS层一般Xilinx UltraScale里叫做CMACIntel的叫做E-Tile硬核或者100G MAC IP。测试时最容易搞混的一点是我们说的“100G测试”究竟是测光模块本身还是测FPGA到模块这段的高速电接口还是测整条端到端的网络链路。三种测试的目标、手段和判断标准完全不同。光模块回环测试测的是光电转换和光纤传输质量FPGA内部串行回环测的是SerDes和PCB布线质量端到端测试测的才是整机业务质量。1.2 测试拓扑和回环方式要提前定好我的做法是在设计测试用例之前先把回环方式定义清楚回环类型回环位置能验证的内容典型误码要求FPGA近端串行回环GT收发端内部FPGA SerDes、时钟、PCS绑定BER 1e-15PCB走线回环板级走线或连接器PCB阻抗、连接器质量BER 1e-15光模块电回环模块内部收发短接模块电路、主机侧管理接口BER 1e-12光纤回环光纤把TX和RX连接光模块收发、光纤链路BER 1e-12端到端业务回环对端交换机/设备整机业务、FEC、上MAC层无丢包注意不同回环点之间是逐级验证、逐级排除的关系不建议一上来就做端到端。比如我在测试时先做FPGA串行回环这一级通常能达到极低的误码率因为信号根本没有离开芯片然后做光模块的电回环如果这里出现误码说明模块和FPGA之间的CAUI-4电气链路有问题再然后做光纤回环如果这里出现误码说明光模块发送端和接收端问题——注意这里的“接收端”往往包含了模块内部的CDR和DSP问题未必全部出在光纤上。1.3 速率关系为什么25G变成了25.78125G这是一个让很多刚入门的工程师困惑的点。100G Ethernet的线速率不是精确的25G而是25.78125G。为什么因为100GE在PCS层采用了64B/66B编码每64比特原始数据编码成66比特编码开销是2/64也就是约3.125%。相应地MAC层的速率是100Gbps经过编码后物理层的速率就要变成100 * 66/64 103.125Gbps再除以4条通道每条就是25.78125Gbps。这个速率差会在测试里带来几个实际影响。第一参考时钟必须是精确的161.1328125MHz对应103.125Gbps或者用156.25MHz经过内部PLL倍频不能随便用一个25M的晶振去凑。第二流量仪的线速打流如果设置为100G实际上物理层跑的是103.125GMAC层才会收到100G的净荷速率。第三如果使用FEC还要考虑FEC带来的额外开销和时延在长距传输场景下这些细节直接关系到链路能否建立。2. 光模块侧的控制与管理寄存器访问是第一道门槛2.1 QSFP28管理接口和I2C地址分配光模块不是插上电就能用那么简单。在模块正常工作之前主机必须先通过I2C接口读取模块的相关信息并确保模块处于正确的配置状态。QSFP28标准规定了一个两线串行接口地址0x50用于访问低128字节的寄存器空间地址0x51用于访问高128字节的寄存器空间比如部分诊断信息和页选择。在测试中我习惯先写一个简单的I2C扫描脚本用FPGA内部的I2C控制器或者外接的USB-I2C适配器去读模块的标识寄存器。SFF-8636规范在偏移0x00处定义了模块标识符QSFP28应该是0x0D0x01到0x03是连接器类型、收发器编码等访问这个区域能确认线缆和模块是QSFP28而不是早期的QSFP。对于100G模块测试有几个寄存器非常关键寄存器偏移内容测试中的意义0x00模块标识符确认模块类型为QSFP280x0D0x03收发器编码区分SR4、LR4、AOC等0x0D模块温度高低温测试时判断散热是否正常0x0E供电电压确认模块供电在3.15V-3.45V范围内0x16-0x19接收光功率判断光链路是否建立、光功率是否在合理范围0x1A-0x1D发射光功率判断模块发射是否正常0x03-0x06告警标志锁定光链路异常的具体方向0x7D页选择访问更高页的数据时需先设置2.2 对应I2C读取脚本的编写示例如果是在调试阶段我用FPGA建立一个I2C主机然后通过串口下发读写命令Python侧快速验证数据合理性。下面是一个简化但可用的示例假设I2C总线通过FPGA内部的PIO模拟实现FPGA侧接收模块地址和寄存器偏移并返回数据import time import serial SER_PORT COM12 SER_BAUD 115200 def i2c_read(addr_i2c, reg): cmd R {0:#x} {1:#x}\n.format(addr_i2c, reg) ser.write(cmd.encode()) line ser.readline().decode().strip() # 返回格式示例: OK 0x1e if line.startswith(OK): return int(line.split()[1], 16) return None ser serial.Serial(SER_PORT, SER_BAUD, timeout1) time.sleep(0.1) # 读取0x50地址下的模块温度0x0D temp_code i2c_read(0x50, 0x0D) # 有符号数单位0.01度 if temp_code is not None: if temp_code 0x8000: temp_code - 0x10000 temp_celsius temp_code / 256.0 print(模块温度: %.2f C % temp_celsius) # 读取0x50地址下的模块类型0x00 ident i2c_read(0x50, 0x00) print(模块标识: 0x%02X % ident)上面的read函数里有一个细节温度寄存器在QSFP28里用的是16位有符号数但I2C读取通常是8位一读所以要连续读两次再拼起来。很多时候你以为读一个寄存器就能解决问题但实际上光模块的寄存器访问涉及字节序、符号扩展、告警标志闩锁等等这部分是测试中容易忽略的坑。2.3 模块复位和低功耗模式的控制QSFP28的硬件控制引脚有两个特别重要ModSeL模块选择和LPMode低功耗模式。模块默认上电后如果LPMode为高模块会进入低功耗状态部分功能不工作。很多测试板第一次上电光模块不亮就是LPMode这个引脚没有正确拉低。ModSeL用于选中模块对于单模块应用直接接地即可但在多模块设计中要注意这个引脚不能悬空悬空的状态不确定可能选不中模块。另外还有一个ResetL引脚低电平有效复位。这个引脚一般由FPGA GPIO控制在上电后得保持至少2ms的低电平然后再释放模块才能正常初始化。我在测试中曾经遇到一个现象模块偶尔能link成功偶尔不能概率性问题后来用示波器观察ResetL引脚发现释放时的上升沿有毛刺再接一个10K上拉电阻解决。此类问题在高速测试中非常典型软件上看起来是随机故障根子其实在硬件信号完整性上。3. FPGA侧工程准备硬核配置与时钟复位3.1 用100G硬核MAC/PCS还是用第三方IPFPGA实现100G光口首先要决定MAC/PCS用什么实现。Xilinx UltraScale平台的CMAC硬核是业界最常用方案集成在GTY/GTM收发器附近自带100GE的PCS支持RS-FEC和Fire Code FEC。用CMAC的优势是资源占用极低、代码路径固定、很少有人能靠软逻辑实现同样的性能所以除非是在做研究性质的实现否则强烈建议直接用硬核。但硬核不等于不需要配置。CMAC在例化时需要关注几个关键参数协议选为100GE、FEC模式Auto/RS-FEC/Fire Code/None、线速率25.78125G、参考时钟选择161.1328125MHz或通过MMCM分频。FEC的选择直接关系到链路误码容限RS-FECRS(528,514)纠错能力更强时延更大适合长距光纤段短的情况Fire Code的时延较小适用于数据中心内部。如果模块和FPGA都在同一个机柜内距离短到可以忽略就算不用FEC也可能跑稳定但标准规范推荐开启FEC。3.2 参考时钟和复位时序最容易翻车的地方100G链路对参考时钟的质量要求非常苛刻。CMAC的参考时钟频率必须精确到数十ppm以内相位噪声直接决定SerDes的眼图质量。PCB上参考时钟的走线要远离高速信号时钟芯片的去耦电容要加足这些是保证测试结果可复现的基础。复位时序更是关键。我第一次调试就吃了这个亏复位信号只给了几十微秒实际上CMAC的复位流程要求参考时钟稳定后必须等待PLL锁定然后依次释放GT复位、PCS复位、MAC复位每个阶段之间还需要等待状态标志。很多IP核的手册里都写了复位时间要求但实际做的时候在代码里加一个简单状态机控制复位释放流程比靠延时凑数要靠谱得多。以下是一个CMAC复位时序的简化示例Verilog思路// 复位流程 // 1. 等待gt_ref_clk稳定通过counter延时实现 // 2. 拉高gt_rx_reset / gt_tx_reset等待gt Tx/Rx reset done // 3. 拉高pcs_rx_reset / pcs_tx_reset等待pcs reset done // 4. 拉高mac_rx_reset / mac_tx_reset等待mac reset done // 5. 复位完成link可以开始建立 always (posedge user_clk) begin if (!sys_rst_n) begin rst_state RST_IDLE; gt_rx_reset 1b0; pcs_rx_reset 1b0; mac_rx_reset 1b0; end else begin case (rst_state) RST_IDLE: begin gt_rx_reset 1b1; rst_state RST_GT_WAIT; end RST_GT_WAIT: begin if (gt_rx_reset_done gt_tx_reset_done) begin pcs_rx_reset 1b1; pcs_tx_reset 1b1; rst_state RST_PCS_WAIT; end end // ... 依次推进 endcase end end注意上面的值不能直接用于实际工程真实项目里还需要根据具体IP核的datasheet调整复位保持等参数。但核心思路通用就是“等待状态标志而不是盲目延时”。3.3 用户侧接口AXI4-Stream数据通路CMAC的用户侧通常是512位宽的AXI4-Stream接口时钟频率约322.265625MHz。也就是说FPGA逻辑每个时钟周期要处理512位数据。这个接口有几个信号特别容易出错tkeep、tuser、tlast。tkeep在不同厂商IP里定义不同有的IP的tkeep不是每字节有效而是以4字节为一个粒度需要判断tkeep的编码方式。tuser里往往包含了包的错误标志、FCS错误标志、EOF和SOF位置。数据通路调试时建议先用集成式误码仪IBERT验证物理层再用MAC侧的环回CMAC loopback验证MAC层然后把数据通路接入业务逻辑。如果只是做测试最简单的数据处理是直接把接收到的AXI数据写进DDR再由CPU读取分析或者直接在FPGA内部做一个“第N个包错位重抓”的逻辑这样能快速定位数据通路上的截断或拼接错误。4. 百G级误码测试与数据通路验证从PRBS到满速率跑流4.1 物理层验证IBERT和PRBS模式FPGA高速通道调试我一般从Xilinx IBERT集成式比特错误率测试开始。IBERT不需要配置任何上层逻辑直接用Vivado Hardware Manager把比特流下载进去然后打开GT通道的眼图扫描和误码测试界面。IBERT支持把GT配置成PRBS发生器/检测器常用PRBS31、PRBS23、PRBS15、PRBS7。PRBS31和PRBS23更接近真实数据的统计特性适合用来做误码评估。实际测试中连续跑30分钟、1亿Gbit数据零误码是最基本要求。但要注意IBERT的物理层PRBS测试通过只能说明SerDes和PCB布线没问题并不能说明MAC/PCS数据通路没问题。原因很简单PRBS不经过MAC层数据被直接映射到SerDes而真实流量要经过PCS编码、FCS校验、MAC地址处理等等。所以物理层测完还得做上层的数据完整性测试。4.2 数据通路验证用已知码流比对用FPGA内部产生固定报文经过CMAC发出再从接收端收回来比对是数据通路验证的常用办法。比如我常会生成一个递增序列的包号或者生成一个训练码流pattern在接收端检测是否出现数据错位、丢包、乱序。这个过程里有一个细节MAC层会插入IFG帧间隙、Preamble和SFD所以接收端比对时不能直接拿“发出数据”和“接收数据”做逐字节比较而是要解析出以太网帧之后再做比较。如果是纯FPGA内部测试可以跳过MAC层直接对PCS层做回环这样能快速验证PCS内部对齐标记和编码是否正确。另一个重要手段是在CMAC的发送端和接收端之间插入IP层回环测试逻辑。做法是接收端把收到的以太网包原样转给发送端再发出去然后把IBERT设置为改PRBS为“自发自收”。这样可以在不需要外部流量仪的情况下验证整条MAC通路是否存在FCS错误、CRC错误、Oversize包等。4.3 用流量仪打流线速和丢包率怎么测如果条件允许用Spirent或IXIA这类流量仪做端到端测试是最接近真实业务的方式。流量仪测试有两大重点线速转发和丢包率。线速是100G也就是每秒要发出约1450万线速64字节小包以64字节为例100GE线速每秒小包数约为100 * 10^9 / (84 * 8) ≈ 148.8万这里要注意以太网帧最小64字节加帧间隙12字节和前导8字节单帧传输时间是84字节所以线速小包是每帧672ns每秒约148.8万帧线速小包计算确实要按84字节来算而实际这个值大概在148.8万帧量级。这个计算可以用在测试准备阶段用来判断流量仪是否真的跑到了线速、FPGA侧有没有出现长时间阻塞。丢包率测试建议采用RFC 2544的方法从小包到大包逐级加流直到出现丢包找到FPGA/DDR/CPU处理链路的吞吐瓶颈。100G测试的一个实际困难是FPGA里如果接了CPU核比如ZynqMP并通过了AXI总线和DDR访问那整机吞吐往往不是100G瓶颈可能在DDR带宽或缓存一致性上。测试时要把这种瓶颈和光口本身的误码区分开否则容易误判为光模块问题。4.4 误码分析和FEC统计误码分析不能只看最终有没有误码还要看误码数出现的强度和分布。100G系统的误码来源大致分为随机误码和突发误码前者的产生和光信噪比、接收灵敏度相关后者的产生往往和电源噪声、串扰、模块DSP突发错误相关。如果模块支持FEC功能FEC纠错计数是一个非常有用的指标。当FEC纠错计数持续增加说明链路余量在恶化链路虽然没断但随时可能断。用FPGA读取模块的FEC纠错统计寄存器配置一个阈值告警在某次测试中帮我提前发现了光纤被弯折导致的光功率下降问题比光功率告警来得更早。5. 实测踩坑记录这些坑让我多花了一周时间5.1 光功率“看起来正常”但link不起来有一次测试中我读到的模块接收光功率在-6dBm模块的灵敏度指标是-10dBm按理说光路没问题但就是不link。后来查文档发现这个模块是LR4类型的波分模块内部有4个不同波长的接收通道各个通道的光功率是分开的而我只读了其中一个通道另外几个通道有一个功率异常低。从此以后我养成了一个习惯凡是波分类型的光模块读取接收光功率时一定是把4个通道全部读出来逐通道对比不能只看数组里第一个数据。5.2 CMAC复位标志显示完成但数据不通这个坑是让我记忆最深刻的。复位状态机已经等到了所有reset_done标志link也被本端和对端设备都识别到了但实际一跑流量全丢。后来打开Vivado的硬件管理器看GT的状态寄存器发现TX和RX没有出现对齐submit信号始终没有拉高。排查到根因的日子我用了快一整天。最终判断是CMAC配置里有一个选项“RX alignment”被设置为了自动模式下它要求端到端必须有一次“远端故障指示”帧来触发PCS重新对齐而我做的端到端拓扑里恰好有一台不支持100G标准的开发板导致这个帧始终没发出来。解决办法是手动触发一次PCS对齐或者把CMAC的alignment模式改为软件控制。5.3 高速走线靠近电源层导致眼图边缘在PCB Layout完成后的测试中某一组GT通道通过IBERT扫描眼图发现眼宽比其他通道少了约20%但还勉强合格。后来量了PCB板上的走线发现有一条通道的过孔恰好跨过了电源层的一个分割缝造成阻抗不连续。这种问题在100G这种高速率下会直接表现为误码率不稳定特别是在温度升高后更加明显。所以如果你测到某个通道的误码率略高于其他通道不要急着怀疑模块先去看PCB Layout里的过孔、换层、走线参考层是不是干净的。5.4 模块告警闩锁的“假报”问题光模块的很多告警标志是闩锁的也就是说当告警事件发生时对应的bit会被置位并且保持住即使事件已经消失bit仍然是1必须通过写入操作清除闩锁状态。我在测试中遇到过模块一直报“TX fault”怎么配置都不行以为模块坏了后来才发现是上一次测试中TX功率瞬降触发了故障闩锁模块已经恢复正常但标志位还停在1。用I2C写入相关控制寄存器清除闩锁状态后告警才消失。这段经历说明一个道理测试时读到的告警状态是“曾经发生过的告警”还是“当前正在发生的告警”取决于你是否在读取前先做了状态清除。建议在测试程序中启动时先对所有状态寄存器做一次清闩锁操作再读取实时值。5.5 过温环境下误码急剧增加的定位思路在高温测试环节我发现模块温度超过65度以后误码开始增多。最初怀疑是模块本身的温度性能不行但后来用FPGA内部温度传感器和板卡上的NTC比对发现模块温度和FPGA温度都在正常范围倒是模块供电电压掉了0.1V左右。追查下去发现是电源模块在高温下电流能力下降配合PCB上过细的电源走线导致供电压降而模块内部DSP在低电压下高频性能变差误码自然增加。这个案例的问题定位思路值得记住高速误码问题不一定在高速链路上电源、地的直流稳定性同样会引起高速模块工作异常。排查时要把电源轨实测情况和数据链路并列来看别一上来就怀疑光口。6. 从测试结果到量产测试策略的思考前面写的都是开发调试阶段的测试方法但如果你和我一样需要把这类100G光口测试延伸到产线环节需要考虑的问题会更多。产线测试和研发测试的差异在于研发测试追求的是深挖问题和边界产线测试追求的是快、准、省。产线测试不可能像研发那样跑30分钟IBERT一般会压缩到几十秒内的PRBS测试加链路建立检测再用光功率和FEC纠错计数做快速判定。我在产线测试方案里通常设置三个档位的结果判定PASS、MARGIN、FAIL。PASS是误码率和光功率都远超合格线MARGIN是接近边界需要人工复核FAIL是直接判定不良。同时产线测试固件必须支持远程控制指令测试电脑通过串口或者以太网控制FPGA完成所有测试流程这样可以接入MES系统自动记录结果和序列号避免人工记录出错。另外产线测试的测试项不要设计成“测到通过为止”而是“测到结果稳定”一旦出现不稳定结果立即停止标记为疑似不良交给工程人员分析。这样能尽量避免把隐性不良产品流向客户。还有一个容易被忽略的点产线上不同的工位之间可能出现同一批模块不一致的问题。我曾经遇到过一批模块在研发工位测试通过但在产线工位测试失败最后发现是两个工位使用的测试光纤长度不同导致光衰减差异。所以产线测试环境的光纤、衰减器、跳线需要进行定期校准和统一规格管理否则测试结果的可比性会很差。7. 一些测试工具和调试手法的补充100G光口测试的工具有哪些值得常备除了前面提到的IBERT、流量仪和I2C脚本最好还有光功率计、可调光衰减器、以及可以抓光口电信号的示波器。光功率计用来做光纤链路和模块输出功率的绝对测量衰减器用来测试接收灵敏度和链路余量示波器虽然很难直接抓到25G电信号需要用高速探头但抓模块的管理信号、复位信号、电源纹波足够了。调试手法上我推荐一个做法在FPGA逻辑里做一个“分步执行寄存器”调试接口把需要控制的关键信号GT reset、PCS reset、MAC reset、模块复位、LPMode全部映射到一组可读写寄存器里这样用串口或者JTAG就能在调试过程中动态控制复位时序而不用每次都重新编译一个版本。另一个有用的技巧是在CMAC接收路径上插入统计模块实时统计接收到的报文总数、CRC错误数、长度错误数、空闲错误数并通过寄存器读出。实际链路调通后这些计数器是每天运行状态监控的重要组成部分。只要这些数字持续为0说明链路是很健康的。如果你用的是Zynq UltraScale这一类集成ARM核的器件还可以直接在Linux环境下用Python或者C去访问光模块的I2C寄存器配合PetaLinux里封装好的I2C驱动在系统层面做在线监控。这就是“光模块MCU”的思路即用MCU/ARM负责模块的管理和状态监控FPGA负责数据面处理。许多量产设备中光模块控制功能真的是交给一颗独立MCU或者Zynq里的ARM核来做的FPGA只管业务数据两者通过内部寄存器通信职责划分清晰。在应用层测试方面FPGA图像处理业务接入100G光口后常见的一大问题是小包冲击能力差因为图像帧长往往很大而且有周期性。与其拿真实的图像数据去测光口不如在FPGA内部用一个AXI数据发生器合成“接近图像传输模式”的以太网帧比如每帧长度9126字节的巨型帧验证光口在巨型帧和突发流量下不会出现FCS错误。这样既避开了图像处理链路本身的不确定性又能单独考核光口数据通路。最后分享两点个人的实操心得第一点是关于参考时钟的调试。实测下来如果参考时钟频率有偏差光模块是link不上的而这一点在FPGA的IP核配置界面里往往不会直接报错只会显示“link down”或者频繁翻转。遇到这种问题第一个动作就是用频谱仪或者示波器量一下FPGA参考时钟输入的频率和抖动不要再反复改FEC配置和复位逻辑。第二点是想提醒做FPGA的同行光模块测试很多问题看起来是“模块问题”但实际根因经常在FPGA周边的电源、时钟和复位设计。决定业务成功率的往往就是这些基础工程而不只是GT速率和IP核选型。把基础做扎实了100G光口测试和调试就能少掉一半以上的坑。
返回列表