Нет, это не шутка. В действительности к VGA, DVI, HDMI можно подключать различные устройства, и даже питать их. И это очень удобный способ работы с различными устройствами и нестандартное использование обычного интерфейса.

Ларчик просто открывается, всё дело в том, что в интерфейсе VGA (а также в других видеоинтерфейсах) присутствует ещё одна шина данных I²C, которая доступна для использования и её легко можно применить в своих самоделках.

▍ В поисках шины I²C


На самом деле, задумка очень простая. В одной из задач мне понадобилось найти в компьютере шину I²C для подключения весьма специфического устройства.

В обычном компьютере обычно присутствует несколько подобных шин. В этом легко можно убедиться, просто введя:

ls -la /dev/i2c*
crw-rw---- 1 root i2c 89, 0 сен 24 12:35 /dev/i2c-0
crw-rw---- 1 root i2c 89, 1 сен 24 12:35 /dev/i2c-1
crw-rw---- 1 root i2c 89, 2 сен 24 12:35 /dev/i2c-2
crw-rw---- 1 root i2c 89, 3 сен 24 12:35 /dev/i2c-3
crw-rw---- 1 root i2c 89, 4 сен 24 12:35 /dev/i2c-4
crw-rw---- 1 root i2c 89, 5 сен 24 12:35 /dev/i2c-5
crw-rw---- 1 root i2c 89, 6 сен 24 12:35 /dev/i2c-6

Целых шесть шин I²C! Но где обитают эти шины, и как к ним получить физический доступ?

Самый «простой» способ — это получить непосредственно с разъёма PCI/PCI-e. Но для этого нужно делать какую-то плату-расширитель.

На материнской плате, которую я использую сейчас и о которой писал в статье «Серверные мощности в домашнем ПК» есть специальный разъём PMBUS, для подключения блока питания.



Это вполне официальный способ подключения к шине I²C и служит для управления серверным блоком питания, режимами его резервирования и получение данных энергопотребления.


Распиновка разъёма PMBUS

Эмпирическим путём было установлено, что на разъёме PCI/PCI-e и на контактах PMBUS, это одна и та же шина I²C (даже электрически связана между собой). В системе она видна как файл-устройство /dev/i2c-0. Но, вместе с тем на ней висит достаточно большое количество устройств. В чём можно легко убедиться:

i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- 08 -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- UU -- UU -- UU -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 2e UU 
30: 30 -- 32 -- 34 -- -- -- -- -- -- -- -- -- 3e -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- 52 -- 54 -- -- -- -- -- -- -- -- -- -- -- 
60: -- 61 -- -- -- -- -- -- -- 69 -- -- -- -- 6e -- 
70: -- -- -- -- -- -- -- --           

Так уж получилось, что устройство пересекалось по адресам с устройствами на материнской плате, а по определённым причинам адреса устройства поменять я не мог. Попытки «подвинуть» по адресам микросхемы на материнской плате тоже не увенчались успехом.

Поэтому пришлось искать другой вариант. И тут я вспомнил, что в интерфейсе VGA тоже присутствует шина i2c, при этом разъём на материнской плате у меня свободен.


Свободный разъём на материнской плате

Монитор для компьютера к нему подключить уже не получится, а вот всякие I²C-железки, вполне.

▍ Подключаем дисплей 20x4 по I²C к VGA


Благодаря the_matrix, у меня появился в хозяйстве этот дисплейчик, с шиной I²C на своём борту, и я решил на нём потестировать, а заодно и продемонстрировать подключение своих устройств по шине I²C к ПК.

Начну с того, где же найти шину в разъёме VGA. Эта шина есть и в других интерфейсах, таких как HDMI, DVI. Нужна она для того, чтобы получить параметры монитора. Это именно та шина, по которой драйвер понимает, какие параметры допустимы именно для вашего монитора.

Достоинство этой шины в том, что она совершенно пустая и на ней нет занятых адресов, если вы, конечно, подключаете без монитора. А следовательно можно её использовать как угодно.


Где обитает I²C в разъёме VGA

Нужно просто взять 4 провода, и подключить к соответствующим местам на дисплее. Питание к питанию, шину к соответствующим контактам, которые подписаны.


Подключение

Самое главное, после подключения не забыть покрутить резистор контраста и убедиться, что видны тестовые линии.


Регулировка контраста

Если вы всё сделали правильно, то дисплей можно будет увидеть на шине I²C следующей командой:

i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --           

Если вы видите не пустые поля, а некоторый адрес, значит вы всё сделали правильно. В моём случае дисплей живёт по адресу 0x27 (справедливости ради — это 0x4E, но не будем путать людей).

Если устройство видно, значит, всё готово к варварским экспериментам. Если нет, то проверяйте подключение.

▍ Программирование


Как обычно, всё хорошее придумано за нас. И писать библиотеку мне совершенно не хотелось, тем более что я уже достаточно пописал для этих дисплеев, особенно после статьи «Создание собственных драйверов под Linux».

