3. 视频图像处理系统架构设计

视频图像处理系统的架构设计,本质上是在“像素流”这条主线上做三件事:把数据从哪里来、经过哪些处理、到哪里去讲清楚;把不同来源和不同去向的时钟域划分清楚;把每一级的带宽算清楚,确保不会在某个环节出现“堵点”。如果这三件事没有在架构阶段定下来,后面写 RTL 时往往会出现跨时钟域握手混乱、DDR 带宽不够、模块接口反复修改等问题。本节以 Lattice FPGA 为平台,给出一条从摄像头输入到显示输出的完整数据通路设计方法。

一、数据通路的整体分层

一条典型的视频通路可以划分为四个层次:采集层、缓存层、处理层和显示层。采集层负责把摄像头输出的原始时序转换为内部统一的像素流;缓存层负责跨时钟域和帧率匹配;处理层完成图像算法;显示层把处理结果按显示时序送出。以常见的 1080p@60Hz 系统为例,摄像头可能输出 MIPI CSI-2 或 DVP 并行接口,显示端可能是 RGB 并口或 HDMI。无论接口如何变化,内部都应尽量收敛到一条统一的像素流格式,例如 pixel_data[23:0] + hsync + vsync + de,这样处理层模块才能复用。

采集层的关键是“解串与对齐”。如果摄像头是 DVP 接口,PCLK 直接作为像素时钟,只需做位对齐和同步信号整形;如果是 MIPI CSI-2,则需要先经过 D-PHY 硬核或软核解串,再通过 CSI-2 协议层解析出像素。Lattice 的 CrossLink-NX 或 CertusPro-NX 系列通常提供 MIPI D-PHY 硬核,可以在架构上把“物理层—协议层—像素层”明确分开,避免把协议解析和图像处理混在一个模块里。

二、时钟域划分

视频系统中至少存在三个时钟域:摄像头输入时钟域、处理时钟域和显示输出时钟域。如果使用 DDR 缓存,还会增加一个 DDR 控制器时钟域。时钟域划分的原则是:同一功能模块尽量在单一时钟域内完成;跨时钟域只传递必要的控制信号和像素数据,并且必须使用异步 FIFO 或双口 RAM 做隔离。

以 1080p@60Hz 为例,像素时钟约为 148.5MHz。如果摄像头输出 1080p@30Hz,输入像素时钟约为 74.25MHz,而显示端需要 148.5MHz,两者之间就必须通过帧缓存做速率匹配。此时常见的做法是:输入域写入异步 FIFO,处理域从 FIFO 读出并写入 DDR,显示域从 DDR 读出并送出。跨时钟域的信号包括帧同步、行同步和有效数据,建议统一封装成 video_stream 接口,并在接口内部使用 async_fifo 做隔离。

视频图像处理系统数据通路与时钟域划分 采集层 摄像头 / MIPI D-PHY DVP 并行接口 像素时钟 74.25MHz 缓存层 异步 FIFO / 帧缓存 DDR 控制器 跨时钟域隔离 处理层 色彩空间转换 缩放 / 滤波 / 叠加 处理时钟 148.5MHz 显示层 RGB / HDMI 输出 显示时钟 148.5MHz 时序生成 时钟域 A:PCLK 74.25MHz 时钟域 B:DDR 200MHz 时钟域 C:处理 148.5MHz 时钟域 D:显示 148.5MHz 带宽估算与模块划分(以 1080p@60Hz、24bit RGB 为例) 环节 数据量/帧 带宽需求 说明 摄像头输入 1920×1080×3B ≈ 6.22MB ≈ 373MB/s 30fps 输入 DDR 写入 6.22MB/帧 ≈ 373MB/s 写带宽 DDR 读出 6.22MB/帧 ≈ 373MB/s 读带宽 显示输出 1920×1080×3B ≈ 6.22MB ≈ 746MB/s 60fps 输出 注:以上为示例估算,实际带宽需考虑消隐区、突发效率与 DDR 刷新开销,通常预留 20%~30% 余量。

三、带宽估算方法

带宽估算的核心公式是:带宽 = 分辨率 × 每像素字节数 × 帧率 × 冗余系数。以 1080p@60Hz、RGB888 为例,单帧数据量为 1920×1080×3 ≈ 6.22MB,60fps 下显示输出带宽约为 373MB/s。如果输入是 30fps,则输入带宽约为 186MB/s。若系统需要同时读写 DDR,则总带宽需求约为 373MB/s(写)+ 373MB/s(读)= 746MB/s。Lattice CertusPro-NX 的 DDR3 控制器在 16bit 位宽、400MHz 时钟下理论带宽约为 1.6GB/s,扣除刷新和突发效率后,实际可用带宽约为 1.1~1.2GB/s,因此上述 746MB/s 的需求是可行的,但仍建议预留 20%~30% 余量。

如果处理层需要做多帧缓存或算法需要多次访问 DDR,例如 3×3 卷积需要同时读取三行像素,则带宽会成倍增加。此时应优先考虑在片内用行缓存(Line Buffer)减少 DDR 访问次数,而不是盲目提高 DDR 频率。行缓存的容量通常为 1920 × 3B × 3 ≈ 17.3KB,对于 Lattice FPGA 的 EBR 资源来说是可以接受的。

四、模块划分方法

模块划分应遵循“高内聚、低耦合”的原则,并且每个模块的接口尽量统一为 video_stream 格式。建议的模块划分如下:

  • csi2_rx:MIPI CSI-2 协议解析,输出像素流;
  • dvp_rx:DVP 并行接口采集,输出像素流;
  • frame_buffer:异步 FIFO + DDR 控制器,完成跨时钟域和帧率匹配;
  • csc:色彩空间转换,例如 RGB 转 YUV 或 YUV 转 RGB;
  • scaler:图像缩放,支持双线性插值;
  • osd:字符或图形叠加;
  • display_timing:显示时序生成,输出 RGB 或 HDMI 时序。

每个模块内部应尽量使用单一时钟域,跨时钟域只发生在 frame_buffer 和 display_timing 之间。模块之间的握手信号建议使用 valid/ready 或 de 信号,避免使用复杂的自定义协议。对于 Lattice FPGA,建议使用 Radiant 或 Diamond 中的 IP 核生成器配置 DDR 控制器和 PLL,确保时钟频率和相位关系正确。

设计提示:在架构阶段就应确定每个模块的时钟频率、数据位宽和吞吐率,并画出时钟域交叉点。跨时钟域信号必须经过同步器或异步 FIFO,禁止直接使用两级触发器同步多比特数据。

五、一个可参考的架构参数示例

假设系统要求:输入 1080p@30Hz MIPI,输出 1080p@60Hz HDMI,处理算法为 RGB 转 YUV 加 2× 缩放。则架构参数可设定为:输入像素时钟 74.25MHz,处理时钟 148.5MHz,显示像素时钟 148.5MHz,DDR 时钟 400MHz(16bit)。输入带宽约 186MB/s,DDR 读写各约 373MB/s,显示输出约 373MB/s。模块划分上,csi2_rx 工作在 74.25MHz,frame_buffer 跨 74.25MHz 和 148.5MHz,csc 和 scaler 工作在 148.5MHz,display_timing 工作在 148.5MHz。这样划分后,每个模块的时序收敛压力可控,跨时钟域路径清晰,后续 RTL 实现和调试都会更加顺利。

架构设计不是一次性的工作,而是随着算法复杂度、接口类型和器件资源不断调整的过程。建议在架构阶段就建立一张“数据通路—时钟域—带宽”的对照表,并在每次修改后重新核对,避免后期出现难以定位的带宽瓶颈或跨时钟域错误。