☰
CameraLink Base/Medium/Full带宽、端口映射与调试避坑
2026/11/4 6:28:09 网站建设 项目流程

简介:围绕Camera Link相机输出Base、Medium、Full三种模式的接口配置,这份文档面向工业相机与图像采集卡选型、调试及视觉系统集成人员,帮助厘清不同模式下Channel Link路数、并行视频位宽、相机控制与串行通信线对的差异。内容从Camera Link标准产生背景和Channel Link技术优点切入,说明其基于LVDS多路复用的连接方式,依次展开基本模式、中级模式、完整模式的收发器配置、最高28/56/84位并行传输能力与线缆使用特点,并涉及端口A至H的定义和分配。压缩包内为1个doc文件,约168KB,便于按主题查阅。已有2116人学习下载。读者可据此核对相机与采集卡接口是否匹配,理解三种模式在带宽、连接与布线上的取舍,为高分辨率工业视觉方案设计和现场排错提供参考。

1. 从一台 8K 线扫相机说起:Base、Medium、Full 三档到底差在哪

去年帮某实验室调一台线扫相机,8K 像素、12 位输出,相机铭牌写着 CameraLink,采集卡也标 CameraLink,插上去就是黑屏。翻了两天才发现不在代码,而在模式:相机按 Base 输出,采集卡默认按 Full 的三组通道轮询,第二、三组端口上全是悬空数据,帧有效信号对不上,图像自然出不来。搜 CameraLink 的资料,网络上铺天盖地是 26-pin 引脚表,讲清楚 Base、Medium、Full 这三档怎么选、带宽怎么算、端口怎么铺的反而少。这三档不是速度档位开关,是实打实的 1 组、2 组、3 组 Channel Link 通道,装几组就只传几组像素位,多出来的位宽拿钱也买不到。

2. Channel Link 与 LVDS 的底子:为什么带宽按 28 位一档往上加

2.1 一组 Channel Link 就是 28 位并行转 4 对 LVDS

CameraLink 的物理层不是什么自研黑科技,是把一组 Channel Link 收发器搬过来用。发送端收进 28 位单端 CMOS/TTL 并行信号加 1 路时钟,做 7:1 串行化,拆成 4 对 LVDS 数据流加 1 对 LVDS 时钟流,一共 5 对差分线;接收端再把 4 路串行数据连同恢复出来的时钟还原成 28 位并行数据和一个同步时钟。所以一组通道的原始位宽被钉死在 28 位,这就是后面所有模式划分的物理天花板。

LVDS 本身的电气参数决定了它能跑多远:差分摆幅 350mV 左右,靠差分对抵消共模噪声,跳变快、功耗低,理论极限在 1.9Gbps 量级。Channel Link 把 4 对数据线一起用,单组能到 2.38Gbps。这个数字不是随便写的,它等于像素时钟乘 7 再乘 4 对:85MHz × 7 × 4 ≈ 2.38Gbps。看懂了这条乘法,后面算带宽就不用查表了。

线缆侧的收益也很直观。同样传 28 位数据,传统 RS-422 方案要在线上挂 56 只终端电阻,换成 Channel Link 只要 11 只:4 对数据线 8 只、1 对时钟线 2 只、加最多 1 只地。终端电阻少意味着连接器可以做小、屏蔽要求可以降、线缆能大批量做,这才是 CameraLink 当年能统一工业相机接口的真实原因——不是性能碾压,是把整条链路的成本压下来了。

2.2 三档模式复用的是同一套东西,只是叠加了几组

标准把 28 位拆开用:24 位给像素数据(端口 A、B、C 各 8 位),剩下 4 位塞视频使能信号——LVAL(行有效)、FVAL(帧有效)、DVAL(数据有效)和一个 Spare,分别落在串行器的第 24、25、26、23 号引脚上。这个分配在三种模式下都一样,只是通道组数不同。

模式Channel Link 组数像素端口有效像素位宽线缆根数典型每周期像素数(8 位)
Base1A、B、C24 位13
Medium2A~F48 位26
Full3A~H64 位28

