做FPGA开发,尤其是想往图像处理方向走的朋友,HDMI 视频输入与环路输出实验基本是绕不开的一课。它听着像是个“外设接口实验”,但跑通之后你会发现,整个视频采集链路——从 TMDS 差分信号到 RGB888 像素流、从行场同步到数据有效信号、从像素处理到再输出——全都串起来了。黑金的 FPGA 基础课程里把这个实验放在很靠前的位置,我认为是对的:它门槛不高,不需要 DDR 帧缓存,又能让你肉眼直接看到 FPGA 在“干活”。这个实验做完,你再去碰图像滤波、目标检测、多路拼接这类项目,心里才真正有底。这篇文章我会尽量按带新人时的思路来写,实验构架以 Xilinx Artix-7 系列开发板加外置 HDMI 收发芯片的经典方案为例,适合入门到进阶的 FPGA 开发者参考。
1. 实验定位与整体设计思路
1.1 为什么入门视频实验首选 HDMI 接口
FPGA 接触视频接口的路径其实不少,常见有 HDMI、DVI、LVDS、MIPI、eDP 等等。但真正适合拿来入门“视频数据流处理”的,HDMI 是最友好的一档。原因很直接:HDMI 在逻辑侧解出来的数据格式非常干净,本质上就是“像素时钟 + RGB888 + DE + HS + VS”这几根信号,和早期 VGA 的时序模型一脉相承。你不用先去折腾 MIPI 那种基于 lane 的字节流解包,也不用像 LVDS 那样纠结串行通道映射,HDMI 接收芯片已经帮你把最麻烦的 TMDS 解码做完了,FPGA 要做的只是按 DE 信号把像素数据接住,然后该怎么处理就怎么处理。
同时 HDMI 接口本身非常普及,信号源随手就能找到。电脑主机、电视盒子、游戏机,甚至一块带 HDMI 输出的开发板,都能当实验信号源。显示器也到处都有,不用额外买专用设备。对比之下,MIPI 信号源基本只能在手机模组和专用测试板上找,eDP 又大多出现在笔记本屏幕上,配套的转接板都不好买。所以我一直建议新人:如果目标是先搞懂视频流在 FPGA 里是怎么流动的,从 HDMI 入口下手,是性价比最高的路径。
1.2 环路输出到底在“环”什么
“环路输出”这个词,英文叫 Loop-through,字面意思就是信号从入口进来,经过处理后形成一条环形的通路再送出去。放在这个实验里,具体干的事情是:外部 HDMI 信号源输出的视频信号,通过 HDMI 线接到 FPGA 开发板的 HDMI 输入接口,板上的接收芯片把串行的 TMDS 信号解码成并行 RGB888 数据送进 FPGA,FPGA 内部可以对这路视频做任意处理(比如灰度化、颜色反转、叠加边框),处理完的数据再送给 HDMI 发送芯片编码成 TMDS 信号,从 HDMI 输出接口出去,最终在显示器上显示出来。
这个“环”的意义在于:它完整经历了一次“视频进来 → FPGA 处理 → 视频出去”的闭环。信号源、开发板、显示器三者串在一起,形成一条有始有终的链路。跟那种只做 HDMI 输出、用 FPGA 内部生成彩条信号的实验相比,环路输出多了“外部视频输入”这一环,难度上了一个台阶,因为你要面对的是外部信号源的时序、时钟恢复、有效数据窗口这些真实问题。跟“视频输入后存到 DDR 再做处理和输出”的方案相比,环路输出又是简单的:不需要帧缓存,不涉及跨时钟域大带宽改动,输入输出用同一套时钟体系就能跑通。
1.3 系统链路逐级拆解
先看整体链路,每一级的作用都很清楚:
| 链路节点 | 说明 | 关键动作 |
|---|---|---|
| 视频信号源 | 输出标准 HDMI 信号 | 分辨率、刷新率决定像素时钟 |
| HDMI 输入线缆 | 传输 TMDS 差分信号 | 线材质量影响信号完整性 |
| 板上 HDMI 接收芯片 | 完成 TMDS 解码,恢复像素时钟和 RGB 数据 | 输出 DCLK、DE、HS、VS、24bit 数据 |
| FPGA 内部处理模块 | 接收并行视频流,做像素级处理 | 灰度化、反色、画框、直通 |
| 板上 HDMI 发送芯片 | 将 RGB888 重新编码为 TMDS 输出 | 配置像素格式、时钟极性 |
| HDMI 输出线缆 | 将处理后的信号送进显示器 | 环路输出完成 |
| 显示器 | 呈现最终图像 | 根据时序自动识别分辨率 |
链路里最容易让人忽略的是“接收芯片帮你解掉了 TMDS”,很多教程没有明说这一点,导致新手以为 FPGA 直接去解 HDMI 差分信号。实际上,除非你的板子用的是带 HDMI 硬核的 SoC 方案,或者你准备用 FPGA 逻辑自己写 TMDS 收发(这种也不是不行,Xilinx 7 系列可以直接用 GTP/GTX 或者 ISERDES 做,但难度和调试成本都在另一个量级),否则普通开发板上 HDMI 输入输出几乎都是靠外部芯片完成的。搞清楚了这条链路,后面调试出问题才知道往哪一级查。
2. HDMI 协议基础与收发电路要点
2.1 TMDS 编码与速率计算
要顺利做这个实验,HDMI 的物理层和数据格式还是得知道一些。HDMI 使用 TMDS(Transition Minimized Differential Signaling)传输数据,物理上是 4 对差分线,其中 3 对传数据、1 对传像素时钟。每对数据线上,每个像素时钟周期要传 10 bit 经过 8b/10b 编码后的串行数据。换句话说,TMDS 每通道串行速率 = 像素时钟 × 10。
这个式子非常重要,很多新人在选型、约束、查问题的时候都会用到。举两个例子:
- 720p60:像素时钟 74.25 MHz,TMDS 每通道串行速率就是 742.5 Mbps,三个数据通道合计约 2.2275 Gbps。
- 1080p60:像素时钟 148.5 MHz,TMDS 每通道串行速率 1.485 Gbps,三个数据通道合计约 4.455 Gbps。
注意这里不直接等于“HDMI 带宽”的常见宣传值,因为官方标称带宽通常按单通道最高速率乘上因子,而且有不同定义口径。但在 PCB 布线、信号完整性分析、以及判断某块板子能不能支持某种分辨率时,按“像素时钟 × 10 × 通道数”去估算实际承载的数据量是准确的。
在实验环境里,我建议优先用 720p60 或 1080p30 做调试,像素时钟分别是 74.25 MHz。这个频率对 Artix-7 这类中低端 FPGA 来说非常轻松,引脚逻辑时序随便约束一下就能过,布线压力小。一上来就跑 1080p60 也不是不行,但如果你用的是没有认真做阻抗匹配的杜邦线或者面包板来飞 TMDS 信号(这么干的人真有),大概率会出一堆莫名其妙的花屏问题。
2.2 引脚定义与输入电路设计
HDMI Type-A 接口大家见得最多,一共 19 个引脚。除了 4 对 TMDS 差分线,还有几根对实验影响很大的信号,背下来不亏:
| 引脚 | 信号名 | 作用 |
|---|---|---|
| 1/3,4/6,7/9 | TMDS Data2/1/0 差分对 | 三路像素数据 |
| 10/12 | TMDS Clock 差分对 | 像素时钟 |
| 13 | CEC | 消费电子控制,实验一般不用 |
| 14 | Reserved | 保留,通常不接 |
| 15/16 | SCL/SDA | DDC 通道,读取 EDID 用 |
| 17 | DDC/CEC GND | 地 |
| 18 | +5V Power | 热插拔检测和 DDC 供电 |
| 19 | HPD | Hot Plug Detect,热插拔检测 |
输入电路设计上,接收端通常要对输入的 TMDS 差分对做 100 Ω 差分端接,这是差分信号的标配,不做端接信号反射会很难看。HDMI 输入接口附近还要加 ESD 防护,因为 HDMI 线缆经常热插拔,静电打进来是家常便饭。很多开发板会直接选用自带 ESD 保护功能的 HDMI 连接器,或者在差分线上加 TVS 管,这都是成熟做法。
另外很多人会搜“HDMI 供电电流需要多大”这个问题。HDMI 规范里,源端 +5V 引脚要求至少能提供 50 mA 电流,这块电主要供给 DDC 通道、HPD 检测和接收芯片的 IO 电平使用,功耗并不大。但有一个认知得纠正:HDMI 线的 +5V 绝不是给整个开发板供电用的,更不能指望它带动 FPGA 内核。实验里如果电源方案设计不合理,靠 HDMI 的 5V 去驱动整块板子是极其危险的,轻则掉电重启,重则烧接口。真正常见的做法是:HPD 信号用一个电阻上拉到接收板自己的 3.3V,+5V 只做检测和 DDC 供电,FPGA 供电走板卡独立电源。
2.3 接收与发送芯片选型对比
HDMI 环路输出实验的硬件核心,是输入侧接收芯片和输出侧发送芯片。常见方案有两类:第一类是完全靠 FPGA 内部逻辑或硬核收发器实现 TMDS 编解码,板上只需要 HDMI 连接器和端接电阻;第二类是外置 HDMI 编解码芯片,FPGA 只处理并行 RGB 数据。入门实验几乎都是第二类。
黑金 EGO1 这类基于 Artix-7 的板子,用的就是第二类方案。接收侧常见的是 Silicon Image 的 SiI9022 或 ADI 的 ADV7611,发送侧常见的是 SiI9134、ADV7513 这类芯片。它们的工作分两段:接收芯片把 TMDS 解码成并行 RGB888 和 DCLK、DE、HS、VS,发送芯片则做逆过程。FPGA 夹在中间,只需要按芯片手册配置好寄存器、接好数据总线,剩下的就是视频流处理逻辑的事了。
选择这类芯片要注意几个点:一是接收芯片对分辨率的自适应能力,好的芯片能自动检测 720p、1080p、甚至 4K 时序,差的芯片需要你在寄存器里手动指定时序参数;二是时钟恢复能力,低端芯片在信号源非标准时序时可能锁不住;三是输出数据格式要确认清楚,是 RGB888 还是 RGB565,DE 极性是高还是低,这些都会直接影响 FPGA 逻辑设计。拿到一块陌生的开发板,第一步永远是仔细读原理图,确认芯片型号、数据位序、复位和 I2C 配置方式,别想当然。
3. 核心细节解析与图像处理模块设计
3.1 从 TMDS 到 RGB888:时序恢复过程
接收芯片输出给 FPGA 的信号,核心是这几根:像素时钟 DCLK、数据有效 DE、行同步 HS、场同步 VS,以及 24 bit RGB 数据。实际上你完全可以把接收芯片想象成把 HDMI 线里的“串行像素快递”拆成了“并行像素包裹”,DE 信号就是包裹上的“有效”标签——DE 为高时,DCLK 上升沿对应的 RGB 数据是真实图像内容;DE 为低时,数据落在消隐区,没有显示意义。
这里想补充一个概念,DE 信号在 VGA/HDMI 时序里和 HS/VS 是配套出现的。一个完整的视频帧由行同步、后肩、有效像素、前肩组成,DE 只在整个有效像素区间拉高。计算像素时钟有个公式:行总长 H_Total 乘以场总长 V_Total 再乘以刷新率,就是像素时钟。以 1080p60 为例,H_Total=2200,V_Total=1125,2200×1125×60=148.5 MHz。这个算法在调试外部信号源时尤其有用——如果接收芯片输出的 DCLK 频率和你预期不符,说明输入分辨率或刷新率跟你想的不一样。
实验里你不需要在 FPGA 里重建时序,接收芯片会把恢复出的 DCLK 和行场信号都给你。但有个细节要注意:有些接收芯片输出的 HS/VS 是低电平有效,有些是高电平有效,极性配置在初始化寄存器里。调试时一旦发现画面左右错位、上下跳,首先要怀疑的就是同步极性没配对。
3.2 像素处理模块的 Verilog 实现
环路输出最大的学习价值就在于:在任何一路视频流中间,你可以插入一个“处理盒子”。先看最基础的直通,数据进来什么都不改,直接给发送芯片,这能验证整个链路是否通。接着就可以做像素级处理了。这里给出一个灰度化模块的参考写法,代码不复杂,但对理解视频流很有帮助:
module video_proc( input wire clk_pix, // 像素时钟 input wire rst_n, input wire [7:0] r_in, input wire [7:0] g_in, input wire [7:0] b_in, input wire de_in, input wire hs_in, input wire vs_in, output reg [7:0] r_out, output reg [7:0] g_out, output reg [7:0] b_out, output reg de_out, output reg hs_out, output reg vs_out ); // 灰度计算公式:Y = 0.299R + 0.587G + 0.114B // 定点化系数取 77/256、150/256、29/256,误差很小 reg [15:0] gray_sum; reg [7:0] gray; always @(posedge clk_pix or negedge rst_n) begin if (!rst_n) begin gray_sum <= 16'd0; gray <= 8'd0; end else if (de_in) begin gray_sum <= r_in * 8'd77 + g_in * 8'd150 + b_in * 8'd29; gray <= gray_sum[15:8]; end end // 同步打拍,保证数据、DE、HS、VS严格对齐 always @(posedge clk_pix or negedge rst_n) begin if (!rst_n) begin r_out <= 8'd0; g_out <= 8'd0; b_out <= 8'd0; de_out <= 1'b0; hs_out <= 1'b0; vs_out <= 1'b0; end else begin de_out <= de_in; hs_out <= hs_in; vs_out <= vs_in; if (de_in) begin r_out <= gray; g_out <= gray; b_out <= gray; end else begin r_out <= 8'd0; g_out <= 8'd0; b_out <= 8'd0; end end end endmodule这里有个很多新手容易忽略的问题:数据在模块里打了几拍,DE、HS、VS 也必须跟着打同样的拍,否则图像内容会和同步信号错位,画面轻则出现边缘偏色、重则整幅图偏移。实际上,处理延迟多少拍,同步信号就要跟着延迟多少拍,这是所有视频处理流水线的铁律。上面代码里 de_out、hs_out、vs_out 都只打了一拍,和 r_out、g_out、b_out 严格对齐,这就是对的。
3.3 环路直通与带处理模式的切换要点
环路输出实验里,建议做一个可以随时切换直通和处理模式的开关,这样调试会更直观。可以分配一个按键,按一下直通,再按一下灰度,再按一下反色或者颜色通道交换,立刻就能在显示器上看到 FPGA 到底在做什么。这个设计对新人理解“可编程逻辑在视频链路上做的事”有奇效。
切换模式时要特别注意一个坑:任何时刻都不要让输出端的 DE 信号提前拉高或者延后拉低。有些人处理帧内画框、叠加 OSD 时,为了省事直接改 DE 的宽度,结果就是行有效区被拉伸或者压缩,显示器很可能直接黑屏或者花屏,严重的会触发显示器重新协商分辨率。正确做法是:DE 受输入驱动,只在有效像素数据上做替换,不要改动 DE 本身的时间宽度。
还有一个容易被忽略的点:发送芯片的输入时钟极性、数据格式、输出分辨率,必须从寄存器层面和接收侧保持匹配。曾经有人接收侧解出来是 RGB888、DE 高有效,发送芯片配置还停留在 RGB565、DE 低有效,画面全是花的,查了很久才意识到是寄存器没配。建议把接收芯片和发送芯片的初始化脚本统一放在工程里管起来,做成复位后自动配置,改分辨率时一起改。
4. 实操手记:从零搭建环路输出工程
4.1 硬件连接与实验环境准备
做实验之前,先把设备准备好。你需要一块带 HDMI 输入输出接口的 FPGA 开发板,一张带 HDMI 输出的信号源,这里用电脑主机或者笔记本都行,还有两根 HDMI 线和一个带 HDMI 输入口的显示器。注意,很多笔记本的 HDMI 口是输出口,不能当输入用;信号源务必确认是输出口。连接方式:信号源 → HDMI 线 → 开发板 HDMI IN,开发板 HDMI OUT → 另一根 HDMI 线 → 显示器。这样整个回路就搭起来了。
开发工具方面,Xilinx 平台用 Vivado,不同版本对器件支持有差异,Artix-7 用 2018.3、2020.1 这类长期维护版本都行。实验不涉及复杂 IP,一个标准工程够用。我个人习惯在工程根目录下面把 src、constraints、ip 三个目录分开,src 放 RTL,constraints 放 XDC 约束,ip 放 MMCM 这类 IP 工程文件。这个习惯在实验变复杂后收益很大,不然等到你加帧缓存、加 DDR、加 ILA 的时候,工程一团乱,光是找文件就够烦的。
4.2 Vivado 工程搭建与约束编写
完整步骤写下来很啰嗦,但核心流程是固定的:
- 新建工程,器件选你板子对应的 Artix-7 型号,比如 XC7A35T。
- 添加接收芯片初始化模块(多数开发板会提供 Verilog 源码,通过 I2C 配置芯片寄存器),以及发送芯片初始化模块。
- 添加视频处理顶层逻辑,把接收侧输出的 DCLK、DE、HS、VS、RGB 数据引到内部处理模块,再从处理模块输出到发送侧。
- 添加时钟资源。直通场景可以直接用接收芯片输出的 DCLK 作为全局时钟;如果需要把 720p 转换为其他时序,就要用 MMCM/PLL 重新生成像素时钟,比如把 74.25 MHz 倍频。
- 编写 XDC 约束文件,包括引脚位置约束和时钟约束。
- 综合、实现、生成 bitstream,烧录到 FPGA,插上 HDMI 线和显示器,观察效果。
引脚约束是新人最容易栽的地方。XDC 里必须对每一根接收和发送数据线、时钟线、I2C 引脚做 PACKAGE_PIN 绑定。不同开发板引脚定义完全不同,务必去查板子的原理图,不要猜。时钟约束也很重要,如果接收芯片输出的 DCLK 是 74.25 MHz,你可以在 XDC 里显式声明:
create_clock -name hdmi_rx_clk -period 13.468 [get_ports hdmi_rx_clk_p]74.25 MHz 对应的周期是 1/74.25 MHz ≈ 13.468 ns。这样 Vivado 在时序分析时才会以这个时钟域为基准去检查逻辑路径。有些人偷懒不写时钟约束,结果实现之后时序报告一片 red,烧进去显示器就是雪花,回头还以为是代码问题。
4.3 在线调试:ILA 抓信号
环路输出实验里,调试手段比写代码还重要。Vivado 的 ILA(Integrated Logic Analyzer)核非常实用,你可以把接收侧的 DCLK、DE、HS、VS、RGB 数据引到 ILA,然后在显示器出问题的时候抓一拍波形看看数据对不对。
我最常用的调试顺序:先抓 DE 和 HS/VS,确认时序关系是否符合输入分辨率。比如信号源是 720p60,DE 为高的周期应该占每个行周期的绝大部分,HS 应该每行脉冲一次。如果抓到的时序根本不对,先查接收芯片有没有初始化成功、芯片输出极性寄存器是否配错。时序正常之后,再看 RGB 数据在 DE 为高时是否有变化,如果数据一直是 0,多半是数据总线位序接反了,或者芯片输出了 RGB565 而你按 RGB888 解了。数据有变化但画面还是不对,再怀疑同步信号和数据的对齐问题。
这里有件事多说一句:ILA 触发条件不要一上来就设得很复杂。新手喜欢用“R==255 && G==0 && B==0”抓红点,结果抓半天抓不到。正确姿势是先设深触发条件,比如 DE 上升沿、VS 上升沿,把一整行甚至一整帧的波形抓下来,再看局部。视频信号是周期性的,只要你抓到了 DE 有效窗口,任何一处像素异常都能顺藤摸瓜查下去。
4.4 扩展玩法:FMC 联动与图像算法进阶
环路输出实验做完,路并没有走完,恰恰是起点。最自然的扩展方向之一是往 ARM 侧联动。像 STM32H743 这类带 FMC 接口的 MCU,可以直接通过 FMC 总线和 FPGA 连接,FPGA 把采集到的视频帧通过 FMC 间接传给 MCU 去做算法处理,再由 MCU 传送回 FPGA 输出。这种“FPGA 做前端采集和预处理、ARM 做高层算法”的构架,在很多工业相机、视频分析设备里都能看到。做这个扩展实验时,重点在于 FMC 读写时序的握手设计,以及视频数据流的缓冲切分,难度比纯 FPGA 环路输出高一些,但方向很值得走。
另一个扩展方向是往图像算法上板方向走。灰度化只是最简单的像素处理,之后可以做颜色空间转换、直方图均衡、高斯滤波、边缘检测,甚至卡尔曼滤波这类更复杂的算法在 FPGA 上的定点化实现。有人觉得算法上板门槛高,但核心套路其实是一致的:视频流进来,按行按窗口去处理像素,再把结果同步输出。好莱坞电影那种实时特效背后,本质上也是这条流水线做了很多级而已。
还有做 MIPI 或 eDP 转 HDMI 项目的朋友,会频繁遇到“时序、lane 数、速率”的匹配问题。拿 eDP 来说,它同样是差分线传输视频,lane 数常见 1/2/4 对,每 lane 速率按像素时钟和通道占比换算,思路和 HDMI 一模一样。搞懂了 HDMI 的“像素时钟 × 通道数 = 总带宽”这个基本模型,碰到其他高速视频接口,至少不会被名词吓住。
5. 常见问题排查与避坑清单
5.1 无视频输入问题定位
显示器没有任何画面,是环路输出实验里出现频率最高的问题。遇到这种情况,不要第一时间怀疑 FPGA 代码,先按链路排查。第一步看信号源是否真的输出了 HDMI 信号,单独插到显示器上确认一下。第二步确认 HPD 信号是否正常,很多接收芯片是靠 HPD 电平判断下游设备是否连接的,HPD 没拉高,信号源根本不会把信号输出出来。第三步检查接收芯片初始化是否成功,I2C 配置有没有写到寄存器里,最简单的判断方式是抓 I2C 波形,或者看芯片手册里状态寄存器的值。第四步才轮到检查 FPGA 内部逻辑。
还有一个容易踩的坑:没有插好 HDMI 线导致“无视频输入”。HDMI 接口没有机械锁扣,比较松,插不到位时 TMDS 通道会接触不良,芯片检测不到时钟,自然没有 DE 信号。我见过不少新人折腾一下午,最后发现是线没插到底。所以排查的第一步永远是物理层,线、接口、供电,都确认了再往下查。
5.2 花屏、错位与颜色异常
花屏、错位这类问题,绝大多数和同步时序有关。先整理一个快速对照表:
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
| 完全花屏、雪花点 | TMDS 时钟没锁住、端接问题 | 检查接收芯片时钟锁定状态、线缆质量 |
| 图像整体左移/右移 | HS 极性反了或 DE 对齐错误 | ILA 抓 HS/DE 波形,确认极性寄存器配置 |
| 图像上下跳动 | VS 极性反了 | 调整发送芯片同步极性配置 |
| 偏色严重 | 数据位序错、RGB888/RGB565 格式不匹配 | 对照原理图检查数据总线映射 |
| 图像颜色正常但有噪点 | 像素时钟抖动、线缆过长 | 换短线材、适当调整时序约束 |
| 画面一半正常一半花 | 有效像素窗口截断 | 检查 DE 高电平宽度是否覆盖全部有效像素 |
调试花屏的时候强烈建议大家用桌面壁纸而不是纯色屏做信号源,这样能一眼看出图像有没有左右错位。OLED 和普通 LCD 显示器在接收异常时序时的表现还不一样,有些显示器容错性强,画面虽然错位但不黑屏;有些直接显示“无信号”。所以不要拿显示器“有没有画面”当唯一判定标准,抓波形看时序才可靠。
5.3 HDMI 供电、HPD 与线材问题
搜索记录里高频出现的“HDMI 供电电流需要多大”和“HDMI 电路”相关疑问,在实验里最容易转化为实际问题的是这几种:一是开发板 HDMI 接口的 +5V 检测电路供电不足,导致 HPD 拉不高,信号源不输出;二是使用了特别长的 HDMI 线,信号衰减严重,接收芯片锁不住时钟;三是用了一些转接器、分配器,它们内部自己做了 EDID 管理,可能导致信号源输出了一种开发板不支持的分辨率。
应对建议很直接:优先使用 1 米以内的品牌 HDMI 线;确认开发板的 HDMI +5V 检测电路设计是否符合规范,必要时用万用表量一下 HPD 引脚电平;如果用了转接器,先去掉转接器直连测试。有些开发板的 HDMI 输入口和输出口共用同一个 EDID EEPROM,环路输出时输入和输出会互相干扰,这种板子建议先把发送侧和接收侧的 I2C 地址区分配置好,避免读写冲突。这个细节在某几款低价开发板上真实存在,查问题的时候可以留意。
5.4 避坑清单:新手最容易犯的五个错误
最后按我带新人的经验,总结五个高频错误,踩过的基本都说疼:
第一,不查原理图就飞线。HDMI 数据线位序错了,图像必然偏色或花屏,而且显得很低级。第二,忘记同步打拍。数据延迟了但 DE/HS/VS 没跟着延迟,图像边缘出现色偏或错位。第三,不写时钟约束。综合实现一堆时序违例,烧进去又不稳定,调试变成玄学。第四,盲目上 1080p60。如果对信号完整性和时序约束没把握,先用 720p60,跑稳了再升分辨率。第五,所有问题都归咎于 FPGA 代码。HDMI 这个链路,硬件、线材、芯片配置、信号完整性都可能出问题,先分层排查,再动手改逻辑。
这些错误都不是什么高深问题,但确实是最消磨时间的。做实验时养成一个习惯:每次修改后只改一个变量,然后观察显示器变化,不要同时动代码、约束和芯片配置,否则出了问题都不知道是哪一步引入的。
最后说点个人体会
黑金的这个实验我前后带过不少新人做,自己也在不同板子上重新搭过好几遍。每次做都有收获,尤其是当你意识到显示器上的每一帧画面,都是从一对对差分线上的高速串行信号一路解码、处理、再编码出来的,那种“把抽象协议变成可见图像”的感觉,非常上瘾。如果你正在学 FPGA,这个实验值得仔仔细细做一遍,甚至做完再故意制造几个故障去排查,收获会比照着教程跑通一次大得多。FPGA 这东西,看着教程觉得自己懂了,那是错觉;亲手把一个复杂链路跑通、再亲手修好它,才是真的懂了。