做这个项目的时候我其实已经默认了一个前提4K视频在消费端早就不是新鲜事但在工业检测、医疗影像、视频会议一体机这类设备里很多还是靠专用芯片在撑。专用芯片好用是好用可一旦遇到非标分辨率、特殊叠加需求、或者需要快速改接口协议的时候基本就卡死了。FPGA的好处就在于接口和算法都能自己说了算尤其国产FPGA这几年资源越做越厚拿来做4K视频通路已经不是“能不能做”的问题而是“怎么做才稳”的问题。这篇就是从一个实战项目的角度完整记录我用紫光同创PG2L200H开发板从零搭一套4K视频处理系统的过程。项目核心链路是HDMI输入、FPGA内做缓存和图像处理、再HDMI输出全程用紫光同创的PDS开发工具。涉及的核心问题包括4K60的时序参数怎么算、TMDS信号怎么编解码、DDR帧缓冲怎么做跨时钟域、HDMI输入输出怎么配置才不踩坑以及我在调试中实际遇到的花屏、无图、时序不收敛等问题和排查方法。如果你手上刚好有同款开发板或者在做国产FPGA的视频类项目这篇可以直接当参考手册用。哪怕是新手跟着把HDMI信号定义和像素时钟计算这块啃下来后面调起板子来也能少走不少弯路。1. 项目总体设计与选型思考1.1 为什么视频处理会选择FPGA方案现在的SoC方案比如瑞芯微、全志、海思对4K视频的支持很成熟已经有H.264/H.265硬编解码、ISP、HDMI输出这些完整能力。但实际落到项目里有相当一部分需求是SoC并不好干的比如把4K输入拆成多个区域分别缩放后再拼屏、在原始视频流上叠加自定义的图形或字符、对不同来源的视频做帧级同步切换、或者需要极低的端到端延迟。这些功能如果依赖SoC往往要么没有对应接口要么延迟控制不住。FPGA方案的核心价值是“数据通路可定制”。视频流在FPGA里可以被拆成像素级、行级、帧级来处理每一级的时序、带宽、资源都是可控的。而且FPGA天然适合并行处理4K60的视频流一个像素时钟进来在FPGA内部可以做多路并行处理吞吐量足够。这里还必须提一个现实背景国产化替代。很多行业项目已经明确要求主控、可编程逻辑器件这类核心元器件优先选国产。紫光同创是国产FPGA里落地项目比较多的厂商之一PG2L200H也算主流型号性能和生态足够支撑视频处理这类中等规模应用。1.2 PG2L200H选型依据选PN2L200H或者说PG2L200H这颗芯片主要看四个方面。第一是逻辑资源。视频处理链路里输入解码、缩放、OSD、输出编码这些模块加起来逻辑消耗一般在5万到10万LUT量级具体看算法复杂度比如双线性插值这类需要一定的乘法器资源。PG2L200H的逻辑规模足够富余不会因为资源紧张而把设计改得别扭。第二是内置DSP和块RAM。视频缩放滤波、色彩空间转换都要用到较多的乘法累加运算DSP硬核的数量直接决定算法能不能在一个像素时钟周期内完成计算。块RAM则用于行缓冲、FIFO、系数存储尤其在4K分辨率下行缓冲动辄上千字节块RAM太小会非常被动。第三是高速收发器SerDes。4K60 4:4:4 8bit的HDMI信号单通道TMDS数据速率接近6Gbps这已经远远超出普通IO口的处理能力必须依靠SerDes才能实现接近或达到HDMI 2.0带宽的信号收发。一定要确认所用封装和型号有没有引出足够的SerDes通道。第四是外部存储器接口。4K视频处理基本绕不开帧缓存DDR3/DDR4控制器是刚需。PG2L200H支持标准的DDR接口这部分在选型时要确认开发板上用的DDR颗粒类型和位宽避免后续写控制器时发现接不上。1.3 系统模块划分整套4K视频处理系统可以划分为四块模块职责关键资源HDMI输入模块接收TMDS串行信号时钟恢复、8b/10b解码、同步信号提取SerDes、PLL、IO视频处理模块色彩空间转换、缩放、OSD叠加、帧缓存读写控制DSP、BRAM、DDR控制器DDR存储模块视频帧缓存、多帧乒乓、跨时钟域缓冲DDR控制器、FIFOHDMI输出模块时序生成、TMDS编码、串行发送SerDes、PLL、IO每个模块之间用AXI-Stream或自定义像素总线连接核心信号就是像素数据、行有效、帧有效、像素时钟。这种模块化设计方便单独仿真也方便后续替换算法模块。2. HDMI输入输出信号定义与电路设计要点2.1 HDMI接口信号逐个说清楚HDMI接口最常用的是Type A类型的19个引脚看起来不多但每一组信号都有自己的脾气。在做FPGA板级设计的时候至少要把下面这三类信号搞清楚。TMDS数据信号是三对差分线TMDS Data0、Data1、Data2另外还有一对差分时钟TMDS Clock。数据线上传输的是编码后的像素信息和数据包音频、辅助数据时钟线传输的是像素时钟。HDMI 1.4时代像素时钟最高340MHz到了HDMI 2.0像素时钟可以到594MHz每对数据线的速率就是像素时钟的10倍。DDC通道本质是一条I2C总线用来读取显示设备的EDID扩展显示标识数据让源端知道显示设备支持什么分辨率、什么色彩格式。FPGA做发送端时要通过DDC读取接收端EDID做接收端时则要响应源端的DDC请求把预存的EDID返回回去。这个通道一旦不通源端可能直接不输出信号。HPDHot Plug Detect是热插拔检测引脚。源端靠它感知显示设备是否接入输出端通常要维持一个高电平表示“我在这里”。在FPGA接收端项目中外部5V信号来自源端经过分压或比较器后给到FPGA的普通IOFPGA检测到插入事件后启动后续初始化流程。还有两个容易被忽略的信号5V Power是源端提供的5V电源用于给接收端的EDID电路供电这也是判断HDMI线是否插入的重要依据CEC是消费电子控制通道大部分工业项目用不到但如果你想做联动控制这条线也需要引出来处理。2.2 FPGA直接接HDMI还是用桥接芯片很多刚接触FPGA视频项目的人都会问一句能不能把HDMI接口直接连到FPGA上答案是能但有条件。直接连接意味着FPGA的SerDes或高速IO要直接承受TMDS电平好处是省了芯片、成本低、灵活性最高。代价是时序收敛难度大尤其4K60这种速率下PCB走线、阻抗匹配、端接、ESD保护都必须做得非常讲究。另一种方案是使用HDMI桥接芯片比如接收端用ADV7611或LT6911UXC这类芯片把HDMI信号转成并行RGB或MIPI CSIFPGA只接并行数据总线。发送端则用SiI9134或IT66121之类的发送器把并行RGB转成HDMI。这种方案大大降低了FPGA端的时序要求开发周期短很多但会损失一部分灵活性也增加了BOM成本。实际项目怎么选标准很直接如果速度在1080p级别FPGA GPIO或者低速SerDes就能处理可以考虑直接连如果目标是4K60且要求灵活定制链路建议上直接SerDes方案这是真正能发挥FPGA价值的路径如果项目周期紧不太想碰高速PCB设计就老老实实用桥接芯片。这个项目的核心是学原理、打通链路所以我选择直接用SerDes方案所有信号都从FPGA管脚进最大化保留可玩性。2.3 电路设计要点这几条必须守住HDMI传输线是100欧姆差分阻抗PCB上差分对走线必须严格按100欧姆控制阻抗对内等长也非常重要TMDS数据线与时钟线之间也有长度差要求通常控制在几十密尔以内具体看接口速率和参考设计约束。ESD保护不能省。HDMI接口裸露在外面经常热插拔静电打坏SerDes管脚的事故我见过不止一次。每个TMDS差分对、DDC、5V、HPD都要加专用的HDMI ESD防护器件选寄生电容尽量小的型号否则会劣化高速信号质量。HPD设计时要注意不能直接把5V拉进FPGA。通常的做法是HDMI座子的HPD引脚通过1k电阻上拉到5V然后经过电阻分压或电平转换把高电平降到FPGA bank可接受的范围再接一个RC滤波防止插拔瞬间的毛刺误触发生成中断。DDC上拉电阻一般用1k到10k范围内的值上拉到还是5V。如果FPGA bank的IO电平是3.3V或1.8V就需要做电平转换或者在FPGA内部用开漏结构加外部上拉到3.3V的方式处理。需要特别提醒DDC信号频率虽然不高但因为它跨接在源端和FPGA之间走线也不要随便拉很长。3. 4K60视频通道参数计算与配置方法3.1 从分辨率推像素时钟这是所有设计的地基4K分辨率也就是3840x216060Hz刷新率RGB 4:4:48bit色深这个模式下的像素时钟不是简单分辨率乘刷新率还要算上消隐区。HDMI 2.0标准里4K60 4:4:4 8bit的常用时序参数是水平有效像素3840水平消隐期560前肩88同步脉宽44后肩148具体值有细微差异参考VIC时序表一行总像素3840 560 4400垂直有效行2160垂直消隐期90前肩4同步脉宽5后肩36等一帧总行数2160 90 2250像素时钟 4400 × 2250 × 60 594MHz这就是4K60最核心的地基数字。后面所有的逻辑设计、FIFO深度计算、DDR带宽评估都从这594MHz出发。TMDS单通道数据速率 像素时钟 × 10 / 3不对准确说是每通道数据速率等于像素时钟乘以10。因为TMDS编码把一个8bit像素数据变成10bit串行数据每个像素时钟周期内三个通道同时传每个通道都是10bit所以单通道速率 594MHz × 10 5.94Gbps。这个5.94Gbps就是为什么SerDes成了必需品。普通IO能跑的速率一般在1.5Gbps左右5.94Gbps必须上SerDes。同时这个数值距离HDMI 2.0定义的单通道6Gbps上限非常接近设计时留的余量并不多所以时钟抖动、电源噪声这些指标都要仔细控制。3.2 发送端并行像素怎么变成TMDS串行信号HDMI发送端的核心作用是把并行RGB数据和行场同步信号按照TMDS协议编码再串行发送出去。TMDS编码本身就是8b/10b编码的一种变体。简单说在数据周期内8bit视频数据被转换成10bit直流平衡编码同时把DE数据使能、HSYNC、VSYNC包含在控制周期里。编码的目的有两个直流平衡避免传输线长期处于高或低电平导致接收端无法判别和时钟恢复辅助。在FPGA实现中这个过程分成三步第一步像素数据经过TMDS编码器变成10bit并行数据。编码器在DE有效时对RGB三个通道分别编码在DE无效的消隐期发送控制码对应HSYNC、VSYNC的组合。第二步把10bit并行数据送入串行器。FPGA的SerDes一般支持各种位宽模式比如10:1或8:1的并串转换。这里选择10:1模式直接用像素时钟的10倍频时钟作为串行时钟。第三步串行差分信号从SerDes的发送端差分对输出经过PCB走线到HDMI座子。编码器写起来其实不难难点在时序。这里给一个关键代码思路// TMDS编码核心理念 // 每个通道 // 输入8bit video_data, 2bit control, DE // 输出10bit tmds_data always (posedge clk_pixel) begin if (de) begin // 数据周期做8b/10b编码 tmds_data encode_video(video_data); end else begin // 控制周期根据CTL0/CTL1编码成固定的控制码 tmds_data encode_control({vsync, hsync}); end end实际工程中TMDS编码器还需要注意三个通道的编码逻辑其实是相同的可以参数化复用有些设计会做色彩空间转换后再编码注意保持通道间对齐编码器输出是10bit并行跨时钟域时一定要用FIFO不能直接打拍。3.3 接收端TMDS串行信号怎么恢复成并行像素HDMI接收端相对复杂一些。理论上接收端要先恢复时钟再从高速串行数据中恢复出10bit并行数据然后做8b/10b解码最后把RGB和同步信号还原出来。时钟恢复这一环不同实现方式差别很大。如果TMDS时钟线直接可用比如主芯片支持可以把时钟线的差分信号输入到PLL/MMCM的参考时钟引脚用它来产生采样时钟。但5.94Gbps的数据率和594MHz的参考时钟之间不是整数倍关系单纯PLL倍频到5.94GHz不现实。更常见的是利用SerDes自带的CDR时钟数据恢复功能锁定到TMDS数据流的频率这时候TMDS时钟线可以不用只作为参考频率引导CDR锁定。FPGA实现接收端的标准流程是第一步SerDes接收端把三对TMDS数据线上的串行差分信号转成并行10bit数据。这个过程需要CDR锁定到5.94Gbps的速率。第二步做通道对齐。三个数据通道之间可能存在相位差需要通过TMDS的通道对齐机制固定训练序列或者基于字符对齐来保证三通道的10bit数据在同一个时钟周期内对齐。第三步8b/10b解码恢复出8bit像素数据和控制信号。第四步根据解码出的DE、HSYNC、VSYNC生成标准的像素同步信号进入视频处理链路。接收端最容易出问题的地方是CDR锁定的参考频率设置。有的SerDes要求参考时钟是数据速率的特定分数倍如果参考时钟给错CDR就锁不定表现出来就是完全没有画面。3.4 PDS工程里的引脚、时钟、时序约束怎么配紫光同创的开发环境是PDS当你把RTL写好、综合通过后如果引脚和时序约束不写全烧进板子大概率是跑不起来的这里把关键约束项列一下。引脚约束包含两部分位置约束和电气约束。位置约束就是把每个信号对应到芯片的具体管脚一般由开发板的原理图决定PDS工程里可以通过图形化界面配置也可以直接写约束文件。电气约束则是告诉布局布线器管脚的电平标准比如TMDS差分对通常使用LVDS或自定义差分标准普通控制信号使用LVCMOS33或LVCMOS18。这里需要特别注意SerDes专用引脚的约束方式和普通IO完全不同必须按照PDS里SerDes IP的向导配置来。时钟约束是整个时序约束的灵魂。4K60系统里至少有三个时钟域像素时钟域594MHzDDR时钟域比如800MHz或933MHz串行收发域5.94Gbps或SerDes内部并行域。每个时钟都要用create_clock正确声明跨时钟域的路径要设置false path或使用同步器/FIFO打断。一条典型的时钟约束命令大概是这种结构create_clock -name clk_pixel -period 1.684 [get_ports clk_pixel_i] create_clock -name clk_ddr -period 1.071 [get_pins {ddr_phy_inst/clk_ddr}]实际项目中我还会额外检查SerDes的字节时钟和像素时钟之间是否满足时钟关系。如果用了异步FIFO则需要在FIFO内部由IP核自动处理跨时钟域约束文件里要把FIFO的输入输出路径设置为set_clock_groups -asynchronous。4. 视频处理链路核心模块实现4.1 输入捕获模块把同步信号和有效像素分开视频流进了FPGA之后第一步不是处理像素而是把时序信息提取出来。HDMI接收端解码后有三个关键信号DE数据有效、HSYNC行同步、VSYNC帧同步以及并行RGB数据。输入捕获模块要做的事情就是根据这三个信号生成后续模块需要的像素流控制信号。在DE为高的期间每个像素时钟周期写入一个像素DE变低进入消隐区时暂停写入。HSYNC和VSYNC的极性不一定相同有的信号源是正极性有的是负极性所以宏定义或者寄存器里要可配。VSYNC有效沿到来时说明一帧数据结束可以产生帧同步脉冲用于驱动帧缓存的写操作。一个典型的捕获模块核心状态可以归纳为捕捉到VSYNC后清空状态准备接收新帧在DE有效时将像素数据、行坐标和列坐标同步输出行坐标在DE上升沿加1列坐标在每个像素时钟加1遇到DE下降沿清零。这里生成的坐标信息对后续做OSD叠加和缩放处理很有用。4.2 DDR帧缓冲跨时钟域和撕裂问题的处理4K60的RAW视频数据量很大。以RGB888计算一帧3840x2160的画面大约是24.9MB60帧就是接近1.5GB/s的数据流量。虽然FPGA内部可以直接流水线处理但一旦涉及OSD、多帧缓存、格式转换等操作就必须把帧存到DDR里。DDR控制器通常使用IP核读端口和写端口都是独立的。典型做法是把DDR空间分成两个或三个帧缓冲区以帧为单位做乒乓操作。写通道从一个源接收读通道向处理模块送数据。这里最容易出问题的点是跨时钟域。输入像素时钟是594MHzDDR的工作时钟往往不是整数倍关系所以必须用异步FIFO来跨时钟域。在写端像素数据先写入FIFOFIFO再向DDR突发写在读端DDR读出的数据写入另一个FIFO由下游模块的像素时钟读出。有一点必须提醒如果读写两端使用同一个帧缓冲地址不做帧同步控制画面会出现撕裂Tearing。撕裂的本质是读端还在读第N帧数据写端已经开始覆盖第N帧。解决办法有三种放弃同步接受轻微撕裂适合显示要求不高的场合使用帧IDFrame ID做读写同步保证读端只读写完的帧使用三缓冲写端轮流写两个缓冲读端总是读最新的完整帧。工业级项目我推荐后面两种。三缓冲会多占用约25MB带宽和空间但如果DDR带宽有余量换来的是稳定的画面体验值得。4.3 色彩空间转换RGB和YCbCr互转的定点实现视频信号在不同环节使用的色彩空间不一样HDMI传输通常允许RGB和YCbCr两种格式而很多视频算法比如缩放、编码更喜欢在YCbCr空间处理。色彩空间转换是必需模块。以BT.709标准为例RGB转YCbCr的浮点公式是Y 0.2126R 0.7152G 0.0722BCb -0.1146R - 0.3854G 0.5B 128Cr 0.5R - 0.4542G - 0.0458B 128FPGA里不能直接算浮点通常做法是放大到定点数。比如把系数放大256倍用8位小数表示Y (54R 183G 18B) 8Cb (-29R - 99G 128B 32768) 8Cr (128R - 116G - 12B 32768) 8实现的时候有一个容易犯的错误Cb和Cr加了128偏移这个偏移是0到255范围内的中心值在FPGA内部对8bit有符号数做加法时容易溢出建议在运算前把RGB数据当作有符号数处理扩展位宽最后截断前做饱和度钳位。定点化带来的误差其实很小系数选择可以按需求调整精度但要注意DSP资源消耗。三路转换需要多个乘法器如果DSP不够用可以考虑用移位加替代部分乘法。PDS的IP目录里一般也有颜色转换IP但在自定义系统里手写模块更直观。4.4 缩放与OSD实用算法的入门实现视频缩放是FPGA里比较吃资源的算法。最常用的是双线性插值它通过目标像素的坐标反向映射到源图像坐标取周围四个像素加权平均。双线性插值需要两个方向的插值系数FPGA实现时通常分两步先做水平缩放使用多个行缓冲存储源图像连续几行再做垂直插值。缩放质量要求不高的场合最近邻缩放算法也可以但4K缩到1080p时锯齿会比较明显。实际项目中如果面积和时序允许直接上双线性插值系数用定点乘法实现大概消耗少量DSP和BRAM效果能接受。OSD叠加的原理是alpha混合输出像素 背景像素 × (1 - alpha) 前景像素 × alpha。在FPGA里alpha是一个0到255的值乘法用DSP实现整条路径的关键是对齐OSD图层和背景视频流的坐标要严格同步。由于涉及到帧缓冲读和OSD图层读通常要在DDR控制器前端做一个小的仲裁器保证两个读请求的优先级和带宽分配合理。4.5 值得留意的音频嵌入扩展内容HDMI不仅能传视频还能内嵌音频。如果做的是视频会议、直播一体机这类产品音频功能基本不能少。音频在HDMI里以音频数据包的形式嵌入在消隐期传输属于辅助数据通道。FPGA实现时先接收I2S音频流打包成HDMI规定的音频帧格式再在发送端的消隐期插入。做音频嵌入时要特别关注音频时钟和像素时钟的关系必须保证音频数据的采样率与HDMI包之间的时间戳对应关系正确。很多项目卡在这一步画面正常但接收端无声多半是音频时钟恢复和包时间戳没对齐。5. 调试实录典型问题与排查方法5.1 先给一张问题排查速查表这套系统调试过程中我把遇到的问题按现象分了类整理成一张表遇到问题可以直接照着查。现象可能原因排查方向完全无画面HDMI无输出发送端PLL未锁定检查PLL配置、参考时钟是否输入完全无画面HDMI无输出引脚约束错误核对原理图、SerDes引脚绑定显示设备报无信号发送端未读取/未响应DDC用I2C调试工具抓DDC波形确认EDID数据画面花屏或噪点TMDS通道未对齐检查SerDes通道对齐配置画面花屏且有规律帧缓冲读写地址错位检查DDR地址产生逻辑和突发长度画面撕裂读写帧同步丢失检查帧ID同步逻辑只有静止画面或残影跨时钟FIFO溢出检查FIFO深度、读写时钟频率比时序不收敛布局布线报错约束不完整补充时钟约束检查组间路径5.2 第一次上板无图时怎么一步步定位我第一次把综合后的bitstream烧进板子HDMI接上显示器屏幕显示“无信号”。这个结果其实不意外但排查的时候要有条理。第一步确认发送端PLL是否锁定。用开发板上的LED把PLL locked信号引出来如果LED不亮说明PLL没有锁定。这时要检查参考时钟是否有输入、PLL参数是否计算正确。我这次的问题是参考时钟输入引脚没有约束对PLL根本拿不到时钟。第二步PLL锁定正常后还是没图检查引脚约束。在PDS里逐个核对TMDS差分对、DDC、HPD的引脚位置和电平标准发现有一组数据差分信号的正负极性接反了修改后画面有了。第三步画面有了但不稳定几秒钟就黑屏一次。查了HPD引脚发现有抖动源端认为设备反复插拔于是触发重新协商。在HPD引脚上加RC滤波并增加去抖时间后问题解决。5.3 花屏和绿屏大概率是数据通道问题花屏和绿屏通常是数据链路的问题。绿屏有一个很典型的成因RGB或YCbCr数据位错位或通道顺序调错G通道的数值跑到了其他通道上。如果源端输出是YCbCrFPGA里却按RGB来解析也会出现明显偏色的现象。检查方法很简单用单一纯色画面比如纯红作为输入源观察FPGA接收端解码出的三通道数据。如果每一帧数据中R分量不符合预期就检查解码和位映射。花屏还有一种常见原因是DDR控制器读写时序不稳定。DDR跑在较高频率时如果参考时钟、电源噪声、片内端接参数其中一个设置不对读写数据偶发错误。排查时用I2C或串口把DDR控制器的错误计数读出来先排除物理层问题再排查上层地址逻辑。5.4 时序不收敛约束文件里的学问布局布线阶段最让人头疼的是时序不收敛。4K60这种设计里像素时钟高达594MHz即便分成多路并行处理关键路径依然很紧张。我遇到过好几次setup导致时序违例最终解决方法大多不是调逻辑而是检查约束。印象最深的一次SerDes输出的10bit并行数据送到解码模块路径太长时钟域约束也没有明确。解决方法是插入寄存器链pipeline并用set_max_delay约束跨域路径同时把源寄存器和目标寄存器之间所有组合逻辑拆开降到一拍内完成时序就收敛了。另外PDS中的综合策略也要调整。视频处理链路里乘法器多综合时选择面积优化或速度优化会直接影响结果。建议在时序紧张时对乘法器和除法器模块单独设置速度优先其它逻辑保持默认这样兼顾资源与性能。5.5 关于在线调试工具的建议PDS自带的逻辑分析仪和虚拟IO功能在调试中非常有用。建议在写RTL时就把关键内部信号预留出来PLL锁定、FIFO满空、帧同步脉冲、行同步计数、像素数据总线这些信号在调试阶段接到逻辑分析仪上线上观测比猜要快得多。还有一个小技巧在代码里加一个调试寄存器通过I2C或UART接口实时修改某个参数比如输出分辨率、缩放系数、OSD开关这样不用每次改代码重新综合布线调试周期能缩短不少。最后再分享一点个人体会这个项目做下来一个很深的感受是4K视频处理系统本身没有特别神秘的魔法它的骨架就是“像素时钟计算、TMDS编码解码、帧缓冲调度、时序约束收敛”这四件事。把这四件事挨个吃透任何分辨率的视频链路基本都能搭起来。还有一点选国产FPGA做这类项目不要只看资源和价格开发工具的熟悉程度会很大程度上影响项目进度。我建议先花一两天时间把PDS基本流程走通亲手点亮一个LED、跑通一个简单的时序约束再动手做HDMI这种复杂接口会比直接冲高速设计顺利得多。如果你正准备做类似的视频处理项目或者已经在调HDMI跑不出图希望这篇能帮你少走几步弯路。实际操作中如果遇到具体问题欢迎随时交流。