注意 Full 那一行:三组 28 位加起来是 84 位,但第三组只引出 G、H 两个端口共 16 位像素数据,剩余位宽没有定义成像素槽。所以 Full 的有效像素位是 24 + 24 + 16 = 64 位,不是 84 位。很多选型表上写「84 位」指的是通道位宽总和,拿它去算像素率会算高一截,这是血泪经验。

还有一条容易被忽略:相机控制信号 CC1~CC4 和串行通信 SerTC、SerTFG 走的是独立的 RS-644 LVDS 差分对,不占 Channel Link 的 28 位,而且在三种模式下永远只有一组。这 4 对控制加 2 对串口,加上第一组 Channel Link 的 5 对,正好 11 对差分,塞满一个 26-pin MDR。第二组、第三组没地方放了,所以 Medium 和 Full 必须上第二根线缆,这就是它们要两根线的全部原因。

2.3 把带宽算成 MB/s:像素时钟、tap 数与位深的三角关系

选型时最常被问的一句是「我这台相机能不能接 Base 卡」。答案不在相机分辨率,而在这三个数的乘积:像素时钟、每时钟输出的像素数(tap)、单像素位深。三者乘积不能超过模式给出的位宽预算。

用代码把这件事算清楚,改参数就能复用:

# CameraLink 三档模式的位宽预算与实际吞吐估算 MODES = { # ports: 有效像素端口数(每端口 8 位); cables: 需要几根 MDR 线缆 "Base": {"groups": 1, "ports": 3, "cables": 1}, "Medium": {"groups": 2, "ports": 6, "cables": 2}, "Full": {"groups": 3, "ports": 8, "cables": 2}, } def budget(mode, clock_mhz=85, bits_per_pixel=8): m = MODES[mode] payload_bits = m["ports"] * 8 # Base 24 / Medium 48 / Full 64 pixel_rate = payload_bits / bits_per_pixel # 每周期能塞几个像素 max_taps = int(pixel_rate) # 必须向下取整,不能取半像素 gbps = payload_bits * clock_mhz / 1000.0 # 有效像素带宽 mbyte = gbps * 1000 / 8 # 换算成 MB/s return { "mode": mode, "payload_bits": payload_bits, "max_taps": max_taps, "clock_mhz": clock_mhz, "payload_gbps": round(gbps, 2), "mbyte_per_s": round(mbyte, 1), "cables": m["cables"], } for mode in ("Base", "Medium", "Full"): for bits in (8, 10, 12): r = budget(mode, clock_mhz=85, bits_per_pixel=bits) print(f'{r["mode"]:6s} {bits:2d}bit -> {r["max_taps"]} tap, ' f'{r["payload_gbps"]} Gbps, {r["mbyte_per_s"]} MB/s, {r["cables"]} 根线') # 相容性判断:相机需要的 tap 数超过预算就是接不上,不是调参能救的 need = 4 # 相机手册标称 4 tap bits = 12 for mode in ("Base", "Medium", "Full"): ok = need * bits <= MODES[mode]["ports"] * 8 print(f"{need} tap x {bits} bit 能否跑 {mode}: {ok}")

这段逻辑里有两个参数必须理解清楚。clock_mhz不是相机标称的帧率,是像素时钟,常见档位 40/66/85MHz,对应收发器芯片的不同速度等级,85MHz 是 3.3V 器件里比较通用的一档。bits_per_pixel要按真实输出位深填,不能按「反正 8 位够用」拍脑袋,12 位像素在 Base 模式下最多只能塞 2 个 tap(24/12=2),想跑 4 tap 12 位必须上 Medium。

跑出来的结论很直观:85MHz 下 Base 的有效像素带宽约 2.04Gbps、255MB/s,Medium 约 4.08Gbps、510MB/s,Full 约 5.44Gbps、680MB/s。拿相机的「分辨率 × 位深 × 帧率」直接和这三个数比,比看任何选型表都快。

