
MIPI 摄像头这几年在嵌入式视觉项目里几乎是默认选项手机模组产业链成熟、分辨率高、体积小、功耗低随手一抓就是几百万像素的现成方案。但真到项目里把两路、四路甚至更多 MIPI 摄像头同时接进来很多人第一反应是找个多路输入的 SoC 不就完了。问题在于通用 SoC 的 MIPI 输入通道数量、CSI 控制器带宽、以及多路并发时的调度能力往往卡得死死的尤其是工业检测、环视拼接、多目立体视觉这类场景四路 1080p60 同时进来SoC 侧要么丢帧要么直接跑不动。这时候 FPGA 的价值就出来了——它不挑通道数CSI-2 协议可以自己解DDR 带宽可以自己算多路聚合的调度逻辑完全掌握在自己手里。这篇内容面向的是已经摸过 FPGA、做过图像采集、但对 MIPI 多路聚合还没有完整落地经验的工程师。我会把FPGA MIPI 多路视频聚合方案这件事从物理层一直讲到 DDR 调度和输出重点讲清楚每一层为什么这么设计、参数怎么算、坑在哪里。不是教科书式的协议复述而是我实际做过多路 MIPI 聚合项目之后觉得真正值得写下来的东西。1. 多路 MIPI 聚合到底难在哪先看清问题的全貌1.1 单路 MIPI 采集和四路聚合复杂度不是一个量级单路 MIPI 采集的典型链路是摄像头模组输出 MIPI D-PHY 差分信号FPGA 的 MIPI 硬核或 SelectIO 接收解出 CSI-2 包提取像素数据写进 DDR 或者直接送显示。这条路走通之后很多人会觉得多路不就是复制四份吗。实际做下来会发现复制四份带来的不是线性增长的工作量而是几个维度的复杂度同时爆炸。第一是物理层通道数。一路 MIPI 通常 2 lane 或 4 lane四路就是 8 到 16 对差分线。FPGA 的 MIPI 硬核数量有限比如某些器件只有两组 D-PHY 硬核四路就得靠 SelectIO 软实现或者用外部桥接芯片。第二是 CSI-2 协议解析的并发。四路摄像头各自独立出包包长、帧率、时序都不同步解析状态机必须完全独立不能共用。第三是 DDR 带宽和仲裁。四路 1080p60 RAW10 的数据率算下来接近 4 Gbps加上读写开销DDR 的有效带宽必须留足余量。第四是输出侧的聚合格式是把四路拼成一个大画面还是分时轮询输出还是各自独立通道直接决定了后端架构。很多人低估了多路这两个字。单路调通可能两周四路稳定跑起来可能要两个月多出来的时间基本都花在时序收敛、带宽核算和跨时钟域处理上。1.2 先算清楚带宽账再决定架构做多路聚合之前第一件事不是画框图而是算带宽。以四路 1080p60、RAW10 为例单路像素时钟是 148.5 MHz每像素 10 bit单路数据率是 148.5M × 10 1.485 Gbps。四路合计 5.94 Gbps。这是有效像素数据率但 MIPI CSI-2 还有协议开销包头、包尾、ECC、CRC、行消隐实际 D-PHY 上的线速率要乘一个 1.2 到 1.3 的系数。所以四路 D-PHY 总吞吐大概在 7 到 7.7 Gbps。这个数字决定了几个关键选型。DDR 侧如果写进 DDR3理论带宽要按数据率的 2 倍以上留余量读写各占一半也就是 DDR 有效带宽至少 12 Gbps 才比较从容。DDR3-1600 的 16 bit 位宽理论带宽是 1600M × 2 × 16 51.2 Gbps看起来够但实际有效带宽受刷新、bank 冲突、仲裁影响能到 60% 到 70% 就不错了所以 16 bit DDR3 跑四路是够的但如果你还要同时读出来做拼接显示读写叠加就要重新算。路数分辨率帧率单路数据率四路合计D-PHY 线速率估算2 路1080p601.485 Gbps2.97 Gbps约 3.8 Gbps4 路1080p300.7425 Gbps2.97 Gbps约 3.8 Gbps4 路1080p601.485 Gbps5.94 Gbps约 7.5 Gbps4 路4K305.94 Gbps23.76 Gbps约 30 Gbps从表里能看出来四路 4K 就是另一个世界了DDR 和 D-PHY 都要重新选型。所以架构设计的第一步永远是明确分辨率和帧率别上来就谈方案。1.3 聚合的三种典型形态多路聚合不是只有一种做法实际项目里常见三种形态选错了后面全是返工。第一种是空间拼接四路画面拼成一个 2×2 的大画面输出。这种形态对 DDR 的读写模式最友好因为每路写进 DDR 的固定区域读出来的时候按行扫描地址连续突发效率高。缺点是拼接边界要做同步四路帧必须对齐否则拼出来会有撕裂。第二种是分时轮询四路轮流输出到同一个显示通道比如每路显示 1/4 秒。这种对带宽要求最低但实时性差适合监控类应用。第三种是独立通道四路各自独立输出到不同的后端比如四路分别送四个编码器。这种对 FPGA 资源要求最高但灵活性最好。选哪种形态取决于后端是显示、编码还是进一步处理。我做过的一个工业检测项目用的是空间拼接因为后端是一块大屏操作员要同时看四个工位。另一个车载项目用的是独立通道因为四路要分别送不同的算法模块。2. D-PHY 物理层接收从差分信号到字节流2.1 硬核 D-PHY 和 SelectIO 软实现的取舍FPGA 接收 MIPI D-PHY有两条路。一条是用器件自带的 MIPI D-PHY 硬核比如某些 FPGA 系列集成了专门的 D-PHY 接收器支持 HS 和 LP 模式时序由硬核保证你只需要配置 lane 数和速率。另一条是用普通 SelectIO 加 IDELAY、ISERDES 软实现靠 oversampling 或者源同步来恢复数据。硬核的优点是省心HS 模式下的 skew、deskew、字节对齐都由硬核处理你拿到的基本是干净的字节流。缺点是数量有限一个器件可能只有一两组四路就不够用。软实现的优点是通道数不受限只要 IO 够想接几路接几路。缺点是 HS 速率上不去一般软实现能稳定跑到 800 Mbps 到 1 Gbps 每 lane 就不错了再高对 IDELAY 校准和时钟相位要求非常苛刻。我实际项目里的做法是混合两路用硬核两路用 SelectIO 软实现。这样既保证了高速路的稳定性又扩展了通道数。软实现那两路跑的是 1080p30每 lane 500 Mbps 左右比较稳。2.2 HS 模式下的 deskew 校准为什么容易出问题MIPI D-PHY 的 HS 模式是多 lane 并行传输每个 lane 有自己的 skew。接收端必须做 deskew把所有 lane 对齐到同一个字节边界。硬核一般自动做软实现就要自己处理。deskew 的难点在于MIPI 协议规定 HS 传输开始前会发一个同步序列HS Sync通常是 0xB8 的 pattern。接收端要检测这个 pattern然后确定每个 lane 的延迟。问题在于如果 IDELAY 的初始值不对或者时钟相位偏了pattern 可能检测不到或者检测到了但对齐错了 lane。我踩过的一个坑是四路里有一路始终解不出正确的字节查了半天发现是那一路的 lane0 和 lane1 在 PCB 上走线长度差了 8 mm导致 skew 超过了 IDELAY 的调节范围。后来在 PCB 上重新绕了等长线才解决。所以硬件设计阶段MIPI 差分对的等长要求一定要卡死一般要求 lane 间 skew 小于 0.1 mm差分对内小于 0.05 mm。软实现 D-PHY 的时候IDELAY 的 tap 值不要写死要做动态扫描。上电后先扫一遍 tap找到能稳定解出 HS Sync 的窗口取窗口中心值。这样对温度和电压漂移也有一定容忍度。2.3 LP 模式和 HS 模式的切换时序MIPI D-PHY 不是一直跑在 HS 模式帧消隐期间会回到 LP 模式省电。LP 和 HS 的切换有严格的时序要求LP 是 1.2V 单端信号HS 是 200mV 差分信号两者电平域不同接收端要能正确检测切换。软实现的时候LP 检测和 HS 接收通常用不同的 IO 标准。LP 用 LVCMOS 1.2VHS 用差分。切换的瞬间IO 的输入缓冲要重新配置这个切换如果慢了会丢掉 HS 的前几个 bit导致同步失败。我的做法是在 LP 检测到 HS 请求后提前几个周期就把 IO 切到差分模式宁可早一点也不要晚。因为 HS Sync 序列前面还有一段准备时间早切不会误触发晚切就直接丢数据。3. CSI-2 协议解析多路并发的状态机设计3.1 CSI-2 包结构拆解CSI-2 的数据以包为单位传输每个包有包头、有效载荷、包尾。包头是 4 个字节第一个字节是 Data ID包含虚拟通道号和数据类型第二个字节是 Word Count 的低 8 位第三个字节是 Word Count 的高 8 位第四个字节是 ECC。包尾是 2 个字节的 CRC。对于 RAW10 图像数据数据类型是 0x2B。虚拟通道号VC在多路聚合里非常关键因为四路摄像头可以配置成不同的 VC接收端靠 VC 来区分数据来自哪一路。但实际项目里很多摄像头模组的 VC 是固定的 0改不了这时候就只能靠物理通道来区分也就是每路独立解析。解析状态机的核心是检测包头、校验 ECC、根据数据类型和 Word Count 决定后续处理、收集有效载荷、校验 CRC。单路的状态机不难难的是四路并发。四路的状态机必须完全独立不能有任何共享状态否则一路出错会污染其他路。3.2 虚拟通道和物理通道的映射策略前面提到VC 可以区分数据来源但前提是摄像头支持配置 VC。我遇到的大部分模组VC 都是 0少数高端模组支持 0 到 3。所以实际项目里更可靠的做法是物理通道映射每路摄像头接独立的 D-PHY lane解析出来的数据直接打上物理通道标签不依赖 VC。如果模组支持 VC那就可以把四路 VC 配成 0、1、2、3然后所有 lane 的数据汇总到一个解析状态机靠 VC 分流。这种做法的好处是节省解析资源坏处是如果 VC 配错了四路数据会串。我一般倾向于物理通道映射虽然多占一点逻辑资源但确定性好调试也直观。3.3 行缓冲和跨时钟域处理CSI-2 解析出来的像素数据时钟域是 D-PHY 的字节时钟而后续写 DDR 的时钟域是 AXI 时钟两者不同源。所以必须做跨时钟域处理。常见做法是用异步 FIFO把像素数据从字节时钟域搬到 AXI 时钟域。FIFO 的深度要算够。以 1080p60 RAW10 为例一行 1920 像素每像素 10 bit一行就是 19200 bit也就是 2400 字节。如果 FIFO 深度不够行消隐期间来不及搬完下一行就溢出。我一般会留两行的深度也就是 4800 字节以上给仲裁和 DDR 写入留出缓冲。跨时钟域还有一个坑是帧同步。四路摄像头的帧起始时间不同如果要在 DDR 里做空间拼接必须等四路都到齐了才能开始拼。所以需要一个帧同步机制记录每路的帧号四路帧号对齐后才触发拼接逻辑。4. DDR 读写调度多路聚合的带宽心脏4.1 多端口 DDR 访问的仲裁设计四路数据同时要写 DDR如果再加一个读端口做显示就是五个端口抢一个 DDR 控制器。仲裁策略直接决定了带宽利用率和实时性。常见的仲裁有轮询、优先级、加权轮询。轮询最公平但实时性差优先级能保证关键端口但可能饿死低优先级端口。我实际用的是加权轮询加紧急优先级的混合策略正常情况下四路写端口和一路读端口按权重轮询权重根据数据率分配当某个端口的 FIFO 快满时临时提升它的优先级避免溢出。仲裁器的实现要注意DDR 的突发长度是固定的比如 8 或 16仲裁切换不能打断突发。所以仲裁的最小粒度是一个突发不能按单次传输切换。4.2 写通道的地址规划和 bank 交错四路数据写 DDR地址规划有两种连续分区和交错分区。连续分区是每路占一段连续地址比如路 0 占 0x00000000 到 0x01000000路 1 占 0x01000000 到 0x02000000以此类推。交错分区是四路数据按行或按块交错存放。连续分区的好处是地址计算简单读出来的时候每路独立适合独立通道输出。交错分区的好处是读出来做拼接的时候地址连续突发效率高适合空间拼接输出。DDR 的 bank 交错也要考虑。DDR3 一般有 8 个 bank如果四路数据都往同一个 bank 写bank 冲突会很严重。我的做法是把四路的基地址分散到不同的 bank比如路 0 从 bank0 开始路 1 从 bank2 开始这样并发写入时 bank 冲突最小。4.3 读通道的拼接输出时序如果输出是空间拼接读通道要按拼接后的画面顺序读。比如 2×2 拼接输出一行是路 0 的第 N 行左半 路 1 的第 N 行右半下一行是路 2 和路 3。所以读地址不是连续的要在四路的地址空间之间跳。这种跳地址的读突发效率会下降。优化方法是把每路的行数据先读到行缓冲再从行缓冲拼成输出行。这样 DDR 读还是按行连续读突发效率高拼接在行缓冲里做。行缓冲的深度要能存下两路的一行也就是 2 × 1920 × 10 bit 38400 bit约 4.8 KB。用 Block RAM 实现注意位宽要匹配RAW10 可以按 16 bit 存浪费一点空间但处理简单。5. 输出侧从 DDR 到显示或编码5.1 输出接口选型MIPI DSI、LVDS 还是并行 RGB聚合后的画面要输出接口选择取决于后端。如果后端是 MIPI 屏就用 DSI 输出如果是 LVDS 屏就用 LVDS如果是编码芯片可能用并行 RGB 或 BT1120。MIPI DSI 输出和 CSI-2 输入类似也需要 D-PHY但方向相反。如果 FPGA 有 DSI 硬核直接用没有的话软实现 DSI 比 CSI-2 更难因为 DSI 的 LP 模式命令交互更复杂。我一般优先选 LVDS 或并行 RGB 输出简单可靠除非后端强制要求 MIPI。5.2 帧率匹配和丢帧策略四路输入的帧率可能和输出帧率不一致。比如四路都是 60 fps输出屏是 60 Hz看起来匹配但四路的帧起始时间不同步聚合后可能某一帧缺一路。这时候要有丢帧或补帧策略。我的做法是维护一个帧计数器四路都到齐才输出一帧如果某一路超时没到就用上一帧的数据补上同时标记这一帧为不完整。这样显示不会闪但能看出哪一路有问题。5.3 调试手段怎么知道数据对不对多路聚合调试最痛苦的是不知道哪一级出了问题。我的经验是分层加调试手段。物理层用 ILA 抓 D-PHY 的原始字节看 HS Sync 有没有解出来。协议层抓 CSI-2 包头看 Data ID 和 Word Count 对不对。DDR 层抓写入地址和数据看有没有写错位置。输出层抓时序看行场信号对不对。每一层都留一个测试模式比如物理层可以发固定 pattern协议层可以发彩条这样逐级排查比盲猜快得多。6. 实操中真正会卡住你的几个细节6.1 时钟方案别小看这一个晶振多路 MIPI 聚合涉及多个时钟域D-PHY 字节时钟、CSI-2 解析时钟、AXI 时钟、DDR 时钟、输出像素时钟。这些时钟如果都来自不同的晶振相位关系不确定跨时钟域处理会很麻烦。我的做法是尽量用一个参考时钟通过 MMCM/PLL 生成所有需要的时钟。这样各时钟同源相位关系确定跨时钟域 FIFO 的深度可以算得更准。如果摄像头模组需要独立时钟也要确保这个时钟和 FPGA 主时钟同源或者至少频率是整数倍关系。6.2 复位策略软复位比硬复位更可控多路系统里某一路出问题不应该影响其他路。所以复位要分路每路有独立的软复位通过寄存器控制。硬复位一拉整个系统都停了调试的时候很痛苦。软复位的顺序也有讲究先复位 D-PHY 接收再复位 CSI-2 解析再复位 DDR 写通道最后复位输出。顺序反了可能会有残留状态。6.3 温度漂移对 D-PHY 的影响D-PHY 的 HS 速率对温度敏感尤其是软实现的时候。夏天实验室没空调跑一会儿就发现某一路开始丢数据。后来加了温度传感器发现温度升高后 IDELAY 的最佳 tap 值漂了 2 到 3 个 tap。解决办法是定期重新校准 IDELAY比如每帧消隐期间扫一次 tap动态调整。这样虽然增加了一点逻辑但稳定性提升明显。6.4 PCB 走线等长不是唯一要求前面提了等长但 PCB 上还有几个要求容易被忽略。差分对的阻抗要控制在 100 欧姆误差 10% 以内。差分对之间要保持足够间距一般 3 倍线宽以上减少串扰。参考层要完整不能跨分割否则阻抗不连续。这些在画板阶段就要和 PCB 工程师对齐板子回来再改就晚了。7. 资源估算和器件选型参考7.1 逻辑资源大概占多少以四路 1080p60 RAW10 聚合为例粗略估算D-PHY 接收软实现每路约 2000 LUT四路 8000 LUTCSI-2 解析每路约 1500 LUT四路 6000 LUTDDR 仲裁和读写约 5000 LUT输出拼接约 3000 LUT加上其他杂项总共约 25000 到 30000 LUT。Block RAM 主要用在行缓冲和 FIFO约 20 到 30 块。DSP 基本不用。这个量级中端 FPGA 就能装下。如果 D-PHY 用硬核LUT 还能省不少。7.2 DDR 位宽和速率怎么选前面算过四路 1080p60 需要 DDR 有效带宽 12 Gbps 以上。16 bit DDR3-1600 理论 51.2 Gbps有效按 60% 算是 30 Gbps够用。但如果还要读出来做拼接读写叠加就要留更多余量。我一般建议 32 bit DDR3-1600 或 16 bit DDR4这样余量充足调试时不用天天盯着带宽。7.3 选型时容易忽略的 IO 资源MIPI D-PHY 的差分对要接在支持高速差的 IO bank 上不是所有 IO 都能跑 1 Gbps 以上。选器件的时候要看 IO 手册确认目标 bank 支持的最高速率。另外LP 模式需要额外的单端 IO如果 bank 的 IO 数量紧张要提前规划。8. 写在最后多路聚合的工程化思路多路 MIPI 聚合这件事技术点拆开看都不算特别难难的是把它们组合起来还能稳定跑。我做了几个项目之后最大的体会是架构设计阶段多花一周算清楚带宽、时钟、复位、调试接口比后面调两个月都值。尤其是调试接口一定要在架构阶段就留好每一级都能抓数据、能注入测试 pattern这样出问题的时候才有手段定位。另外别追求一次把所有路都跑通。先跑通一路把物理层、协议层、DDR、输出全链路验证一遍再复制到四路。复制的时候注意资源翻倍带来的时序压力四路的时序收敛比单路难得多必要的时候降频或者加流水线。