FPGA实战:HDMI视频环路输出实验详解
2026/9/8 6:37:28 网站建设 项目流程

做视频处理的人,对“环路输出”这个词一定不陌生。你去现场盯一套视频切换设备,最常见的设计就是:输入信号进来,一路直通给下一级设备,另一路给FPGA做分析和处理。这个功能在监视器、导播台、视频采集卡上到处都是,术语叫Loop-out。但对于刚学FPGA的朋友来说,把一片能点亮流水灯的板子,升级成“能接收HDMI、能输出HDMI、还能在中间做图像处理”的开发平台,是一次质的飞跃。

这个实验来自黑金云课堂的FPGA基础系列,标题就叫“HDMI视频输入与环路输出实验”。它完整地带你走一遍HDMI视频链路的全流程:源端设备输出HDMI信号,接收芯片解码,FPGA拿到并行视频数据,再转发给HDMI发送芯片重新编码,最后在显示器上看到画面;同时,FPGA还可以从这条通路里“偷”一份数据,做灰度、抽边、叠加字符之类的处理。

适合谁?一类是完全没接触过视频接口、只会跑仿真的初学者,这个实验是真实视频链路最直观的入口;另一类是做过UART、SPI这类低速外设的工程师,想了解高速视频数据在FPGA里是如何流动的。整个实验下来,你对TMDS、EDID、I2C、像素时钟这些概念会有非常具体的体感,而不是停留在手册上的名词。

1. 项目概述与实验目标

1.1 环路输出解决的是什么问题

在一个视频链路里,输入信号有很多种去处。最简单的就是直接输出到显示器。但实际工程项目里,往往不止这么简单:

  • 安防监控机房,前端摄像头信号进解码器,解码器要把画面转发给电视墙,同时本地也要留一版原始画面供操作员实时监看;
  • 视频会议终端,远端信号进来,本机除了要显示,还要把画面发给外录设备存一份;
  • 图像处理设备,既要输出处理后的增强视频,又要流出原始视频给另一台分析设备。

这些需求的共同点就是:一份输入,至少两份输出,而且经常要求其中一路与输入几乎无延迟。环路输出就是这样来的。具体到FPGA实验里,我们并不会让数据绕过FPGA走物理捷径,而是让信号先进入FPGA,再在内部产生两个分支。这样FPGA就像个“分线器+处理器”,既不会破坏原始信号的时间关系,又能顺手完成图像处理任务。这也是“环路输出”在FPGA项目中比纯硬件环通更实用的存在形式。

1.2 实验平台与芯片选型

这次实验用到的核心硬件,我基于黑金开发板常见的配置来讲,如果你手头是别的板子,原理也是通用的:

  • FPGA:Xilinx Artix-7系列(以AX7201或AX7020为参考,芯片型号例如XC7A35T/XC7Z020)
  • HDMI接收芯片:IT6801
  • HDMI发送芯片:IT6613
  • 板载时钟:通常为50MHz
  • 输入源:一台支持HDMI输出的笔记本或机顶盒
  • 输出设备:普通HDMI显示器

选IT6801和IT6613,纯粹是因为它们便宜、资料多、寄存器数量适中。它们的接口不是原生HDMI,而是将TMDS信号转换成简单的并行RGB数据,非常适合FPGA入门。相比ADI的ADV7611/ADV7513,ITE芯片寄存器要直白得多,新手不至于一开始就被复杂的“自动检测”机制劝退。如果你板子上的芯片不同,后面讲的流程同样适用,只需要把寄存器地址、配置流程换成对应芯片手册里的值就行了。

1.3 整体数据流与实验设计思路

整个实验的数据流可以这样理解:

  1. 笔记本HDMI输出TMDS差分信号,进入开发板的HDMI座子;
  2. IT6801将TMDS解码,输出24bit RGB并行数据和像素时钟;
  3. FPGA内部做环路:一份数据直接送IT6613(透传路径),另一份数据进图像处理模块(例如灰度转换);
  4. IT6613将并行数据重新编码为TMDS,经HDMI座子输出给显示器;
  5. 显示器显示画面,就代表整个环路打通了。

这样设计的好处是,环路输出可以先不写任何图像处理代码,直接把RX芯片的输出逻辑映射到TX芯片的输入,用最短路径验证“视频通道能通”。然后再在分支上叠加图像处理,就很容易定位问题是出在协议配置还是出在处理模块。实验目标其实就两条:一是把HDMI视频输入链路跑通,二是让环路输出从无到有地建立起来,为后续视频处理项目搭好地基。

