Считываем и декодируем информацию о VGA-мониторе

6 ноября 2018

Ранее в статье Учим iCEstick передавать видео-сигнал по VGA мы узнали, как работает VGA. Однако кое-что осталось за кадром. Когда я подключаю VGA-кабель к ноутбуку и говорю xrandr, программа выводит список разрешений, поддерживаемых монитором. Как она получает эту информацию?

Оказывается, что в каждом VGA-кабеле есть шина I2C. Под нее отведены пины 12 (SDA) и 15 (SCL). Ну раз такое дело, давайте возьмем HydraBus и подключимся к этим пинам:

Считывание EDID при помощи HydraBus

Просканируем адреса на шине:

i2c1> scan
Device found at address 0x37
Device found at address 0x50
Device found at address 0x51
Device found at address 0x52
Device found at address 0x53
Device found at address 0x54
Device found at address 0x55
Device found at address 0x56
Device found at address 0x57

Из всех этих устройств нас интересует устройство с адресом 0x50. Если честно, я не знаю, для чего нужны остальные, и есть ли они на всех мониторах. Итак, с этого устройства нам нужно прочитать 128 байт:

i2c1> [ 0xA0 0x00 ] [ 0xA1 hd:128 ]
I2C START
WRITE: 0xA0 ACK 0x00 ACK
I2C STOP
I2C START
WRITE: 0xA1 ACK
00 FF FF FF FF FF FF 00  04 72 AC 00 66 F6 00 01  |  .........r..f...
0A 14 01 03 68 34 1D 78  2A EE D1 A5 55 48 9B 26  |  ....h4.x*...UH.&
12 50 54 B3 0C 00 71 4F  81 80 95 00 81 00 D1 C0  |  .PT...qO........
01 01 01 01 01 01 02 3A  80 18 71 38 2D 40 58 2C  |  .......:..q8-@X,
45 00 09 25 21 00 00 1E  00 00 00 FD 00 38 4B 1E  |  E..%!........8K.
53 12 00 0A 20 20 20 20  20 20 00 00 00 FF 00 4C  |  S...      .....L
47 34 30 38 30 31 36 34  32 32 30 0A 00 00 00 FC  |  G4080164220.....
00 41 43 45 52 20 58 32  34 33 48 51 0A 20 00 F6  |  .ACER X243HQ. ..
NACK
I2C STOP

Здесь 0xA0 — это адрес устройства, сдвинутый на один бит влево и с нулем в младшем бите, означающим запись. Следом мы передаем байт 0x00, означающий адрес в памяти, с которого мы хотим начать читать. Передаваемый следом байт 0xA1 — это снова сдвинутый на один бит адрес устройства, но на этот раз с единицей в младшем бите, что означает чтение. Затем мы считываем 128 байт и выводим их в виде hex dump’а.

Полученные байтики — это данные в формате EDID, Extended Display Identification Data. Сей формат неплохо описан в Википедии, так что нам не должно составить труда его декодировать.

Первые 8 байт представляют собой фиксированный заголовок. Следующие два байта 04 72 хранят три буквы имени производителя, по пять бит на каждую букву:

>>> "{:08b}".format(0x04)
'00000100'
>>> "{:08b}".format(0x72)
'01110010'
>>> chr(ord('A') - 1 + 0b00001)
'A'
>>> chr(ord('A') - 1 + 0b00011)
'C'
>>> chr(ord('A') - 1 + 0b10010)
'R'

Ну да, устройство действительно было произведено компанией Acer. Байты AC 01 это код продукта, а 66 F6 00 01 — его серийный номер. Такой же серийный номер можно найти на наклейке с обратной стороны монитора. Дальше идут байты 0A 14. Это неделя и год производства дисплея, 10-ая неделя (возможно, 11-ая, если производитель нумерует их с нуля) 1900 + 20 = 2010 года. Сзади монитора написано, что он сделан в марте 2010. Вроде, все сходится. Идущие следом байты 01 03 означают версию EDID 1.3. Если версия иная, скорее всего, что-то пошло сильно не так.

Дальше мы немного пропустим и рассмотрим байты 35-37 (нумерация байт начинается с нуля): B3 0C 00. Это битовая маска, отражающая поддержку дисплеем «традиционных» разрешений и FPS. Декодируется она следующим образом:

1 - 720×400 @ 70 Hz
0 - 720×400 @ 88 Hz
1 - 640×480 @ 60 Hz
1 - 640×480 @ 67 Hz
0 - 640×480 @ 72 Hz
0 - 640×480 @ 75 Hz
1 - 800×600 @ 56 Hz
1 - 800×600 @ 60 Hz

0 - 800×600 @ 72 Hz
0 - 800×600 @ 75 Hz
0 - 832×624 @ 75 Hz
0 - 1024×768 @ 87 Hz, interlaced
1 - 1024×768 @ 60 Hz
1 - 1024×768 @ 72 Hz
0 - 1024×768 @ 75 Hz
0 - 1280×1024 @ 75 Hz

Ну и последний байт 00 говорит нам о том, что дисплей не поддерживает 1152x870 @ 75 Hz и не имеет никаких «manufacturer-specific display modes».

Далее мы видим последовательность:

71 4F 81 80 95 00 81 00 D1 C0 01 01 01 01 01 01

Каждые два байта кодируют поддерживаемое разрешение, всего до 8 возможных дополнительных разрешений. Специальная последовательность 01 01 означает пустое значение. Попробуем декодировать первые два байта:

>>> (0x71 + 31) * 8
1152
>>> "{:08b}".format(0x4F)
'01001111'

В первом байте закодировано количество пикселей по горизонтали. Во втором байте старшие два бита 01 означают aspect ratio 4:3 (00 = 16:10, 01 = 4:3, 10 = 5:4, 11 = 16:9), а в младших шести битах закодирована частота:

>>> 60 + 0b001111
75

Итого получаем 1152x864 @ 75 Hz. По аналогии оставшиеся байты декодируются в 1280x1024 @ 60 Hz, 1440x900 @ 60 Hz, 1280x800 @ 60 Hz и 1920x1080 @ 60 Hz.

Сравним получившийся список разрешений и FPS с выводом xrandr:

VGA-1 connected (normal left inverted right x axis y axis)
   1920x1080     60.00 +
   1280x1024     60.02
   1440x900      59.89
   1280x800      59.81
   1152x864      75.00
   1024x768      70.07    60.00
   800x600       60.32    56.25
   640x480       66.67    59.94
   720x400       70.08

Вроде, сходится. Таким образом, еще одна загадка вселенной успешно разгадана.

Метки: .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.