做嵌入式图像采集这些年,我经手过不少 MIPI 接口摄像头转 USB 的方案。早几年最顺手的组合就是 CYUSB3014 加一颗小规模 FPGA:FPGA 负责解 MIPI CSI-2 的包,把并行数据灌给 FX3 的 GPIF II 接口,再通过 USB 3.0 发给上位机。后来 Cypress 把 MIPI CSI-2 接收器直接做进了 CYUSB3065 这颗芯片,原本要靠 FPGA 折腾的活被一颗芯片全包了,板上从“两片大山”变成“一片搞定”。这篇文章就从我实际做过的两代方案说起,把 MIPI CSI-2 转 USB 3.0 图像采集的硬件设计、PCB 布线、固件配置和调试经验完整梳理一遍,给正在做类似项目的工程师一个参考。
1. 为什么放弃 FX3+FPGA,转投 CX3 方案
1.1 FX3 方案的构成与痛点
CYUSB3014(也就是常说的 FX3)是一颗非常优秀的 USB 3.0 外设控制器,内置 ARM926EJ-S 内核,最大的特色是那个可以灵活配置的 GPIF II 接口,支持同步从 FIFO、SRAM、异步 ADMUX 等多种模式。但 FX3 本身只有并行接口,没有 MIPI CSI-2 接收能力,所以接 MIPI 传感器必须要做一次协议转换。常见的做法是加一颗 FPGA 或 CPLD,让 FPGA 去完成 MIPI 物理层接收、协议层解包、行缓存和并行数据输出,然后再给 FX3 的 GPIF II 灌数据。
这种方案的“痛”做过的人都知道:FPGA 硬件设计要考虑 DDR 引脚、Bank 电压、MIPI IP 核授权,逻辑代码要处理跨时钟域、FIFO 深度和 GPIF II 时序,调试时逻辑分析仪一接就是十几根线,想把某一帧数据抓下来看异常非常麻烦。而且一片像样的小规模 FPGA 也要几十块人民币,加上配置 Flash、时钟管理,BOM 和 PCB 面积成本都上去了。功耗和发热在紧凑型相机里也是个问题。
我自己第一版方案就是 FX3+FPGA,板子面积做到了 40mm x 40mm 以内,但为了把 FPGA 和 FX3 的走线理清楚差不多改了三次版。第一次是 FPGA 的 MIPI 引脚分配不合理,导致 Bank 电压冲突,电平标准配不了;第二次是 GPIF II 的布线跨分割了,导致同步从 FIFO 时序不稳定,偶尔图像撕裂;第三次才勉强跑稳 1080p30。吃力,但也能用。
1.2 CX3 的集成优势到底在哪
CYUSB3065(CX3)是 Cypress 专门为图像采集应用推出的型号,核心思路很简单:把 FX3 的 GPIF II 输入端替换成 MIPI CSI-2 接收器,其余 USB 3.0 协议栈、DMA、ARM 内核基本沿用 FX3 的框架。
CX3 内部的 MIPI CSI-2 接收器支持 D-PHY v1.1 规范,可配置 1/2/4 lane,每个 lane 最高 1.5Gbps,支持 RAW8、RAW10、RAW12、YUV422、RGB888 等常见数据类型,还内置了虚拟通道(Virtual Channel)识别。传感器通过 MIPI 接口直接连到 CX3,CX3 通过 I2C 总线去配置传感器寄存器,数据经内部 DMA 路径直接送往 USB 3.0 端点。没有 FPGA 参与,代码层面也简单很多。
这块方案的直接收益是 BOM 精简、PCB 缩小、开发周期变短,调试时也不需要同时维护 FPGA 和 FX3 两套工具链。如果你做的是 USB 工业相机、内窥镜、显微镜、医疗影像这类产品,CX3 是更贴合“图像采集”这个主线的选型。
下表是我在项目中最直观的对比:
| 维度 | FX3 + FPGA | CX3(CYUSB3065) |
|---|---|---|
| MIPI 支持 | 需外部 FPGA 实现 | 内置 CSI-2 接收器 |
| BOM 成本 | 高(FPGA+Flash+时钟) | 低 |
| PCB 面积 | 大 | 小 |
| 开发复杂度 | 高(FPGA+ARM 双平台) | 中等(单 ARM 平台) |
| MIPI 调试难度 | 高 | 相对低,但仍有坑 |
| 灵活性 | 高(可做预处理) | 中(上游无处理逻辑) |
| 量产可靠性 | 取决于 FPGA 逻辑 | 较高 |
1.3 选型建议:不要盲目跟风
如果你只是要从 MIPI 传感器拿图像到 PC,没有复杂的预处理需求,那 CX3 几乎是更优解。但如果传感器是并口、Sub-LVDS 这类非标准接口,或者你需要在采集端做降噪、坏点校正、图像拼接等预处理,那 FX3+FPGA 这条路绕不开,FPGA 的并行处理能力仍然是 CX3 替代不了的。
还有一点要提醒:CX3 的 MIPI 接收和 DMA 路径是为“视频流”设计的,数据从 MIPI 进来的直接走硬件 DMA 通道到 USB 端点,ARM 内核基本不碰像素数据,这点和 FX3 完全一样。但如果你采集的不是连续图像而是单帧触发数据,MIPI 的帧同步事件和 DMA 缓冲策略就要多花些心思配置,不然容易丢失首帧或尾帧。
2. 硬件架构设计:先画好系统的骨架
2.1 系统级架构
CX3 方案的硬件结构比 FX3 时代清楚得多。传感器模组的 MIPI 差分对直接连到 CX3 的 MIPI_RX 引脚,通常至少 4 对数据 lane 加 1 对时钟 lane,一共 5 对差分线。CX3 的 I2C 主机接口连接传感器的 SCL/SDA,用于读写寄存器。GPIO 则负责传感器的复位、电源使能、闪光灯同步这类控制信号。USB 3.0 一侧,CX3 通过 SS_TX/SS_RX 差分对连接到 USB 3.0 连接器,另外还要保留 D+/D- 这些 USB 2.0 信号线,因为即便设备跑在 SuperSpeed 模式,USB 2.0 通道也必须物理连通,否则主机根本不会识别设备。
电源部分需要同时兼顾 CX3 和传感器两边的需求。CX3 的主要电源轨有 3.3V 的 IO 电源、1.2V 的核心电源、1.2V 的 MIPI PHY 模拟电源,以及 USB PHY 相关的电源。传感器一般需要 AVDD、DOVDD、DVDD 三路供电,电压可能是 2.8V/1.8V/1.2V 或根据型号而定。时钟方面,CX3 需要一颗 19.2MHz 的晶振作参考时钟,传感器则一般需要一颗主时钟(MCLK),可以由 CX3 的 CLKOUT 引脚提供,也可以单独放晶振。
2.2 供电设计与上电时序
先说 CX3 自身的电源。MIPI PHY 的模拟电源(VDDA_1P2)是整板最敏感的一路,纹波和噪声会直接反映在 MIPI 信号的眼图上。我见过一个案例,有人图省事用 DC-DC 给这路供电,结果 MIPI 眼图一塌糊涂,图像丢帧丢到没法看。后来换成低噪声 LDO 之后瞬间正常。我的原则是:PHY 模拟电源必须用 LDO,并且滤波电容要贴近芯片引脚,至少 4.7uF 加 0.1uF 的组合,必要时再串一颗磁珠隔离。
传感器的上电时序是关键且容易被忽略的坑。很多传感器数据手册里会画出严格的上电顺序,比如先 DVDD、再 DOVDD、最后 AVDD,间隔至少几百微秒。如果你用单个可调电源同时拉三路,没有做时序控制,芯片 ID 读出来会时好时坏,甚至完全没响应。我第一版板子就吃过这个亏,为了省一个电源管理芯片,结果在时序问题上折腾了三天。
推荐做法是:用带 Power Good(PG)输出的 LDO 做级联控制,上一路电源稳定后再使能下一路,或者在每路电源的 EN 引脚上接 RC 延时电路,调整延时值来满足上电顺序。量产产品更建议直接选用专用的电源时序控制芯片,像 TPS65730 这类 PMIC,省心很多。
2.3 时钟、复位与启动模式
CX3 的参考时钟是 19.2MHz 晶振,负载电容根据晶振厂家的规格来选,通常在 6pF 到 12pF 之间。晶振精度建议在 20ppm 以内,不然 USB 3.0 的 SS 链路训练可能会因为频率偏移而失败,症状就是设备只能枚举成 USB 2.0。晶振走线要短,尽量靠近 XI/XO 引脚,走线包地处理,底部对应层不要布线。
复位和启动模式也是 PCB 设计阶段就要预留好的。CX3 的 XRESET 引脚是低电平有效复位,一般用一颗 10kΩ 电阻上拉到 3.3V,再接一个 0.1uF 电容到地做上电延时复位。PMODE[2:0] 三个引脚决定启动方式:USB Boot、I2C Boot(EEPROM)、SPI Boot(Flash)。开发阶段通常用 USB Boot,把固件直接加载到 RAM,掉电就没了;量产则用 SPI Boot,固件烧写到板载 SPI Flash 里,上电后自动加载。
这里有个隐藏坑:PMODE 引脚在 PCB 上一定要用电阻明确拉高或拉低,不能悬空。我有一版样板就是 PMODE 悬空,结果部分板卡在 USB Boot 和 I2C Boot 之间随机选择,量产测试时枚举不稳定,排查了很久才发现是这个原因。后来把所有 PMODE 引脚都通过排阻显式配置,问题彻底消失。
2.4 MIPI CSI-2 链路与 I2C 控制
MIPI CSI-2 的信号由 1 对时钟 lane 和 1 到 4 对数据 lane 组成,全部是差分信号。CX3 内部已经集成了接收端的偏置和终端电路,PCB 上一般不需要额外并联 100Ω 差分终端电阻。如果你在板上放了额外的端接电阻,反而可能让等效阻抗变低,导致信号反射,这种画蛇添足的做法不建议使用,除非你仔细核对过数据手册明确要求。
I2C 控制链路的电平需要和传感器匹配。现在的传感器大多支持 1.8V 或 3.3V 的 IO 电平,CX3 的 I2C 引脚电平取决于 VDDIO 的电压。如果传感器是 1.8V 而 CX3 IO 是 3.3V,就需要做电平转换。I2C 总线的上拉电阻一般在 2.2kΩ 到 4.7kΩ 之间,400kHz 速率下太小会下拉困难,太大则上升沿过缓,容易产生通讯错误。实际调试时可以先用逻辑分析仪看波形,再微调上拉阻值。
3. PCB 设计:高速信号马虎不得
3.1 MIPI 差分对的布线实践
MIPI 高速信号对 PCB 布局布线的要求很高,这也是我在 FX3 时代就养成的习惯:MIPI 信号绝对不跨分割、不过太多孔、不和数字信号并行走。差分阻抗要控制在 100Ω ± 10% 的范围内,具体线宽线距要根据板厂的叠层参数计算,比如 6 层板、L1 到 L2 介质厚度约 4mil 的情况下,4.5mil 线宽、7mil 间距(中心距 12mil)才能接近 100Ω。
组内等长(时钟 lane 或同一数据 lane 的 P/N 之间)要控制在 ±5mil 以内,组间(各 lane 之间)尽量控制在 ±20mil 以内。如果必须换层,过孔旁边一定要放地过孔,为回流信号提供完整的参考路径。我第一次做 CX3 板子时,MIPI 时钟线换层没有加地过孔,结果偶尔丢帧,眼图也有明显闭合,补上地过孔后问题消失。
CX3 是 BGA 封装,MIPI 引脚扇出时要特别注意:优先让 MIPI 信号走在顶层,通过激光盲孔下到内层再走线,尽量避免在 BGA 下方穿越和干扰。如果走线需要跨到另一层,务必保留完整的地参考平面,不要在 MIPI 区域下方布置其他数字信号线,特别是 I2C、GPIO 这类翻转频繁的控制线。
3.2 USB 3.0 高速线布局
USB 3.0 的 SS_TX/SS_RX 差分阻抗要求是 90Ω ± 10%。TX 对和 RX 对之间要保持足够的间距,至少 3 倍线宽以上,避免串扰。每对差分线上需要放置 0.1uF 的 AC 耦合电容,这个电容要放在靠近连接器一侧,并且两条线上的电容位置要对称,否则会造成相位偏移,影响链路信号完整性。
一个常见的接法是:CX3 的 SS_TX 接到连接器的 RX 引脚,CX3 的 SS_RX 接到连接器的 TX 引脚。听起来很简单,但实际画板时很多人会搞反,尤其是连接器库封装不规范的时候。我建议画完原理图后,对照连接器数据手册逐一核对引脚定义,不要想当然。USB 2.0 的 D+/D- 也要按 90Ω 差分阻抗布线,虽然速率只有 480Mbps,但为了保证兼容性,还是按高速信号对待。
连接器的外壳地建议通过 1MΩ 电阻并联 1nF 电容接到数字地,这种做法兼顾 ESD 泄放和 EMI 抑制。USB 连接器附近要放 TVS 防护管,D+/D- 和 SS_TX/RX 每一对都要保护,我见过不少板子省掉 ESD 器件,结果生产和使用中端口被静电打坏。
3.3 电源平面、去耦电容与地完整性
模拟电源和数字电源的地平面不要分割,这一点要反复强调。很多人习惯把模拟地和数字地在 PCB 上用一条线隔开,然后用磁珠连接,这在低频电路里是可行的,但在 MIPI PHY 这个场景下,地平面一旦分割,高速回流信号就没有了连续路径,眼图一定会恶化。正确做法是地平面保持完整,模拟电源通过磁珠或 0Ω 电阻和数字电源隔开,滤波电容就近、低阻抗地回到芯片地引脚。
去耦电容的布置原则是“就近、低感”。每个电源引脚旁至少放一颗 0.1uF 的电容,板级电源入口处再放 10uF 左右的钽电容或大容量 MLCC。MIPI PHY 和 USB PHY 附近的去耦要更加密集,因为这些区域瞬态电流大、频率高,如果去耦不到位,电源纹波会直接调制到高速信号上。
DC-DC 电感的摆放也要注意,电感会产生交变磁场,如果太靠近 MIPI 或 USB 差分线,会引入周期性的噪声干扰。如果空间无法避免,至少要在电感和高速信号线之间加地平面屏蔽,或者把电感放在另一面。
4. 固件与配置:把硬件的潜力释放出来
4.1 开发环境与工程框架
CX3 的开发环境还是用 EZ-USB FX3 SDK,老用户会觉得很亲切。SDK 里包含 CX3 专用的 MIPI 配置工具,可以用图形界面配置 lane 数、数据率、数据类型、分辨率等参数,然后自动生成 C 代码,省去手写 CSI-2 寄存器配置的繁琐。开发阶段通常从 UVC 示例工程开始,把它当成骨架,再改动描述符和传感器初始化部分。
CX3 的固件框架和 FX3 一样,核心是 Cypress 提供的 RTOS(ThreadX)和 API 库。初始化流程一般是:启动系统、配置 IO、配置时钟、配置 USB(CyU3PUsbStart)、配置 MIPI 接收(UVC 工程中会自动做)、配置 DMA 通道、注册事件回调。开发时用 USB Boot 加载固件到 RAM 调试,修改代码后重新加载,整个过程几分钟就能完成,效率很高。
量产阶段需要把固件烧写到板载 SPI Flash。CX3 可以从 SPI Flash 启动,上电后引导加载程序把固件搬运到 RAM 运行。SPI Flash 选型一般是 W25Q16 这类 16Mbit 的型号,容量足够放下 UVC 固件。烧写工具可以用 SDK 里的 Control Center,也可以把烧写功能集成到你自己的上位机工具里,方便产线批量烧录。
4.2 MIPI CSI-2 配置关键参数
MIPI 配置的核心是 Csi2Config 结构体,里面有几个参数必须精确匹配传感器输出:laneCount、dataRate、pixelFormat、parallanFactor(也可以是类似的像素位数配置)、分辨率、行长度、帧间隔。
最关键的是数据率的计算。以 1080p60 YUV422(每像素 16bit)为例:
- 原始像素数据量:1920 × 1080 × 60 × 16 / 8 = 248,832,000 字节/秒,约 237.3 MB/s。
- MIPI CSI-2 协议在每行、每帧还要加入包起始码、行有效数据、帧结束码、CRC 等开销,实测一般要再加上 5% 到 10%。
- 如果选择 4 lane MIPI,每 lane 需要的数据率大约是:237.3 × 8 × 1.1 / 4 ≈ 522 Mbps。这个数值远低于 1.5Gbps 的 lane 上限,说明 1080p60 YUV422 用 4 lane 是余量充足的,甚至 2 lane 也能跑。
- 反过来,如果你要做 4K30 RAW10,换算下来 3840 × 2160 × 30 × 10 / 8 ≈ 310.7 MB/s,加上开销后约 342 MB/s,MIPI 侧要用 4 lane 且每 lane 速率约 750 Mbps,USB 侧也要注意实际带宽余量。
pixelFormat 和数据类型(DT)要严格对应,比如 RAW10 对应 0x2B,YUV422-8bit 对应 0x1E,RGB888 对应 0x24。这一项配错了,图像到 PC 端不是花屏就是颜色完全错乱。另外 CX3 的 UVC 设备描述符里也会声明格式,二者必须保持一致。
4.3 传感器初始化与 I2C 调试
传感器初始化是整套系统里最容易出问题的环节。以 OV5640 为例,它的 I2C 7 位地址默认是 0x3C,寄存器地址是 16 位,写操作需要先发送寄存器高字节、寄存器低字节,再发送数据字节。如果你按 8 位寄存器地址的方式去写,传感器根本不会响应。
调试 I2C 的第一步永远是读取芯片 ID。OV5640 的 chip ID 寄存器是 0x300A 和 0x300B,读出来应该分别是 0x56 和 0x40。只要这一步通过,说明 I2C 物理链路、地址模式和传感器供电都是正常的。读不到 ID 时,优先检查传感器供电、MCLK 是否存在、复位引脚是否释放、I2C 上拉是否到位。
传感器的初始化序列一般很长,几十上百行寄存器写入很常见。建议把初始化脚本放到一个结构体数组里,每条包含寄存器地址和值,固件启动时循环写入,并在关键步骤之间加入延时,特别是 PLL 配置、输出格式切换这类寄存器,写完后要留出稳定时间。我习惯先让传感器输出测试图(Test Pattern),验证 MIPI 通路和 USB 链路都正常后,再切回真实图像,这样排查问题能省很多时间。
4.4 UVC 描述符与数据通路
UVC(USB Video Class)设备之所以能被 Windows、Linux、macOS 免驱识别,靠的就是标准描述符。描述符里要定义视频控制接口(VideoControl)和视频流接口(VideoStream),视频流接口中还要列出所有支持的分辨率、帧率、格式组合。1280x720p30、1920x1080p30、1920x1080p60 这些组合必须逐一声明,否则主机侧的应用就选不到对应模式。
数据通路上,CX3 的 MIPI 接收器把数据写到 DMA 缓冲区,再由 DMA 引擎搬运到 USB 端点。DMA 缓冲区的数量和大小需要权衡:太少了可能造成下溢(缓冲区空导致 USB 传输中断),太大了又占用 RAM。固件示例工程里默认配置通常可以满足 1080p60 的带宽需求,实测不够时优先调整 DMA 描述符的数量和大小,而不是盲目去改 MIPI 侧参数。
USB 3.0 的 Bulk 端点实测带宽在 PC 上一般能到 380~420MB/s,比 USB 2.0 时代不到 40MB/s 的可用带宽高了一个数量级,所以 1080p60 YUV422 在 USB 3.0 上完全不是问题。但如果设备只枚举成 HighSpeed(USB 2.0),带宽就只有约 35~40MB/s,1080p30 YUV422 都勉强,这时就要检查为什么 SS 链路训练失败。
5. 调试实录:从一片寂静到图像流畅
5.1 上电第一步:先量电源,别急着跑固件
很多新手拿到板子第一件事就是插上 USB 开跑,结果枚举失败、图像不出,就开始怀疑芯片坏了。我的习惯是上电后先拿示波器把电源轨挨个量一遍:3.3V 是否到位、纹波多少、1.2V 核心电源是否稳定、上电顺序是否满足手册要求。MIPI PHY 的模拟电源在高速传输状态下纹波最好控制在 20mV 以内,如果超过这个值,后面图像丢帧基本是可以预见的。
接着量 19.2MHz 晶振是否起振,用示波器看频率、幅度和波形质量。晶振不起振或者频率偏移过大,USB 3.0 的 SS 链路就可能训练失败,设备只能识别为 USB 2.0。实测中我遇到过晶振负载电容选错导致频率偏了 200ppm,主机端时好时坏,最后换了正确的负载电容才稳定。
电源和时钟确认没问题后,再检查复位:测量 XRESET 引脚在上电后是否从低电平变高电平,复位时间是否符合数据手册要求。如果复位不释放,芯片会一直停留在复位状态,USB 根本枚举不出来。
5.2 I2C 链路调试:先让传感器“开口说话”
电源时钟复位都正常,下一步就是把传感器先调到“开口说话”的状态。我的做法是在 CX3 固件里加一段临时代码,或者用 Cypress 的调试工具直接发 I2C 命令,读取传感器的 ID 寄存器。只要能读到正确的 ID,I2C 链路就是通的,可以继续配置传感器。
读不到 ID 时的排查顺序是:传感器 AVDD/DOVDD/DVDD 是否都正常、MCLK 是否有时钟波形、复位引脚是否释放、I2C 上拉是否连接、传感器地址是否正确(有些传感器有多个可选地址,取决于 ADDR 引脚电平)、地址模式是 16 位还是 8 位寄存器。
如果 I2C 总线上有多个设备,还要检查地址冲突。用逻辑分析仪抓 SCL/SDA 波形,能看到 START、地址字节、ACK/NAK 信号。如果波形一直停在高电平没有时钟,可能是 I2C 总线被挂在某个设备上,这时可以尝试给 I2C 设备单独断电再上电。
5.3 MIPI 信号测量:眼图、电平和 LP 状态
MIPI 信号的测量需要 1GHz 以上带宽的示波器和差分探头,普通 500MHz 探头很难看到真实信号质量。重点量时钟 lane 的眼图:HS 模式下差分摆幅一般在 150~300mV 之间,眼图张开度要足够大,上升沿和下降沿要陡峭。如果眼图明显闭合,优先怀疑阻抗不连续、参考平面断裂、电源噪声过大。
如果没有差分探头,可以用单端探头测 P 或 N 对地的波形作为参考,但这样测出来的幅度是差分摆幅的一半,且包含共模分量,不能完全反映真实信号质量,只能作定性判断。
MIPI D-PHY 在空闲时进入 LP-11 状态(时钟和数据 lane 都是高电平),如果看到 LP 状态异常,比如某一根线一直为低,多半是物理连接错误或芯片配置问题。CX3 还支持 MIPI PHY 测试模式,可以发送固定 pattern 来验证接收通路,但实际项目里更常用的是让传感器输出 Test Pattern,然后观察主机端收到的图像,这种方法能一次性验证 MIPI 通路、DMA 通路、USB 通路和 UVC 描述符,效率很高。
5.4 USB 枚举失败排查流程
USB 枚举失败是排查难点,但也是有章可循的。常见症状不外乎几种:插入无任何反应、识别为 Unknown Device、枚举为 USB 2.0 而不是 USB 3.0、枚举成功但加载不了驱动。
先查硬件层面:VBUS 是否有 5V,USB 连接器是否虚焊,D+/D- 是否连通,SS_TX/RX 是否在 CX3 和连接器之间接对了方向,AC 耦合电容是否焊接正常。USB 3.0 设备必须同时有 USB 2.0 的 D+/D- 通道,如果 D+/D- 没有连好,主机根本不会识别设备。
软件层面:确认固件里是否调用了 CyU3PUsbStart、是否注册了事件回调、设备描述符中的 VID/PID/class code 是否正确。用 Cypress 的 UsbControlCenter 可以看到设备枚举在哪个阶段失败,或者用 USB 协议分析仪抓取枚举包,看设备是否能响应主机发送的标准请求。
如果设备枚举成 USB 2.0 而不是 SuperSpeed,大概率是 SS 链路训练失败,最常见的原因是 SS_TX/RX 接反、AC 耦合电容缺失、阻抗不匹配、参考时钟频率漂移。链路训练过程发生在物理层,固件基本无法干预,只能靠硬件排查。
5.5 花屏、丢帧、帧率低的定位思路
花屏通常不是随机故障,而是配置不一致导致的。图像像楼梯一样斜切,几乎可以肯定是行长度(Line Length)配置错误;颜色乱但轮廓清晰,是像素格式(DT)或 UVC 描述符格式不匹配;图像有绿色或粉色条带,可能是 RAW 和 YUV 的位宽错误。排查时先切到低分辨率低帧率(比如 320x240),确认通路正常后再逐步升分辨率,这样能快速定位问题出在数据格式还是带宽。
丢帧则需要看带宽余量。如果 MIPI 数据率刚好超过 USB 实际可用带宽,丢帧是必然的。实测 USB 3.0 Bulk 带宽受电脑主机、线缆、驱动影响很大,有的机器只有 300MB/s 甚至更低。这时要么降低分辨率/帧率,要么压缩数据格式(比如从 YUV422 换成 MJPEG),而不是盲目加大 DMA 缓冲。
帧率异常还有一个非常隐蔽的原因:UVC 描述符里声明的帧间隔(dwFrameInterval)和传感器实际输出帧率不一致。比如传感器实际输出 30fps,但描述符写成了 15fps,主机按描述符的帧间隔计时,图像就会看起来像慢动作,实际传输带宽却是够的。这种问题用 USB 分析仪抓取视频流端点就能看出来。
6. 经验之谈:几次翻车教我的事
6.1 三个印象深刻的坑
第一个坑是 PHY 模拟电源用 DC-DC。样板为了省成本用小型 DC-DC 给 VDDA_1P2 供电,结果 MIPI 眼图极为难看,图像丢帧严重。换回低噪声 LDO 后问题消失。从那以后,所有涉及 MIPI/USB PHY 的模拟电源,我一律用 LDO,而且在线路上预留磁珠位置,方便需要时再加隔离。
第二个坑是 PMODE 引脚悬空。刚开始设计时觉得 PMODE 是配置引脚,不用管它,结果生产了 50 块板子,其中 6 块枚举不稳定,时好时坏,一直以为是焊接问题。后来用万用表量到 PMODE 引脚电压在临界值附近随机漂移,才知道是启动模式在“跳”。把所有 PMODE 引脚用排阻显式固定后,故障率降为零。
第三个坑是 MIPI 时钟线换层没有地过孔。这个坑排查了整整两天,症状是图像偶尔丢帧,每次丢帧的间隔没有规律。用近场探头扫 MIPI 区域,发现时钟线跨层位置有明显的辐射尖峰,补了一个地过孔后尖峰消失,丢帧不再出现。高速信号换层时,回流路径的连续性比你想的更重要。
6.2 如果重新设计一次,我会改哪些
如果重来,我会在 PCB 上给所有关键信号加测试点:三路传感器电源、19.2MHz 时钟、MIPI 时钟 lane、I2C 的 SCL/SDA、CX3 的 XRESET、PMODE 各引脚。调试时省了拿万用表到处找点的功夫,效率提升明显。
I2C 总线上我会预留两种上拉电平的位置,兼容 1.8V 和 3.3V 传感器,因为项目中途换传感器型号是常有的事,有了预留就不需要改版。USB 连接器附近一定会加 ESD 保护,D+/D-、SS_TX/RX 四对信号全部加 TVS,生产测试时静电打坏端口这种事,一次都嫌多。
还会在 CX3 旁边留一颗小的 MCU 或者 FPGA 辅助调试,用来做 MIPI 包统计、I2C 抓包、GPIO 控制这类事。量产固件不需要它,但开发调试周期里能省非常多时间,这种投入完全值得。
6.3 后续还可以怎么扩展
CX3 方案稳定之后,扩展方向其实很多。多目同步就是其中一个方向,多个 CX3 用同一路外部触发信号做帧同步,可以拼出全景相机或者双目视觉系统。深度相机也是一个热门方向,用 CX3 接 ToF 传感器,深度数据可以通过 UVC 扩展单元(Extension Unit)打包传给主机,上位机不用装私有驱动。
如果要接的传感器数量多、每路带宽高,还可以考虑“FPGA 汇聚 + CX3 输出”的架构,FPGA 做多路 MIPI 汇聚和 ISP 前处理,CX3 只负责 USB 3.0 传输通道。这种组合保留了 FPGA 的灵活性和 CX3 的 USB 协议栈稳定性,算是比较成熟的工业级方案。
做硬件设计这件事,踩坑不可怕,可怕的是踩完不知道怎么改。我这几块板子做下来,最大的体会是:方案选型决定上限,电源和 PCB 决定下限,固件调试决定能不能交付。CX3 把 FPGA 省掉了,但该较真的地方一样都跑不掉。如果你正好在 MIPI CSI-2 转 USB 3.0 这条路线上打转,希望这篇记录能帮你少折腾几个通宵。以后有空,我再把多目同步和基于 UVC 扩展单元做深度数据的坑也整理出来。