提示:算完带宽还要留 20% 余量。像素时钟是标称值,实际相机内部 PLL 会有偏差,采集卡侧的时钟恢复也有抖动,贴着上限跑在长线缆上很容易偶发丢行。

选型的三步走:先按位深和 tap 数算出每周期需要的位宽,卡进 24/48/64 三档;再看相机像素时钟是否超过采集卡收发器等级;最后确认采集卡是否支持所需的线缆根数和通道分组。三步里任何一步不过,换卡比调参便宜。

3. 端口分配不是顺序的:A~H 八个端口怎么落到真实像素

3.1 端口是 8 位逻辑字,和 TX/RX 引脚编号是错位的

这是 CameraLink 里最容易翻车的一处。直觉上端口 A 的 8 位应该接着串行器的 TX0~TX7,实际标准给的映射是打乱的:A0 接 TX/RX0、A1 接 1、A2 接 2、A3 接 3、A4 接 4、A5 接 6、A6 接 27、A7 接 5。B 端口更乱:7、8、9、12、13、14、10、11。C 端口:15、18、19、20、21、22、16、17。

为什么要这么排?因为 28 位信号在 PCB 上走线时,要兼顾串行器引脚顺序、连接器引脚顺序和差分对的分组,最终选了一个对布线最友好的方案,代价是逻辑位序被打散。这个映射由标准固定,改不了,只能在 FPGA 或采集卡固件里按表重排。

同组内端口复用也是这个逻辑:端口 D 与端口 A 共用同一批 TX/RX 引脚,端口 E 与 B 相同,端口 F 与 C 相同;第二组通道的 G、H 也一样复用 A、B 的引脚。所以「端口」是逻辑槽位,「引脚」是物理通道,一组 28 位里能塞下三个 8 位端口加 4 位控制,靠的就是这种复用。

3.2 从 1 tap 到 8 tap:像素怎么铺到端口上

单像素输出时只用了端口 A,像素的 bit0~bit7 依次落到 A0~A7。双 tap 时第一个像素走 A、第二个走 B。三 tap 走 A/B/C。这就是 Base 模式的上限。Medium 再加一组,D/E/F 承接第 4~6 个像素。Full 再加 G/H,凑到 8 个。

位深超过 8 位时,一个像素要跨两个端口。常见的 10 位、12 位相机会把低 8 位放一个端口、高位放另一个端口,剩余高位补零或填其他信息。这里没有强制规定,不同厂商的打包方式可能不同,必须以相机手册的「Pixel Format / Tap Geometry」章节为准。我见过一家相机把 12 位拆成「低 8 位在 A、高 4 位在 B 的低 4 位」,也见过反过来的,接错就是灰度值整体错位但图像轮廓还在,特别迷惑人。

3.3 用脚本把映射表生成出来,对帧格式时直接用

手工抄映射表容易出错,尤其是要写 FPGA 解串模块或者配置采集卡的端口重排寄存器时。下面这段把标准和常用 tap 配置一起生成,输出可以直接贴进约束文件或配置表:

# CameraLink 端口位 -> Channel Link 串行器引脚号(单组 28 位基准) PORT_PIN = { "A": [0, 1, 2, 3, 4, 6, 27, 5], "B": [7, 8, 9, 12, 13, 14, 10, 11], "C": [15, 18, 19, 20, 21, 22, 16, 17], } # 复用关系:第二组 G/H 与第一组 A/B 同引脚,D/E/F 同 A/B/C REUSE = {"D": "A", "E": "B", "F": "C", "G": "A", "H": "B"} # 视频使能与杂项位,同样落在 28 位里,不占像素端口 CTRL_PIN = {"Spare": 23, "LVAL": 24, "FVAL": 25, "DVAL": 26} def dump(mode_taps): """mode_taps: 每周期像素槽列表,如 ['A','B','C','D'] 表示 4 tap""" used = [] for idx, port in enumerate(mode_taps): base = REUSE.get(port, port) # 映射回复用前的基础端口 pins = PORT_PIN[base] used.append((idx, port, base, pins)) print(f"tap{idx} -> Port{port} (复用 {base}) 引脚: {pins}") # 校验:像素端口 + 控制位不能超过 28 total = len(mode_taps) * 8 + len(CTRL_PIN) assert total <= 28, f"位宽超限: {total} > 28,需要升一档模式" print(f"本组占用 {total}/28 位,剩余 {28 - total} 位") print("=== Base 3 tap 8bit ===") dump(["A", "B", "C"]) print("=== Medium 6 tap 8bit ===") dump(["A", "B", "C", "D", "E", "F"]) print("=== Full 8 tap 8bit(跨两组通道)===") dump(["A", "B", "C", "D", "E", "F", "G", "H"])