Нашёл хорошую годную статью Raspberry Pi with I2C 2004 LCD и просто взял готовый проект с гитхаба https://github.com/CaptainStouf/raspberry_lcd4x20_I2C.

Клонирую его, перехожу в папку проекта и достаточно теперь выводить сообщения прямо из питона:

git clone https://github.com/ArcadiaLabs/raspberry_lcd4x20_I2C.git
cd raspberry_lcd4x20_I2C/
python3

Запускаю python и подключаю модуль:

import lcddriver

После этого нужно инициализировать класс и очистить дисплей:

lcd = lcddriver.lcd()
lcd.lcd_clear()

Ну и можно вывести что-то прикольное. Например, машинку, из моего поста про драйвера:

avto  = ["            ___     ",
         "     .--.  [STP]    ",
         ".----'--,'--.|      ",
         "'-()-----()-'|      "]

for i in range(4):
    lcd.lcd_display_string(avto[i],i+1)




Хотел реализовать в динамике, как было там. Но что-то нахрапом не удалось и стало лениво.

Давайте котика попробуем вывести:

cat = [" |\\__/,|   (`\\",
        " |_ _  |.--.) )",
        " ( T   )     /", 
        "(((^_(((/(((_/"]
for i in range(4):
     cd.lcd_display_string(cat[i],i+1)


Но котик получился не очень.


Котик

А причина достаточно простая, в кодировке дисплея отсутствует обратная косая черта «\». Можно даже убедится в этом, посмотрев в документацию.



Вместо неё подставляется вот такая вот кракозябра.

▍ Заключение




На поиск альтернативных способов подключения к шине I²C меня подвигли рабочие задачи, когда не удалось подключить устройство к шине PMBUS из-за конфликта адресов. На голой материнской плате в системе было видно всего два устройства. Одно из которых было PMBUS+PCI/PCI-E, а другое было VGA.

Несмотря на некоторую странность подключения своего устройства к разъёму VGA, способ оказался простым и надёжным, активно используется в наших проектах.

На самом деле, я далеко не первый, кто пишет о подобных способах подключения по видеоинтерфейсу устройств к шине I²C. Не так давно наткнулся на перевод статьи «Прямое подключение крохотного OLED-дисплея по HDMI», где человек так заморочился, что даже сделал отдельный драйвер для дисплея.

▍ Полезные ссылки


  1. Raspberry Pi with I2C 2004 LCD.
  2. Документация на дисплей.
  3. Создание собственных драйверов под Linux.
  4. Прямое подключение крохотного OLED-дисплея по HDMI.
Telegram-канал и уютный чат