2. HDMI视频输入链路核心知识点

2.1 TMDS信号与像素时钟

HDMI接口传输视频信号的底层机制是TMDS(Transition Minimized Differential Signaling,最小化差分传输)。它三条数据通道、一条时钟通道,共4对差分信号。每对差分线上的数据率是像素时钟的10倍,为什么要乘10?因为每个8bit的色彩数据会被编码成10bit,多出的2bit用于实现直流平衡,让长时间传输保持信号的电气特性稳定。

拿1080p60来算,像素时钟是148.5MHz。每通道传输速率就是148.5MHz × 10bit = 1.485Gbps,三通道加起来约4.455Gbps。不同的分辨率对应不同的像素时钟,这决定了FPGA侧并行数据的频率。这也是为什么在调试时,第一步应该用示波器看RX芯片输出的像素时钟有没有起来——如果时钟都没有,后面全是空中楼阁。

视频数据在TMDS中被分成了三种类型:视频数据期、数据岛期和控制期。正常画面传输时,只有DE(Data Enable)为高的那段才属于有效像素;DE为低的那段传输控制信号和音频辅助数据。所以FPGA这边其实只要关注DE、HSYNC、VSYNC和并行数据这四组信号就够了,TMDS的编解码工作已经由接收芯片完成。很多初学者会纠结要不要自己写TMDS解码,我的建议是:先别,等你把环路输出跑通,再去研究物理层不迟。

2.2 DDC、EDID与HPD

很多人第一次调HDMI会遇到“源端明明接入了,但就是没有输出”的情况。这个问题十有八九出在DDC和HPD上。

HPD是HDMI座子上的一根信号线。当接收设备准备好接收视频时,HPD会被拉高到2.7V以上。源端检测到HPD高电平后,才会通过DDC通道去读取EDID。EDID是显示设备的“自我介绍”,描述了它支持哪些分辨率、支持哪种色彩格式。流程看起来简单,实际调试中的坑非常多。EDID要么存在外部EEPROM里,要么由接收芯片内部生成。如果FPGA侧的I2C配置没有让芯片正确响应DDC请求,源端就会认为对面是块“哑屏”,于是干脆不输出信号。黑金板上一般会接好EEPROM,物理链路没问题,但新手容易在代码里忘记初始化I2C总线的上拉配置,导致HPD正常而DDC不通。

另外,HPD的建立是有时序要求的。源端设备检测到HPD高电平之后,会立刻尝试读取EDID,如果这个过程中DDC总线上没有应答,有的源端会进入“半睡半醒”状态,即使之后EDID回复正常了,也要重新插拔一次HDMI线才能恢复。所以在调试时,如果改了EDID相关代码,最好重新插拔一下HDMI线再测试。

2.3 接收芯片输出的数据约定

RX芯片输送给FPGA的并行数据虽然叫“RGB”,但实际可能有多种格式:RGB888、RGB565、YUV422、YUV444等。寄存器的配置决定了FPGA拿到的是哪种。入门实验建议统一配置为RGB888,24bit,行场同步加DE的模式,这也是IT6613最容易接受的输入格式。

这里要特别提醒:不同的分辨率、不同的芯片手册,对“DE是否与数据对齐”的描述可能不一致。有些芯片在数据有效期外,data总线上不是确定的电平,如果TX芯片不具备数据保持能力,可能导致屏幕边缘有彩条干扰。所以FPGA侧最好做一级打拍对齐,把DE和数据严格同期。这也是后面4.3节里那个看起来简简单单的时序逻辑,实际作用远比表面大得多的原因。

3. 环路输出设计方案选型

3.1 直通环路与缓存环路的取舍

环路输出听起来简单,但设计上有个岔路口:直通还是进缓存再输出。

直通是指RX芯片出来的数据,在FPGA里不做任何缓存和延迟,一拍一拍地转发给TX芯片。它的优点是延迟极小,整个链路延迟只有芯片本身的几个时钟周期加编码延迟,肉眼完全感知不到。缺点是如果你想做分辨率转换,直通模式做不了,因为输出像素时钟和输入像素时钟必须相同。

缓存模式是把视频先写进DDR3/DDR4,然后用一个独立的输出时钟读出来。它的优点是能做缩放、帧率转换、多画面拼接等处理;缺点是延迟最少增加一帧以上,而且会引入DDR控制器和跨时钟域设计,代码复杂度大幅上升。对“HDMI输入与环路输出”这个入门实验来说,先用直通模式打通链路是绝对正确的第一步。很多工程师一上来就做缓存,结果调了一周还没出画面,最后发现先把链路打通才是一切的基础。