REUSE这个字典是关键,它体现「D 和 A 共用引脚」这条规则;assert那行是后悔药,tap 配多了会直接抛异常而不是悄悄生成一张错的表。实际对帧格式时,还要把每个 tap 的像素顺序和相机的 Tap Geometry 对齐,比如 4 tap 相机常见的排列是 A/B/C/D 或 A/C/B/D 交替,这个顺序错了图像会出现规律性条纹,肉眼一看就知道是排布问题而不是链路问题。

注意:G、H 只在 Full 模式的第三组通道上出现,且第三组只引出 16 位。写解串逻辑时如果按 8 个端口 × 8 位 = 64 位去分配缓冲区,第三组的高 8 位要显式填零或丢弃,否则拼出来的行会整体偏移。

4. 连接器、线缆与四条控制线:硬件侧最容易翻车的地方

4.1 26-pin MDR 的引脚分组:11 对差分怎么分

连接器用 26-pin MDR(Mini D Ribbon),针脚分配是标准固定的,临时拿别的连接器替代基本没戏。26 根针的分组逻辑是:第一组 Channel Link 5 对(4 数据 + 1 时钟)占 10 针,相机控制 CC1~CC4 共 4 对占 8 针,串口 SerTC/SerTFG 共 2 对占 4 针,剩下 4 针是内外屏蔽。

功能组差分对数说明
第一组 Channel Link54 对数据 + 1 对时钟,承载 A/B/C 端口
相机控制 CC1~CC44采集卡输出、相机输入,低电压差分
串行通信 SerTC/SerTFG2一发一收,异步串口
内屏蔽2 针推荐在相机端接数字地
第二组 / 第三组 Channel Link5 + 5只在第二根线缆上出现

第二根线缆的结构更简单:Medium 只用 5 对(第二组),Full 用 10 对(第二组 + 第三组),剩下的是屏蔽和空脚。所以 Full 模式的两根线缆不能随便互换——第一根带控制和串口,第二根纯数据,插反了相机连指令都收不到。

4.2 线缆选型只看三个参数:长度、屏蔽、双绞

标准给的边界是 10 米,实际工程里我一般按 3~5 米设计,超过 5 米就要开始怀疑。这不是保守,是 LVDS 在 85MHz 像素时钟下,7:1 串行化后单对线上的符号率已经到 595Mbps 量级,线缆的插入损耗和差分 skew 直接吃掉眼图余量。

选型看三点。长度:成品线有 1m、2m、3m、5m、7m、10m 几档,别自己剪线压接,MDR 的压接工艺对阻抗一致性要求很高,手工做的接头在 85MHz 下十有八九出问题。屏蔽:必须是双绞加整体屏蔽结构,每对差分线单独双绞,外层再包一层屏蔽,内屏蔽按标准推荐接相机侧数字地,采集卡侧通过 0Ω 电阻下地。双绞:时钟对和数据对不能随意并排走,时钟对要单独包地或者远离数据对,否则时钟串到数据对上就是全屏随机噪声。

没用到的差分对必须处理。标准明确推荐在两端各接 100Ω 终端电阻,因为悬空的差分对在高频下就是天线,反射回来的能量会耦合到相邻对上。Base 相机接 Full 采集卡时,第二、三组通道全悬空,如果采集卡侧没做内部终端,出图随机丢行几乎是必然的。

4.3 控制信号与串口:CC1~CC4 的默认含义和最小通信配置