Комментарии (36)


  1. ProstakovAlexey
    27.09.2022 12:21
    +1

    Очень интересно. На моем компуктере тоже много I2C устройств оказалось. А можно как узнать что это за устройства и посмотреть что передается в шине? Вдруг что-то полезное там есть.


    1. dlinyj Автор
      27.09.2022 12:29

       i2cdetect -l
      i2c-1   i2c             mga i2c                                 I2C adapter
      i2c-0   smbus           SMBus I801 adapter at 0400              SMBus adapter
      

      Как вариант, а вообще только с доками на материнскую плату. На своей я эмпирическим путём. Ещё можно ID устройств считывать и гуглить что это там висит


    1. Javian
      27.09.2022 13:09
      +3

      Только осторожнее записывайте в них https://habr.com/ru/post/413099/


      1. atrosinenko
        28.09.2022 11:42
        +1

        Кстати да, чтение SPD оперативки, вроде, довольно типичный пример применения видимых в системе I2C-интерфейсов.


        1. nochkin
          28.09.2022 19:06
          +1

          Раньше можно было и писать, кстати.


      1. nochkin
        28.09.2022 19:05
        +3

        Я как-то писал программу для обновления прошивки (не EDID, а именно полной прошивки) монитора по обычному подключению VGA через I2C шину. Там вообще много чего можно сделать такого, в том числе и деструктивного.


    1. atrosinenko
      27.09.2022 23:46
      +5

      Ниже уже упомянули DDC, но вскользь. А я недавно был очень удивлён, когда полез гуглить, что же это за загадочный пункт "DDC/CI: Enable" в меню моего монитора. Оказывается, давно есть стандарт, чтобы управлять монитором с компьютера: поставил ddcutil из репозитория -- и можно, например, регулировать яркость по HDMI. Ну или видеовход на мониторе на VGA переключить (но это уже попахивает настройкой фаервола по ssh).


      1. Stalker_RED
        28.09.2022 10:13
        +1

        В отличие от фаерволла вы можете переключить входящий сигнал и кнопочками из меню монитора.

        Это очень удобно если у вас несколько источников сигнала для монитора.

        Например два монитора, к которым подключены ноут и десктоп, и kvm-свитч, который у еет переключать мышь с клавиатурой, но только один монитор.

        Второй придётся переключать руками в меню монитора или вот такими командами. Их и из-под винды можно отдавать.


        1. atrosinenko
          28.09.2022 11:30
          +1

          Про кнопочки, разумеется, согласен -- просто "улыбнуло" наличие такого параметра. На самом деле не удивлюсь, если команды DDC принимаются сразу со всех видеовходов, но тут уже от монитора зависит.


  1. PR200SD
    27.09.2022 12:44
    +1

    Это только с Linux работает, или на W тоже можно?


    1. dlinyj Автор
      27.09.2022 12:52

      То что можно - это без сомнения. Но видимо будет несколько сложнее.


  1. termsl
    27.09.2022 12:50
    +3

    Вот бы еще пример, как из-под винды к данной шине обращаться.


    1. VBKesha
      27.09.2022 13:05
      +1

      По виндой раньше всё зависело от дров видюхи. Есть тулина www.entechtaiwan.com/lib/softmccs.shtm она умеет с мониторами общаться через этот I2C(DDC).
      Думаю если сильно приспичит то можно пореверпсить, в поисках того как она это делает.


    1. SGordon123
      27.09.2022 14:12

      Вот примерчики бы на эти функции где тон найти ... https://learn.microsoft.com/en-us/windows-hardware/drivers/display/i2c-bus-and-child-devices-of-the-display-adapter Или надо свой драйвер видеоадаптера под это сочинять?


  1. StSav012
    27.09.2022 16:50
    -9

    Как же воняет тот код с GitHub! Надеюсь, его в таком виде не используют.


  1. zurabob
    27.09.2022 17:26
    +2

    дисплей живёт по адресу 0x27 (справедливости ради — это 0x4E, но не будем путать людей).

    Почему 0x4e? Согласно спецификации, адрес - это 7 бит, следующих за условием СТАРТ, и в данном случае это именно 0x27. Очень часто почему-то указывают сдвинутый влево адрес вместе битом с направления передачи, это неправильно, это действительно часто путает и приходится пробовать 2 варианта, если недоступен даташит.


    1. dlinyj Автор
      27.09.2022 17:39

      В документации часто указывают старший адрес. Например на блоки питания. Так что поэтому приходится думать. Ну и по логике бит, таки полный адрес выглядит так. Но я согласен с вами.


  1. steanlab
    27.09.2022 23:16
    +1

    Все гениальное-просто.
    Спасибо!


  1. vectorplus
    28.09.2022 02:01

    Прикольная штука. Только, вроде, VGA разъем уже мало где есть?


    1. axe_chita
      28.09.2022 05:07
      +1

      На видеокартах VGA разъём уже выпилили, но на материнских платах он всё еще востребован


    1. redsh0927
      28.09.2022 05:36
      +3

      Дык в HDMI тоже есть и2ц, где-то тут был пост как на него вешали мелкий олед 128х64


      1. Javian
        28.09.2022 07:43
        +1

        Прямое подключение крохотного OLED-дисплея по HDMI

        https://habr.com/ru/company/ruvds/blog/659507/


      1. vectorplus
        28.09.2022 08:54

        Ха, даже думал спросить, нет ли этой штуки в HDMI :)


      1. dlinyj Автор
        28.09.2022 09:48

        Ссылка в посте


    1. dlinyj Автор
      28.09.2022 09:49

      Вначале дал список интерфейсов: dvi, vga, hdmi


      1. vectorplus
        28.09.2022 09:54

        Сори, невнимательно читал.


  1. mambet
    28.09.2022 12:19
    +1

    Но ведь можно передавать через i2c какое-нибудь небольшое разрешение (типа 320x200) и выводить, получается, нормальную VGA картинку... Пусть и с низкой частотой... (задумался)


    1. dlinyj Автор
      28.09.2022 12:21
      +1

      В конце есть ссылки, и там так и делают.


  1. raspberry_pi_soft
    28.09.2022 13:43
    +1

    Отличная статья! Интересно попробовать будет, и не только такой дисплей подключить. Навскидку есть дома модули АЦП и OLED дисплеи...


    1. dlinyj Автор
      28.09.2022 16:00
      +1

      У меня на работе висит громадное количество устройств вот так через VGA.


  1. Dmitry_Rya
    28.09.2022 14:10

    Где можно купить такой экран?


    1. dlinyj Автор
      28.09.2022 14:11

      Достаточно просто найти где они продаются.

      Простите за такое капитанство, просто откровенную рекламу делать не хочу.


      1. nochkin
        28.09.2022 19:16

        Ай-яй-яй. Теперь получилась реклама для Google!


  1. HEXFFFFFFFF
    29.09.2022 04:23
    +2

    Вообще есть специализированные чипы преобразователи интерфейсов. Тыкаешь его в usb , а на выходе получаешь com, i2c, spi, итд не помню точно названия но это что то из разряда ftdi. Такой чип например используется в дебагере для esp32


    1. Javian
      29.09.2022 08:04

      Как пример адаптеры-переходники USB-1-Wire часто встречаются в системах мониторинга температур в помещениях.


    1. dlinyj Автор
      29.09.2022 11:44

      Пробовал его. Начался цирк с драйверами и настройкой. Очень ненадёжно, особенно для промышленного применения. Но это тоже допустимый вариант.