← На главную

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

Ранее в статье Учим 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

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