ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FPGA图像处理入门:HDMI视频输入与环路输出实验全解析

FPGA图像处理入门:HDMI视频输入与环路输出实验全解析 FPGA图像处理这一路绕不开一个门槛怎么把一路标准的HDMI视频信号接进来再想办法送出去。之前我在《黑金云课堂》的FPGA基础课上就用AX7A035带着大家做了一次HDMI视频输入与环路输出实验。这个实验一句话描述就是外部信号源通过HDMI线接到开发板的HDMI IN口视频数据进入FPGA以后不做额外处理原样发到HDMI OUT口送到显示器上显示。听起来像直连但中间经过了完整的接收、解码、时序重建、编码、发送流程任何一个环节出错屏幕都不会亮。跑通这个实验等于把FPGA图像处理里最底层的视频通路彻底打通了后面再做帧缓存、缩放、滤镜、AI前处理都有基础。这篇东西写给两类人刚入门FPGA、想走图像处理方向的朋友以及已经会写逻辑但从来没碰过视频时序的工程师。我会从整体架构讲起把HDMI信号链路、FPGA内部逻辑、工程约束和调试方法一条线讲完希望能帮大家少走点弯路。1. 实验整体架构与设计思路1.1 环路输出到底练了什么很多人第一次听到“环路输出”这个名词会误以为就是拿一根线把输入和输出口短接。实际上在FPGA设计里环路输出是一条完完整整的数字视频通路HDMI输入信号进入FPGA引脚经过差分接收、串并转换、字节对齐、像素重组后变成一组并行RGB数据和行场同步信号随后这组数据再经过并串转换、TMDS编码从输出引脚送出去。整个过程中数据不是在芯片外部流传的而是在FPGA内部走了一圈。这一圈走下来练到的东西非常扎实。首先是视频时序你要理解什么是有效像素、什么是行消隐、什么是场消隐DE信号为什么可以作为像素数据的门控。其次是时钟HDMI输入的像素时钟是外部信号源给的你的逻辑必须老老实实跟着这个时钟跑不能想当然地用开发板晶振。第三是数据通路输入侧和输出侧如何保证像素对齐寄存器打拍是必须的。这些能力是后面做任何视频算法的地基所以我说它是FPGA图像处理里最值得先做一遍的实验。另外环路输出实验还能帮你建立一个判断标准如果显示器上出现了画面说明接收链路是通的如果画面稳定不闪烁、颜色正确说明时序重建和编码发送链路也没问题。这比单纯仿真通过要有说服力得多因为上板验证才是硬道理。1.2 接收方案选型IP核与原语直连HDMI输入在FPGA里有两种主流实现方式实验前要先搞清楚自己用的是哪条路。第一种是用Xilinx官方的HDMI 1.4/2.0 RX IP配合Video Timing ControllerVTC这类视频时序IPIP会自动完成TMDS差分信号接收、串并转换、通道对齐等复杂工作对外输出AXI4-Stream视频流。第二种是自己在RTL里调用IBUFDS、ISERDESE2、BUFPLL等底层原语从物理层开始手动恢复数据和时钟也就是Xilinx应用笔记XAPP589里那套DVI/HDMI 1.4接收方案。我在课程里建议入门阶段直接用IP核。原因很简单HDMI接收链路里最麻烦的不是逻辑本身而是高速串行数据的比特对齐和通道对齐这些代码自己写不但容易出错而且一旦出错很难定位。IP核把这些工作封装好了你可以把注意力先放在视频时序和像素流上。等跑通了IP核方案再回过头去看XAPP589原语方案那时你会发现对信号链路的理解会提升一个层次。但这不意味着原语方案不重要。恰恰相反你迟早要面对它因为IP核会掩盖很多细节。比如IP核内部为什么会有一个动态相移校准模块为什么数据lane需要bitslip对齐这些问题在IP核方案里你完全感受不到。所以我个人的建议是第一次做环路输出用IP核第二次再用原语方案重写一遍两次做完才算真正吃透HDMI视频输入。1.3 为什么环路输出适合当第一个视频实验选择这个实验作为“FPGA基础”系列的第一课不是随随便便定的。视频相关的实验有很多比如单路HDMI输出、VGA显示、VDMA帧缓存、图像缩放但这些都是单向链路要么只做发送要么依赖外部存储。环路输出实验天然是一个闭环输入端给了你最真实的视频源输出端给了你最直观的结果反馈。更重要的是环路输出实验的调试成本低。它不需要DDR3不需要VDMA不需要MicroBlaze软核只需要FPGA本身的逻辑资源和一对HDMI接口。只要你对Vivado的基本操作还算熟练新建工程、添加约束、综合布线、下载bit文件这一套流程走下来是可以在一两个小时内看到实际画面效果的。这种快速反馈对初学者建立信心特别重要。还有一个细节在于环路输出实验是理解“跨时钟域”问题的最佳铺垫。虽然最基础的环路输出是直接用输入时钟发数据不涉及跨时钟域但你会问一个很自然的问题如果显示器只支持别的分辨率怎么办如果要叠加一个本地生成的菜单界面怎么办这不就需要本地时钟和输入时钟协同了吗带着这些疑问去做后面的VDMA和帧缓存实验你才会有方向感而不是盲目地抄代码。所以环路输出实验在整套课程里起到的是承上启下的作用。2. HDMI信号链路与关键参数2.1 TMDS差分信号与物理层HDMI接口的物理层用的是TMDSTransition Minimized Differential Signaling最小化传输差分信号传输方式。它一共有4对差分信号其中3对是数据通道分别传输R、G、B信号在4:4:4采样下就是三个颜色分量还有1对是时钟通道。每对差分信号由P和N两根线组成靠两根线上的电压差来传信号抗干扰能力比单端信号强很多。这也是为什么HDMI线可以做得比较长而且不容易受外部电磁干扰。TMDS协议里的数据编码很有意思它不像UART那样直接发送原始数据而是先把8位像素数据做两轮编码扩展成10位数据再发出去。第一轮编码让输出的数据跳变次数尽可能少第二轮编码根据当前通道的直流偏移决定是否翻转信号保证整个链路直流平衡。这样做的目的是降低电磁干扰同时让接收端可以从数据信号里恢复出稳定的时钟信息。所以你在FPGA内部看到的像素数据是8位或者多位并行而外部引脚上实际跑的却是10倍于像素时钟的比特流。还有个容易混淆的概念是HDMI和DVI在TMDS物理层上是兼容的也就是说很多情况下一个DVI显示器插上HDMI转接头也能显示画面因为视频部分是同一套编码。差别主要在于HDMI多了音频、CEC、DDC这些辅助通道。做基础实验时很多开发板其实只接了TMDS视频信号和DDC通道音频相关引脚都没连这并不影响视频显示但会让你误以为HDMI音频不存在。等以后做到音视频同步的项目时就要特别注意这部分。2.2 从像素时钟到完整时序参数视频时序是所有图像处理的基础HDMI环路输出实验里最需要背下来的就是像素时钟和行场时序参数。拿最常见的1080p60来说有效分辨率是1920x1080但实际在一帧画面里除了有效像素还有水平消隐和垂直消隐。标准的CEA-861时序里1080p60的一行总长度是2200个像素时钟一帧总行数是1125行乘以60帧就得到像素时钟频率2200 × 1125 × 60 148.5MHz。这个148.5MHz就是像素时钟每个时钟周期对应一个像素点。如果分辨率变成720p60那一行总长度是1650总行数是750像素时钟就是1650 × 750 × 60 74.25MHz。你可以看到不同分辨率对应的像素时钟差异很大这就是为什么FPGA环路输出实验不能随便用一个固定时钟去采样而是必须从HDMI时钟通道里恢复出真实的像素时钟来驱动逻辑。除了像素时钟还要关注三个控制信号DEData Enable数据有效、HSYNC行同步和VSYNC场同步。DE高电平表示当前正在传输有效像素低电平期间是消隐区HSYNC和VSYNC分别指示行和场的同步脉冲位置。对于接收端来说DE是核心因为DE高电平期间的数据就是真正的画面像素你只需要按顺序采下来即可。HSYNC和VSYNC虽然对纯视频数据不重要但要想让显示器正确识别发送端必须按照严格的时序重新生成它们。提示做环路输出实验建议先在PC上用软件查一下你输入信号源的EDID时序。很多显示器对时序极其敏感如果HSYNC或VSYNC宽度差一个像素时钟显示端可能直接黑屏连提示都不给。2.3 板级电路与HDMI供电细节FPGA开发板上的HDMI接口虽然看起来就是一个简单的座子实际电路里有不少门道。TMDS差分信号从HDMI座子到FPGA引脚之间通常会串接共模电感、ESD保护二极管有些板子还会加AC耦合电容。这些器件都是为了保证高速信号质量实验时如果你发现信号不稳定第一步就应该检查这些器件的焊接和参数是否正常。供电问题更容易被忽略。HDMI规范要求输出端的5V引脚至少要有50mA的供电能力很多开发板直接用板上电源随便给HDMI座子供了几十毫安结果就是显示器经常间歇性黑屏、识别不到信号。我实测下来5V供电能力最好做到200mA以上同时要在靠近接口的地方放几颗去耦电容比如10uF和100nF并联这样信号源初始化的电压波动才不会影响到TMDS发送端。另外还要注意FPGA的I/O Bank电压。如果开发板把HDMI座子直接接到FPGA的HR Bank这个Bank的VCCO电压必须正确配置。7系列FPGA在接收TMDS信号时很多板卡会把它配置成TMDS_33电平标准这要求Bank电压为3.3V。如果Bank电压设成1.8V或者2.5V就算引脚还能工作信号的电气特性也不对上板时会出现电平判定错误轻则花屏重则烧毁引脚。3. FPGA内部逻辑设计3.1 输入侧数据恢复输入侧要做的事是从HDMI时钟通道恢复出像素时钟再从3个数据通道里恢复出10位并行数据。如果用Xilinx的HDMI RX IP这些工作都在IP核内部完成你只需要给IP提供参考时钟和复位然后把恢复出来的视频流信号接出来就行。但是理解这个过程还是很有价值的尤其是对底层原语方案。从物理层看HDMI时钟通道送来的是一个差分时钟信号频率等于像素时钟。比如1080p60就是148.5MHz这个时钟可以直接经过IBUFDS转成单端时钟再通过BUFIO送到数据lane的ISERDESE2模块作为高速采样时钟。至于数据信号由于3个数据通道上跑的比特流量是像素时钟的10倍ISERDESE2需要做1:4或1:8甚至1:10的串并转换把连续的比特流切成长度为10或8的并行数据。这里有一个非常关键的细节接收端怎么知道10位数据的边界在哪里这就是所谓的比特对齐。HDMI/DVI发送端在数据空闲态会发送特殊的控制字符接收端通过检测这些控制字符的位置来滑动比特窗口找到正确的字节边界这个过程叫“调整(bitslip)”。如果对不齐你收到的RGB数据会整体错位画面颜色会乱成一团。IP核方案里这个对齐是自动完成的原语方案里就需要自己写状态机来控制bitslip。3.2 像素重组与时序提取比特对齐完成之后你拿到的还是交织的串行数据需要按通道重组回RGB像素。在HDMI 4:4:4采样下通道0、通道1、通道2分别对应蓝色、绿色、红色有些配置顺序不同具体看编码映射。每个通道一个像素是8位数据三个通道合起来就是24位RGB888。Xilinx的HDMI RX IP对外输出的正是这种重组好的并行像素格式所以IP方案里这一步是透明完成的。接下来要提取时序。数据通道在有效区传的是像素数据在消隐区传的是控制信号。DE信号在前端已经解出来了HSYNC和VSYNC则可以通过检测控制字符或者直接由VTC IP从数据流中恢复。对环路输出实验来说你真正需要的是DE高电平期间的像素数据和对应的像素时钟。这里要提醒一个容易栽跟头的点从IP核输出的AXI4-Stream视频流和原始的DE/HSYNC/VSYNC信号并不是完全等价的。AXI Stream只有数据有效信号TVALID和最后一个像素信号TLAST你需要借助Video Timing Controller之类的模块把AXI Stream重新转换成带DE、HSYNC、VSYNC的并行视频时序再送给发送端。我见过不少人在这个转换上卡壳其实只要理解了DE就是TVALIDTLAST对应一行结束思路就顺了。3.3 输出侧时序重建输出侧的任务是把处理后的像素数据重新编码成TMDS差分信号发出去。先不要管那些信号名核心要保证的是三件事像素时钟正确、行场同步信号时序正确、数据通道编码正确。像素时钟的输出可以用输入恢复出来的时钟这是环路输出实验最简单的做法。因为输入和输出共用一个时钟域数据不需要跨时钟域处理只要把像素数据、DE、HSYNC、VSYNC打一拍送到发送端编码器就可以。如果将来要做帧率转换或者格式转换就需要在中间加异步FIFO或者DDR缓存那是后话。行场同步和消隐参数需要严格按照目标分辨率来配置。环路输出实验里目标分辨率就是输入信号源的分辨率所以直接用接收端恢复出来的同步信号重新生成即可。但如果你以后做HDMI发送手里只有一组RAW RGB数据就必须自己计算H_active、H_total、H_sync_start这些参数填到VTC或者自己的时序计数器里。TMDS编码发送一般也交给IP核或者封装好的tmds_encoder模块完成。需要注意编码器和OSERDESE2模块需要两个时钟并行侧用像素时钟比如148.5MHz串行侧用10倍像素时钟的比特时钟。这个高速比特时钟一般由MMCM/PLL生成。在做IP核方案时Vivado的HDMI TX IP会自动创建相关时钟域你只需要按向导提示连接参考时钟即可大体上不用手动操心。4. 工程实践约束、代码与调试4.1 引脚约束与时钟约束上板之前引脚约束是必须认真核对的一步。HDMI输入和输出都是差分信号每对差分信号的P侧和N侧引脚要分别绑定。以Artix-7开发板为例HDMI RX的3个数据通道加1个时钟通道共4对差分引脚HDMI TX同样需要4对差分引脚。Vivado的XDC约束里对差分对通常只需要对P侧设置IOSTANDARDN侧会自动继承但建议P和N都显式约束避免奇奇怪怪的告警。时钟约束的重点是告诉工具输入像素时钟的频率范围。由于HDMI信号源的分辨率不确定像素时钟可能从几十MHz到一百多MHz变化。你可以创建一个虚拟时钟或者直接约束输入时钟端口频率用目标分辨率来设置。比如计划跑1080p60就需要约束create_clock -name hdmi_rx_clk -period 6.734 [get_ports hdmi_rx_clk_p]。6.734ns就是148.5MHz的周期。这里要理解这种约束只在静态时序分析时有效实际运行时时钟频率还是取决于信号源但约束不写Vivado的综合布线可能会优化得过于悲观。还有一个常见坑是HDMI时钟通道的引脚要确保在同一Bank而且三个数据通道也最好在同一个Bank。如果跨了BankBUFIO资源的布局会受到很大限制布线困难甚至直接失败。我在AX7A035上第一次做这个实验时就是因为一个数据通道被安排在相邻Bank导致时序收敛很痛苦。后来查了原理图老老实实把引脚按Bank调整问题才解决。4.2 核心代码结构与示例环路输出实验的代码结构说白了就是接收、直通、发送三大块。如果使用Xilinx HDMI IP代码里主要是例化IP核和VTC再把RX侧的视频流信号接到TX侧。为了说明最核心的思路我在这里写一个简化版的直通模块演示从并行RGB像素流到像素流输出的打拍处理。module hdmi_loopback #( parameter C_PIXEL_WIDTH 8 )( input wire pix_clk, input wire rst_n, input wire [23:0] video_rgb_i, input wire video_de_i, input wire video_hsync_i, input wire video_vsync_i, output reg [23:0] video_rgb_o, output reg video_de_o, output reg video_hsync_o, output reg video_vsync_o ); always (posedge pix_clk or negedge rst_n) begin if (!rst_n) begin video_rgb_o 24d0; video_de_o 1b0; video_hsync_o 1b0; video_vsync_o 1b0; end else begin video_rgb_o video_rgb_i; video_de_o video_de_i; video_hsync_o video_hsync_i; video_vsync_o video_vsync_i; end end endmodule这个模块就是把输入信号完整地打了一拍然后输出实际工程里视频信号从IP核输出到你自己的处理模块之间也会做类似打拍来改善时序、避免亚稳态。真正做环路输出时RX IP输出的像素流不经过这个模块也行直接在顶层连线到TX IP但那样就没有教学意义了。我还是建议大家保留这样一个寄存器打拍环节方便用ILA抓信号时看清楚数据路径。在真实工程里RX侧和TX侧中间还可能插入一些简单的图像处理比如RGB转灰度、图像颜色反转等。测试阶段我常常让用户加一个颜色反相逻辑让环路输出画面和原始画面在视觉上有明显区别这样能立刻判断数据处理链路有没有生效。注意到没有这比盯着完全相同画面的屏幕去猜输出是否正常要高效得多。4.3 仿真与上板验证环路输出实验的仿真比一般逻辑模块要麻烦一点因为你需要一个输入视频测试激励。最简单的做法是写一个Testbench用计数器模拟一行行像素和DE、HSYNC、VSYNC信号产生一组固定颜色条纹的数据输入到你的环路模块然后在输出端验证数据和时序是否一致。仿真里通常不需要等整帧跑完只看几行有效像素就能确认逻辑正确。我自己常用的一种激励方式是生成一个彩条测试图样比如一行内红绿蓝三色分段。这样在仿真波形里很容易判断通道顺序是否反了、亮度和色度是否错位。上板时再用一个实际信号源比如电脑的HDMI输出输入1080p60信号进行验证。电脑可以设置为扩展屏模式然后在HDMI输出分辨率里选1080p60这样信号源稳定且容易控制。上板验证有一个重要的检查顺序先看时钟通道用ILA抓一下恢复出来的像素时钟是否在预期频率附近再看DE信号确认是否有连续的高电平有效区然后看RGB数据确认像素值是否有规律变化最后看显示器画面。我在课上强调过很多次不要一上来就看屏幕因为屏幕黑屏只能说明某个环节断了但根本定位不了问题。把信号链路一层层看过去比猜要快得多。5. 常见问题排查与避坑记录5.1 常见问题速查表做这个实验大家遇到的问题其实高度集中我把这几年见过的典型问题整理成一张表方便你排查时直接对照。现象可能原因排查思路显示器完全黑屏输入信号没进FPGA先确认用ILA能看到像素时钟和DE信号若看不到检查HDMI线、信号源是否开启画面花屏、杂色数据通道比特对齐失败用IP核时检查通道对齐状态信号自研RTL时检查bitslip状态机颜色失真比如红蓝互换RGB通道映射错误检查RX IP输出通道与TX IP输入通道是否按B/G/R顺序连接画面闪烁或间歇黑屏输出5V供电不足实测HDMI座子5V的电流能力尽量保证50mA以上最好200mA显示器提示无信号输出时序参数不对检查TX侧VTC配置的分辨率、刷新率是否与输入一致图像偏移或边缘有花边行场消隐参数不对确认HSYNC/VSYNC的前肩、同步脉冲、后肩宽度是否符合CEA-861综合布局布线失败HDMI引脚跨Bank重新查看原理图把同一组TMDS通道的引脚安排在同一个Bank上电后芯片发烫I/O Bank电压配置错误立即断电核对Bank VCCO电压与XDC中的IOSTANDARD是否匹配这张表没法覆盖所有情况但覆盖了90%的入门问题。如果你遇到的问题不在这张表里最有效的方法就是把ILA触发条件全部去掉先抓一拍看数据是什么样再一步一步往前后方向移动触发点直到找到第一个信号异常的位置。5.2 调试经验与独家技巧这里分享几个细节平时文档里一般不写。第一个是HCGHot Plug Detect热插拔检测信号。很多人在调试时忽略了这个信号实际上显示器和信号源之间是靠HPD引脚来通知“我插上了设备”的。如果开发板上的HPD上拉电阻没焊或者信号没接到FPGA显示器可能永远检测不到HDMI输入。实验时务必确认开发板原理图中HPD引脚的连接状态。第二个是EDID的问题。显示器通过DDC通道向信号源报告自己支持的分辨率。FPGA开发板如果不实现一个EDID ROM信号源可能默认输出一个低分辨率格式甚至不输出信号。黑金AX7A035这类板卡一般会把HDMI座的DDC引脚接到一个EEPROM或者FPGA逻辑上用来模拟EDID。如果你的实验板没接EEPROM那就要考虑在FPGA里用I2C逻辑模拟一个最简EDID否则电脑端根本不会把它识别成显示器。第三个技巧是调试环路输出时可以故意把输出分辨率配错看看显示器的错误提示。比如输入是1080p60你却把TX配置成720p60这时显示器通常能正常点亮但画面要么缩放变形要么只显示部分区域。通过这个现象你反而能确认输入和输出两边链路都是通的问题只出在时序配置上。这个经验看起来很笨但在没有示波器的环境下非常实用。最后再说一个跟逻辑无关但影响很大的坑HDMI线材的质量。TMDS信号在1080p60下速率已经到1.485Gbps劣质线材或者超过2米的普通线信号衰减会非常明显导致偶尔黑屏、花屏。实验台上尽量准备一根短的高质量HDMI线最好带认证标志可以省掉大量无效排查时间。做这个实验我个人最大的体会是视频这个东西时序对了画面就出来了时序不对怎么猜都是白费。所以不管用哪种方案一定要先把像素时钟和DE、HSYNC、VSYNC这几个信号在ILA里面看明白再去看屏幕。环路输出只是一个起点跑通之后建议你下一步试试在这个通路上加一个异步FIFO把输入像素时钟域和输出像素时钟域分开再配一个简单的彩色条纹生成器人为生成一个本地时钟域的静态画面用按键切换静态画面和直通画面。这个小小的改动能让你真正理解跨时钟域和帧同步的意义也为后面接触VDMA和DDR帧缓存打下基础。最后再分享一个小技巧做环路输出上板调试时把显示器分辨率设置成720p60会比1080p60更容易成功。因为720p60的像素时钟只有74.25MHz时序裕量更大很多信号质量问题在这个分辨率下不会爆发适合先确认链路功能。等720p稳定跑通再切换1080p锻炼一下信号完整性调试能力。一步一步来视频这条路就能走得很稳。
返回列表