3. EDID数据块解析:EDID 128字节主块结构、EDID扩展块(CTA-861、DisplayID)概述
好,咱们接着聊。上一章我们把EDID的读取流程走了一遍,从I²C时序到原始字节抓取,算是把「怎么拿到数据」搞明白了。但拿到手的数据是什么?一堆0x00、0xFF,看着就头大。
这一章,我们就来拆解这128个字节。说白了,就是教你怎么读懂EDID这块「显示器的身份证」。
3.1 128字节主块:显示器的「身份证」
每个EDID,不管是什么版本,开头一定有128字节的主块。这是强制性的,没有这128字节,系统根本认不出你的显示器。
我个人习惯把这128字节分成几个功能区:
- Header(0-7字节):固定为 00 FF FF FF FF FF FF 00。这是EDID的魔数,用来校验是不是有效的EDID数据。我在项目中遇到过,有些山寨显示器这个头就不对,读出来是乱码,系统直接黑屏。
- 厂商信息(8-17字节):包含制造商ID、产品代码、序列号。制造商ID是三个大写字母的PNP ID,比如DEL代表戴尔,SAM代表三星。
- 版本信息(18-19字节):版本号和修订号。目前主流是1.3和1.4。1.4版本支持更多的色彩深度和色域信息。
- 基本显示参数(20-24字节):包括模拟/数字接口类型、屏幕尺寸、伽马值、电源管理支持等。
- 色度信息(25-34字节):红绿蓝白四色的色坐标。这个对色彩管理很重要,我调过一台专业显示器,色坐标数据写错了,导致校色仪怎么都校不准。
- 时序信息(35-53字节):包含标准时序和详细时序描述块(DTD)。
- 详细时序描述块(54-125字节):4个18字节的块,每个块可以描述一个标准时序,或者用来存放显示器名称、序列号字符串、显示器范围限制等。
- 扩展块标志(126字节):表示后面还有多少个128字节的扩展块。0表示没有扩展块。
- 校验和(127字节):前127个字节的和加上这个字节,结果应该为0。
核心要点:128字节主块是EDID的基石。你读到的第一个字节必须是0x00,最后一个字节的校验和必须正确。否则,这组数据就是废的。
3.2 详细时序描述块(DTD)—— 显示器的「核心参数」
DTD是EDID里最重要的部分。它用18个字节描述一个完整的显示时序。包括分辨率、刷新率、同步信号极性、前后肩等。
嗯,这里要注意:DTD的18个字节结构如下:
字节0-1: 像素时钟 (单位10kHz)
字节2: 水平有效像素 (低8位)
字节3: 水平消隐 (低8位)
字节4: 水平有效像素 + 水平消隐 (高4位各占一半)
字节5: 垂直有效行数 (低8位)
字节6: 垂直消隐 (低8位)
字节7: 垂直有效行数 + 垂直消隐 (高4位各占一半)
字节8: 水平同步偏移 (低8位)
字节9: 水平同步脉冲宽度 (低8位)
字节10: 垂直同步偏移 (低4位) + 垂直同步脉冲宽度 (低4位)
字节11: 水平同步偏移/脉冲宽度 (高2位) + 垂直同步偏移/脉冲宽度 (高2位) + 水平/垂直同步极性
字节12-17: 其他标志和保留位
看着是不是很绕?我刚开始学的时候也觉得头大。其实你想想看,这18个字节就是把一个时序的各个参数拆开,塞进不同的位里。解析的时候,需要按位拼接。
举个例子,一个1920x1080@60Hz的时序,像素时钟大约是148.5MHz。在DTD里,这个值会存为14850(因为单位是10kHz)。
小技巧:解析DTD时,我建议先写一个结构体把18个字节映射好,然后用位运算提取每个字段。别用手算,容易出错。我曾经手算过一个DTD,结果把水平同步和垂直同步搞反了,画面一直偏左。
3.3 扩展块:CTA-861 和 DisplayID
128字节的主块,说实话,空间很有限。尤其是现在显示器功能越来越多,HDR、高刷新率、多声道音频……主块根本装不下。所以就有了扩展块。
扩展块从第127个字节之后开始,每个扩展块也是128字节。第一个扩展块的第一个字节表示扩展块类型。
3.4 CTA-861 扩展块
CTA-861(以前叫CEA-861)是最常见的扩展块类型。它主要用于消费电子设备,比如电视、显示器、投影仪。
CTA-861扩展块的结构:
- 字节0:固定为0x02,表示这是CTA-861扩展块。
- 字节1-2:版本号和附加标志。
- 字节3:DTD块的数量(通常为0-6个)。
- 字节4-127:数据块集合。每个数据块有类型、长度和内容。
数据块的类型包括:
| 类型代码 | 含义 | 常见用途 |
|---|---|---|
| 0x01 | 音频数据块 | 支持的音频格式(LPCM、AC3、DTS等) |
| 0x02 | 视频数据块 | 支持的CEA时序列表(如720p、1080p) |
| 0x03 | 厂商特定数据块 | HDMI、DP等厂商自定义信息 |
| 0x04 | 饱和度数据块 | 色彩饱和度信息 |
| 0x05 | 色彩管理数据块 | 色彩特性文件信息 |
我在项目中遇到过,有些电视的CTA-861扩展块里,音频数据块写的是支持Dolby Atmos,但实际解码器不支持,导致播放器一直选不到正确的音频格式。嗯,这就是数据块和硬件不匹配的典型问题。
3.5 DisplayID 扩展块
DisplayID是VESA推出的新一代扩展块标准,用来替代老旧的EDID扩展机制。它更灵活,支持更长的数据块,也支持更复杂的显示设备描述。
DisplayID扩展块的第一个字节是0x70(或者0x71、0x72,表示不同版本)。
DisplayID的核心是「数据块」的概念。每个数据块有:
- 块头:包含块类型、块长度、版本号。
- 块体:具体的数据内容。
常见的DisplayID数据块类型:
- DisplayID时序块:描述详细的显示时序,比DTD更灵活,支持非标准分辨率。
- DisplayID接口块:描述显示接口类型(HDMI、DP、USB-C等)和版本。
- DisplayID色彩特性块:描述色域、色彩深度、HDR支持等。
- DisplayID物理尺寸块:描述显示器的物理尺寸和对角线长度。
注意:DisplayID和CTA-861可以共存。一个EDID可以有多个扩展块,比如第一个扩展块是CTA-861,第二个是DisplayID。解析时,需要根据第一个字节判断类型,然后分别处理。
3.6 实战:解析一个真实的EDID
光说不练假把式。我们拿一个真实的EDID数据来解析一下。假设我们从显示器读到了以下128字节(十六进制):
00 FF FF FF FF FF FF 00 10 AC 12 34 56 78 90 00
24 1C 01 03 80 34 1D 78 EA 5D 35 A5 55 50 9F 27
12 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 02 3A 80 18 71 38 2D 40 58 2C
45 00 00 00 00 00 1E 00 00 00 FF 00 41 42 43 31
32 33 34 35 36 37 38 0A 00 00 00 FC 00 44 45 4C
4C 20 55 32 37 31 39 51 0A 00 00 00 FD 00 32 4B
1E 53 11 00 0A 20 20 20 20 20 20 00 00 00 00 00
我们来拆解一下:
- Header:00 FF FF FF FF FF FF 00 ✅ 正确。
- 厂商ID:10 AC 表示制造商ID是「DEL」(戴尔)。
- 版本:01 03 表示版本1.3。
- 基本参数:80 34 1D 78 表示数字接口,屏幕尺寸约34英寸,伽马值2.2。
- DTD:从54字节开始,第一个DTD是 02 3A 80 18 71 38 2D 40 58 2C 45 00 00 00 00 00 1E。解析出来是1920x1080@60Hz。
- 显示器名称:从FC标签开始,后面跟着「DELL U2719Q」。
- 校验和:最后一位是0x00,前127位求和后加上0x00应该为0。算一下,嗯,正确。
避坑指南:我曾经在解析一个EDID时,发现校验和怎么算都不对。后来发现是I²C读取时,最后一个字节被截断了。所以,校验和不对的时候,先检查读取流程,别急着怀疑EDID数据本身。
3.7 知识体系结构图
下面我用一张SVG图,把EDID数据块的解析逻辑串起来。你看完这张图,应该能对整个结构有个全局认识。
这张图把EDID的解析路径画得很清楚。你从主块开始,先确认基础信息,然后根据扩展块标志决定要不要继续往下读。如果是CTA-861,就按消费电子那套来解析;如果是DisplayID,就按VESA的新标准来。
我个人建议,在实际开发中,先写一个通用的EDID解析器,把主块和扩展块分开处理。主块解析用固定偏移,扩展块解析用类型分发。这样代码结构清晰,也方便后续扩展。
好了,这一章的内容就到这。EDID的数据块解析,说白了就是「按字节拆、按位拼、按类型分」。你只要把128字节主块的结构记熟,再掌握CTA-861和DisplayID的扩展块类型,基本上就能应付绝大多数显示器的识别工作了。