ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

FPGA视频开发入门:HDMI环路输出从硬件到调试全解析

FPGA视频开发入门:HDMI环路输出从硬件到调试全解析 FPGA视频开发的门槛往往不是Verilog语法而是你面前那条什么信号都好的HDMI线缆一旦接上开发板就黑屏。做视频方向的朋友应该都有体会调接口比调算法痛苦得多。所以黑金云课堂这套FPGA基础教程里把“HDMI视频输入与环路输出”放在比较靠前的位置我是很赞同的——这个实验看着简单实际上把FPGA视频开发里最难啃的接口链路整个串了一遍。这篇博文就围绕这个实验把我自己做环路输出时的思路、硬件要点、代码结构和调试方法完整梳理一遍给准备动手或者正在被黑屏折磨的朋友一份可直接参考的笔记。先说清楚这篇内容适合谁。如果你刚入门FPGA、板子上有HDMI输入输出接口但不知道从哪里开始如果你拿到黑金或其他Artix-7开发板跑通LED流水灯之后想进入视频方向又或者你已经在做视频接口相关项目但对TMDS、EDID、HPD这些概念还停留在“听过”的阶段——这篇文章就是为你准备的。1. 环路输出是什么凭什么当FPGA视频第一课1.1 真实设备中的Loop Out环路输出这个功能在视频行业里其实很常见。你去看看拼接处理器、视频矩阵、广播级监视器背面除了HDMI输入口往往还有一个标着“LOOP OUT”或者“环路输出”的口。这个口做的事情很简单把输入信号原封不动地再复制一份出去不经过任何图像处理、缩放、叠加。为什么需要它因为现场设备经常要级联。比如一个信号源要同时送到三台显示器手头又没有分配器那就可以把三台显示器用HDMI线串起来信号源接第一台第一台的LOOP OUT接第二台第二台的LOOP OUT再接第三台。环路输出就是让信号能“穿透”这台设备继续往后走。在FPGA里做环路输出本质上也是同一件事把HDMI RX接收端恢复出来的视频流原样交给TX发送端发出去。代码量可能不到几十行但这条链路一旦跑通说明你已经把视频信号从物理层到协议层完整打通了。1.2 为什么第一个视频实验选它很多新手拿到带HDMI接口的FPGA板子第一反应是直接去调图像处理算法比如灰度转换、边缘检测、卡尔曼滤波。这个想法我能理解但实操中会陷入一个非常痛苦的境地显示器是黑的你根本不知道是HDMI接收没通、时序没对齐、还是算法写错了。接口问题和算法问题搅在一起排查起来一层叠一层。环路输出的价值就在于它把算法变量全部去掉只做一件事——验证视频通路能不能稳定工作。你不需要写复杂的图像处理只需要把RX的数据搬到TX。如果出图了说明整条链路是通的后面挂什么算法都行如果不出图问题一定出在链路本身排查范围非常明确。这也是黑金教程把环路输出放在视频实验靠前位置的原因。它不是一个“炫技”的实验而是一个“打地基”的实验。1.3 做之前先明确验收标准动手之前先定一个清晰目标避免做着做着失去方向。我给自己定的验收标准是这样的信号源电脑、机顶盒、手机转接器输出720p或1080p开发板接上后显示器能稳定出图。拔掉HDMI线再插回去重复几次系统不宕机、画面能恢复。换一个不同的分辨率比如从720p切到1080p在正确配置下也能出图。最后一个不一定在基础实验里做但如果能支持说明你对时序的理解已经很扎实了。这个实验能不能过直接决定了你后面做帧缓冲、图像缩放、OSD叠加时有没有一个可靠的调试底座。2. 动手前必须吃透的HDMI物理层与像素时钟2.1 4对差分线怎么把像素装进去HDMI的物理层走的是TMDSTransition Minimized Differential Signaling差分串行协议一共有4对差分线3对数据线1对时钟线。源端把并行的像素数据串行化后从这3对数据线送出去每一对线专门负责一个颜色分量——你可以理解成一条线管红色、一条管绿色、一条管蓝色。但这里有个关键点并行像素数据是8bit一个分量HDMI发送端会把它编码成10bit再串行发送。所以每一条数据通道上的实际串行速率等于像素时钟乘以10。举个例子1080p60的像素时钟是148.5MHz那么每一条通道的串行速率就是1485Mbps换算过来就是1.485Gbps三条通道加起来总带宽约4.455Gbps。新手听到1.485Gbps这种数字容易慌觉得很高端。其实在FPGA里处理它并没有想象中那么恐怖因为你不是用逻辑去“追赶”这个速率而是用专门的硬件原语——输入端用ISERDESE2把高速串行信号解成并行输出端用OSERDESE2把并行信号串行化。你的FPGA逻辑始终跑在像素时钟148.5MHz或74.25MHz这个频率上真正的高速部分被原语消化了。2.2 DE信号和高低电平周期的意义TMDS协议里没有像网络数据包那样的包头包尾它是靠一个叫DEData Enable数据使能的信号来区分当前传输的是什么内容。DE为高电平时三通道传输的是像素数据一个时钟周期发一个像素的24bitRGB各8bit。DE为低电平时传输的是控制信号主要是行同步HSYNC和场同步VSYNC。这两个同步信号各自只有1bit合起来2bit通过TMDS编码后也在数据通道里传。你可以把DE理解成一把刀把连续的数据流切成了两段有效图像区域和消隐区域。接收端拿到DE、HSYNC、VSYNC这三个信号再配合像素时钟就能准确地还原出一帧一帧的图像。这就是为什么HDMI对时序参数极其敏感——它没有额外的帧标记全靠这些同步信号来对齐。你在配置TX输出时序时如果行消隐前肩、同步脉冲宽度、后肩这些参数和源端不匹配显示器立刻就会表现异常。2.3 像素时钟的算法和几个常用数值像素时钟的计算公式很简单像素时钟 ≈ 水平总周期 × 垂直总周期 × 帧率其中水平总周期包括有效像素、前肩、同步脉冲、后肩垂直总周期包括有效行数、前肩、同步脉冲、后肩。拿最常见的两个分辨率来说参数720p601080p60有效分辨率1280×7201920×1080水平总周期16502200垂直总周期7501125像素时钟74.25MHz148.5MHzTMDS时钟74.25MHz148.5MHz单通道串行速率742.5Mbps1485Mbps总带宽约2.23Gbps约4.455Gbps对入门级FPGA开发板来说720p60是比较舒服的工作点74.25MHz像素时钟不高不低布局布线压力小IO带宽也宽裕。1080p60就接近很多入门级板卡IO能力的上限了所以如果你用的板子比较基础我建议先跑720p跑稳了再挑战1080p。在调试中如果发现1080p偶尔出花屏或者信号质量差降分辨率排查是一个很实用的手段。2.4 有独立时钟线意味着什么注意看上面表格里有一行叫“TMDS时钟”。HDMI和PCIe、以太网这些接口有一个非常大的区别它专门用了一对差分线来传像素时钟接收端不用从数据流里做时钟恢复CDR。这一点帮了FPGA开发者大忙。没有CDR意味着什么意味着你不需要在FPGA里去写复杂的时钟数据恢复逻辑只需要把TMDS时钟直接当成像素时钟来用或者送进PLL/MMCM做倍频和相位调整。数据通道上要做的工作相对简单一些只需要做“比特对齐”——也就是找到每个10bit编码字的边界把串行数据正确切成并行数据。当然简单是相对的。比特对齐这个操作在调试时依然是翻车重灾区后面第五节我会详细讲怎么排查。3. 硬件连接与供电HDMI座子不是插上就行3.1 先分清你的板子是直连还是带PHY芯片开始写逻辑之前一定要先翻开你手里板子的原理图看清楚HDMI输入接口是直接用差分线连到FPGA的IO还是中间经过了一颗HDMI PHY接收芯片比如ADI的ADV7611这类。这两种方案在FPGA里的设计路径完全不同。直连方案下FPGA要自己处理TMDS解串、比特对齐、编码解码灵活度高但难度也高黑金云课堂这类基础实验一般走的是这个路线因为它最能讲清楚底层原理。带PHY芯片的方案则简单得多PHY芯片已经把TMDS信号解成了并行视频总线比如BT.1120格式FPGA只需要读并行数据和时钟就行但这种方案你能学到的东西也少。如果你手上是不带PHY的直连板子恭喜你这个实验做完你对HDMI的理解会比用PHY芯片的人深一个层次。另外说一句如果你用Vivado打开工程却发现自己板子型号不在器件列表里不用怀疑工程文件坏了多半是安装Vivado时没有勾选对应的FPGA系列比如7系列或UltraScale系列。该补装补装该重装重装这不是代码问题。3.2 端接、ESD和I/O电平直连方案下硬件上有几个点会影响信号质量尤其是掉以轻心就全黑屏。第一是差分端接。HDMI接收端的差分对之间必须有100Ω的跨接电阻这组电阻一般画在HDMI座子附近。如果板子设计省掉了这个电阻高速信号没有阻抗匹配波形反射严重常见表现就是画面闪烁、花屏严重的直接没有信号。第二是IO电平标准。在Xilinx 7系列里HDMI输入输出通常用TMDS_33或者LVDS电平标准具体用哪个要看你的板卡设计不能上来就随便选个LVCMOS——电平标准选错了IO端口的电压阈值不对信号进来就是一堆乱码。第三是ESD保护。HDMI是热插拔接口静电放电是家常便饭。正规板子在座子后面都会放ESD防护芯片。这里给个小提醒调试时不要用示波器探头直接在座子引脚上乱戳一方面容易短路另一方面可能会把静电引到器件上搞坏一片。3.3 电源、HPD和EDID三个“假装没看见就会死”的细节新手在这个实验上翻车一半以上不是栽在代码上而是栽在下面这三个硬件细节上。第一个是电源。HDMI座子上有一个5V引脚但这个5V是信号源设备比如电脑输出的“检测电压”用来告诉接收端“线插好了”电流很小毫安级。网上经常看到有人问“HDMI供电电流需要多大”其实这是个误解——HDMI座子上的5V不是用来给设备供电的FPGA开发板必须用自己的USB口、电源适配器或者板载电源来供电。如果你以为插上HDMI线板子就能通电那肯定开不了机。第二个是HPDHot Plug Detect热插拔检测。接收端通过HPD引脚告诉源端“我准备好了你可以输出信号了”。HPD没有拉高电脑会认为显示器没连接HDMI口不会输出任何信号。开发板上HPD一般通过电阻上拉到3.3V或者由FPGA引脚控制。如果你发现电脑能识别到显示器但就是没有画面先拿万用表量一下HPD电平。第三个是EDIDExtended Display Identification Data。源端怎么知道该输出什么分辨率、什么刷新率靠读取接收端的EDID数据。这个数据一般存在一个EEPROM里或者由FPGA通过I2C接口动态回放。如果EDID是空的或者内容不对源端要么不输出要么输出一个奇怪的分辨率显示器自然没图或者异常。这三个细节每一个都能让你的实验“看起来莫名其妙失败”。所以硬件阶段不要急着写代码先把这三个点摸清楚。4. 环路通路的逻辑设计RX解串、时钟直通与TX回放4.1 RX侧解串链路的四个环节假设你的板子是FPGA直连HDMI座子RX侧的数据通路大致分成四个环节。第一个环节是差分缓冲。TMDS差分对信号进入FPGA后先用IBUFDS把差分信号转成单端信号数据通道和时钟通道都要这么做。第二个环节是输入延迟调节。HDMI的差分对在PCB上走线、经过连接器会有细微的时序偏差。FPGA里用IDELAYE2原语给数据通道加可调的延迟单位大概在几十皮秒量级用来补偿这些偏差。第三个环节是解串器。ISERDESE2把高速串行信号转成并行信号。因为TMDS是10bit编码实际工程中可能先用1:8解串再用其他逻辑补成10bit或者直接按1:10来设计取决于你选用的具体方案。第四个环节是比特对齐。串行数据只有一串比特流你要找到每个10bit编码字从哪里开始。一般做法是利用TMDS控制字符的固定码型来扫描边界然后通过“滑动比特位”让解串结果对齐。做完这四个环节你就能在FPGA里恢复出像素数据和DE、HSYNC、VSYNC了。这四步看起来简单但每步都对应着不同的故障现象调试时一定要有耐心。4.2 环路输出最核心的决策用谁家的时钟这是环路输出实验里最关键的一个决定也是很多教程一笔带过但实际工程里必须想清楚的地方TX发送端的像素时钟从哪里来有两条路可以走。方案A是时钟直通直接用RX恢复出来的TMDS时钟作为TX的像素时钟。这样做的好处是输入和输出完全同源不需要任何帧缓冲理论上整个环路只有几十纳秒的延迟。代码最简单符合“环路输出”的原始定义——信号进来什么样出去就什么样。坏处是如果上游信号源有抖动输出也会跟着抖。方案B是时钟隔离RX把数据写成异步FIFO或DDR帧缓冲TX用本地晶振产生的时钟从缓冲里读数据。好处是输入输出解耦可以改变分辨率、刷新率还能在不打断上游的情况下叠加OSD。但代价是需要额外管理跨时钟域和帧同步问题。基础实验应该选方案A。原因很简单这个实验的目的是验证链路不是练习跨时钟域。你把方案A跑通了再去做方案B心里会对“为什么要帧缓冲”有更直观的认识。顺便说一句方案A里RX恢复的TMDS时钟虽然能直接用但为了保证TX侧的信号质量建议让这个时钟先过BUFG或者MMCM再驱动TX逻辑不要拿原始时钟到处乱驱动。这在布局布线阶段能减少很多时序收敛的麻烦。4.3 直通逻辑的Verilog最小骨架下面这段代码就是环路输出的核心在基础实验里你甚至可以把它写到模块的顶层几乎没有多余的东西。// 简化示意HDMI环路直通 // rx_clk为从TMDS时钟恢复出的像素时钟 // module hdmi_loop_through ( input wire rx_clk, input wire rx_de, input wire rx_hsync, input wire rx_vsync, input wire [23:0] rx_pixel, output wire tx_de, output wire tx_hsync, output wire tx_vsync, output wire [23:0] tx_pixel ); // 环路输出数据原样回放 assign tx_de rx_de; assign tx_hsync rx_hsync; assign tx_vsync rx_vsync; assign tx_pixel rx_pixel; endmodule注意这段代码是高度简化的示意真实工程里你还要在前面加RX解串链路在后面加TMDS编码和OSERDESE2输出中间可能还需要加几级寄存器流水线来满足时序收敛。但这个骨架想表达的意思很明确环路输出在逻辑层面就是“搬数据”没有任何算法。你要花心思的地方全在接口的物理层和解串对齐上。4.4 EDID回放和HPD的落地方案EDID在环路输出实验里有两类做法。最省事的是板载EEPROM。很多HDMI开发板上已经有一颗EEPROM出厂就写好了EDID数据。这种情况下FPGA不需要参与DDCDisplay Data Channel通信插上电脑就能识别到屏幕。前提是EEPROM内容是对的如果识别出来的分辨率不对或者根本没有识别可能要自己用I2C编程器重新烧写EDID。另一种做法是用FPGA实现一个I2C从机当源端通过HDMI的SDA/SCL引脚来读EDID时FPGA把事先存在ROM里的EDID数据回放回去。这个方案灵活度高以后想支持动态分辨率切换、模拟不同显示器EDID都可以改代码实现适合想深入练习I2C状态机的朋友。但在基础实验里我不建议一上来就在FPGA里写I2C从机先把主链路跑通EDID用EEPROM解决。不管用哪种方案都要记得检查HPD是否正常拉高。有些开发板的HPD引脚是和FPGA相连的如果FPGA没有配置这个引脚的输出默认可能是低电平电脑端就会认为“没有显示器”自然不输出。这是硬件配置问题不是逻辑问题但在逻辑代码里也得有对应处理。4.5 TX输出的最后几级TX侧的链路和RX相反并行像素数据先经过TMDS编码器把8bit像素数据编码成10bit同时把HSYNC/VSYNC编码成控制字符然后送进OSERDESE2做并转串最后通过OBUFDS转成差分信号输出到HDMI座子。TX侧相对RX侧少了一个大麻烦——不需要做比特对齐。因为你自己是发送端比特边界完全由你决定编码器在哪个bit边界发数据接收端就必须在那个边界去对齐。这也是为什么很多HDMI发送端的调试比接收端轻松。如果你用的是Xilinx的官方HDMI IP这些原语都被封装好了配置一下就能跑。但如果你是为了学习我强烈建议至少手写一次TX链路和RX解串别直接上IP。用IP跑通只能算会用工具手写一次你才知道TMDS编码里那些控制字符是怎么回事DE信号是怎么和像素数据交替发送的。5. 上板调试从全黑到稳定出图的完整排查链路5.1 把“黑屏”拆成三个层面环路输出实验里你遇到的所有问题都可以拆到三个层面里去看这个思维方法非常重要。第一个层面是电信号层。HDMI线插上后TMDS时钟对有没有差分信号HPD是不是高电平5V检测电压是否正常这些问题从原理图就能找到测量点用万用表就能排查一大半。没有示波器也能做很多判断比如用万用表量HPD电平、量5V电压。第二个层面是数字链路层。FPGA内部有没有解出DE、HSYNC、VSYNC像素数据是不是周期性变化这一层主要靠Vivado的ILA逻辑分析仪来抓信号。第三个层面是协议层。EDID内容是否正确输出的时序参数是否符合VESA/CEA标准显示器支不支持你当前的分辨率排查的时候一定要自下而上先确认电信号层没问题再查数字链路层最后才去怀疑协议层。很多人一黑屏就怀疑EDID、怀疑代码里的时序参数结果量了一下HPD是低电平白折腾半小时。5.2 用ILA定位问题的一个具体思路Vivado里的ILAIntegrated Logic Analyzer是FPGA调试最常用的工具。环路输出实验里我建议你先把下面这几个信号加到ILA探针里rx_clk恢复出的像素时钟rx_hsync、rx_vsync行场同步rx_de数据使能rx_pixel[23:0]像素数据抓这些信号的时候时钟域选rx_clk。如果你的恢复时钟本身有问题ILA压根跑不起来这也是一个有效的检查手段。抓完波形之后怎么判断按优先级看三件事。第一rx_clk到底有没有在跑。如果ILA触发不了或者抓到是全0大概率是TMDS时钟就没有正确恢复出来。回去查电信号层查差分时钟有没有进FPGA、时钟引脚有没有约束对。第二rx_hsync和rx_vsync有没有周期性的脉冲。这两个信号是判断“数字链路层是否解通”的关键。如果解串和比特对齐做对了HSYNC和VSYNC一定是规律翻转的。如果这两个信号都不动问题基本出在ISERDESE2或比特对齐逻辑上。第三rx_de为高时rx_pixel是不是在变化。哪怕你输入的是静态画面HDMI发送端也会以一定频率刷新数据所以DE高电平期间像素值不可能是完全静止的。如果DE正常但像素值恒定不变说明解串出来的数据有问题或者IDELAY的延迟配置不对。这一套排查下来至少能定位到八成以上的问题。5.3 常见现象、可能原因和排查手段速查表把我在做这个实验以及帮别人看问题时遇到的现象整理成一张表遇到问题可以直接对号入座现象可能原因排查手段电脑识别不到显示器HPD未拉高、EDID为空万用表量HPD电平检查EEPROM或I2C回放逻辑显示器全黑但电脑显示已连接TMDS时钟未恢复、解串链路没通用ILA看rx_clk和rx_de检查IBUFDS/IDELAYE2花屏、雪花点比特对齐错误、IDELAY延迟不对扫描IDELAY的tap值检查比特对齐逻辑颜色通道互换红蓝对调R/G/B通道映射接反对照原理图检查数据通道和RGB的对应关系画面有滚动条纹时序参数和源端不匹配、行场同步位置不对检查HFP/HSW/HBP和VFP/VSW/VBP参数热插拔后不恢复HPD处理不完善、ESD导致器件异常检查热插拔流程图重新插拔并观察HPD电平变化1080p出图不稳定720p正常信号质量余量不足、IO速率逼近上限尝试降低分辨率验证检查端接电阻和线材这张表不一定覆盖所有情况但它能帮你把排查方向确认下来。如果你碰到的问题不在表里也先按“电信号层到数字链路层到协议层”的顺序查一遍基本都能缩小范围。5.4 别急着怪代码先怀疑线和屏这是个老生常谈但必须强调的点。我见过太多人花一整天调代码最后发现是HDMI线的问题。HDMI线缆质量参差不齐尤其是在跑1080p60的时候劣质线缆的衰减很严重表现出来就是画面闪烁、花屏甚至完全无信号。另一个容易被忽略的是显示器本身。不同显示器对输入信号的容错能力差别非常大有的显示器对同步信号的偏差很敏感稍微不对就黑屏有的显示器则很宽容花屏也硬显示。做环路输出实验时如果条件允许准备一台已知工作正常的监视器和一根已知好用的线交叉验证一下。这个习惯能帮你省掉大量无意义的调试时间。我自己就踩过这个坑。有一次调TX时序怎么调都觉得参数没问题但显示器就是偶尔闪一下黑屏。后来换了一根短线、质量好的HDMI线问题立刻消失。从此我在调试这类高速接口时永远默认“线材可能有问题”直到用替换法排除为止。6. 环路直通跑通后的三条扩展路线6.1 加帧缓冲让输入输出真正解耦环路直通跑通之后你可能很快会发现它的限制输入是什么分辨率输出就必须是什么分辨率输入一旦闪断输出也跟着闪断。要解决这个问题就要加帧缓冲。做法是在RX和TX之间插入一个异步FIFO或者DDR3/DDR4帧缓冲。RX侧把恢复的视频数据写入缓冲TX侧用本地晶振产生的时钟从缓冲里读数据。这样输入和输出被缓冲隔开输入抖动不会直接传到输出甚至可以做到输入1080p、输出720p这种跨分辨率转换。做帧缓冲是个绝佳的进阶练习它会把异步FIFO读写字长、帧同步、缓存管理这些知识点一次性练到位。比直接去学那些复杂算法实在得多。6.2 在通路上挂图像处理环路直通和帧缓冲做好了你的视频数据通路就是一个标准的“输入—流水线—输出”架构。这时候你想在中间挂任何图像处理都很方便灰度转换、色彩空间转换、边缘检测、OSD叠加、缩放全都只是在这条通路上插入一个模块的事。很多人在网上问“FPGA图像处理怎么入门”其实入门的重点不在算法本身而在于你能不能稳定地拿到一帧一帧的视频数据。环路输出实验就是帮你去掉这个最大的障碍。通路都不通再好的算法也出不来效果。6.3 我建议的后续学习顺序以黑金这套教程的进度为参考我给新手朋友建议的顺序是这样的先搞定HDMI环路输出再做一块“行缓冲或帧缓冲”然后是简单的像素级图像处理灰度、二值化、边缘检测最后再上OSD叠加、缩放、多分辨率适配这些综合功能。每走一步都以“画面稳定不出错”为验收标准。别急着追求花哨效果先把每一步的链路底层吃透。如果你正在做这个实验卡在某一个现象出不来对照第五节那张表一层一层查大概率能解决问题。等这条直通链路稳定出图之后你会明显感觉到FPGA视频开发里最难的那道坎已经过去了。后面再遇到问题你至少知道该往哪个方向看而不是对着黑屏发呆。
返回列表