3.2 线上分离还是线下分离

在FPGA内部做环路还有两种数据分离方案。一种是“线上分离”,把RX芯片的数据同时接到两个逻辑模块,各自处理后输出;另一种是“线下分离”,即先接收进FIFO,再在FIFO的同时读端口分流。

我的建议是不要一开始就上FIFO。对于1080p60的逐像素处理(灰度、阈值、边缘),FIFO和异步FIFO只会在入门阶段增加不确定性。做环路实验时,面对的数据流可以完全视为同步数据流:RX芯片输出像素时钟由外部输入,TX芯片直接使用同一时钟,所以整个透传链路都在一个时钟域内,不需要FIFO跨时钟。只有当你加图像处理模块并出现多时钟时,才需要认真规划跨时钟域,那时再引入FIFO也来得及。

3.3 环路输出中的信号重建

如果RX芯片和TX芯片的工作时钟不同,或者TX芯片需要独立于RX芯片的像素时钟,就需要做信号重建。所谓重建,就是把DE、HSYNC、VSYNC和数据重新生成,用一个新时钟把它们打出去。这个过程通常需要FIFO缓存一行、一帧乃至多帧数据。

在纯环路透传中,重建不是必需的。我建议初学阶段把TX芯片的输入时钟直接接成RX芯片恢复出的像素时钟RX_PCLK。这看起来有点“偷懒”,但它能让你避开95%的跨时钟域问题。等把环路输出调通了,再去研究帧缓冲方案也不迟。讲真的,我见过太多人一开始就琢磨“要不要用DDR3缓冲”,其实这个实验最核心的价值在于让你理解视频通路的基础,而不是去搞复杂存储架构。

4. FPGA实操:从工程搭建到环路打通

4.1 创建工程与XDC约束

在Vivado中新建工程,芯片型号按你的板子选。黑金AX7020的话选XC7Z020CLG484,如果是一块小一点的AX7201,选XC7A35TFTG256。新建完工程后,先把XDC约束写好,我习惯先约束引脚,因为引脚错了代码再对也白搭。

典型的XDC长这样:

