FPGA 进阶 28:视频/图像流水线——行缓存、卷积窗口、帧缓存与 HDMI 收发
本文是
fpga/进阶层第 32 篇。视频/图像是 FPGA 最经典的流式处理场景:像素随时钟一个个到达,边到边算、不攒整帧。存储结构靠 BRAM 行缓存,乘加靠 DSP48,接口靠 AXI4-Stream,输出物理层靠 LVDS/SerDes。
本文要回答的问题
- 视频数据在 FPGA 里是什么形态?行/场/有效信号怎么配合?
- 3×3 滤波、缩放这类邻域操作为什么要用行缓存+滑动窗口?
- 什么时候必须上帧缓存(DDR)?乒乓怎么切?
- HDMI 的 TMDS 是什么?不用高速收发器能做 1080p 吗?
一、视频是一条"像素流"
传感器/解码器输出的是连续像素流:像素时钟 pclk 每个沿送一个像素,按从左到右、从上到下扫描,行与行、帧与帧之间有消隐期(blanking,不送有效像素,留给显示器回扫)。

同步三件套:
| 信号 | 含义 | 用法 |
|---|---|---|
hs(行同步) | 一行开始的脉冲 | 输出给显示器;内部少用 |
vs(场同步) | 一帧开始的脉冲 | 帧边界、软件触发 |
de(data enable) | 当前像素有效 | 内部流水线统一用 de,级联最稳 |
内部模块用两个计数器(x、y 坐标)+ de 随数据一起打拍传递:流水线延迟几拍,de/坐标就打几拍,永远不要在中间模块用自己数的 hs/vs 去重新猜有效窗口。
常见分辨率参数(典型值):
| 格式 | pclk | 行总/有效 | 帧总/有效行 |
|---|---|---|---|
| 720p@60 | 74.25 MHz | 1650 / 1280 | 750 / 720 |
| 1080p@60 | 148.5 MHz | 2200 / 1920 | 1125 / 1080 |
| VGA 640×480@60 | 25.175 MHz | 800 / 640 | 525 / 480 |
二、邻域算子:行缓存 + 滑动窗口
滤波、缩放、边缘检测(Sobel)、形态学都要 K×K 邻域。不可能为每个像素等一帧——用 K-1 行缓存 + K×K 寄存器窗口:

- 行缓存:宽度=一行像素数,用 BRAM 真双口 RAM 搭成环形/延迟线——口 A 写当前行,口 B 读出 K-1 行之前的像素;K=3 用 2 块;
- 窗口:每行一个移位寄存器链(tap),新像素从左端进、整行右移,得到
window[0..2][0..2]; - 卷积:9 个像素 × 9 个系数 → DSP48 乘加树,1 拍或几拍流水出结果。
资源粗算:1080P 亮度 8bit,一行 1920×8bit ≈ 2 块 18Kb BRAM/行,3×3 窗口 2 行 ≈ 4 块 BRAM;RGB 三通道 ×3。
边界处理:第一行/最后一行/左右边缘邻域不完整,常用复制边界(缺失像素取最近边界值),或 zero padding,或直接丢边输出小一圈。
三、帧缓存:什么时候必须进 DDR
行缓存只解决"邻域"问题;以下场景要整帧缓存(进 DDR):
- 帧率/分辨率转换:输入输出帧率不同(如传感器 60fps、显示 30fps);
- 缩放比 < 1 的下采样缓冲、旋转、畸变校正(输出像素要随机访问输入帧任意坐标);
- OSD/图层叠加:UI 层和视频层合帧;
- 慢于实时的算法:软件取帧处理后回显。
乒乓(ping-pong):两块帧缓存,写 A 时读 B、帧末交换,读写不撞车、不会撕裂画面。写侧常用 AXI DMA/VDMA 把流写进 DDR,读侧按显示时序回读;VDMA 自带帧缓存管理和同步信号,是 Zynq 视频通路的标配。

