FPGA入门首选:HDMI环路输出实验从原理到调试全解析 📅 发布时间:2026/9/7 5:49:42 👁 浏览次数: 1. 为什么说 HDMI 环路输出是 FPGA 入门的最佳起点1.1 视频接口选型HDMI 比你想的更友好做 FPGA 图像处理这条路几乎每个人都会在视频接口上卡一段时间。VGA 虽然时序简单但模拟信号在现在的显示器上越来越难适配很多新显示器甚至直接砍掉了 VGA 口。DVI 信号逻辑简单可接口体积大而且只支持视频不支持音频实际项目中用得越来越少。MIPI 在手机屏和摄像头模组上用得多但时序和协议都复杂调试要示波器看差分信号新手很容易被劝退。相比之下HDMI 是目前最合适的入门选择。HDMI 在物理层上其实脱胎于 DVITMDS 差分信号传输机制是相通的但 HDMI 接口普及度极高家里随便就能找到几根线、几个显示器。更重要的是FPGA 厂商尤其是 Xilinx 和 Intel对 HDMI 的支持非常成熟Xilinx 有现成的 Video Timing Controller、DVI/HDMI Transmitter/Receiver IP 核配合硬核或软核的 I2C 控制器基本可以绕开最底层的 TMDS 编码细节做通链路。加上现在开发板价格也下来了黑金、正点原子、米联客这些厂商的 FPGA 开发板不管是 Artix-7 还是 Cyclone V 系列板载 HDMI 输入输出接口都是标配。入门阶段用一块几百块的板子就能跑通 HDMI 视频输入与环路输出实验性价比和成就感都非常高。1.2 环路输出解决没有显示就没有调试的尴尬很多初学者在接触 HDMI 视频输入实验时会遇到一个痛点板上只有一个 HDMI 输出接口输入信号进来之后如果不做任何处理直接接显示器画面根本出不来因为输入和输出之间没有任何逻辑支撑。于是你什么也看不见只能对着时序图和代码猜这对新手极不友好。环路输出Loop-through实验解决的就是这个尴尬。它的思路很简单HDMI 输入进来之后通过 FPGA 内部直接连到 HDMI 输出把画面原封不动地送出去。这样的话只要链路通了显示器上立刻就能看到输入源的画面这个反馈是即时的、直观的。整个实验的目的不是在传输过程中做什么花哨的图像处理而是让你先确认输入链路没问题、输出链路没问题、时钟恢复没问题在这个基础上再做后续的画面缩放、叠加、识别等处理才有底。这个环路结构也是很多商用设备的底层方案。比如视频会议终端、画面分割器、KVM 切换器上经常会有一个 HDMI 环路输出口就是把输入信号直接转发给下一级设备避免因为单一设备的故障或者关闭导致整个信号链路中断。所以别看这个实验听着基础它的应用场景是真实存在的理解了它后面再去做帧缓存、多路输入切换思路会清晰很多。另外环路输出实验还有一个隐性的价值调试任何视频接口相关的 IP 核时你都需要一个最小可用系统来验证输入侧捕获的数据是否正确。环路输出就是这个最小系统的天然载体输入数据恢复出来是什么样经过 FPGA 内部直接送出去就是什么样任何中间环节出了问题用显示器一眼就能看出来。2. 硬件基础与信号链路搞懂 TMDS 和 DDC 再动手2.1 做这个实验需要准备哪些硬件在动笔写代码之前先把实验台搭好。我做这个实验时的核心硬件清单如下FPGA 开发板我用的是一块基于 Artix-7 XC7A35T 的黑金 AX7A035 开发板板载一个 HDMI 输入接口和一个 HDMI 输出接口输入侧带了一块 ADV7611 芯片做 HDMI 转并行 RGB 信号。如果你用的是别的板子只要确认板载有 HDMI 输入输出接口就能做类似实验逻辑上大同小异。有一点要注意有些板子的 HDMI 输入是靠 FPGA 引脚直接接 TMDS 差分对的比如很多国产小板子这种板子在约束和代码上会麻烦一点但原理一样。视频源任意的 HDMI 输出设备都可以机顶盒、笔记本、树莓派、甚至另一块输出测试画面的 FPGA 板都行。我建议用笔记本或者树莓派因为可以灵活设置输出分辨率和刷新率方便验证不同参数。显示器或电视带 HDMI 输入的都可以推荐至少支持 1080p 的方便直接对比输入输出。HDMI 线缆至少两根一根接输入、一根接输出。建议尽量用短线尤其是输入侧因为开发板上的 HDMI 座子通常不是标准阻抗匹配最好的劣质长线很容易引入信号完整性问题到时候画面闪屏、雪花点排查起来非常费劲。电源开发板标配电源注意电流余量要够这个我后面专门说。2.2 TMDS 通道与 DDC 通道的分工HDMI 接口在物理上包含四对差分信号和若干控制引脚其中四对差分信号是核心三对数据通道D0、D1、D2加一对时钟通道CLK。像素数据经过 8b/10b 编码后被分配到三对数据通道上串行传输时钟通道则传输像素时钟接收端用这个时钟来采样数据通道上的比特流。8b/10b 编码的作用有两个一是保证传输过程中直流平衡避免信号在长距离传输后产生直流偏移二是提供了足够的跳变沿方便接收端从数据流中恢复时钟。在 HDMI 1.4 以内的规范里像素时钟最高到 340MHz 左右对应 4K30Hz 或者 1080p120Hz 这个量级数据通道的串行速率是像素时钟的 10 倍。比如 1080p60Hz 的像素时钟是 148.5MHz那 TMDS 数据通道上的串行速率就是 1.485Gbps。DDCDisplay Data Channel通道是基于 I2C 协议的像素时钟和串行链路是隔离的专门用来传输 EDID 数据。EDID 简单说就是显示器给视频源的一份自我介绍文件里面写了这台显示器支持哪些分辨率、哪些刷新率、对应的像素时钟是多少。视频源设备比如笔记本上电后会通过 DDC 读取显示器的 EDID然后在这个范围内选择一个合适的分辨率输出信号。环路输出实验里输入侧的视频源也是靠 DDC 去读你接的那台显示器或者任意 HDMI 信号接收设备的 EDID。这里面有个在开发板设计时需要留意的点如果你的开发板在 HDMI 输入接口和输出接口之间做了 DDC 通道的串联很多带环路输出设计的板子会这样做那显示器插在输出口上时源设备就能直接读到它的 EDID但如果开发板没有做这个串联你就需要外接一个 EDID 模拟器或者用 I2C 逻辑在 FPGA 里模拟一个 EDID否则很多视频源检测不到显示器就不输出信号。黑金的 AX7350 这块板子我没记错的话是做了输入输出 DDC 串联处理的但不同板卡差异很大动手前先看一下原理图确认你这块板的 DDC 是怎么走的。2.3 HDMI 供电电流与接线细节HDMI 接口里有一个 5V 的电源引脚规范要求源端设备要能提供最大 50mA 的电流这个电流主要是给接收端的 HDMI 接收芯片或者 TMDS 接收缓冲器供电的。如果开发板设计得中规中矩这个 5V 会经过一个 LDO 或者 DCDC 变换成接收芯片需要的电压所以整块 FPGA 开发板的功耗来源之一就是这个 HDMI 输入的 5V。实测下来大部分开发板整体的 HDMI 相关电路输入接收芯片加输出驱动芯片或者 FPGA 内部终端电阻对 5V 电源的需求在 100~200mA 左右不算大但如果你用的是那种设计比较粗糙的 USB 供电小板接上 HDMI 线和显示器之后可能会出现电压跌落导致重启的情况这时就要果断换成外部电源。另外有个接线细节HDMI 座子是带屏蔽壳的很多开发板上这个屏蔽壳和地平面是直接相连的正常情况没问题但要确保开发板的电源适配器是接地的那种不然通过 HDMI 线缆形成了地环路在某些环境下会出现低频纹波干扰画面表现为缓慢的水平滚动条纹。我在实验室就遇到过这个问题换一个三插脚的电源适配器就解决了排查起来比较折腾提前知道能省很多时间。3. 工程搭建与代码实现从零写一个最小环路3.1 方案选型用 IP 还是自己写 TMDS 收发器在 Vivado 工程里实现 HDMI 环路有两种大方向。第一种是全部用 Xilinx 提供的 IP 核Video Timing ControllerVTC用来生成和解析视频时序DVI/HDMI Transmitter/Receiver IP其实 7 系列里主要是 DVI IPHDMI 的扩展功能需要额外逻辑用来做 TMDS 编解码。第二种是完全自己写 RTL用 ISERDESE2 和 OSERDESE2 原语自己去怼 TMDS 串行收发。我这个实验用的是第一种原因很直接本实验的核心目标是打通输入到输出的通路不是研究 TMDS 编码算法用成熟的 IP 核可以把时间花在理解整体数据流和时序上而不是纠结于 8b/10b 编码的细节实现。用 IP 核有个隐性好处是 IP 核自带的时序约束文件比较完整对入门来说少了很多约束文件的坑。自己写 TMDS 收发器虽然对理解底层有巨大帮助但对新手来说时序约束不过、上板黑屏的概率非常高容易打击信心。我的建议是第一遍用 IP 核做完环路实验确保整条链路通了之后再回头去看数据手册和 RTL 源码把 TMDS 编码器一章一章啃下来这样做既有全局观又有细节感效率反而更高。3.2 详细实现流程从创建工程到输出画面下面是这个实验的完整流程每个环节我都标了容易踩的坑。第一步创建 Vivado 工程选用你开发板对应的 FPGA 型号。以我用的 XC7A35T 为例新建工程后先到 IP Catalog 里例化以下四个 IPDVI Transmitter、DVI Receiver、Video Timing Controller、AXI I2C Controller如果输入侧用了 ADV7611 这类芯片就需要用来配置接收芯片的寄存器如果你的板子输入侧是直连 FPGA就不需要这个。第二步把 DVI Receiver 的输入引脚连接到板卡原理图上对应的 HDMI 输入引脚DVI Transmitter 的输出引脚连接到 HDMI 输出引脚。这里要重点确认 TMDS 差分对的正负极性。有些人上板黑屏或者画面颜色怪异查了半天发现是 RX 的 P/N 反了但 DVI Receiver IP 又不允许直接在引脚端翻转极性因为模块内部没有反相逻辑只能在约束文件里把差分对的正负端对调来解决。如果是直连 FPGA 的板子这个操作是合法的如果输入侧有 ADV7611 这类芯片那引脚是芯片输出的并行信号就不存在这个问题了。第三步VTC 的配置。Video Timing Controller IP 可以配置成自动检测输入时序或固定生成输出时序两种模式。在这个实验里输出侧用 VTC 生成你想要的固定时序比如 1080p60Hz输入侧也需要 VTC 来解析输入的视频时序。需要特别注意DVI Receiver IP 内部会自动检测输入的行场同步和有效数据信号VTC 只是辅助做时序解析和生成两者配合时要保证时钟域处理正确。很多人在这一步会把时序搞混我的建议是输入侧先用 ChipScope/ILA 抓一下 DVI Receiver 输出的 vsync、hsync、de 信号确认输入时序参数后再去调输出 VTC不要凭感觉输入。第四步编写顶层代码把 IP 串起来。逻辑非常简单输入侧 DVI Receiver 输出的 RGB 数据和 de/vsync/hsync 信号直接连接到输出侧 DVI Transmitter 的输入端口。像素时钟也不需要做跨时钟域处理因为接收端恢复出的像素时钟直接作为输出端的像素时钟。关键代码如下所示// 环路输出核心逻辑 // rx_pclkDVI Receiver 恢复出的输入像素时钟 // rgb_data_inDVI Receiver 输出的 24bit RGB 数据 // de_in / vsync_in / hsync_in输入视频时序控制信号 dvi_transmitter u_tx ( .tmds_clk_p (tmds_clk_p), .tmds_clk_n (tmds_clk_n), .tmds_data_p (tmds_data_p), .tmds_data_n (tmds_data_n), .rgb_pclk (rx_pclk), // 直接把输入像素时钟给输出 .rgb_vsync (vsync_in), .rgb_hsync (hsync_in), .rgb_de (de_in), .rgb_data (rgb_data_in) // 直接把输入数据透传给输出 );这段代码就是一个无脑透传没有任何缓存、没有帧缓冲因此延迟极低基本就是一两个时钟周期的事。这也是环路输出的经典实现方式。第五步编写约束文件XDC。除了引脚约束还要生成一个非常重要的时序约束输入时钟约束。如果你的开发板输入侧接了 ADV7611那么 ADV7611 输出的像素时钟是它自己产生的时钟FPGA 的一个 MMCM/PLL 要用这个时钟作为输入然后生成接收逻辑和输出逻辑所需的时钟这一步通常需要在 XDC 里用 create_clock 声明这个异步时钟输入。如果直连 TMDS 差分对那么时钟是由 DVI Receiver IP 内部恢复的约束文件会由 IP 自动生成你只需要把源时钟约束好就行。第六步综合、布线、生成 bitstream下载到开发板。打开显示器给视频源上电正常情况下你会在显示器上看到视频源的画面。如果没画面进入下一节的排查流程。3.3 视频时序参数1080p 不是随便配出来的为了让你不只是抄代码这段说一下 VTC 参数从哪来。以 1920x108060Hz 为例像素时钟是 148.5MHz。这里的 148.5MHz 不是拍脑门定的而是从 VESA 时序标准查来的。VESA 标准对 1080p60Hz 给出了详细的行场时序参数水平方向一行总共 2200 个像素时钟周期其中有效像素 1920前肩H Front Porch88同步脉冲H Sync44后肩H Back Porch148垂直方向一帧总共 1125 行其中有效行 1080前肩V Front Porch4同步脉冲V Sync5后肩V Back Porch36。这些数字加起来2200 × 1125 × 60Hz 148.5MHz刚好是像素时钟。VTC IP 里配置这些参数时要区分清楚 VESA 标准和 HDMI 标准在某些刷新率下参数不同比如 1440p60Hz 用 CVT 和 CEA 标准的参数就不一样但 1080p60Hz 的这个 CEA 参数是最通用的几乎所有显示器都支持做实验首选它。如果你用的视频源输出分辨率不是 1080p你需要先查对应标准的时序表把 VTC 的配置改掉然后再去调像素时钟频率两者必须严格匹配。4. 调试方法与故障排查实战中我踩过的那些坑4.1 无视频输入从源端到终端逐级定位最常遇到的问题就是显示器黑屏无视频输入五个字直接打在屏幕上。这个问题可以从信号链路的最源端开始排查。先确认视频源本身有没有信号输出。把视频源直接用 HDMI 线接到显示器上如果能正常显示说明源没问题问题出在开发板的链路上。如果源端都不输出检查源端的显示设置确认它是否识别到了显示器。如果用了 DDC 通道串联的设计显示器插在开发板输出口上但源端没识别到十有八九是 DDC 通道断了或者开发板上的 I2C 缓冲芯片没供电。确认源端没问题之后用 ILA集成逻辑分析仪抓 FPGA 内部信号。把 ILA 的探针接到 DVI Receiver 输出的 vsync、hsync、de 和像素时钟上如果这些信号全是 0说明 DVI Receiver 没有正确恢复输入信号。接着往前面查看接收侧的 PLL 是否锁定注意 7 系列里 DVI Receiver IP 通常会输出一个 pll_locked 信号如果一直拉低大概率是 TMDS 输入有问题或者参考时钟配置不对。如果 PLL 锁定了但 de 信号一直不跳变那就是 TMDS 通道上的数据没被正确解析检查差分引脚约束是否正确或者干脆用示波器看 HDMI 输入座子上的差分信号有没有波形。还有一个很隐蔽的坑开发板上 HDMI 输入接口的 5V 检测信号HPDHot Plug Detect。很多视频源是靠 HPD 引脚是否被拉高来判断显示器是否接入的。如果开发板原理图上 HPD 没有正确处理比如没接上拉电阻源端就不知道有设备接入自然也不会输出信号。排查时可以直接测一下 HDMI 座上 5V 和 HPD 之间的电压正常情况下 HPD 应该是高电平。如果是低电平那问题就出在这里。4.2 图像偏色、闪烁、雪花点信号完整性问题画面上有雪花点或者斜纹闪烁属于典型的高速信号完整性问题。我遇到过几种情况按概率排序如下第一种是线缆问题。HDMI 线太长或者质量太差损耗大导致眼图闭合。这种问题的特征是短细线可能没问题一换长线就花屏。解决办法最简单也最有效换一根短线最好 1 米以内出现在实验阶段不要用杂牌线。第二种是地环路问题。这个在上一节提到过表现为水平滚动条纹频率在几十 Hz 以内。优先检查开发板的供电电源是否三脚接地再把 HDMI 线的屏蔽层接触是否良好检查一遍。第三种是 TMDS 终端电阻问题。如果你的开发板输入侧是直连 FPGA 引脚那么 FPGA 的差分输入引脚需要配置 100 欧终端电阻DIFF_TERM这个必须在 XDC 约束里显式设置set_property DIFF_TERM TRUE [get_ports hdmi_rx_clk_p] set_property DIFF_TERM TRUE [get_ports hdmi_rx_data_p[0]] set_property DIFF_TERM TRUE [get_ports hdmi_rx_data_p[1]] set_property DIFF_TERM TRUE [get_ports hdmi_rx_data_p[2]]如果漏了这一步信号反射会非常严重画面上必然出现雪花点或者重影。这个坑我当年是花了两个晚上才定位出来。第四种是供电不足。前面提到 HDMI 5V 电流需求如果电源适配器虚标开发板的 HDMI 接收芯片工作不稳定会出现间歇性黑屏或者颜色失真。这时可以直接用万用表量一下 HDMI 座子上的 5V如果带载后发现电压掉到 4.5V 以下果断换电源。4.3 常见问题速查表现象可能原因排查/处理办法显示器显示无视频输入视频源没识别到接收端检查 HPD 引脚电平和 DDC 通路黑屏但 PLL 锁定输出时序参数配置错误用 ILA 确认输入 de/vsync/hsync 后再比对 VTC 配置画面雪花点严重TMDS 终端电阻未启用在 XDC 里加 DIFF_TERM 约束颜色偏色如偏紫、偏绿RX 数据通道错位或者极性翻转检查差分对 P/N 是否反接数据通道是否映射错水平滚动条纹地环路干扰换三插脚电源适配器检查 HDMI 屏蔽层间歇性黑屏供电不足量 HDMI 5V 电压换电源适配器图像有锯齿或边缘拖影像素时钟不稳检查 MMCM/PLL 配置和时钟来源确认 DVI Receiver 恢复时钟质量4.4 演示一个实际调试过程1080p 输入 1080p 输出最后分享一次完整的调试过程帮大家把整个思路串起来。那次是在实验室里做这块 AX7350 的环路输出验证视频源是笔记本的 HDMI 口。上电后显示器显示无信号。我先把笔记本直接用 HDMI 线连到显示器显示器正常亮排除了源端和显示器的硬件问题。然后把线接回开发板用 ILA 抓 DVI Receiver 的输出信号。发现 vsync 和 hsync 是有的但 de 信号只在非常小的范围内跳变看起来像是同步到了但有效区域不对。因为 vsync/hsync 有了说明 TMDS 接收链路基本是通的问题大概率出在 VTC 对输入时序的解析上。我进到 VTC 的配置里把水平前端、水平同步、水平后肩这些参数对照我查到的输入信号时序重新核对了一遍发现我不小心把源端输出的分辨率设成了 1366x768而 VTC 里还是 1080p 的参数。这种分辨率匹配问题靠眼睛看信号波形其实不容易发现但 VTC 会判断出 de 的时间占比和标准 1080p 差别很大。改回正确的分辨率配置后重新生成 bitstream下板画面立刻就出来了。整个调试过程大概十分钟核心就是一步步确认链路锁定问题层级。5. 实验之后还能怎么玩跑通了环路输出说明你已经掌握了 HDMI 视频输入输出的基本链路。下一步有几个方向我觉得很有意思方向一在链路上加一个简单图像处理比如灰度化、反色、亮度调节。这个时候你不需要改任何输入输出逻辑只需要在 RGB 数据透传的位置插入一个组合逻辑或者流水线处理画面效果立竿见影这几乎是理解 FPGA 图像处理流水线最好的入门方式。方向二加入 DDR3 帧缓存。有了 DDR 帧缓存之后就能实现输入输出的帧率转换、画面冻结、画中画、像素格式转换等功能。环路输出是从低延迟直通走向帧缓存处理的必经跳板。方向三做输入分辨率自适应检测。前面提到 VTC 可以自动检测输入时序如果把输入分辨率检测代码写出来配合动态时钟切换就能做成一个无论你插什么分辨率进去输出设备都能正常显示的通用视频接口模块这也是很多商用量产设备的基本功能。我个人在实际做这个实验的时候最大的体会是FPGA 视频处理的复杂度不在于代码量而在于整个链路的时序和信号完整性概念。环路输出实验用最少的逻辑把这条链路的所有环节都过了一遍相当于给之后的图像处理学习打了一个非常扎实的地基。如果你也准备做 FPGA 图像处理方向多花点时间把这个实验做透后面一路会顺很多。