Подключаем алфавитно-цифровой экран к VGA

j1l1fpnq4oh5sxfybdd_twwors8.jpeg


Нет, это не шутка. В действительности к 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, для подключения блока питания.

abgnbgrhl6im2s3wamtueofbwqi.jpeg

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

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

Эмпирическим путём было установлено, что на разъёме PCI/PCI-e и на контактах PMBUS, это одна и та же шина i2c (даже электрически связана между собой). В системе она видна как файл-устройство /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, при этом разъём на материнской плате у меня свободен.

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

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

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


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

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

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

tzcl-1lnk1la6mautjihsojsizg.jpeg
Где обитает I²C в разъёме VGA

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

eiufl6ep3nvpikefpqwsyjaiqsi.jpeg
Подключение

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

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

Если вы всё сделали правильно, то дисплей можно будет увидеть на шине 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_lcd4×20_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)

b5ld1xhcrm66hd7agawgpxis1ia.jpeg

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

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

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

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

yjp1uq8jkyu8irhza9qiv6om6kw.jpeg
Котик

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

kbueh5jewab9i8ir_q0f5vjkajq.png

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

▍ Заключение


truqgj9qhbbfu3zf52-pw4graga.jpeg

На поиск альтернативных способов подключения к шине 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-канал и уютный чат

sz7jpfj8i1pa6ocj-eia09dev4q.png

© Habrahabr.ru