做工业视觉项目的人,大概都经历过这种尴尬:相机端是标准CameraLink接口,但产线上两台设备相距二十多米,客户却咬死要用光纤传输,理由是铜缆布线要跨过天花板上的强电桥架,或者单纯就是怕电磁干扰。我最初接到这个需求时,第一反应是找CameraLink转光纤的成品转换器,一问价格,单路就要大几千,而且延迟、帧率、像素格式全被固定死,相机一改配置就得返厂。后来索性在FPGA上做了整套方案——CameraLink接口进来,FPGA完成LVDS解串和像素重组,内部通过GT Transceivers Wizard配置高速收发通道,用Aurora 8B10B作为链路编解码协议,最后从SFP光口把数据送出去。今天把这个项目的关键设计思路、踩坑经历,以及四套工程源码的选型逻辑整理出来,给准备做图像远传或者接口协议转换的朋友一个参考。
这套方案说到底就是一件事:把CameraLink这种短距离并行差分接口,翻译成适合光纤长距离传输的串行高速链路。看似简单,但中间涉及的信号完整性、跨时钟域、链路协议状态机等问题,每一个都能单独写一篇排错笔记。我会尽量按“为什么这么设计”的顺序讲,不光给步骤,也给理由。
1. CameraLink转光口到底解决什么问题
1.1 CameraLink的铜缆宿命:距离与干扰的双重天花板
CameraLink是工业相机领域的老牌接口标准,源自National Semiconductor的Channel Link技术,底层用LVDS差分信号传输。标准定义了几种配置,最常见的是Base配置,使用4对数据LVDS和1对时钟LVDS,理论带宽大约2.38Gbps左右。这套接口在短距离内非常可靠,但一旦距离拉长,问题就来了。
我在现场遇到过最典型的情况是:相机端输出像素时钟85MHz,Base配置,设备间距离超过6米,图像开始出现随机亮线、丢行,甚至直接黑屏。排查了半天,线缆、连接器、工控机都换过,最后发现真正的原因就是LVDS信号在长线缆上的眼图已经闭合得差不多了。这不是某一根线缆质量差,而是CameraLink协议本身的物理层限制——LVDS是电流驱动差分信号,适合板级和短距离设备互联,并不擅长做几十米级别的传输。
除此之外,工业现场的电磁干扰也是一个绕不开的话题。电机、变频器、焊接设备启动瞬间,都能在长距离铜缆上感应出共模噪声。LVDS虽然抗共模干扰能力不错,但前提是接收端的共模范围没有超限。铜缆布线一旦和动力线走同一个桥架,哪怕间距只有十几厘米,图像质量都会肉眼可见地下降。
光纤方案天然免疫这些物理层问题。光信号不导电,不受电磁感应影响,标准单模光纤轻松传几十公里(实际项目中几十米到几百米都算短距离),而且光模块和光纤本身都是成熟工业零件,坏了直接替换,不需要重新穿管布线。这就是为什么这个项目在产线设备改造、远距离采集、医疗影像传输这些场景里都很有市场。
1.2 转换链路的技术路径:解码-缓存-编码-电光转换
整条数据通路其实可以拆成四个阶段。第一阶段是CameraLink信号接收,把LVDS差分线上的串行数据解出来,还原成并行像素数据;第二阶段进FPGA内部,做必要的缓存和时钟域切换,因为解出来的像素时钟和FPGA内部用户时钟不是一个域;第三阶段是把并行像素数据送到GT Transceivers Wizard封装的高速收发通道里,按Aurora 8B10B协议组帧发送;第四阶段是SFP光模块完成电光转换,把高速串行电信号变成光信号送上光纤。
这里有一个关键决策点:对端收到的数据要不要恢复成CameraLink时序?如果远端接的是标准CameraLink采集卡,那就必须在远端FPGA上把Aurora接收到的像素流重新拼成CameraLink的LVDS输出,这相当于做了个“双向翻译”。如果远端是客户自己的采集系统,那直接输出并口数据或者DDR接口的数据就行。这个差异直接影响了工程源码的划分,后面讲四套工程的时候会仔细展开。
其实我在这个项目里还遇到过另一种方案:干脆不要Aurora,直接用自定义的8B10B编解码自己做。后来我放弃了,原因很简单——Aurora 8B10B把通道初始化、通道绑定、错误检测、流控这些脏活累活全干完了,我只需要关心用户数据接口,开发周期能缩短一半以上。但这个选择也有代价,就是Aurora核心的复位时序和通道对齐机制像个黑盒子,一出问题就会懵,这个坑后面单独讲。
2. CameraLink解码侧:先把LVDS串行流还原成像素
2.1 Base/Medium/Full三种配置到底差在哪
CameraLink协议按数据带宽分成Base、Medium、Full三档,理解它们的差异是选型的第一步。
Base配置是基础版,用一组Channel Link芯片(比如DS90CR288A),包含4对数据LVDS和1对时钟LVDS,像素数据位宽是28位。这个28位怎么来的?常见组合是3个8位颜色通道加4位同步信号,刚好28位。每个LVDS数据通道是7:1串行,也就是一个时钟周期内每个通道传7个bit,4个通道合起来正好28bit。像素时钟范围一般是20MHz到85MHz,所以Base带宽上限就是85M × 28bit ≈ 2.38Gbps。
Medium配置用两组Channel Link芯片,数据LVDS加到8对,像素位宽56位。Full配置用三组,数据LVDS12对,像素位宽84位。Full配置下,像素时钟85MHz时,带宽能到7.14Gbps,这是SDR模式下CameraLink的天花板。
需要明确一点,这些配置的区别不只是带宽,还涉及连接器类型。Base用单根MDR 26pin或者SDR 26pin线缆就行,Medium和Full需要两根线缆(CameraLink规范里叫Link 1和Link 2)。很多新手在这里栽过跟头:相机是Medium配置,但只用了一根线缆,结果图像左上角四分之一有数据,其余全是黑屏。这不是FPGA代码问题,是物理连接就没接对。
2.2 解串芯片方案还是FPGA内建ISERDES方案
CameraLink的LVDS信号进入FPGA之前,有两条技术路线可选。
第一条路线是板卡上放专用解串芯片,比如TI的DS90CR288A、DS90UB864这些。芯片把LVDS差分信号直接转换成28位并行数据加一个像素时钟,FPGA这边只需要按同步时序采样就行。好处是简单可靠,时序约束压力小,芯片厂商已经把串行数据的bit对齐和时钟恢复做好了。坏处是BOM面积大,多一颗芯片就多一份成本和故障点,而且有些芯片的工作频率上限就是85MHz,将来想超频很难。
第二条路线是FPGA内部用ISERDES(串行转并行器)自己解。CameraLink信号直接进FPGA的LVDS IO引脚,在FPGA内部完成7:1解串。好处是不用外挂芯片,灵活性高,甚至可以在FPGA里做眼图扫描来补偿线缆长度。但难度也上来了:输入时钟的相位调整、每个BANK的延时控制、set_input_delay约束、bit slip对齐,每一步都需要对FPGA底层时序有足够理解,否则解出来的数据就是乱的。
我在这个项目里选的是芯片解串方案。核心原因在于要给不同FPGA型号的用户提供可移植工程——芯片解串后FPGA只处理并行数据,A7、K7、K725T、甚至国产FPGA都能用同一套逻辑;而ISERDES方案和具体FPGA系列的IO资源绑定太紧,移植起来要重写的约束代码太多。如果你的应用是单一板卡、追求极致成本,那可以考虑ISERDES路线;但如果是做通用方案、服务不同客户,解串芯片方案在工程交付上优势明显。
2.3 像素时钟与用户时钟的跨时钟域处理
解串芯片输出的像素时钟从哪来?它是由CameraLink线缆里的LVDS时钟通道经芯片PLL恢复出来的,频率等于相机的像素输出时钟。这个时钟和FPGA的系统时钟(比如200MHz)没有任何相位关系,和GT参考时钟(比如150MHz)也不同源。所以数据从解串芯片出来后,第一件事就是跨时钟域。
最简单的做法是异步FIFO。写入侧用像素时钟,读出侧用用户时钟(也就是Aurora发送端的用户时钟)。FIFO深度怎么定?这里面有讲究。以Base配置、2048×2048分辨率、像素时钟85MHz为例:每行有效像素2048个,行消隐大约220个像素时钟周期,所以一行周期约2268个像素时钟。有效期间写入2048个像素,行消隐期间没有写入。读出侧Aurora用户时钟如果也是85MHz档位,理论上一行时间能读完,但Aurora链路偶尔会有流控退避,或者GT的tx_tready信号短暂拉低,所以FIFO必须有足够余量缓冲突发。我这边给了两倍余量,用16K深度、32位宽的标准异步FIFO,实测任何情况下都没溢出过。
这里还有一个很多人忽略的点:解串芯片的像素数据位宽是28位,但图像处理逻辑里通常按32位对齐比较好处理。我当时在写入FIFO之前做了个简单的位宽转换,把28位拼成32位(多个视频流的同步信号也一并打包进去),这样后面Aurora发送端的包格式设计就简单很多。顺序不能反:先对齐位宽,再进FIFO,否则写读两侧位宽不一致会让FIFO的时序分析变得很麻烦。
3. GT Transceivers Wizard + Aurora 8B10B:为什么这对组合最省心
3.1 为什么在SFP方案里优先选Aurora而不是UDP
很多人一听说“光口传图像”,第一反应就是上UDP/IP协议栈,把FPGA当成一个小网卡。理论上这没什么不对,很多万兆网口相机就是这么干的。但UDP方案牵扯的东西太多了:MAC控制、IP层校验、ARP协议、分包重组、多帧缓存、ARP表维护,还有可能要做流控和重传机制。一套完整的UDP协议栈在FPGA里跑起来,光逻辑代码就要几千行,而且调试网络协议比调试纯数据链路要痛苦得多。
Aurora 8B10B的核心价值在于,它是专门为芯片到芯片、板卡到板卡的高速数据搬运设计的轻量透明协议。它不关心你传的是图像还是普通字节流,它只保证一件事:发送端塞进来的数据,接收端按顺序、不丢不重地吐出来。通道对齐、初始化、错误检测这些脏活它全包了,用户接口就是一个简单的流式握手,跟AXI-Stream很像,上手非常快。
还有一点很实际:Aurora的8B10B编码保证DC平衡,接收端可以稳定恢复时钟,而且编码开销固定为20%,带宽规划非常可预期。UDP协议栈里,帧间隙、MAC前导码、IP头、UDP头这些开销加起来,有效带宽计算要麻烦得多。所以在这个项目里,Aurora几乎是最优解——除非客户明确要求跟标准以太网设备互联,否则我不会去碰UDP。
3.2 线速率怎么算:从一个Base相机案例推导
GT Transceivers Wizard配置里的核心参数就是线速率(Line Rate)。定得太低,有效数据传不完;定得太高,GT不一定能稳定锁定,SFP模块也可能不支持。这个参数必须算清楚,不能拍脑袋。
假设相机是Base配置,像素时钟85MHz。CameraLink每个LVDS数据通道7:1串行,Base共有4个数据通道,所以原始位流速率是85MHz × 4 × 7 = 2.38Gbps。这是纯粹的图像数据速率,还没算任何编码开销。
进入Aurora 8B10B后,每8个bit变成10个bit,数据速率放大到2.975Gbps。再加上Aurora协议本身肯定有一些开销:通道初始化序列、流控字,还有将用户数据封装成帧时可能的空闲补齐。实际有效载荷速率会比2.975Gbps再高一点,但不会太多,我们按5%的余量计算,得到约3.12Gbps。
接下来看GT线速率档位。7系列FPGA GTX在3.125Gbps档位非常成熟,SFP模块在这个速率下绝大多数都能工作(1.25G-4.25G范围都支持),PCB布线压力也不大。所以最终定的是3.125Gbps。这个选择的余量其实很健康,因为Base相机的实际像素时钟往往是70-80MHz居多,3.125Gbps净带宽有接近4:1的冗余,链路稳定性非常好。
Medium配置的计算类似:像素时钟85MHz,8对LVDS数据,原始速率85MHz × 8 × 7 = 4.76Gbps,8B10B后5.95Gbps,考虑Aurora开销,用6.25Gbps线速率正好卡在档位上。Full配置就更紧一些:原始速率7.14Gbps,8B10B后8.925Gbps,需要10Gbps线速率。这里提醒一点:Full配置下,如果你用的FPGA只有GTX(最高支持12.5Gbps),也能工作,但SFP模块和PCB布线要求就高一个档次了。如果条件允许,Full配置我其实更推荐Aurora 64B66B方案,编码开销降到3%,线速率可以压到7.4Gbps左右。不过这是另外一个话题了,这篇先不展开。
3.3 Aurora的复位与初始化时序是最容易翻车的地方
Aurora核心用起来简单,但它的复位时序极其敏感。GT Transceiver本身有两级复位:一个是GT的复位信号,释放后要等待TX_RESET_DONE和RX_RESET_DONE拉高;Aurora核心还有自己的初始化过程,最后CHANNEL_UP和LANE_UP信号拉高才算链路建立完成。很多工程一上电就同时把reset和gt_reset拉高释放,结果就是CHANNEL_UP永远不亮。
我实践的稳妥做法是做一个三级复位控制器。第一级:系统上电后等待时钟PLL锁定(一般锁定时间<10ms);第二级:拉低Aurora核心的reset,等待至少10个用户时钟周期再释放;第三级:等GT_RESET_DONE拉高后,再等PLL_LOCK信号稳定,最后再拉高Aurora的RESET释放信号,开始等待CHANNEL_UP。
光这样还不够。有一次我在调试中遇到一个诡异现象:Aurora的CHANNEL_UP已经亮起,图像数据也能传,但偶尔会出现一帧图像整体右移几十个像素的情况。排了两天才发现问题出在通道绑定后的数据对齐上——Aurora的8B10B对齐保证了字节边界正确,但没有帮你做“图像行起始位置”的帧对齐。解决办法是在用户逻辑里加入同步字:发送端在一帧图像开始前插入一个固定模式(比如0xBCBCBCBC),接收端检测到这个模式后重置行计数。这个机制简单粗暴,但非常有效,从此再也没有出现过图像错位。
4. 四套工程源码的分工逻辑与选型对照
4.1 四套工程按什么维度划分
标题里说提供4套工程源码,很多人可能以为这是同一个工程的四个小改动,实际不是。在我这个项目的交付结构里,四套工程是按“输入配置 + 板卡平台”两个维度交叉划分的,每一套都是一个可以独立跑起来的完整Vivado工程,包含约束文件、IP配置、源码和测试脚本。
第一套是CameraLink Base输入 + Aurora 3.125Gbps发送。这是最通用的版本,覆盖市面上大部分Base接口面阵相机和线阵相机,FPGA资源占用最小,逻辑简洁,适合作为学习样板,也是我推荐大多数用户第一套上手跑的工程。
第二套是CameraLink Medium输入 + Aurora 6.25Gbps发送。需要考虑两路Channel Link数据的合并,像素位宽从28位变成56位,GT通道可以配置成2条GTX通道绑定(Channel Bonding),也可以先把56位数据打包成两条Aurora流再在接收端合并。这两种方案各有优劣,我最终选了双GT通道绑定方案,因为Aurora的通道绑定机制天然解决了多通道数据一致性问题。
第三套是Aurora接收 + CameraLink输出,也就是远端恢复工程。这一套解决的是“光纤到远端后,怎么把数据还原成CameraLink时序给老式采集卡”的问题。它和发送端镜像对称,但难点在LVDS输出侧的时序约束,以及物理连接器的驱动能力配置。
第四套是特定FPGA型号的移植版。不同板卡的GT参考时钟引脚位置、SFP电源管理引脚、CameraLink解串芯片的中断/使能引脚都不同。我在这套工程里把平台相关的引脚约束、时钟树配置单独抽出来,方便用户改造成自己的板卡。
4.2 按接口配置和板卡资源选型的对照表
这里放一张选型对照表,方便你直接定位该跑哪套工程。
| 工程编号 | CameraLink配置 | GT线速率 | 典型FPGA平台 | 资源占用(约为) | 适用场景 |
|---|---|---|---|---|---|
| 工程A | Base | 3.125Gbps | A7系列 / K7系列 | LUT约1.2万,BRAM约20块 | 大部分Base面阵相机、线阵相机远传 |
| 工程B | Medium | 6.25Gbps(双通道绑定) | K7系列 / V7系列 | LUT约2万,BRAM约40块 | 高分辨率面阵、高速线阵(如8K线扫) |
| 工程C | 从Aurora链路恢复CameraLink输出 | 3.125Gbps/6.25Gbps | A7 / K7 | LUT约1.5万,BRAM约30块 | 远端接标准CameraLink采集卡 |
| 工程D | 按用户板卡定制 | 按需 | 不限 | 按实际评估 | 已有FPGA板卡需要做功能移植 |
选型时核心看两件事:相机的CameraLink配置决定需要多大原始带宽,GT线速率必须覆盖住;板卡的GT资源决定能不能同时跑多路,以及能不能支撑起6.25Gbps甚至更高的线速率。A7系列的GTX虽然也能跑6.25Gbps,但实际余量和信号完整性往往不如K7,所以Medium配置我一般建议直接上K7系列,别在A7上死磕。
还有一个容易忽略的选型维度是参考时钟。四套工程里每套的GT参考时钟频率都不同(3.125Gbps对应GT refclk我用的是150MHz,6.25Gbps用的是156.25MHz),原因是GT的PLL频率规划需要在一个合理范围内。如果你在配置GT Transceivers Wizard的时候直接把线速率从3.125Gbps改成6.25Gbps,但refclk还是150MHz,那IP会告诉你“Out of Range”——因为150MHz倍频不到6.25Gbps对应的整数倍关系。这个细节在工程移植时特别常见,忘了改refclk导致综合出来的IP直接报错。
5. 落地过程中真正耗时间的三个坑
5.1 SFP模块兼容性:TX_DISABLE和RX_LOS别当装饰
GT高速链路跑起来之后,最容易被忽略的就是SFP模块的管理引脚。SFP笼子有十几个引脚,通信用的只有TXP/TXN和RXP/RXN两对差分线,但控制用的TX_DISABLE和状态用的RX_LOS这两个引脚,如果不处理,能让你白折腾好几天。
TX_DISABLE是高电平有效,就是拉高时光模块不发光。很多通用SFP笼子默认把TX_DISABLE引脚上下拉到有效状态,或者用户板卡原理图上这个引脚没做处理,导致GT的TX端有数据但光模块死活不发光。另一位同行的经验是:上电后先把TX_DISABLE拉高再拉低,等模块内部完成初始化和CDR锁定,再开始传数据。实测这是一种比较稳妥的启动顺序。
RX_LOS的意思是接收信号丢失,来自光模块内部的检测电路。问题是不同厂商模块对RX_LOS电平的定义不一致,有的模块在正常接收时RX_LOS是低电平,有的模块则是高电平。如果直接把RX_LOS接到FPGA的复位逻辑上,就可能出现“光路明明正常,但FPGA检测到LOS异常导致复位”的灵异现象。我现在的做法是RX_LOS信号加一个100ms左右的滤波窗口,期间如果LOS持续拉高才认为是断纤,否则忽略。这个“滤波窗口”的做法在工业现场尤其重要,因为光模块刚上电的几百毫秒内,RX_LOS经常会出现一个短暂的抖动高电平。
5.2 Aurora通道Lane Up不起来的排查链路
Aurora的CHANNEL_UP不置位,是这个问题里问得最多的。我自己遇到的时候,一开始也是瞎试,后来整理出了一套固定的排查链路,按这个顺序走,基本能在半天内定位问题。
第一步看时钟。用ILA抓GT的TXOUTCLK和用户时钟,确认频率和IP配置一致。GT refclk配置错误是高频问题,比如原理图上用的是125MHz晶振,IP里却配成150MHz。这时候GT的TX_OUT_CLK频率就会明显偏离预期,ILA一抓就能看出来。
第二步看回环。GT Transceivers Wizard里自带回环模式测试,可以先在IP配置里把Loopback设为Near-End PMA,然后发一个固定数据模式接收回来,验证FPGA内部GT收发通路是否正常。如果Near-End PMA回环通过,说明GT的PMA和PCS基本没问题,问题在外部物理链路。
第三步看SFP和光纤。用光功率计测发送端光功率是否在SFP模块标称范围内,如果光功率正常但远端收不到,把光纤接到另一个设备上交叉验证,排除光纤断芯的问题。这一步没什么技术含量,但能节省大量排查时间。
第四步看Aurora配置。如果回环全过、光模块也没问题,但CHANNEL_UP就是不亮,那就是Aurora核心自身的初始化问题。常见原因包括GT在IP中的参考时钟源配置和实际不符、Aurora核的通道数配置与实际GT通道数不符、或者核心版本和Vivado版本不匹配。这种问题只能逐个对照IP配置界面排查,没有捷径。
5.3 IBERT和ILA配合的调试验证流程
新板卡刚焊好的时候,千万别直接跑整个工程。我养成了一个习惯:先跑IBERT(Integrated Bit Error Rate Tester),这是Vivado硬件管理器内置的GT误码率测试工具,直接下载到FPGA就能用,不需要写一行逻辑。
IBERT的步骤很简单:在Vivado里创建一个IBERT工程,配置成要测的GTX位置和线速率,综合生成比特流下载,打开Hardware Manager,选择对应的GT通道,设置成回环模式,然后连续发PRBS数据。如果误码率长时间为零,眼图模板余量也够,说明GT的物理层是健康的。这一步过了,后面定位协议层问题才有底气。
IBERT通过后,再烧正式工程。这时候用ILA抓Aurora用户接口的信号,重点看三个信号:user_rx_tvalid(接收数据有效)、user_rx_tdata(接收数据内容)、channel_up(链路状态)。我先用一个计数器在发送端循环发送递增数,接收端如果收到的是连续递增序列,说明数据链路完全正常。然后再把CameraLink数据接进去,如果图像有错位,再用前面说的同步字机制做帧对齐。
这套“IBERT验证物理层+ILA验证数据链路+同步字验证图像对齐”的组合,是我在多个项目里沉淀下来的标准调试验证流程。整套流程走完,基本上能把物理层、链路层、应用层的问题逐层隔离,不用再做盲目的“改代码-烧写-看效果”循环。
最后说一点个人体会:这个项目里真正让我花了最多时间的不是GT,也不是Aurora,而是CameraLink那一侧的时序余量。GT和Aurora只要配置正确、复位时序合理,基本一次就能跑通。反倒是CameraLink的LVDS信号在板卡上布线不佳时会偶发误码,这种问题随机性强、复现概率低,排查起来最折磨人。所以如果你打算做类似的转换器,我会建议先把CameraLink的解串和像素重组做到稳定可靠,再上光口链路。否则高速链路一通,你根本分不清问题是出在光口还是源头源头。SFP模块选型也直接在项目初期敲定,别在模块上省成本——工业场景里稳定比价格重要得多。