
做机器视觉的朋友应该都碰到过这个尴尬相机选的是CameraLink接口画质稳定、传输可靠结果线缆长度卡在十米以内产线稍微绕一点路就掉链子。客户不会因为这件事改布局相机和工控机的距离就摆在那于是CameraLink转SFP光口这种需求越来越频繁地出现在FPGA项目里。我在几个AOI检测和远距离图像采集项目里反复折腾过这套架构最终固定下来的方案就是标题里写的GT Transceivers Wizard Aurora 8B10B。这套组合的优点很直接不依赖厂商私有协议、IP核免费、逻辑资源占用可控并且只要FPGA选型正确线速率余量可以给到非常大。下面把我实际的工程做法、配置参数和踩坑记录完整展开给准备做同样需求的朋友一条能直接走的路。1. CameraLink转SFP光口机器视觉现场绕不开的传输改造1.1 为什么要把CameraLink搬到光纤上CameraLink本身是好东西尤其是对工业相机来说它信号抖动小、时序稳定、相机支持度高。但限制也很死Base模式在最大像素时钟85MHz下推荐线缆长度只有10米左右即使降低时钟跑也很难超过15米。很多3D相机、线阵相机甚至需要Medium或Full模式线缆更粗、更硬、更贵。实际项目里相机往往装在设备内部或运动机构上而图像处理主机放在几十米外的电气柜里。这中间隔着电缆拖链、屏蔽管、过墙接口普通CameraLink线缆根本不可能布过去。换GigE相机要改采集成像链路成本高周期长用CameraLink光纤延长器又是专用设备价格几万块且灵活性差。所以自己用FPGA做CameraLink转光纤、对端再还原回CameraLink或直接进采集卡就成了性价比最高的方案。用FPGA做的好处也明显像素格式和行场时序都握在自己手里中间想做图像预处理、ROI裁剪、多路合并都方便。比起买成品光电转换器自己造的板子还能把图像数据顺带打包成更利于后端处理的格式。1.2 CameraLink协议里真正要搬走的是哪几位数据CameraLink的数据结构说复杂不复杂。Base模式下一个Channel Link芯片组包含4对LVDS数据线加1对LVDS时钟线在像素时钟的上下沿把28位并行数据串行传出。这28位通常就是24位图像数据通常按X/Y/Z三个通道分配对应RGB888加上4位控制信号FVAL帧有效、LVAL行有效、DVAL数据有效、SPARE保留。做FPGA端接收时如果用解串芯片比如常见的DS90CR288A芯片会直接输出并行的28bit数据和像素时钟FPGA拿到的就是这个信号。要是省掉解串芯片直接用FPGA的LVDS/ISERDES接收也能还原出同样的28bit和像素时钟只是需要额外处理bit slip不建议新手一上来就这样搞。带宽估算很简单假设相机是1280x102460HzRGB888图像带宽就是1280乘1024乘60乘24bit约1.89Gbps。Base模式在85MHz像素时钟下的承载上限约2.38Gbps含控制位跑这种分辨率还勉强够。但要是相机的像素时钟超过85MHz或者要跑Full模式的三组Channel Link那就得用更宽的传输通道——这也是后面选10G光口而不是千兆光口的原因。2. Aurora 8B10B和GT Transceivers Wizard这对组合为什么能扛住视频流2.1 Aurora 8B10B协议的工作逻辑Aurora是Xilinx自家定义的高速串行链路协议8B10B编码版本主打轻量化和低延迟。8B10B编码大家应该不陌生就是把每8bit数据扩展成10bit码字保证直流平衡和足够多的跳变沿便于接收端恢复时钟。Aurora协议本身做得比较简洁链路初始化阶段发送端和接收端通过握手序列对齐建立lane_up和channel_up状态建立完成之后用户数据就可以通过AXI-Stream接口灌进去IP核负责加控制字符、多lane绑定时分发数据、接收端再去偏斜。协议开销主要就是10/8编码开销加上少量控制字符没有以太网那种复杂的MAC、IP、ARP逻辑所以非常适合做实时视频流。在10.3125Gbps线速率下8B10B编码的实际有效数据带宽是10.3125乘以0.8约8.25Gbps。我们按1.89Gbps的图像带宽算一下余量超过4倍。这意味着即使相机分辨率再翻倍或者把两路Base相机合并进一路光口带宽也绰绰有余。2.2 为什么选GT Transceivers Wizard而不是自己写SerDes刚开始接触高速收发器的人很容易有个误区觉得GTX/GTP就是FPGA里的一组差分收发引脚配置一下就行。实际上高速串行收发器牵涉到PLL频率规划、参考时钟分配、PMA/PCS层配置、8B10B开关、弹性缓冲、时钟修正、通道绑定等一系列细节。自己写RTL去控制这些底层寄存器和状态机工作量非常大而且时序收敛很难。GT Transceivers Wizard就是Xilinx提供的图形化配置工具把线速率、参考时钟、用户数据宽度、极性翻转、环回模式这些参数直接填表生成IP核。生成之后你拿到的是一组被封装好的GTX/GTP收发通道用户侧接口也比较规整。Aurora 8B10B IP核再跑在GT通道之上负责链路层的初始化、数据分帧和对齐。这两层配合等于把从物理层到链路层的大部分工作用IP核吃掉了我们要做的只剩应用逻辑。当然用IP核不等于什么都不用管。时钟树的连接、复位的顺序、IP核生成之后与用户逻辑的握手这些还都得自己搞清楚否则光link up就能卡你一星期。后面两章会重点讲。3. Vivado里从GT Wizard到Aurora IP配置细节与参数表3.1 GT Transceivers Wizard配置速查表直接给我验证过能跑通的配置值大家先照着配再理解每一项为什么这样填。配置项我的取值说明目标FPGAKintex-7 XC7K325T-2要跑10G级别线速率A7的GTP上不去Line Rate10.3125 Gbps匹配主流10G SFP光模块Reference Clock156.25 MHz标准参考时钟必须走GTREFCLK专用引脚TX/RX均使能Aurora握手需要双向通道用户数据宽度4 Bytes对应32bit AXIS接口PLL选择CPLL单通道场景下配置简单8B10B编码使能Aurora 8B10B协议要求特别说一下参考时钟。156.25MHz在10.3125Gbps线速率下是Xilinx官方最常见的搭配但前提是你板上必须有干净的差分参考时钟源接到GTREFCLK引脚。很多的坑都出在把参考时钟接到了普通IO上结果CPLL锁定不稳定信道时好时坏。FPGA选型也要注意。Artix-7上的是GTP最高线速率大约6.6Gbps跑10.3125G是不可能的。如果预算确实紧也可以把线速率降到3.125Gbps然后选对应的光模块Aurora 8B10B协议不用变逻辑代码基本不用动。只是带宽余量会缩小。3.2 Aurora 8B10B IP核的配置要点GT Wizard配置完在工程里添加Aurora 8B10B IP核配置界面里有几个选项要一致Aurora配置项我的取值说明Line Rate10.3125 Gbps必须和GTWizard一致GT Refclk156.25 MHz必须和GTWizard一致Dataflow ModeDuplex全双工握手需要InterfaceStreaming直接AXI-Stream简单Flow Control不勾选视频流不需要协议级流控Lanes1单通道先调通不够再加这里重点讲一下为什么选Streaming模式。Aurora 8B10B的Frame模式会提供SOP/EOP等帧边界信号看似方便但一旦接收端出现误码导致帧边界错乱状态恢复比较麻烦。Streaming模式就是一个持续的数据流加valid信号帧边界完全由我们自己在用户数据里定义反倒灵活。视频数据里本身就带FVAL/LVAL丢几行也能从下一行边界恢复完全够用。还有一点容易忽略Aurora IP例化后的S_AXI_ACLK时钟必须接GT的用户时钟也就是GT Wizard生成的TXOUTCLK分频出来的时钟。32bit接口、10.3125Gbps线速率下这个时钟约是257.8125MHz。有人图省事把S_AXI_ACLK接了FPGA板上的100MHz系统时钟结果Aurora IP内部时序全乱channel_up永远拉不起来。3.3 时钟和复位的连接顺序这套架构的复位顺序很关键我建议按下面的顺序操作先给GT Wizard的IP核发reset等pll_lock和txresetdone/rxresetdone信号拉高。等待大约几百微秒确认GT通道稳定后再释放Aurora IP的复位。Aurora IP跑完初始化和对端握手后lane_up信号拉高随后channel_up拉高。channel_up拉高之后用户逻辑再开始向Aurora发送数据。如果直接把两个IP的复位绑在一起释放Aurora可能在GT还没稳定的情况下就开始初始化经常会出现第一帧图像花屏、后面才恢复的现象。我一开始图省事用同一个复位信号控制所有模块后来发现错帧率明显偏高改成延迟链控制之后才干净。4. 顶层RTL怎么搭视频通过光口的完整数据流4.1 CameraLink接收端从解串芯片到异步FIFO硬件上如果用了DS90CR288A这种解串芯片FPGA收到的就是28bit并行数据加一路像素时钟。先别急着直接接进Aurora像素时钟是跟着相机走的和GT用户时钟完全是两个时钟域中间必须做异步FIFO。FIFO的深度不用太大。Base模式相机即便全速输出写入突发速率也就是像素时钟乘以4字节约2.24GbpsAurora侧读出带宽8.25Gbps远大于写入。所以FIFO只用来吸收两个时钟域的相位抖动和短时流量不均深度设512或1024就够。但要注意FIFO写侧的数据必须在DVAL有效时才写入否则会把行消隐和帧消隐期的无效数据也打包进去。从数据量来说消隐期数据丢了不可惜只需要在FVAL和LVAL有效范围内取数据。4.2 数据打包用户帧格式设计Aurora只负责把数据送到对端不会关心你传的是什么。为了让接收端能正确恢复行场时序并检测丢帧需要在图像数据前加自定义包头。我用的帧格式是每行一个包字段字节数内容帧同步头4固定值0xAA55AA55帧号2发送端每帧递增行号2当前行号有效像素数2这一行有效像素个数保留字段2填充0像素数据N字节一行图像数据32bit对齐这个包头看起来占了不少带宽但一行1280像素数据量5120字节包头只有12字节开销完全可以忽略。RTL里给一个示意// Aurora Streaming接口发送 assign s_axi_tdata {camera_pixel[23:0], fval, lval, dval, spare, 4b0}; assign s_axi_tvalid fifo_valid; // 有数据就给valid assign s_axi_tlast line_end; // 行尾标志Streaming模式下可不用把28bit CameraLink数据塞进32bit tdata低4位预留接收端拆包时直接从tdata[27:24]取控制位tdata[23:0]取像素处理起来非常直观。还有一个容易踩的点Aurora的tdata是32bit如果发送端不主动处理tkeepIP会默认4字节全部有效也就是低4位pad字节也会占用光口带宽。视频带宽本来就富余这样没问题但如果你后面想上多路合流最好在打包时把低4位有效利用起来或者改用tkeep配合压缩。4.3 4套工程源码的定位和复用方法这一套方案我拆成了4个工程每个工程解决一个具体场景联调时能快速定位问题工程名方向核心内容解决什么问题cameralink_tx_sfp发射CameraLink解串异步FIFOAurora TX相机信号远传到主机端sfp_rx_cameralink接收Aurora RX时序恢复CameraLink输出光纤信号还原成采集卡可识别的时序aurora_loopback_test自测GT回环ILA抓状态信号调通物理层和Aurora链路multi_cam_mux扩展两路Base合路到一路10G光口多相机复用光纤资源第一个工程是主项目基本就是第四章讲的结构。第二个工程是配对的接收端Aurora RX恢复出的32bit数据流里解析包头还原FVAL/LVAL再用这控制信号驱动CameraLink发送端的28bit时序输出。第三个工程是自测用的。单独把Aurora TX和RX用光纤回环接起来或者用GT的near-end PMA loopback模式配合Vivado的ILA抓取channel_up、lane_up、复位状态和收发数据。项目跑不通的第一步就是先跑这个工程把链路问题限定在物理层还是逻辑层。第四个工程是给多相机场景用的。两路Base信号分别在各自时钟域解析进入同一时钟域后按帧号仲裁把多路数据按优先级塞进同一个Aurora通道。由于10G带宽远大于两路Base总带宽合流逻辑可以做得比较简单核心是帧同步和写FIFO时的地址仲裁。5. 实际调试中踩过的坑每一根白发都是工时换来的5.1 光链路物理层先验证IBERT和光模块的电平问题这部分是血泪教训。第一次上板我直接烧了完整工程然后盯着channel_up发呆一动不动。后来养成了习惯任何高速链路项目第一次上板先跑IBERT。IBERT是Vivado里的集成误码率测试工具它会占用GT资源生成一个测试工程直接把GT的TX和RX配置成可调参数测误码率。用IBERT之前先确认光模块的TX_DISABLE引脚是拉低的这个信号高电平会关闭光模块发送。好几个朋友踩过这个坑误以为光模块坏了其实是FPGA控制脚把光模块关了。IBERT扫一遍后再用短光纤把板子的两个SFP口环起来或者用单个SFP环回模块看Bit Error Rate是不是0或者极低。如果BER很高优先检查GT参考时钟的引脚连接、光模块供电和PCB差分走线。5.2 channel_up起来了但数据错极性和字节序问题channel_up能拉起来说明Aurora链路已经握手成功但图像还是花的、数据乱序常见根因有三个第一是差分极性接反。GTX的P/N如果和光模块或连接器之间交叉了channel_up可能起不来但有时候也能起——只是数据全反。这时候打开GT Wizard里的TX/RX Polarity Inversion选项或者直接改原理图都能解决。第二是字节序不对。Aurora的32bit数据发送时内部有MSB/LSB顺序接收端拆包时如果按错方向读取像素通道就会错位。调试时我习惯发送固定pattern比如0xDEADBEEF在接收端抓数据看是原样还是字节交换、bit交换一目了然。第三是8B10B错误码被忽略。Aurora IP有属性接口可以看到hard_error和soft_error计数接收端的逻辑里一定要把这个计数接出来。有时候图像偶尔花一帧现场不好复现但错误计数一直在涨这就指明了问题方向。5.3 CameraLink侧的时序处理和信号完整性问题CameraLink接口的LVDS信号做解串时注意像素时钟的质量。有些相机的像素时钟在低分辨率模式下会间歇性停顿异步FIFO的写时钟不能直接拿这个时钟去驱动其他逻辑否则会出现时序违例。我习惯在解串后加一个简单的时钟有效检测像素时钟停顿超过一定时间就触发回中状态。还有CameraLink满带宽传输时如果板子上解串芯片和FPGA之间的走线太长28bit并行信号的眼图会变差。解决方法是尽量把解串芯片靠近FPGA或者改用低速时钟模式。实在不行就在FPGA内部对像素时钟做一次PLL重新同步但要注意PLL的锁定时间别让相机输出已经开始了PLL还没锁上。5.4 排查链路信道建立失败的完整定位过程外接一个自测工程我一般按下面的顺序排查看光模块的LOS引脚。LOS为高说明接收端没有光进来先查光纤和发光端。用IBERT直接发pattern测误码。如果误码高问题在GT配置、参考时钟或硬件电路先不要碰Aurora。IBERT正常但Aurora起不来检查GT Wizard和Aurora IP的线速率、参考时钟是否完全一致检查S_AXI_ACLK是不是接的GT用户时钟。检查复位顺序是否按GT先复位、Aurora后复位的顺序执行。以上都正常仍然起不来用Vivado的Hardware Manager在线抓Aurora IP的debug端口确认卡在哪一步REFCLK没锁定还是GT没完成复位还是没有对端ACK。这套流程走下来绝大多数链路问题都能在一两天内锁定。我见过不少同行一上来就改RTL其实大部分信道建立失败都是时钟和复位配置问题和数据逻辑关系不大。最后分享两个我现在还在用的小习惯这套CameraLink转SFP光口的方案我前后经历过三个项目迭代。头一个项目花了两周才调通主要时间都消耗在信道建立和各种时钟问题上后来总结出这套标准流程之后第二个项目不到三天就把收发链路跑通了。现在我自己做类似需求时一定先把知识点前置GT Wizard配置是否正确Aurora IP的S_AXI_ACLK是否连对是决定项目周期最关键的两个点。调试时还有一个习惯值得保留硬件管理器里同时挂上Aurora IP的status端口和CameraLink侧的帧计数/行计数信号上电一次就能同时看到链路状态和数据状态不用来回切换窗口。对做这类高速视频传输项目来说这个习惯能省下大量调试时间。