四、色彩空间与格式转换
- RGB ↔ YCbCr(YUV):一组常数矩阵乘加,3×3 乘法 → DSP48;BT.601(标清)/BT.709(高清)系数不同,别混用;
- YUV422/420 → RGB:色度下采样要先做色度插值(复制或双线性),注意 Cb/Cr 与 Y 的对齐延迟;
- Gamma/阈值/查找表:用 BRAM 搭 ROM 做 LUT 映射最省逻辑。
五、HDMI/DVI 收发:TMDS
HDMI 视频期物理层就是 TMDS:8bit 像素 → 10bit 编码(直流平衡、跳变最少)→ 10:1 串行化,RGB 三对差分数据线 + 一对差分时钟线,线速率 = pclk × 10。
| 环节 | 发送 | 接收 |
|---|---|---|
| 编码/解码 | TMDS encoder(异或/同或减跳变 + 游程平衡) | decoder 反操作 |
| 并串转换 | OSERDESE(7:1/10:1 级联) | ISERDESE + IDELAY |
| 位/字对齐 | — | bitslip 找 10bit 边界 |
| 物理电平 | TMDS_33 差分对(Bank 要支持) | 同左 |
要点:1080p@60 线速 1.485Gbps,Artix-7 的 LVDS IO + OSERDESE 就够,不需要 GTX(Xilinx rgb2dvi/dvi2rgb 参考设计即此方案);4K 或 HDMI 2.0 才必须上高速收发器。TMDS 时钟对与数据对的等长、Bank 电压(3.3V TMDS)要在 IO 规划阶段定好。
常见坑对照
| 坑 | 后果 | 正确做法 |
|---|---|---|
| 中间模块自己数 hs/vs 生成有效 | 级联延迟错位、画面漂移 | de+坐标随数据打拍传递 |
| 行缓存深度写成 1920 整行 | 边界差 1 列、画面斜切 | 按整行宽度并留余量仿真验证 |
| 卷积窗口未做边界处理 | 边缘花屏/黑边异常 | replicate 或明确丢边 |
| 帧缓存单缓冲 | 画面撕裂 | 乒乓双缓存 + vs 处切指针 |
| RGB↔YUV 系数 601/709 混用 | 颜色偏色 | 按分辨率选标准、全程定点对齐 |
| TMDS Bank 电压选错 | 输出无画面/烧管脚风险 | 用支持 TMDS_33 的 Bank |
| 像素时钟频率算错 | 黑屏或显示器报不支持 | 严格按标准 pclk(1080p=148.5M) |
相关与延伸
前置/配套:BRAM/URAM 存储设计(行缓存)、DDR MIG(帧缓存)、AXI4-Stream 与 DMA(VDMA)、LVDS 源同步(TMDS 并串转换)、FIR 滤波(二维卷积同源)。 更深的收发器/协议见专家层;硬件协同见板级信号完整性。
一句话总结
FPGA 做视频就是做"像素流流水线":像素随 pclk 一个个到达,边到边算、不攒整帧。同步用 hs/vs/de 三件套,内部统一让 de+行列坐标随数据打拍级联;邻域算子(滤波/缩放/Sobel)靠 K-1 行 BRAM 行缓存 + K×K 滑动寄存器窗口 + DSP48 乘加树,单周期出结果、零帧延迟,边界做复制/置零/丢边处理;只有帧率转换、旋转、OSD 叠加这类需要随机访问整帧的场景才进 DDR 帧缓存,且必须乒乓双缓存在 vs 处换指针防撕裂。HDMI/DVI 的 TMDS 是 8b→10b 编码后 10:1 串行差分发送,1080p@60(1.485Gbps)用 OSERDESE/ISERDESE + LVDS IO 即可、不必上 GTX,注意 TMDS Bank 电压与像素时钟精度;色彩转换(RGB↔YCbCr)就是一组常数矩阵乘加,601/709 系数别混用。