4 对控制线是采集卡输出、相机输入,具体含义由相机制造商定义,但行业里有一套约定俗成的默认用法,调试时先按这个试:

信号常见定义有效电平/边沿
CC1外触发 EXSYNC下降沿触发一帧/一行
CC2像素重置 PRIN低电平有效
CC3扫描方向 FORWARD高电平正向,低电平翻转
CC4厂商自定义看手册

这套默认不是标准强制的,接上去没反应先别怀疑硬件,翻相机手册确认 CC 极性。我踩过一次 CC1 极性搞反的坑:触发信号发出去,相机一动不动,示波器量电平完全正常,最后发现相机要的是上升沿而采集卡默认下降沿,改个寄存器就好。

串口那边简单得多:2 对 LVDS,SerTC 是采集卡发、相机收,SerTFG 反过来。协议用异步串口格式,1 起始位、8 数据位、1 停止位、无校验无握手,最小波特率 9600。标准要求采集卡厂商提供 API 让用户通过动态库管理串口,同时建议提供一个终端程序,能收发字符串或短文件。实际用起来,多数采集卡会把相机串口映射成系统里的一个串口设备,或者封装成 SDK 里的 SerialPort 对象,两种都行,看厂商实现。

调试阶段建议先用 9600 波特率握手,通了再往上提。有些相机支持到 115200 甚至更高,但高波特率对线缆和终端匹配更敏感,链路本身还没验证稳的时候提波特率,出问题分不清是串口配置错还是物理层不行。

5. 避坑与排查:Base 相机插上 Full 采集卡为什么一片黑

5.1 现象:图像全黑或全零,帧有效信号一直不来

原因通常不在物理连接,在通道分组。采集卡默认按 Full 的三组通道轮询,第一组的 FVAL 来了但它还在等第二、三组的使能,拼帧状态机卡在半路。另一种情况是采集卡有「通道选择」参数,出厂默认 Channel 1,而相机接的是另一个物理口。

解决:先把采集卡配置改成 Base / 单通道模式,观察 FVAL 和 LVAL 是否出现。如果采集卡支持通道自动检测,让它跑一次自检;不支持的,手动指定第一组通道。确认出图后再逐级往上加模式,一次只改一个参数。

5.2 现象:图像整体正常但左右半幅错位,或者出现规律性的竖条纹

原因基本可以锁定在 tap 排布或端口位序。4 tap 相机常见两种几何:像素按 A/B/C/D 顺序轮转,或者 A/C 一组、B/D 一组交替。两种都合法,但采集卡的解析必须和相机一致。另一种是端口位序没按标准重排,直接按 TX/RX 顺序当成了 A0~A7,结果每个字节内部的位是乱的。

解决:用渐变测试图或者棋盘格图看错位规律。如果错位周期等于 tap 数,是 tap 几何问题,改采集卡的 tap 顺序参数;如果整幅图像的灰度值都不对但轮廓正确,是位序问题,按第 3 章的表重排。手边没有测试图的话,拿一张均匀灰卡,正常应该是一条直线,位序错了会出现阶梯。

5.3 现象:跑几分钟后开始随机丢行,重新插拔线缆能好一阵

这是典型的物理层余量不足。三种常见诱因:线缆超过 5 米、不是标准双绞屏蔽结构、没用到的差分对悬空没接终端。随机丢行的特点是跟温度和时间相关,冷机好好的,跑热了开始出,因为线缆损耗随温度上升。

解决:先换一根短的标准线缆排除线材,再把像素时钟降一档(85MHz 降到 66MHz)看是否消失,如果降频就好了,说明链路余量不够,要么换线要么降频。悬空对补 100Ω 终端,相机端和采集卡端都要。做完这三步还在丢,查一下相机和采集卡的供电地是不是同一路,地电位差大了 LVDS 共模范围会被顶出去。

5.4 现象:串口发指令没回应,或者回的是乱码

乱码优先查波特率和帧格式,没回应优先查线序和极性。CameraLink 的串口是交叉连接的:采集卡的 SerTC 输出接相机的串口输入,SerTFG 反过来,两端都标着 SerTC/SerTFG 但方向相反,画板子时接成同名对同名就废了。