set_property PACKAGE_PIN R4 [get_ports {rx_data[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {rx_data[0]}] set_property PACKAGE_PIN R5 [get_ports {rx_pclk}] set_property IOSTANDARD LVCMOS33 [get_ports {rx_pclk}]

注意IOSTANDARD要按开发板原理图填,很多板上HDMI芯片IO用的是1.8V或2.5V,填错会导致IO电平不匹配,表现就是偶尔能出画面、偶尔黑屏。绑定引脚时,务必对照原理图把数据位一一对应好。RX芯片的24位数据从D[23:0]接到FPGA的若干个IO脚,TX芯片的24位数据再接到另一组IO脚,顺序丝印经常有反,需要仔细核对。

4.2 I2C初始化状态机

IT6801和IT6613都需要通过I2C配置初始化。FPGA侧写一个I2C主机状态机是比较基础的工作。结构我推荐这样做:

  • 一个状态机负责产生I2C起始/停止/应答信号;
  • 一个状态机负责按寄存器表顺序写入配置;
  • 写完后隔一段延时再读状态寄存器,确认链路锁定。

代码框架可以用三段式状态机来实现,伪代码如下:

localparam S_IDLE = 3'd0; localparam S_WR_ADDR = 3'd1; localparam S_WR_DATA = 3'd2; localparam S_STOP = 3'd3; localparam S_DELAY = 3'd4; localparam S_DONE = 3'd5; always @(posedge clk or negedge rst_n) begin if (!rst_n) state <= S_IDLE; else state <= next_state; end

配置寄存器时不要贪多。对IT6801,最关键的几组寄存器是:芯片软复位、输入格式选择、输出模式选择(RGB888 + DE模式)、音频关闭(如果不需要)。对IT6613,关键是输入数据格式配置,以及输出时钟使能、上电、DVI/HDMI模式选择。第一次调I2C时,建议写一个只读ID寄存器的小测试。能正确读回芯片ID,说明I2C物理链路已经通,再接寄存器配置写就不会迷茫。如果ID都读不回来,先去查I2C地址和上拉电阻。

4.3 环路透传的顶层逻辑

当RX芯片的I2C配置完成、有信号锁定后,FPGA最简的环路透传代码非常短。数据从RX芯片进来,打一拍后给TX芯片:

reg [23:0] tx_data_reg; reg tx_de_reg; reg tx_vs_reg; reg tx_hs_reg; always @(posedge rx_pclk or negedge rst_n) begin if (!rst_n) begin tx_data_reg <= 24'd0; tx_de_reg <= 1'b0; tx_vs_reg <= 1'b0; tx_hs_reg <= 1'b0; end else begin tx_data_reg <= rx_data; tx_de_reg <= rx_de; tx_vs_reg <= rx_vs; tx_hs_reg <= rx_hs; end end

这里有个容易被忽略的细节:IT6613的输入数据格式需要与输出时序严格匹配,特别是DE有效时数据必须有效。所以打拍时要把数据和DE一起打,保证两者相对位置不变。很多人抄代码只打数据不打DE,结果画面正常但行场错位,或者边缘出现噪点。如果你看到画面整体偏移了半个屏幕,十有八九就是DE和数据的对齐出了问题。

4.4 环路输出与图像处理分支

透传打通后,可以开始做第一个图像处理分支。最简单的验证是灰度化:把RGB888转成灰度,再输出。转换公式可以直接用近似移位:

assign gray = (rx_data[23:16] * 77 + rx_data[15:8] * 150 + rx_data[7:0] * 29) >> 8;

这个公式是从BT.601简化过来的,直接用移位近似,不用乘法器。然后可以用一个按键切换输出:按键为0时输出透传原始图像,按键为1时输出灰度图像。这样瞬间就能看到环路输出的效果,也验证了FPGA能在转发的同时做处理。再想多一点,可以在环路上叠加一个OSD时间戳:把当前行号和场号转成ASCII码,在屏幕某个区域覆盖一组像素。这类操作其实就是视频叠加功能,是电视墙、导播设备必备能力。环路输出因为本来就要转发完整画面,叠加OSD会让实验更有成就感。

4.5 时序约束与Vivado设置

虽然是直通环路,XDC里还是要做基本约束。RX芯片恢复出的像素时钟从引脚直接进来,先用IBUFG(或综合工具自动推断)接全局时钟网络,然后在XDC里创建时钟:

create_clock -name rx_pclk -period 6.734 [get_ports rx_pclk]

1080p60对应的像素时钟周期是1/148.5MHz约等于6.734ns。如果你不确定源端分辨率,可以先做成自动检测——IT6801的一个寄存器会报告当前输入分辨率/格式,程序里读出来后再动态选择约束,但入门阶段建议先用一个固定分辨率,例如让笔记本输出1080p60,把period写死。此外,如果TX芯片输出端有时序余量问题(一般不会有,因为只是数据输出),可以随手加一个set_output_delay约束。不做这一步也不会导致综合失败,对于入门实验来说,跑通以后再说细节也完全没问题。

4.6 实验操作步骤实录

我把自己调试的过程按顺序写一下:

  1. 电脑HDMI接到开发板RX口,开发板TX口接显示器;
  2. 上电后先看IT6801的I2C状态,确认HPD已经拉高;
  3. 用串口或者在线逻辑分析仪看rx_pclk是否出现148.5MHz信号;
  4. 配置IT6613后,显示器应当出现画面;
  5. 如果没画面,先用逻辑分析仪抓RX芯片输出的DE和数据,确认输入正常;
  6. 再抓TX芯片输入端的数据,确认FPGA转发正确;
  7. 最后抓TX芯片输出端到HDMI座子的信号,没条件抓高速信号就查寄存器状态。

整个链路从输入到输出是有层级嵌套的,排查时按“接收-转发-输出”顺序来,一定能定位到问题。

5. 常见问题与排查技巧实录

5.1 显示器完全黑屏,信号源检测不到设备

原因大概率在HPD或DDC。先量HDMI座子的HPD引脚,电压至少要2.7V以上。如果偏低,检查RX芯片配置和5V供电。IT6801在1080p60工作时的电流并不大,但如果你用的USB转HDMI线供电不足,也会出现HPD反复跳变的现象。然后读RX芯片的状态寄存器,确认HPD状态位和TMDS时钟检测标志。如果HPD正常但源端仍然报“无信号”,问题一般出在EDID。可以用I2C命令主动读EEPROM中的EDID数据,判断有没有坏块和空数据。

5.2 有画面但花屏

花屏大概率是数据位序错误。比如RX芯片输出RGB888,但FPGA给TX芯片时把高8位和低8位接反;或者RX芯片配置成了YUV422,TX芯片又按RGB888去解释。这些都是一眼看不出来的,只能用逻辑分析仪或者对比寄存器配置去查。

另一个花屏来源是时钟极性。如果你采集到的DE在一个沿,而数据对齐在另一个沿,边缘上就会偶发错位。有的芯片支持反相时钟选择,可以在寄存器里改,也可以在FPGA侧用BUFG加反相器实现。

5.3 颜色明显不对

颜色不对,优先检查RX芯片的输出色彩空间配置。RGB和YUV之间的换算错误会导致颜色发青、发紫。IT6801输出模式寄存器里有RGB/YUV和BT.601/BT.709选择。如果你后续图像处理模块是按照RGB假设写的,前面就必须让RX芯片输出RGB888,否则整套流程全错。这个坑我踩过好几次,每次都是在换了块板子或者换了平台之后,颜色突然异常,最后往回查,全是输出格式配置被默认成了YUV。

5.4 环路输出延迟为什么这么大

如果你的环路输出经过了DDR缓存,那延迟肯定是帧级的。如果确认是直通,理论上延迟最多几十微秒。可以用示波器同时测RX芯片的输入视频和TX芯片的输出视频,对比同一个场消隐脉冲的延迟,正常应该在几个像素时钟以内。如果延迟异常,查一下是不是有某个逻辑把数据误接了FIFO。还有一次我碰到的例子是,有人在FE算法里加了很深的流水线,虽然每一级都是一个时钟,但叠加起来延迟已经到了十几行,这在某些同步要求高的场合是不可接受的。

5.5 常见问题速查表

下面这个表是我整理过的,做HDMI环路调试的时候直接对着查:

现象可能原因排查手段
显示器无信号HPD未拉高量HPD引脚电压,读芯片HPD状态
显示器无信号源端读不到EDID主动读EEPROM,检查I2C上拉
花屏数据位序错位对比原理图,核校位引脚映射
花屏像素时钟极性反示波器测DE与DCLK相位,配置时钟极性
颜色不对RGB/YUV配置错核对RX寄存器输出格式
部分区域闪烁DE与数据未对齐数据打拍时DE一起打
画面偏置同步信号错误检查HSYNC/VSYNC是否进入TX芯片
偶尔黑一下电源纹波大给RX/TX芯片加滤波电容

5.6 一个容易被忽略的硬件细节

IT6613这类发送芯片,输入数据引脚如果在FPGA还没配置完成时悬空,会有不确定电平灌入芯片,轻则画面异常,重则芯片发热。FPGA下载程序之前,如果没有默认约束把IO拉低,芯片输入端会处在高阻态。所以如果下载后画面好了,不下载却黑屏,基本就是这个原因。解决方法是XDC中对所有TX芯片输入引脚加默认下拉:

set_property PULLDOWN true [get_ports {tx_data[*]}]

这个细节很多例子工程都不会写,但实际项目里很有用,尤其是FPGA程序更新重启的间隙,外设芯片经常因此进入异常状态。

6. 扩展与进阶方向

环路输出实验做完,你的FPGA视频路就算入门了。接下来想深入,我建议按这个顺序扩展:

  • 给环路输出叠加字符和时间戳:难度低,能立刻看到屏幕上多个信息标记层;
  • 引入行缓冲做灰度、横向模糊、边缘检测:不需要DDR,但已经进入图像处理领域;
  • 用DDR3做一帧缓存,实现分辨率转换和帧率锁定:这会引入Memory Interface,复杂度上了一个大台阶;
  • 对接Zynq软核,用ARM配置HDMI芯片并处理视频元数据;
  • 做FMC接口通信,比如用STM32H743加FPGA采集视频,ARM侧跑模型做实时分析。最近问这个方向的非常多,本质上就是“FPGA负责视频通路,ARM负责业务逻辑”,环路的视频源就是整套系统的输入口。

不管最后走到哪一步,HDMI输入和环路输出这个基础实验都会反复出现。你以后看任何视频处理板卡的原理图,看到HDMI RX和HDMI TX前后排列,立刻就能明白它大致的工作模式。

我个人做视频处理项目这几年,最大的感触是:很多视频问题都不是算法问题,而是同步问题。你把像素时钟、DE和同步信号之间的关系理解透了,以后再面对复杂视频通路,心里就有底了。这次实验恰好就是把这条路走了一遍,希望你也能跑通自己的第一块开发板,亲眼看到显示器上跳出画面那一刻,你会觉得之前所有的寄存器配置都是值得的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询