简介:本资源是一个面向FPGA开发者的HDMI输出IP核工程包,专为Xilinx全系列器件(从Artix到Virtex)设计,解决高清音视频信号在数字系统中可靠编码与物理层传输的关键问题,适用于多媒体终端、显示控制、嵌入式视频处理等场景。压缩包为ZIP格式,大小仅11KB,包含Verilog/VHDL源代码、测试平台、仿真脚本及用户指南等核心文件,类型精炼、结构紧凑,便于快速集成与功能验证。已有262人学习下载,体现了其在中小型FPGA项目中的实用价值。读者可直接调用该IP实现TMDS编码、EDID读取、HDCP基础支持及HDMI物理层信号生成,无需从零构建协议栈;配套文档清晰说明接口定义与时序约束,测试平台覆盖常见分辨率与音频采样率组合,显著降低HDMI外设驱动开发门槛。
1. 这不是“插根线就能出图”的 HDMI 模块——HDMI Transmitter IP 核本质是 FPGA 上的可编程视频流引擎
很多人看到hdmi-transmitter-ip-master这个名字,第一反应是“找个现成的 HDMI 输出模块,接上 FPGA 开发板就能点亮显示器”。但实际落地时,90% 的失败案例都卡在同一个认知盲区:它不是即插即用的硬件芯片,而是一套需深度协同配置的 RTL 级 IP 核(Intellectual Property Core)。它不包含 PHY 层驱动电路,不封装 TMDS 编码器物理实现,更不自带 EDID 解析逻辑——所有这些必须由设计者在顶层约束、时序收敛、寄存器映射和视频流握手协议中显式定义。典型场景是 Xilinx Zynq 或 Intel Cyclone V 平台,用户需将该 IP 与 AXI-Stream 视频源(如 VDMA、AXI Video Direct Writer)、Clocking Wizard(生成 1x/5x/10x TMDS 时钟)、以及自定义的 I2C 控制模块(读取显示器 EDID、配置 HDCP 寄存器)串联。适合对象很明确:FPGA 视频系统工程师、嵌入式图像处理开发者、需要定制化 HDMI 输出时序(如非标分辨率、双通道 4K@60Hz 分屏)的工业设备方案商。如果你只打算用 Arduino 或树莓派接 HDMI 线,这个 IP 核对你毫无意义;但若你正在调试一个 10Gbps 图像采集链路的最终显示通路,它就是绕不开的底层控制枢纽。
2. 从 Verilog 封装到 AXI-Stream 对齐:HDMI Transmitter IP 核的三层次集成路径
2.1 IP 核结构解析:为什么不能直接例化?必须理解其接口契约
HDMITransmitterIP是典型的参数化 RTL IP,其顶层模块(如hdmi_tx_top.v)暴露三类关键接口:
- AXI-Stream 视频输入端口:
s_axis_tdata(24-bit RGB 或 YUV)、s_axis_tvalid、s_axis_tready、s_axis_tlast—— 注意tlast必须严格对应每帧末尾,否则接收端会丢帧; - 配置寄存器总线:通常为 APB 或 AXI-Lite 接口(
apb_paddr/apb_pwdata/apb_pwrite),用于写入TMDS_CLK_DIV、HDMI_MODE(1.4/2.0)、AUDIO_ENABLE等控制字; - 物理层信号输出:
hdmi_clk_p/n、hdmi_data_p/n[0:2]、hdmi_de、hdmi_hsync、hdmi_vsync—— 这些必须绑定到 FPGA Bank 中支持差分电平(如 TMDS_33)的引脚,并通过 XDC 约束指定IOSTANDARD和DIFF_TERM。
提示:该 IP 核不包含 HDCP 加密引擎。若需合规输出受保护内容,必须额外集成 Xilinx 的
HDCP22_TXIP 或自行实现 AES-128 密钥协商状态机。常见误用是忽略apb_psel信号的采样时序,在 APB 总线未稳定前就发起写操作,导致寄存器配置失败。
2.1.1 关键参数配置表:决定能否成功握手显示器
| 参数名 | 典型值 | 作用说明 | 配置错误后果 |
|---|---|---|---|
TMDS_CLK_DIV | 1, 2, 4, 8 | 设置 TMDS 时钟分频系数,影响最终像素时钟频率 | 值过大导致像素时钟过低,显示器报“超出范围” |
HDMI_MODE | 2'b10 (2.0) | 启用 HDMI 2.0 协议栈,支持 4K@60Hz | 设为 1.4 模式时强行输出 4K60 会导致数据错位 |
PIXEL_REP | 1'b0 | 像素重复模式(0=禁用,1=启用) | 在 1080p@120Hz 场景下需设为 1,否则带宽不足 |
AUDIO_EN | 1'b1 | 使能音频嵌入(需配合 SPDIF 或 I2S 输入) | 设为 0 时 HDMI 输出纯视频,无音频通道 |
2.2 AXI-Stream 数据对齐:RGB 顺序、Blanking 间隔与 tuser 信号的硬性要求
HDMI 协议要求视频数据流严格遵循Active Video → HBlank → VBlank的周期结构。HDMITransmitterIP本身不生成 blanking 信号,而是依赖s_axis_tuser(通常为 2-bit)指示当前数据包类型:
2'b00: Active Video(有效像素)2'b01: Horizontal Blanking(行消隐)2'b10: Vertical Blanking(场消隐)2'b11: Reserved
// 示例:在视频源模块中生成 tuser 信号(以 1920x1080@60Hz 为例) always @(posedge aclk) begin if (rstn == 1'b0) tuser <= 2'b00; else if (vsync && hsync) tuser <= 2'b10; // 场消隐开始 else if (hsync) tuser <= 2'b01; // 行消隐开始 else tuser <= 2'b00; // 默认有效视频 end注意:
tuser必须与tvalid同步更新,且tlast只能在tuser==2'b00时置高(即仅在 Active Video 区域末尾标记帧结束)。若在 HBlank 区间置tlast,IP 核会误判为帧中断,导致显示器同步丢失。
2.2.1 时序约束实操:XDC 文件中 TMDS 差分对的关键写法
在 Vivado 中,TMDS 时钟和数据线必须作为差分对约束,并指定DIFF_TERM(片内终端匹配):
# XDC 约束片段(以 Zynq ZC702 开发板为例) set_property IOSTANDARD TMDS_33 [get_ports hdmi_clk_p] set_property IOSTANDARD TMDS_33 [get_ports hdmi_clk_n] set_property DIFF_TERM TRUE [get_ports hdmi_clk_p] set_property DIFF_TERM TRUE [get_ports hdmi_clk_n] set_property PACKAGE_PIN G19 [get_ports hdmi_clk_p] set_property PACKAGE_PIN F19 [get_ports hdmi_clk_n] # 数据通道约束(注意:hdmi_data_p[0] 与 hdmi_data_n[0] 必须同 Bank) set_property IOSTANDARD TMDS_33 [get_ports hdmi_data_p] set_property IOSTANDARD TMDS_33 [get_ports hdmi_data_n] set_property DIFF_TERM TRUE [get_ports hdmi_data_p] set_property DIFF_TERM TRUE [get_ports hdmi_data_n] set_property PACKAGE_PIN D19 [get_ports hdmi_data_p[0]] set_property PACKAGE_PIN C19 [get_ports hdmi_data_n[0]]未启用DIFF_TERM会导致 TMDS 信号反射严重,眼图闭合,实测表现为显示器闪屏或完全无信号。
3. EDID 解析与动态分辨率适配:让 FPGA 主动“读懂”显示器能力
3.1 EDID 读取流程:I2C 总线上的 128 字节握手协议
HDMI Transmitter IP 核自身不包含 I2C 控制器,必须外挂一个AXI_IICIP(Xilinx)或i2c_master(OpenCores)来读取显示器 EDID。EDID 存储在显示器 DDC 通道的 0x50 地址,标准长度为 128 字节。关键字段包括:
EDID[0x36]:支持的视频时序数量(最多 15 个)EDID[0x38 + i*2]:第 i 个时序的 Horiz. Active(像素数)EDID[0x39 + i*2]:第 i 个时序的 Vert. Active(行数)EDID[0x3A + i*2]:第 i 个时序的 Pixel Clock(单位为 10kHz)
# 使用 Vivado Hardware Manager 验证 EDID 读取(JTAG 连接后执行) # 1. 打开 I2C 总线(假设 I2C 地址为 0x50) write_bd_reg -offset 0x100 -value 0x50 [get_bd_addr_segs axi_iic_0/S_AXI] # 2. 发起读请求(读取前 16 字节) write_bd_reg -offset 0x104 -value 0x00000000 [get_bd_addr_segs axi_iic_0/S_AXI] # 3. 查询状态寄存器确认完成 read_bd_reg -offset 0x108 [get_bd_addr_segs axi_iic_0/S_AXI] # 返回值 0x00000002 表示读取成功提示:EDID 读取失败最常见的原因是
SCL/SDA引脚未接 4.7kΩ 上拉电阻(至 3.3V)。FPGA IO 默认为高阻态,无上拉则 I2C 总线永远处于低电平,axi_iicIP 会持续超时。
3.1.1 动态分辨率切换:基于 EDID 的寄存器重配置序列
当检测到显示器支持 3840x2160@30Hz 但当前运行在 1080p@60Hz 时,需按顺序重写 IP 核寄存器:
| 步骤 | 寄存器地址 | 写入值 | 说明 |
|---|---|---|---|
| 1 | 0x00 | 0x00000000 | 停止 TMDS 输出(写 0 到 enable 位) |
| 2 | 0x10 | 0x00000F42 | 更新PIXEL_CLOCK= 297MHz(4K30 所需) |
| 3 | 0x14 | 0x00000F00 | 更新H_ACTIVE= 3840 |
| 4 | 0x18 | 0x00000860 | 更新V_ACTIVE= 2160 |
| 5 | 0x00 | 0x00000001 | 重新使能输出 |
此过程必须在垂直消隐期(VBlank)内完成,否则可能触发显示器保护机制断开连接。
4. 故障诊断四象限:信号、时序、协议、寄存器的逐层排查法
4.1 TMDS 信号质量验证:用示波器抓取眼图的三个必测点
当显示器显示“无信号”时,优先验证物理层。使用 1GHz 带宽示波器测量以下三点:
| 测量点 | 正常眼图特征 | 异常表现 | 根本原因 |
|---|---|---|---|
hdmi_clk_p/n差分电压 | 幅值 800mVpp ±10%,上升时间 < 150ps | 幅值仅 200mVpp | DIFF_TERM未启用或 Bank 电压错误(应为 3.3V) |
hdmi_data_p[0]/n[0](R 通道) | 眼图张开度 > 70%,抖动 < 0.3UI | 眼图完全闭合 | PCB 走线过长(>15cm)或未做 100Ω 差分阻抗控制 |
hdmi_data_p[2]/n[2](B 通道) | 与 R 通道相位偏移 < 50ps | 相位偏移达 200ps | 三组 TMDS 数据线长度不匹配(ΔL > 2mm) |
注意:不要用万用表测 HDMI 信号!其高频成分(>300MHz)远超万用表带宽,读数恒为 0V,毫无参考价值。
4.1.1 时序报告解读:Critical Path 中的两个致命警告
在 Vivado Timing Summary 中,重点关注以下两类路径:
Slack (MET) : 0.123ns (required time - arrival time) Source: hdmi_tx_top/inst/tmds_clk_gen/clk_out Destination: hdmi_tx_top/inst/tx_core/rgb2yuv_inst/clk Path Group: tmds_clk Warning: [Timing 38-282] The clock net 'hdmi_clk' has no user-defined input delay. This may cause timing analysis to be pessimistic.- 第一行 Slack 值:若为负数(如
-0.456ns),表示时序违例。此时需检查hdmi_clk是否被正确约束为create_clock -name hdmi_clk -period 6.734 -waveform {0 3.367} [get_ports hdmi_clk_p](对应 148.5MHz 像素时钟); - 第二行 Warning:
no user-defined input delay意味着未对hdmi_clk输入端口设置set_input_delay,导致工具无法评估外部时钟抖动影响,必须补充:set_input_delay -clock hdmi_clk -max 1.2 [get_ports hdmi_clk_p] set_input_delay -clock hdmi_clk -min 0.8 [get_ports hdmi_clk_p]
4.2 协议级验证:用逻辑分析仪捕获 HDMI 握手过程
使用 Saleae Logic Pro 16 抓取hdmi_de、hdmi_hsync、hdmi_vsync三线信号,验证是否符合 CEA-861-D 标准:
| 信号组合 | 含义 | 正常周期(1080p60) |
|---|---|---|
DE=1, HSYNC=0, VSYNC=0 | Active Video | 持续 1920×1080 = 2,073,600 个像素时钟 |
DE=0, HSYNC=1, VSYNC=0 | Horizontal Blanking | 持续 220 个像素时钟(含 front/back porch) |
DE=0, HSYNC=0, VSYNC=1 | Vertical Blanking | 持续 22 个扫描行(含 front/back porch) |
若VSYNC高电平持续时间远小于 22 行(如仅 5 行),说明V_TOTAL寄存器配置错误,需检查0x1C地址写入值是否为0x00000452(1080p60 的 V_TOTAL = 1125)。
5. 音频嵌入实战:从 I2S 输入到 HDMI Audio InfoFrame 的全流程配置
5.1 I2S 与 HDMI 音频时钟域对齐:为何必须用独立 PLL
HDMI Audio 要求精确的采样率时钟(如 48kHz、44.1kHz),而 FPGA 主时钟(如 100MHz)无法整除这些频率。必须使用Clocking Wizard生成专用音频时钟:
# 创建 48kHz 音频时钟(用于 I2S 和 HDMI Audio) create_generated_clock -name audio_clk -source [get_pins clk_wiz_0/clk_in1] \ -divide_by 2083 [get_pins clk_wiz_0/clk_out2] # 100MHz / 2083 ≈ 48.007kHz,误差 < 0.02%提示:
HDMITransmitterIP的音频嵌入依赖audio_clk与tmds_clk的整数倍关系。若tmds_clk=148.5MHz,则audio_clk必须为148.5MHz / 3080 = 48.214kHz(CEA-861-D 规定的 HDMI 音频基准),而非任意 48kHz。
5.1.1 Audio InfoFrame 构造:128 字节 payload 的手动填充
HDMI Audio InfoFrame 是嵌入在视频 blanking 区间的数据包,结构如下:
| 字段 | 长度 | 值 | 说明 |
|---|---|---|---|
| Packet Header | 3 字节 | 0x84, 0x01, 0x0A | Type=0x84 (Audio), Version=0x01, Length=0x0A |
| Channel Count | 1 字节 | 0x02 | 2-channel stereo |
| Coding Type | 1 字节 | 0x00 | LPCM uncompressed |
| Sample Size | 1 字节 | 0x00 | 16-bit samples |
| Sample Rate | 1 字节 | 0x03 | 48kHz (0x03=48k, 0x02=44.1k) |
| Channel Allocation | 3 字节 | 0x00, 0x00, 0x00 | Front Left/Right |
该 InfoFrame 必须通过apb_paddr=0x200开始的寄存器连续写入,且写入期间AUDIO_EN=1必须保持有效。
5.2 静音检测与自动恢复:基于hdmi_aud_status寄存器的状态机
IP 核提供0x300地址的aud_status寄存器,bit[0] 表示音频链路状态:
| bit[0] | 含义 | 应对动作 |
|---|---|---|
0 | Audio FIFO underflow(数据断供) | 暂停 I2S 发送,等待缓冲区填充 |
1 | Audio normal | 继续发送 |
// 状态机片段:检测静音并重启音频 always @(posedge audio_clk) begin if (rstn == 1'b0) aud_restart <= 1'b0; else if (aud_status[0] == 1'b0) begin aud_restart <= 1'b1; #1000000 aud_restart <= 1'b0; // 延迟 1ms 后清除 end end此机制可避免因 I2S 数据源短暂中断导致 HDMI 音频永久静音。
本文还有配套的精品资源,点击获取