解决:先用示波器或者逻辑分析仪抓 SerTC 上看有没有波形,没有就是采集卡侧没发出去,查 SDK 的端口号是否选对;有波形但相机不回,把 SerTC 和 SerTFG 对调试试。波特率从 9600 起步,帧格式固定 8N1,不要开流控——标准里根本没有硬件流控线。

5.5 现象:12 位相机在 Base 模式下图像高位丢失,灰度只有 0~255

常见误解是「Base 模式 24 位,12 位像素能跑 2 个 tap,肯定没问题」。问题出在打包方式:有些相机在 Base 模式下只启用端口 A 传低 8 位,高 4 位放在端口 B 的低 4 位,剩下的 4 位空着;采集卡如果按 16 位对齐去取,取到的就是错位的数据。

解决:翻相机手册的 Pixel Format 章节,确认 12 位是「低位对齐打包」还是「高位对齐打包」,在采集卡的像素格式里选对应项。实在找不到对应项,就自己在 FPGA 或上位机里做位移和拼接,用一张 12 位渐变的测试图验证,正常应该从 0 平滑到 4095,出现台阶就是位移量错了。

6. 上电前的五步核对:把像素时钟、tap 数与端口映射一次对平

链路调通之后,我把每次新项目的上电检查固化成了五步,顺序不能乱,因为后面每一步都依赖前一步的结论。第一步,确认相机输出的模式和 tap 数,读相机寄存器或者看铭牌,不要凭印象;第二步,按第 2 章的算法核一遍位宽预算,tap 数乘位深必须小于等于 24/48/64;第三步,确认采集卡的通道分组和线缆根数匹配,Base 一根、Medium/Full 两根,第二根只走数据;第四步,串口握手,9600 8N1 发一条读寄存器指令,能回就说明控制和通信链路都活着;第五步,才去跑图像,先用均匀光看直方图,再用渐变图看位序。

串口握手这一步可以脚本化,省得每次开终端敲:

import serial # 采集卡把相机串口映射成系统串口设备时,9600 8N1 无流控是最小可用配置 # Linux 下常见 /dev/ttyUSB0,Windows 下常见 COM3,按设备管理器/udev 实际改 def handshake(port, cmd: bytes, expect_len=8): with serial.Serial(port, baudrate=9600, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, timeout=0.3) as ser: ser.reset_input_buffer() ser.write(cmd) # 指令字节按相机手册的寄存器读命令填 resp = ser.read(expect_len) if not resp: print(f"{port}: 无回应,先查 SerTC/SerTFG 是否交叉、波特率是否一致") else: print(f"{port}: 收到 {len(resp)} 字节 -> {resp.hex(' ')}") return resp # 示例:读相机型号寄存器(字节内容以厂商手册为准,这里只演示调用结构) handshake("/dev/ttyUSB0", bytes([0x01, 0x00, 0x00]))

这段代码的价值不在功能,在把「有没有回应」这件事变成可重复的一行输出。timeout设 0.3 秒是有讲究的:太短了相机还没处理完就超时,太长了链路断了也要等半天才报错。reset_input_buffer是防止上一次残留数据混进来,调试阶段被这个坑过一次——缓冲里存着上次的半个响应,拼接出来像是相机回了乱码,白查了两小时线序。

还有一个小技巧值得记:验证端口位序不要用实拍图,用相机自带的测试图发生器(很多工业相机内置渐变、棋盘格、灰阶几种图案)。图案是相机内部生成的,不经过镜头和光照,出问题就 100% 是链路和解析的问题,把变量砍掉一半。我一般先用水平渐变看位序,出现阶梯就是位移错;再用棋盘格看 tap 几何,错位周期等于 tap 数就说明排布对不上。

从那以后我每次接新相机,不管对方说得多肯定,上电前都强制走一遍这五步,尤其是第二步的位宽预算,用脚本算一遍只要十秒钟,比事后怀疑人生划算得多。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询