FPGA的学习路径走到HDMI这步,基本就进入视频设备的分水岭了。前头的流水灯、UART回环、SDRAM读写,都还可以在仿真里自嗨;做到HDMI输入和环路输出,意味着你的板子要跟真实世界的播放器、显示器、录像机打交道,各种奇怪问题也会跟着冒出来。
黑金云课堂里这个HDMI环路输出实验,我在不同板卡上做过好几遍,折腾掉不少头发。今天不打算复述一遍课程PPT,而是想把这套实验背后真正关键的事讲透:环路输出到底在跑什么数据流、TMDS解码需要处理哪些细节、两个接口之间的时钟关系怎么设计,以及上板以后那些最让人抓狂的黑屏问题该怎么定位。文章适合已经把跑马灯和串口玩明白、想真正进入视频类FPGA设计的读者,也适合准备应聘图像处理方向岗位的朋友拿来当基本功复习。
1. 先说清楚“环路输出”到底在做什么——它和视频直通有什么本质区别
1.1 环路输出在真实设备里是干什么的
环路输出在专业视频设备里非常常见。你去看看监控行业用的采集卡,很多都带一个“环路输出”口,采集图像的同时把原始信号再送一给本地监看;舞台租赁用的LED发送盒,也经常靠环路输出去级联下一台设备;医疗内窥镜、工业视觉系统里,一个HDMI信号既要进处理算法,又要给操作员实时监视,环路输出就是最基本的方案。
不少初学者把环路输出想得很简单:输入引脚和输出引脚之间拉根线就完了?不是这么回事。HDMI是高速串行数字信号,内部是经过8b/10b编码的TMDS差分链路,你无法像处理模拟视频那样直接并联复制。要实现环路输出,必须先在FPGA内部把HDMI输入完整解码成并行RGB像素流,再经过你自己的数据通路,重新编码成HDMI输出。整个过程不是“接线”,而是“翻译再复述”。
1.2 环路输出 vs 视频直通,差在哪
视频直通通常指某种Agent由硬件自动完成的信号转发,不关心内容、不处理像素。环路输出则强调两条路径并存:一路给本地输出,一路继续进后端处理。真正的环路输出设备,往往还要求本地输出延迟尽量低,否则操作员看到监视画面比实际发生晚几十毫秒,在手术、舞台控场这些场景是没法接受的。
所以做这个实验之前,你心里得先立一个指标:延迟做到多少?纯FPGA直接旁路,延迟可以控制在几十纳秒到一行像素内;如果中间插入DDR3帧缓存,延迟就是1到2帧,也就是16毫秒到33毫秒。黑金这个基础的HDMI环路实验,路线应当是“输入TMDS解码后先进异步FIFO,再直接进TX重新编码”,重点不在缓存和处理,而在把整条通路跑通。
1.3 这个实验能给你带来什么
完成这个实验,你至少能搞明白三件事:TMDS差分信号怎么进FPGA、ISERDES/OSERDES怎么完成串并转换、两个视频接口之间的同步时序怎么处理。这三件事,几乎是所有视频FPGA项目的地基。后来你做图像缩放、边缘检测、多路拼接、SDI转HDMI,拆到最后都是这套东西。面试官问“你做过视频项目吗”,你把环路输出的数据链路讲清楚,可信度就已经很高了。
2. 黑金板上的硬件资源:HDMI座、TMDS网络和时钟拓扑
2.1 板卡选型与接口布局
做HDMI环路实验,核心硬件条件是板卡上至少有两个HDMI接口:一个输入、一个输出。黑金多款FPGA开发板都带了这样的接口布局,常用的Artix-7系列上,HDMI RX和TX座子分别引出四对差分线,三对数据、一对时钟。
我第一次拿到板子,第一件事就是翻原理图和PCB丝印,确认这几个关键点:HDMI座子上的TMDS差分线是直接进FPGA普通IO,还是经过了外部PHY芯片;引脚分配在哪个Bank;该Bank的VCCO供电是多少。黑金这块实验板走的是直连方案,没有外挂HDMI PHY,所有TMDS信号靠FPGA的SelectIO资源接收和驱动。这省掉了PHY配置的麻烦,但要求你理解FPGA侧的电气特性:差分输入需要合适的IOSTANDARD和端接,输出则需要足够的驱动能力。
2.2 “无源HDMI座”和“有源PHY”的区别
很多新手容易在这栽跟头。HDMI座子本身是无源器件,它不像网络接口那样自带变压器和PHY。如果一个板卡写着“HDMI接口”,你要先看原理图上接口和FPGA之间有没有芯片。如果有SiI9134、ADV7511这类HDMI发送芯片,那么FPGA只需要输出并行RGB和像素时钟给芯片,剩下编码由芯片完成;如果没有PHY,直接用OSERDES输出TMDS电平,时序就要完全由FPGA的IO资源承担。
黑金这个实验属于后者,好处是没有芯片配置门槛,坏处是你得自己处理IO约束。我会在后面专门讲引脚约束和时序收敛的坑。
2.3 时钟拓扑:一个输入源就带进来一组时钟
HDMI输入和普通视频接口最大的不同,是它的像素时钟由源端直接送过来。TMDS通道里有单独一对差分时钟,频率在25MHz到165MHz之间(HDMI 1.4最多到1080p60时约148.5MHz像素时钟,每条数据通道的比特率就是像素时钟的10倍,约1.485Gbps)。
环路输出实验里,最稳妥的做法是把输入时钟直接当作输出时钟用。这样输入像素流和输出像素流天然同频同相,省去了一堆跨时钟域问题。黑金基础例程一般也是拿恢复出来的输入像素时钟作为TX侧的参考时钟,配合BUFIO/BUFR把时钟送进BUFR或者MMCM里,给ISERDES和OSERDES使用。
3. HDMI输入侧先要搞定的事:TMDS解码、EDID回读和像素时序恢复
3.1 TMDS的本质:三对串行数据加一对时钟
HDMI物理层用的是TMDS,每条数据通道本质是高速串行比特流,每个像素周期传输10bit。接收端需要用串行时钟把数据并起来,然后做解码。HDMI通常按RGB 8bit模式算,三个通道各对应一个颜色分量,再加上一个专门负责将HSYNC/VSYNC/DE打包进蓝通道的机制。
光理解“串行转并行”还不够。TMDS编码和解码遵循一个复杂的控制字符机制:在视频有效区,10bit编码表对8bit像素数据编码;在消隐区,则传输控制符号或者辅助数据,比如HDMI的音频包、InfoFrame都藏在消隐区。基础环路实验可以暂时不解析消隐区里的数据,但你至少要知道DE信号是怎么恢复的,因为后级所有数据通路全靠DE来判断有效像素。
3.2 解码方案选型:不用付费IP怎么做
Xilinx官方有HDMI 1.4/2.0的收发IP,但对大多数学习板来说授权并不免费,很多黑金例程采用自研的解码逻辑实现。核心是几条硬核资源:IBUFDS接收差分时钟,BUFIO/BUFR给IO逻辑分配时钟,ISERDESE2完成1:8或1:10串并转换,IDELAYE2做比特级相位微调。
如果你没有现成例程,我会建议先找开源的DVI/HDMI解码工程做参考。DVI和HDMI在视频数据通道上极其相似,先跑通DVI解码再补HDMI的控制字符逻辑,是比较平稳的路径。自己手写整套解码时,最痛苦的是设置IDELAY和Bitslip对齐。所谓Bitslip,就是把10bit桶移位,让接收到的串行数据落在正确的字节边界上。这里一个常见误区是一次性把所有通道当成齐头并进,实际上每条通道各自的延迟都不同,必须做逐通道对齐。
3.3 EDID与DDC:没有这个模块,播放器根本不给你信号
上板那天我以为方案已经全通了,结果用笔记本电脑接HDMI输入到黑金板,显示器“无信号”,电脑那边只提示“已连接但显示器未响应”。查了半天,最后发现是DDC通道没通。HDMI源在上电时,会通过I2C总线去读取显示器端的EDID,了解显示器支持的分辨率和刷新率。如果FPGA端没有一个I2C从机返回可靠的EDID数据,源端会认为没有任何显示设备,直接关闭TMDS输出。
所以环路输出实验里,你必须在FPGA里实现一个I2C从机模块,或者借助板载的EEPROM来回放EDID。黑金的例程通常包含EDID处理模块,但很多人会忽略这个模块的重要性。我当时花了大半个小时把EDID的128字节用逻辑分析仪一条一条对,确认厂商ID和时序描述块都对上了,电脑才终于送出来信号。
给一个实操建议:先别自己编EDID,直接从Xilinx官方参考设计或者显示器实际读取的EDID里抓一份1080p60的模板,改成自己板卡的厂商信息,先把链路调通。等后面需要支持4K或者特殊时序,再深入去研究CEA扩展块的格式。
3.4 时钟恢复和像素对齐的完整流程
TMDS输入进FPGA后,时钟恢复并不是用CDR那种方式,因为HDMI单独给了一对时钟,你直接差分接收就行。但这不代表简单。像素时钟进入MMCM/PLL后,要为ISERDES的串行时钟做一个高速倍频,还要生成并行时钟送后续逻辑。串行数据要在眼部中间采样,这就需要IDELAYE2做延迟补偿。
建议的稳定流程是这样:先等MMCM锁定,然后让系统处于复位状态;接着用ILA观察各通道的Bitslip状态,逐个通道调整IDELAY tap,直到能稳定解出控制字符和DE信号。如果你看到画面是整屏斜纹或者颜色错乱,大概率是通道没有对齐,或者IDELAY相位不在采样窗口内。调试时强烈建议把解码后的pixel_clk、de、hsync、vsync和rgb[23:0]全部拉到ILA里,触发条件设成“de上升沿”,数据量不用多,1024深度就够定位问题了。
4. 环路输出的数据通路设计:异步FIFO、场同步和延时取舍
4.1 最省事的直通结构:解码完直接送TX
如果输出端和输入端使用同一个像素时钟,最简环路就是:解码器出来的24bit RGB、DE、HSYNC、VSYNC,打两拍寄存器后直接进TX编码器。这里有个关键点,TX编码器要求DE、HSYNC、VSYNC和RGB数据严格对齐,哪怕只差一个时钟周期,画面都会出现偏色或行场错位。所以不要看到“直通”就只在组合逻辑上连根线,中间务必用寄存器同步打拍。
我最早做实验,为了图省事在 always 块里直接赋值,结果综合后的关键路径乱飞,HDMI输出闪个不停。后来老老实实加了两级寄存器,一切才正常。这背后的原因不只是时序对齐,还有组合逻辑毛刺:高速视频信号上任何毛刺都会被编码器当成数据,画面直接花掉。
4.2 什么时候必须上异步FIFO
如果输出时钟和输入时钟不是同一个源,比如你希望用板载晶振生成稳定的148.5MHz时钟来驱动输出,或者输入信号来自一个不稳定设备,那么两个时钟域之间存在频率偏差和相位抖动,必须在中间插入异步FIFO。
异步FIFO用双口RAM实现,写时钟用输入恢复时钟,读时钟用输出像素时钟。写使能由解码后的DE控制,读使能由TX侧的时序生成器控制。注意:读写两边的DE频率必须基本一致,如果输入是59.94Hz而输出是60Hz,FIFO会慢慢溢出或者读空。所以“异步FIFO解决一切”是个误解,它只能解决相位和瞬时抖动,无法解决长时间帧率不一致。真想解决帧率转换,得上帧缓存+DDR3,这就不是基础实验的范畴了。
4.3 为什么我不建议一上来就加DDR3帧缓存
有朋友看到“环路输出”,第一反应是“我直接加个DDR3帧缓存,读出来再输出,不就随便玩了吗”。技术上行,但会把你拖进另一堆麻烦:DDR3控制器要初始化、要处理行缓冲、要处理跨时钟域,还得面对帧同步和撕裂问题。1080p60一帧数据大约有150万个像素,RGB888一帧约4.5MB,DDR3轻松装下,但调试复杂度会剧增。
基础实验阶段,强烈建议先把无帧缓存的直通做扎实。等你能在一个HDL文件里清晰描述“输入有效像素—FIFO—输出有效像素”这条流水线,再去加DDR3、加缩放器、加OSD,都会顺手很多。视频项目最常见的返工,不是功能不会写,而是数据通路不清,导致后面加模块时到处是异步打架。
4.4 输出重建时那些细小的时序参数
TX编码器侧,除了RGB数据,还要重建行场同步信号。HDMI标准允许HSYNC和VSYNC有不同的极性,源端的VIC(视频标识码)决定了具体参数。环路直通时,最保险的做法是原封不动地转发解码器提取出的HSYNC/VSYNC极性,不要自己做转换。很多花屏问题就是因为你强行把HSYNC极性改了,而显示器和源端之间没有约定好。
另外,DE信号必须覆盖完整有效行。如果解码器输出的DE宽度少了几个像素,画面会出现右侧一条黑带或者左边错位。遇到这种问题,用ILA抓取DE和HSYNC的相对位置,对比HDMI标准时序,基本一眼就能看出来。
5. 上板实测与踩坑记录:黑屏、花屏和时序违例怎么定位
5.1 先把TX通路单独验证一遍
任何闭环问题都很难定位,所以我的习惯是先砍掉输入侧,单独验证FPGA的HDMI输出通道能不能出图。写一个简单的测试图案发生器,用板载或者PLL生成的148.5MHz时钟,直接产生1080p60的彩条信号,送进TX编码器。如果电视机上能正常显示彩条,说明输出侧的引脚约束、OSERDES配置、TX编码逻辑都没问题;这时候再启用HDMI输入环路,如果出问题,嫌疑就集中在输入侧或者两级拼接处。
这个“分而治之”的思路在视频调试里特别重要。因为你面对的是几十个信号、高速差分对、I2C配置、时钟PLL,全部混在一起,很难靠肉眼判断。一次性只让一个环节工作,可以让问题概率收敛。
5.2 黑屏的几类原因,按概率排序
黑屏永远是HDMI实验里最常见的现象。我做了几个项目后总结出一张排查表:
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| 完全无信号,设备不识别 | 未返回EDID,DDC不通 | ILA抓I2C总线,看是否有读请求 |
| 设备识别但屏幕黑 | 源端受HDCP保护,基础工程不解密HDCP | 换非受保护信号源 |
| 指示灯正常但无画面 | TX引脚没约束,或OSERDES没输出 | 检查XDC,用IO Probe抓输出 |
| 有画面但雪花剧烈 | 输入TMDS时钟未锁,PLL抖动 | 看MMCM locked信号 |
| 画面上有规则条纹 | DE/H/VS时序不对 | 用ILA对比标准时序 |
这里要单独说HDCP,因为这是新手最容易碰到的沮丧时刻。电脑、蓝光机、游戏机会对授权内容做HDCP加密,如果FPGA工程没有HDCP解密模块,输入信号就是一堆无法正确解码的密文,画面自然黑的。黑金基础实验不会、也不应该去处理HDCP,这涉及版权和授权问题。解决办法是换用不带HDCP的测试源,比如用HDMI测试图案发生器,或者某些开源板卡/树莓派配置为输出非HDCP信号。不要试图去“绕过”,那不是学习FPGA的正路。
5.3 花屏和颜色错乱的定位链路
花屏比黑屏稍微友好一点,因为至少链路通了。常见三种:斜纹条纹、画面左右错位、红蓝互换。
斜纹条纹十有八九是通道对齐问题。TMDS三条数据通道各自经过不同的PCB走线和IDELAY延迟,必须在接收端通过Bitslip机制把每个通道的10bit边界对齐。你可以在工程里预留一个调试状态寄存器,分别读出每通道的当前Bitslip值,然后在ILA里观察;只有三条通道都对齐,画面才会干净。
红蓝互换不是“电视机识别错”,而是你把输入通道的映射搞反了。HDMI三对数据分别对应R、G、B,但FPGA输入端子的命名有时是D[2:0],没有明确颜色。你需要在解码模块里确认d2对应的是红色还是蓝色,然后在RGB拼接时做对应调整。我调过一台工程样机,输出偏紫,查了两个小时,最后发现是D0和D2接反了。
5.4 引脚约束与时序收敛的实操细节
环路输出实验里,XDC至少要做这几件事:输入差分时钟的create_clock、所有TMDS引脚的set_property、ISERDES/OSERDES相关IO的false path设置。很多朋友直接在Vivado里跑默认约束,然后看timing报告一堆violation,怀疑自己代码写错了。其实高速IO项目,你需要显式告诉工具哪些信号是同一簇,并给输入输出延时留出合理窗口。
引脚号以你手上的原理图为准,我不贴具体物理引脚,但骨架是这样:
set_property PACKAGE_PIN xx [get_ports {hdmi_rx_clk_p}] set_property IOSTANDARD TMDS_33 [get_ports {hdmi_rx_clk_p}] set_property PACKAGE_PIN xy [get_ports {hdmi_rx_clk_n}] set_property IOSTANDARD TMDS_33 [get_ports {hdmi_rx_clk_n}] create_clock -name rx_pixel_clk -period 6.734 [get_ports {hdmi_rx_clk_p}]TMDS_33这个IOSTANDARD要确保你使用的Bank的VCCO确实是3.3V,否则上板风险很大。再强调一次,物理引脚一定要对着自己的板卡原理图来填,千万不要在网上抄一串就锁进去,高速差分引脚接错是可能损坏FPGA IO的。
5.5 HDMI供电电流:一个经常被忽略的物理问题
HDMI座子上的+5V引脚通常能为DDC和部分有源Dongle提供最大约50mA的电流。这是热词里很关心的问题“HDMI供电电流需要多大”。实际上源端输出的5V有电流上限,如果你的板卡HDMI输入座还去给一些有源转换器供电,电流可能不够,导致EDID读取不稳定。
我踩过一次坑:一个HDMI转接器插在FPGA板输入口上,转接器又从同一路5V取电,结果是偶尔识别、偶尔黑屏,非常飘。后来给转接器单独供电,问题立刻消失。所以在你的环路实验里,如果用了信号转换器或者延长线,优先给它们配独立电源,别依赖HDMI的5V输出。
6. 做完环路之后还能怎么扩展:图像处理、多路分发和时序整形
6.1 把环路替换成图像处理管线
环路输出只是起点,很多人做完之后第一件事就是想在里面插图像处理。这个思路完全对,但有一个必须注意的问题:图像处理模块的流水线延迟会改变像素数据和DE之间的相对位置。比如你写了3x3的卷积核,需要若干行缓冲,输出像素比输入像素晚了3行;如果DE、HSYNC、VSYNC没有同步延迟同样多的周期,你会看到图像和同步信号错位,画面撕裂或偏移。
解决办法是在处理模块旁边加一个“同步延迟FIFO”,专门把DE和行场信号的延迟修正到和像素输出一致。凡是做过视频处理加速器的人,都会对这句话深有体会:数据处理永远是小事,同步时序处理才是大事。
6.2 一进多出的HDMI分发
环路输出可以很自然地扩展到多路分发。FPGA内部把解码后的RGB数据扇出到多路TX编码器,每路独立驱动一个HDMI座子,就能做成低成本的HDMI分配器。相比去买专用HDMI分配芯片,FPGA方案的优势是可以在每条输出上做不同的OSD、不同的分辨率缩放、不同的裁剪区域。限制因素主要是FPGA的引脚数量和IO功耗。每路1080p60的TMDS输出占4对差分引脚,三路4K就需要考虑Bank的供电能力。
这类设计在会议室矩阵、多屏拼接、直播导播台里有大量应用。做分发时特别留意:各路TX的复位不能和输入复位共用一个异步复位信号,否则某些路出现初始化不同步,画面会有一路黑一路好。正确做法是每一路TX独立生成一个“像素时钟稳定后拉高”的复位释放信号。
6.3 音频信号为什么没声音
很多做完环路输出的朋友问我,图像转了声音怎么没有。原因很简单:HDMI音频数据藏在消隐区的辅助数据包里,基础实验的TX编码器没有解析甚至没有接收音频。要真正让音频一起走,需要解码器从消隐期提取I2S音频流,再在TX侧根据源端提供的CTS/N值重新生成音频时钟,重新打包进输出流。这一步涉及到音频时钟恢复和精确的包调度,难度比视频本身高不少。
黑金的这个基础实验不处理音频很正常。你只需明确记住:视频同步和音频同步是两套独立机制,音响设备里常说的“音画不同步”,根源就在CTS/N参数和缓冲延迟不一致。真做带音频的HDMI项目,阶段目标是先把Audio InfoFrame和音频FIFO跑通,再考虑和视频拼接。
6.4 什么时候升级到DDR3帧缓存
如果你发现直通环路已经不能满足需求,比如要做画中画、运动检测、任意分辨率缩放,那就必须引入帧缓存。帧缓存带来的额外延迟,在实际系统中通常可以接受,因为现在大部分视频处理链路都在做“1帧延迟”甚至“3帧延迟”。专业视频设备追求低延迟,但也只会在特定档位牺牲画质。
升级到DDR3后,环路输出实验就从“直通实验”变成了“视频处理平台实验”。你可以把DDR3当作中间帧池,输入写一帧,处理器读一帧,输出再读一帧,三个端口用DDR带宽仲裁。1080p60的RGB888总带宽约1.5GB/s,一般DDR3足够,但你需要认真处理Bank管理、行激活策略和写读切换效率,否则带宽利用率可能只有50%,关键路径一高就卡。
基于我自己的经验,做这些高级功能前,先把环路输出那套“解码—FIFO—编码”的心智模型刻在脑子里。再怎么复杂的视频系统,最后拆到数据通路上也就是“写时间、微处理和读时序”三个动作。你把这个实验吃透了,后面接HDMI 2.0、MIPI、DP,逻辑都是相通的。
如果你手头正好在做这个黑金HDMI环路实验,卡在某一步,我建议你按本文顺序重新捋一遍:先确认RX侧EDID和TMDS解码,再验证TX侧彩条输出,然后把两者拼起来。千万不要一上来就怀疑FPGA的性能或者线的质量,绝大多数问题都出在时序对齐和同步信号上。把眼睛盯住DE和高低有效极性这两根线,你能少走很多弯路。