做机器视觉项目的人应该都有同感:项目推进到图像采集这一环,最容易卡住的就是高速接口。前阵子我们接了一个500万像素、80fps黑白相机的采集需求,粗略一算,像素数据量要到3.2Gbps,GigE和USB3都不踏实,Camera Link Full自然成了首选方案。这篇文章就把这个项目从方案评估、硬件接口设计、FPGA逻辑实现到上板调试的完整过程记录下来,重点讲透XILINX 7系列FPGA上LVDS解串、三路端口对齐、像素重组和DDR3写入这几个关键环节。如果你正在做或准备做工业相机采集板,这篇文章应该能帮你少走不少弯路。
1. 方案决策:Full模式的带宽账到底怎么算
1.1 Base、Medium、Full到底差在哪
Camera Link是工业相机领域的老牌接口,由AIA标准组织定义,底层基于National Semiconductor(现TI)的Channel Link技术。很多人对Camera Link的印象停留在"接口线多、连接器大",但对于做采集板的人来说,必须清楚它分为Base、Medium、Full三种配置,本质区别就是用了几个Channel Link通道。
每个Channel Link通道由4对LVDS数据线和1对LVDS时钟线组成。发送端把28位并行数据(24位图像数据加FVAL、LVAL、DVALID、Spare这4个控制信号)串行化,在4对数据线上按7:1比例发出。Base模式用1个Channel Link,Medium模式用2个,Full模式用3个。所以Full模式在连接器上看到的是12对LVDS数据线加3对LVDS时钟线,总共15对差分线,带宽天然是Base的三倍。
1.2 先算清带宽再决定方案
很多项目在接口选型时容易犯一个错误:只看了相机的分辨率和帧率,没有算像素时钟与接口有效带宽的匹配关系。Camera Link的LVDS时钟上限常见为85MHz,Full模式3个端口同时传输时:
- 每个端口每时钟周期传24位有效图像数据
- 单端口有效带宽:85MHz × 24bit = 2.04Gbps = 255MB/s
- Full模式三端口总计:3 × 255MB/s = 765MB/s
这是一个非常有用的参考数字。我们当时的相机是500万像素、80fps、8bit黑白,像素数据量是500万 × 80 = 400MB/s,Full模式的765MB/s刚好能盖住,还留了接近一倍的余量。如果换成同样的参数但用Base模式,255MB/s显然不够;用Medium模式510MB/s也很紧张,因为还要考虑行场消隐期间虽然不传有效数据,但链路开销和DDR3读写切换都会吃掉一部分余量。
这里给个简单的判断表格:
| 模式 | Channel Link数量 | LVDS数据线对 | 85MHz下有效带宽 | 典型适用场景 |
|---|---|---|---|---|
| Base | 1 | 4 | 255MB/s | 200万以下、中低速 |
| Medium | 2 | 8 | 510MB/s | 200万~400万、较高帧率 |
| Full | 3 | 12 | 765MB/s | 500万以上、高帧率、高位深 |
1.3 两条接收路线:FPGA直接解串还是外置芯片
确定Full模式之后,接收端有两条路线。一条是用TI的DS90CR288A这类专用解串芯片,把LVDS先变成28位并行TTL信号再进FPGA,优点是时序压力小、调试简单,缺点是板级多了一颗芯片、物料成本高、灵活性差。另一条是直接利用FPGA的ISERDESE2原语做7:1解串,省掉解串芯片,所有控制权都在FPGA内部。
我最终选了FPGA内部解串。原因有三个:一是这个项目后续要兼容不同相机的像素映射,FPGA内部解串改逻辑就能应对;二是XILINX 7系列的ISERDESE2本身就支持SDR模式7:1解串,属于官方支持的能力;三是省掉两颗芯片后,板卡面积和成本都明显下降。缺点也很明显,就是调试初期要跟位对齐、眼图较劲,这部分下文会详细讲。
2. 硬件接口设计:连接器、引脚规划与信号完整性
2.1 资源评估与引脚规划
Full模式要求FPGA提供15对LVDS差分输入(12对数据加3对时钟),这个数量对于Artix-7或Zynq-7000系列来说完全不是问题。但真正的坑在于引脚所在的Bank必须支持LVDS_25电平标准,并且尽可能放在同一个Bank或者同一个时钟区域内。
我当时用的是XC7A200T,把三组Channel Link的15对差分信号全部安排在一个HP Bank的相邻引脚上。这样做的目的是让各lane的输入延迟尽量一致,减少后续在FPGA内部做deskew的压力。规划引脚时建议打开Vivado的Device视图,逐个Bank查看LVDS引脚对是否合法。7系列FPGA的引脚手册里会标注某些Bank的某些引脚不支持LVDS,或者只能支持LVDS_25而不能支持LVDS_15,这些信息在布板前必须确认好。
还有一个容易忽略的问题:Camera Link的LVDS差分时钟对也要走IBUFDS,而IBUFDS输出的时钟要进入BUFIO或者BUFG才能驱动ISERDESE2。如果你把三组时钟放在同一个Bank但不同时钟区域,逻辑设计阶段的时钟约束会比较难受。我的建议是尽量让三组时钟对落在同一个时钟区域,哪怕牺牲一点布线空间也值得。
2.2 高速LVDS布局布线与端接
Camera Link Full模式的数据率并不算特别高。以85MHz像素时钟为例,每条LVDS数据线上的串行速率为85MHz × 7 = 595Mbps,这个速率对PCB布线来说处于"需要注意但还没到不择手段"的程度。
关键点是同一端口内部的4对数据线加1对时钟线要做到严格等长。按照TI和AIA规范的建议,同一Channel Link端口内部的差分对长度差控制在±5mil以内,差分对内部的P/N两线长度差控制在±2mil以内。三个端口之间的长度差控制在±250ps以内,换算成PCB走线大概是±25mil左右。如果端口间长度差太大,后面做三路端口对齐时会增加不少额外逻辑。
LVDS差分信号必须有100Ω终端电阻。在XILINX 7系列里,IBUFDS本身可以打开内部差分终端,也就是设置DIFF_TERM = "TRUE",这样外部可以省掉端接电阻。我建议在原理图上预留外部端接电阻的位置,前期调试先用内部端接,如果发现信号质量不理想,再焊上外部电阻对比测试。
2.3 连接器选型和复位信号处理
Camera Link物理连接器最常见的三种:MDR26(老式D型)、SDR26(小型高密度)、HDR26(更小型)。Base模式只需要1个,Medium需要2个,Full需要3个。很多工业相机使用SDR26接口,采集板这边我选了MDR26的插座配合标准Camera Link线缆。选连接器时注意确认线缆是标准Camera Link线缆还是PoCL供电线缆,如果相机是PoCL供电,采集板还需要提供12V电源到连接器,别让供电问题卡住整个调试。
还有一个基础但重要的问题:复位信号。FPGA上电后,LVDS解串状态机、FIFO读写指针、DDR3控制器都用各自的复位逻辑。如果复位信号直接由按键或者外部电平产生,很容易出现复位释放时刻与LVDS时钟沿对齐不佳导致的亚稳态问题。我的做法是把外部复位先做两级同步后再统一生成各模块的同步复位释放信号。这个细节看起来不起眼,实际调试中因为复位时序不对导致解串偶发错位的情况并不少见。
3. FPGA内部解串:ISERDESE2的7倍频采样与位对齐
3.1 用MMCM生成7倍频采样时钟
Camera Link接收端解串的关键,是要为每个Channel Link端口生成一个7倍频的采样时钟。以85MHz像素时钟为例,需要把85MHz倍频到595MHz,用这个高频时钟去采样4条LVDS数据线,每采7个bit拼成一位并行数据。
具体实现上,LVDS时钟线进来之后经过IBUFDS转成单端时钟,然后进入MMCM/PLL。MMCM的CLKOUT0配置成7倍频即595MHz,CLKOUT1保留85MHz作为并行数据输出时钟。这里的细节是:595MHz采样时钟建议通过BUFG进入全局时钟网络,再连接到每个ISERDESE2的CLK端口;85MHz作为CLKDIV连接到ISERDESE2的CLKDIV端口。这样ISERDESE2内部会每隔7个采样时钟锁存一次并行数据。
使用MMCM时还要注意,595MHz对于Artix-7的全局时钟网络来说属于偏高频率,但实际项目中跑下来没有问题。如果条件允许,把像素时钟和7倍频时钟的相位关系用约束固定一下,Vivado综合时会更听话。
3.2 ISERDESE2配置的实战细节
7系列FPGA的ISERDESE2是一个通用串行解串器,官方文档UG471里明确支持SDR模式下的7:1解串,这正好匹配Channel Link的物理格式。我自己的例化核心参数大概是这样的:
ISERDESE2 #( .DATA_RATE ("SDR"), .DATA_WIDTH (7), .INTERFACE_TYPE ("NETWORKING"), .NUM_CE (1), .INIT_Q1 (1'b0), .INIT_Q2 (1'b0), .INIT_Q3 (1'b0), .INIT_Q4 (1'b0) ) u_iserdes_lane ( .CLK (clk_595m), .CLKB (~clk_595m), .CLKDIV (clk_85m), .RST (rst_serdes), .CE1 (1'b1), .CE2 (1'b1), .D (data_from_ibufds), .BITSLIP (bitslip_lane), .Q1 (q_out[0]), .Q2 (q_out[1]), .Q3 (q_out[2]), .Q4 (q_out[3]), .Q5 (q_out[4]), .Q6 (q_out[5]), .Q7 (q_out[6]) );DATA_WIDTH设为7是关键,这也是很多第一次接触Camera Link的人容易卡住的地方。因为ISERDESE2还支持4、6、8等宽度,如果按习惯填了8,解出来的数据位完全对不上。每个端口有4条数据lane,就需要例化4个ISERDESE2。三组端口加起来就是12个ISERDESE2,每个输出7位,总共84位解串数据,其中72位是图像数据,12位是控制信号和保留位。
3.3 位对齐的两种校准手段:IDELAY和BITSLIP
解串器把串行bit流变成并行数据后,最头疼的问题就是字边界不确定。Channel Link协议没有像PCIe那样完善的内建训练序列,所以必须自己做位对齐。
我的做法分两步。第一步用IDELAYE2原语调节每条lane的输入延迟,把采样点挪到眼图中心。IDELAYE2在7系列HP Bank下大约每级78ps,一共32级。调试时写一个简单的状态机,把IDELAY的tap值从0扫描到31,观察每个tap下ILA抓到的数据是否稳定、是否有误码,找出一段比较宽的稳定区间后取中间值。
第二步用ISERDESE2的BITSLIP功能做字对齐。BITSLIP每拉一个高脉冲,解串输出会循环移位一位。通过bitslip把FVALU/LVAL/DVALID这三个信号的位置调整到正确组合。典型现象是:如果字边界错了一位,LVAL可能出现在FVAL下降沿之后,或者DVALID在LVAL低电平期间一直为高,这都说明需要继续slipt。
4. 三路端口对齐与像素重组:从72bit总线到DDR3
4.1 三个端口为什么会失步
理论上,Full模式下三个端口在相机端由同一个像素时钟驱动,到达FPGA时频率完全一致。但由于线缆长度、PCB走线、连接器接触等因素,三个端口的LVDS时钟和数据到达FPGA的相位会有几百皮秒到几纳秒的差异。这个固定相位差如果不处理,三个端口解出来的像素数据会错开一个或几个像素周期,图像就会出现严重的横向撕裂。
处理思路是:先用每个端口自己的LVDS时钟完成解串,得到各自时钟域的并行数据。然后以一个端口为基准,检测三端口FVAL和LVAL的上升沿相位差,通过打拍的方式把另外两个端口的有效数据延迟到与基准端口对齐。最简单有效的实现是每一级打一个像素时钟的延迟,配合状态机比较三路LVAL的相对关系,最多延迟几个周期就能对齐。注意不要试图用全局时钟重新采样已解串的数据,那样会引入额外的跨时钟域问题。
4.2 Pixel Mapping重组规则
对齐之后,输入到重组逻辑的是一份72位的多端口像素数据。以我们项目里8bit 3 tap的相机为例,一个像素时钟周期内,三个端口分别输出3个8bit像素。也就是说一个时钟周期里共输出9个像素。相机手册里的Pixel Mapping表会明确指出A口、B口、C口分别对应图像中哪一列、哪一个tap。
重组逻辑要做的就是把这三个端口的数据按相机定义的顺序拼接成连续的像素流。这段逻辑本身不难,难在相机的映射规则偶尔会和你默认的拼接顺序不一样。我建议在调试阶段先让相机输出test pattern,然后在ILA里和相机的测试图像逐一对照,确认重组顺序正确后再对接真实图像。如果不先做这一步,后面FIFO里存进去的像素顺序就是错的,到时候查问题会非常痛苦。
4.3 DDR3写入通道与FIFO深度估算
像素流重组完成之后,需要写入DDR3做帧缓存。这个项目用的是XILINX MIG生成的DDR3控制器,数据带宽完全不是瓶颈。以400MB/s的写入速率为例,DDR3 16bit @ 800MHz的理论带宽约3.2GB/s,写入占比不到13%。
真正的坑在跨时钟域和FIFO深度。像素流时钟域是85MHz(或重组后的等效时钟),DDR3控制器的UI时钟通常是400MHz或更高,之间必须要用异步FIFO衔接。FIFO深度的经验值建议至少能容纳两行像素再加一些突发切换余量。比如一行按4096像素计算,8bit下就是4KB,两行8KB,为了避免频繁出现空满导致DDR3带宽利用率下降,至少留16KB深度。我当时用了16384的FIFO深度,实际占用率大概在60%左右,没有出现溢出。
5. 相机控制链路:SerTC/SerTF下发参数背后的逻辑
5.1 SerTC/SerTF的电气与协议
Camera Link除了图像数据通道,还定义了两条串行通信线:SerTC(板卡发给相机)和SerTF(相机返回板卡)。电气上是LVDS差分对,但协议本质就是通用UART。默认波特率常见的是9600,也有相机支持115200或更高,具体要看相机手册。
FPGA里实现起来不复杂:用IBUFDS把SerTF的差分信号转成单端,接一个UART_RX模块;用OBUFDS把UART_TX模块的输出转成差分,接到SerTC。很多采集板还会把这两条线通过PL侧的UART桥接到Zynq的PS端,这样Linux应用层可以直接用串口工具下发命令,省去在PL里写一堆寄存器。
相机侧通常有一个固定的设备地址,比如常见的0x0C。命令帧格式一般包含起始符、长度、地址、命令码、数据和校验和,具体字段每个厂商定义不同。第一次做的时候务必找厂商要Camera Link串行命令手册,不要凭空猜测帧格式。
5.2 相机参数下发的工程实践
实际项目中,通过SerTC下发最多的命令就是设置曝光时间、触发模式、增益和test pattern。调试阶段尤其离不开test pattern:在确保图像通道还没完全调通之前,先让相机输出内部彩条或渐变图,可以隔离相机端和接收端的问题。
工程上我会把UART_TX、UART_RX、命令解析器打包成一个自定义AXI-Lite IP。这样做的好处是上层软件或者Zynq的PS端通过读写寄存器就能控制相机参数,不用每次改逻辑都重新综合。把UART做成AXI-Lite IP完全是常规操作,XILINX的Vivado里用Create and Package IP向导就能封装,关键是把寄存器地址定义得清晰一些,比如寄存器0配置曝光低16位,寄存器1配置曝光高16位,寄存器2配置触发模式。
提一个实际调试中的坑:SerTC/SerTF两条差分线的极性问题。Camera Link连接器的引脚定义里,SerTC是有极性的,线序接反会导致通信完全不通。上板前用万用表量一下连接器引脚定义,比调半天代码发现是线序问题要划算得多。
6. 上板调试全流程:从单端口验证到全链路联调
6.1 推荐的调通顺序
很多工程师拿到板子习惯一口气把所有逻辑全跑起来,然后对着花屏发愁。我的建议是严格按以下顺序分步验证:
第一步,示波器看LVDS时钟和数据眼图。确认差分信号幅度、共模电压、终端电阻都正常。如果眼图张不开,后面所有调试都是在碰运气。
第二步,只解串A端口,其他端口先屏蔽。在ILA里抓A端口解出的7位数据和LVAL、FVAL、DVALID。先确认控制信号逻辑正确,再切换相机test pattern看数据是不是固定的彩条序列。这一步能排除大部分解串配置问题。
第三步,A端口稳定之后再依次打开B端口、C端口,每个端口单独做IDELAY扫描和BITSLIP对齐。不要试图三个端口一起调,出问题根本分不清是哪一路的问题。
第四步,三路端口都单独稳定之后,做LVAL上升沿对齐和像素重组。
第五步,把重组后的像素流写入DDR3,然后从DDR3读回来,在ILA里比对写入数据和读取数据是否一致。确认无误后再接HDMI显示或者上位机采集。
6.2 实测结果与资源占用
这个项目完整跑通后,我用ILA和示波器做了一轮实测。500万黑白相机稳定工作在80fps,采集链路无丢帧,DDR3写入带宽占用约45%,FPGA整体资源占用LUT约35%、FF约28%、BRAM约40%,余量很大。解串链路在常温下连续跑了48小时没有出现偶发误码。
资源上最大的开销是像素FIFO和DDR3的读写缓存,如果用高分辨率高帧率相机,BRAM占用会明显上升。建议在设计早期就把这些FIFO深度定好,后期加缓存比换芯片痛苦得多。
6.3 常见故障排查表
| 故障现象 | 可能原因 | 处理方式 |
|---|---|---|
| DVALID一直为0 | BITSLIP未对齐,字边界错误 | 对该lane做BITSLIP扫描 |
| 图像左右错位 | 像素重组顺序错误 | 对照相机Pixel Mapping表 |
| 图像上下滚屏 | FVAL/LVAL对齐异常 | 检查三路端口的帧同步延迟 |
| 偶发性花点 | IDELAY tap不在眼图中心 | 重新做tap扫描 |
| 三路端口数据不对齐 | 端口间走线长度差过大 | 代码中增加多拍延迟对齐 |
| SerTC下发命令无响应 | 串口极性接反或波特率错误 | 检查差分极性,核对相机手册 |
最后分享一个从这次项目里沉淀下来的经验:千万不要迷信"先调试后优化",对于Camera Link这种有多个串行通道的接口,一定要把基础的对齐验证流程固化下来,每次上板第一件事就是跑一遍单端口对齐。这个动作看起来费时间,但能帮你从一团乱麻里快速确认问题边界,反而比直接全链路联调省出好几天的调试时间。