HDMI协议基础:从TMDS到EDID,一个工程师的实战笔记

各位同学,今天我们来聊聊HDMI。说实话,HDMI这玩意儿看着简单,不就是一根线连显示器吗?但真要在FPGA上把它实现出来,坑可不少。我当年第一次调HDMI输出时,画面全是雪花,折腾了两天才发现是TMDS时序差了几个纳秒。嗯,咱们今天就把这些基础打扎实。

TMDS编码原理:为什么需要它?

TMDS,全称是Transition Minimized Differential Signaling。翻译过来就是「最小化转换差分信号」。名字挺长,但核心思想很简单:减少信号跳变,降低电磁干扰。

你想想看,如果原始数据是连续的0和1交替,比如01010101,那信号线每传输一个bit就要跳变一次。高频跳变会产生大量EMI,而且接收端也容易误判。TMDS编码就是来解决这个问题的。

具体怎么做的?它把8bit数据编码成10bit。这10bit里,保证跳变次数最少,同时直流平衡(DC平衡)。直流平衡是什么意思?就是传输的0和1数量尽量相等,这样信号的平均电压稳定,接收端不容易漂移。

核心要点:TMDS编码后,10bit数据中最多只有5次跳变,最少可以做到0次跳变。同时,编码器会记录当前「不平衡度」,动态调整编码方向。

我在项目中遇到过一个问题:用逻辑分析仪抓TMDS信号,发现某些像素点总是错位。后来排查发现,是编码器在DC平衡计算时,没有考虑复位后的初始状态。说白了,就是状态机没初始化好。

差分信号与电气特性

HDMI用的是差分信号传输。什么是差分?就是一对线,一根传正信号,一根传反信号。接收端看的是两根线的电压差。

这样做的好处很明显:

  • 抗共模干扰:外部噪声同时影响两根线,但差值不变
  • 低电压摆幅:差分信号只需要几百毫伏的摆幅,功耗低
  • 高速传输:可以跑到几Gbps

HDMI的电气特性,我简单列几个关键参数:

参数 典型值 说明
差分电压 400mV ~ 600mV 峰峰值,取决于TMDS电流源
共模电压 3.3V 以GND为参考
阻抗 100Ω ± 15% 差分阻抗,PCB走线要匹配
上升时间 < 0.3 UI UI = 单位间隔,即一个bit的时间

注意:我曾经在PCB布局时,把差分对的两根线走了不同长度,结果信号质量一塌糊涂。差分对必须等长,误差控制在5mil以内。这是血的教训。

HDMI 1.4 vs 2.0 对比

很多同学问我,到底该用1.4还是2.0?我的建议是:看你的分辨率和刷新率需求。

直接上对比表:

特性 HDMI 1.4 HDMI 2.0
最大带宽 10.2 Gbps 18 Gbps
最大分辨率 4K@30Hz 4K@60Hz
TMDS时钟 最高340 MHz 最高600 MHz
色彩深度 8bit/10bit 8bit/10bit/12bit
HDR支持 有限 完整支持

说白了,如果你只是做1080p@60Hz的显示,HDMI 1.4完全够用。但要做4K@60Hz,必须上2.0。我有个项目,客户非要1.4跑4K@60Hz,结果画面闪烁得跟迪斯科一样。嗯,物理定律是绕不过去的。

像素时钟与分辨率关系

这个知识点,我建议你死记硬背也要记住:像素时钟 = 水平总像素 × 垂直总行数 × 刷新率

举个例子,1080p@60Hz:

  • 水平总像素:2200(包含消隐区)
  • 垂直总行数:1125(包含消隐区)
  • 刷新率:60 Hz
  • 像素时钟 = 2200 × 1125 × 60 ≈ 148.5 MHz

为什么总像素和总行数比有效像素多?因为有消隐区(blanking)。消隐区是干嘛的?说白了,就是给显示器一个喘息的时间,让它从一行末尾回到下一行开头。

小技巧:我在FPGA里生成像素时钟时,通常用PLL锁相环。但要注意,PLL的输入时钟和输出时钟要算好倍数关系。比如输入50MHz,要得到148.5MHz,倍频系数是2.97,不是整数。这时候我会用两个PLL级联,或者用MMCM(混合模式时钟管理器)。

常见的分辨率与像素时钟对应关系:

分辨率 刷新率 像素时钟
640×480 60 Hz 25.175 MHz
1280×720 60 Hz 74.25 MHz
1920×1080 60 Hz 148.5 MHz
3840×2160 60 Hz 594 MHz

EDID与DDC通道解析

EDID,全称Extended Display Identification Data。说白了,就是显示器的「身份证」。里面存着显示器支持的分辨率、刷新率、色彩格式等信息。

DDC通道是I2C总线,用来读取EDID。HDMI规范里,DDC的I2C地址是0xA0(写)和0xA1(读)。EDID数据总共128字节,存储在显示器的EEPROM里。

我当年调试EDID时,遇到一个奇葩问题:显示器明明支持1080p,但FPGA读到的EDID里却没有这个分辨率。后来发现,是显示器的EDID版本太老,只写了720p的信息。解决办法是手动在FPGA里写一个「虚拟EDID」,覆盖掉显示器的数据。

实战要点:EDID的前128字节是强制标准,后128字节是扩展块。读取时,先读前128字节,如果支持扩展,再读后128字节。扩展块里通常包含更详细的信息,比如音频格式、3D支持等。

DDC通道的时序,就是标准的I2C协议。速率一般是100kHz,但有些显示器支持400kHz。我建议你按100kHz来设计,兼容性最好。

知识体系总览

下面这张图,是我自己画的HDMI协议知识体系。你可以把它当作学习地图:

HDMI协议基础 TMDS编码原理 8b/10b编码 最小化跳变 直流平衡 差分信号与电气 抗共模干扰 低电压摆幅 100Ω阻抗匹配 1.4 vs 2.0对比 带宽差异 分辨率支持 HDR支持 像素时钟与分辨率 时钟 = 总像素 × 总行 × 刷新率 消隐区计算 PLL时钟生成 EDID与DDC通道 I2C协议读取 128字节EDID 虚拟EDID覆盖 FPGA实现要点 SerDes接口 时序约束 信号完整性 掌握这些,HDMI输出不再神秘

这张图把今天讲的内容串起来了。你看,TMDS编码是底层传输机制,差分信号是物理层实现,版本对比告诉你选型依据,像素时钟是时序核心,EDID/DDC是握手协议。最后,所有知识都要落到FPGA实现上。

好了,今天的内容就到这里。记住,HDMI协议看着复杂,但拆开来看,每个模块都不难。关键是动手实践,调一次波形,比看十遍书都管用。

可可精品资料库