Если вы белая и пушистая – вам пора в солярий и на эпиляцию.

Меню навигации для мобильных

Светодиодные матрицы

Автор zenon, 12 Апр., 2024, 11:36

« предыдущая - следующая »

zenon

На пробу взял P10 монохром.
Тут (https://ozon.ru/t/nbwZgqW).
↓ спойлер ↓
1712849633160.jpg
[свернуть]
↓ спойлер ↓
1712849633174.jpg
[свернуть]
На микросхемах надписи
DP5125 12H1203
4953  V2G0703
Разобрал с трудом, они под лаком.
Для пробы подключил к Blue Pill.
Библиотека эта (https://github.com/board707/DMD_STM32).
Обсуждение ее тут (https://forum.arduino.ru/t/dmd-stm32-biblioteka-dmd-matricz-dlya-stm32-i-rp2040/8573/1).
Почему-то получил паразитную засветку (https://youtu.be/TXDDk6pXCEg).
Может быть из-за земель/проводов, подключал пинами.
Ну и преобразователь уровней какой-нибудь надо попробовать, питание у нас 5 вольт, а стм-ка 3,3.
На самой плате земли коннекторов P10 и питания звонятся.
На хабре статейка (https://habr.com/ru/articles/372215/).
Схема оттуда:
↓ спойлер ↓
P10_scheme.gif
[свернуть]
Ещё не решил на каком контроллере делать, хотя уже полюбившийся F0 вполне подходит.
К этому же МК хочу подключить 1602 и расположить за панелью, для дублирования и смены выводимого текста.
Вот ещё картинка объясняющая интерфейс передачи данных:
↓ спойлер ↓
p4.gif
[свернуть]


ы. Нашёл у себя 74LVC1G17, надо пробовать.
https://github.com/minamonra/

Slabovik

Преобразователь уровней - TXS0108E
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

Можно и его, но тут двунаправленный не нужен.
На всякий случай надо бы иметь в загажнике уже такой.
Даже 4050 нету, сделаю на SN74, жаль они одноканальные у меня, а тут аж 6 штук наверное надо.
... нужен SN74LVC4245.
https://github.com/minamonra/

zenon

Решил что будет F103.
Взял HEF4050.
Пока для совместимости с DMD библиотекой оствил дефолтные пины, к железному SPI привязаны только Clock (PA5) и Data (PA7), остальные можно перекинуть на любые другие.
Продумать надо на какой таймер кинуть энкодер, дисплей 1602, возиожно IR датчик (ещё один таймер).
Ну и кнопки.
Начал понемногу.
Тут вопрос, на верхнем слое, под контроллером что лучше соединять землю или VDD?
ы. 20-ти пиновый разъём бутербродом хочу соединять с панелью, он в IDC как раз входит, крайние 4 пина не использую, для "прочности".
https://github.com/minamonra/

Slabovik

Что-то я не понимаю, что сподвигло на 4050? Это же не преобразователь уровней... Это типовая 40xx логика.
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

#5
Ничего больше в наличии не было, это временно...
ы. Какие ещё распространённые есть?
4504 вроде можно.
https://github.com/minamonra/

Slabovik

Вообще, 40-я серия, она "экономиная, но медленная КМОП". И у неё напряжение питания типовое 9 вольт. Насколько я знаю, у 4504 минимальное напряжение 5 вольт. Так что 4245 наверное лучший вариант, ну либо ту, что я нарисовал выше. То, что она двунаправленная, её не портит и двунаправленность не мешает (я вообще удивляюсь, как они её такую сделать смогли).

А ты не выяснял, как положение битов соотносится с физическим положением пикселей? Что-то мне думается, что довольно уныло гонять маленький экран, а большой не получится из-за бутылочного горлышка в виде SPI. Всё время хотелось аппаратный вывод замутить, чтобы проц только в ОЗУ изоражение складывал, а остальное оно само...
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

Не, не выяснял ещё. Где-то картинка была как физически расположены светодиоды и последовательность их включения.
Какие-то зигзаги... :)
Свою процедурку писать будем?

ы. ... ни 4504 ни 4245 нету... всё в заказ...
Вроде есть возможность по двум SPI гонять, те, например 6 матриц по три в цепочке.
А вот тут (https://www.tindie.com/products/lightwell/dmd-stm32-shield-for-p10-led-matrix-panel/) есть шилд, не понял ка, но вижу четыре P10 коннектора.

https://github.com/minamonra/

Slabovik

Гонять можно целыми байтами - это 8 SPI параллельно, но из-за организации пикселей они с огромной вероятностью будут разбросаны по разным блокам, из-за чего это будет жуть как неудобно.

Гонять надо много, когда экран становится побольше, а когда изображение динамическое, его обновление надо делать не реже, чем те же 50 Гц. (ради интереса, экран 1920x1200 с обновлением 60 Гц гоняет по интерфейсу 1920*1200*3*60= ~400 мегабайт ежесекундно. Это... много :) )

Но, в принципе, повозиться с этой штукой всяко полезно  :) Написать свою процедуру - а почему бы и нет?
Мне вот не совсем понятно, почему только 4 строки?
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

https://github.com/minamonra/

Slabovik

На дешифраторе D18 я вижу использование только четырёх ROW. Хотя транзисторов по факту 8 - это потому что по два транзистора вместе работают, а значит, что хотя и два транзистора - это фактически одна строка - во всю длину D1~D16 (почему 16?)
Или я чего-то не рассмотрел?

Также не понял, зачем D17 поставили двунаправленный буфер, когда смена направления в нём не используется. Есть регистры попроще в это место...
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

#11
16 байт, 4х8 светодиодов на каждном регистре, 16х4х8 = 32*16.
Почему двунаправленный буфер - не понимаю.
D18 только A0 и A1, тк монохром, надо RGB глянуть, там должно больше использоваться.
ы. nOE вообще-то шимить можно.
Те, на катоды данные по SPI Data (цепочки по 128 светодиодов), аноды - 4 варианта линий A и B.
ыы. Вот ещё (https://sotvorimvmeste.ru/viewtopic.php?f=37&t=198):
ЦитатаПри работе с одним модулем информация на вход R разъёма HUB1.2 с устройства управления уходит четырьмя 128-ми битными посылками, каждый раз выставляя на линиях A и B очередной адрес. Сдвиг данных в регистрах тактируется положительным фронтом сигнала CKL, а на выходы регистров данные переносятся по положительному фронту сигнала SCLK.
https://github.com/minamonra/

Slabovik

Там картинка есть - подтверждает.
В принципе, 1:4 выглядит лучше, чем 1:8, тем более чем 1:16, но расчёт изображения, если биты байта располагать "столбиком" довольно затратен. Выгоднее биты располагать строчкой - тогда они выводятся целиком.

Там не написано, первые задвигаемые байты идут сверху вниз, или снизу вверх? Впрочем, с точки зрения трудоёмкости это всё-равно.

Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

Сварганил макетку, жёстко к ногам привязан только выход на матрицу, SN74LVC4245 ещё не пришли, а они оказываются в две стороны могут, мне надо всё-таки даташиты смотреть! :)
Четыре кнопки, энкодер и дисплей.
↓ спойлер ↓
1713974459379.jpg
[свернуть]
https://github.com/minamonra/

Slabovik

Жизнерадостная надпись :)
А у 4245 направление переключается сразу для всего массива. В принципе, не мешает, если надо только в одну сторону биты гонять.
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

Накидал инит SPI для F1, дефайны для вкл/выкл пинов.
Подключил анализатор на CLK и MOSI, передаю единичку, вижу ... не пойму что вижу???
:)
скрины с анализатора и код тут
https://github.com/minamonra/my_stm_snippets/tree/main/F1/p10m
https://github.com/minamonra/

Slabovik

Видишь лес. А надо смотреть деревья. Пакеты идут много быстрее, чем настроен анализатор. В итоге весь пакет выглядит иголкой. В итоге ничего не видно.
Я не особо разбирался в инитах, но на какой скорости там должно ходить всё? Для разборок не стоит делать высокую скорость, не более мегагерца, а лучше ниже.
И ещё. Там есть третий сигнал. Его тоже надо бы смотреть. Он очень помогает в разборках, если настроен правильно: перед передачей строки его надо опустить, а по окончании поднять, чем переданная информация (строка) будет передана на выход регистров.

Попробуй описывать словами, что именно делаешь. Т.е "настраиваем таймер SPI на такую-то скорость... поднимаем RDY...опускаем......

В общем, clk должен быть похож на меандр, примерно. Data - как попадёт, но меняется реже. Rdy - перед пакетом падает, после поднимается.  Скорость передачи контролируется по clk

зы: а может ли анализатор вообще с такой скоростью работать, с какой контроллер выдаёт? В этом случае лучше осциллограф.
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

#17
Да, вероятно скорость выше, анализатор обычный на стм-ке 24МГц может максимум.
---
У меня таки оно ожило, но пока не так как надо, потому что метод не тот, ну и передаю я всего одну посылку 8-бит, а надо 16.
Сейчас над распутать алгоритм передачи.
Из вышеупомянутой ссылки он такой:
Цитата1. Выдаём по SPI данные для сдвиговых регистров.
2. Устанавливаем лог. 0 на ножке nOE.
3. Устанавливаем лог. уровни на ножках A и B в соответствии с обновляемой группой светодиодов (одной из четырёх).
4. Выдаём на ножку SCLK короткий положительный импульс.
5. Устанавливаем лог. 1 на ножке nOE.
Для переключения PinA-PinB сделал функцию:
void PINAB_change(uint8_t col){
  switch (col) {
    case 0: {PinA0; PinA0;};
    case 1: {PinA0; PinA1;};
    case 2: {PinA1; PinA0;};
    case 3: {PinA1; PinA1;};
  }
}

дальше вопрос в SPI, настроил на 8-ми битный режим, main такой:
do {
  uint8_t _data = 0; // то, что запишем в SPI
  for (col = 0; col < 4; col++) {
    SPI1_send(_data); // 1. передаём данные
    nOE0; // 2. Устанавливаем лог. 0 на ножке nOE
    PINAB_change(col); //  лог. уровни на ножках A и B
    SCLK1; // 3. выдаём на ножку SCLK короткий положительный импульс
    dummy_loop(10);
    SCLK0;
    nOE1;
  }
  delay_ms(10);
  } while (1);
}
Результат происходящего:
https://youtu.be/fBkpjaoDfQo

:: добавлено 01 Май, 2024, 20:07
ы. Да, без RDY (MISO) каша, надо попробовать третий провод и нормально посмотреть.
https://github.com/minamonra/

Slabovik

При инициализации устанавливаем RDY (OE? не помню, как там на картинке) в 1, Clk тоже в 1

При передаче
1. Опускаем RDY
2. запускаем SPI (для одной строки 32x16 надо передать (32/8)*(16/4)=16 байт. Если передать меньше, то строка не обновится полностью - переданное ранее просто сместится далее по регистрам. Байты можно придумать разные, хоть 1-2-3-4-5...
3.a Поднимаем RDY
3.б Выставляем строку AB

Эти два действия надо сделать с минимальным интервалом времени, причём порядок даже не важен. Если разнести во времени, то между этими действиями выведенные данные  светятся на "чужой" строке, а это нам сейчас не надо (можно загонять конечно между делом 16 нулей, либо "жать резет", но это не сейчас).

Далее перво-наперво, посмотри осциллографом, как выглядит Clk.
Далее можно зацепить каналы на Rdy и Data. Синхронизацию на Rdy прицепить по спаду - на экране будет начало посылки. Прицепить по подъёму - будет конец посылки. Ну там разберёшься...
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

RDY это nOE? Который шимить можно?
Тут понял что у меня происходит, PA15, я его и так и эдак - не вижу, как был высоким так и остаётся высоким....
... ну и перекиул сначала на PA6, - и сразу увидел его анализатором, завёл на enable, вижу оба состояния.
перекинул инит на PB15, чтобы себя проверить, не напутал ли я что-то с кодом, нет всё ок, рабодает.
В что с PA15 не пойму, те же манипуляции с ним - не реагирует никак, козы на плате нет, до своей ноги звонится.
Может и до этого была проблема из-за него.
https://github.com/minamonra/

Slabovik

nOE... я забыл про него.
RDY - это не оно. Это строб, по фронту которого происходит перезапись данных из регистра сдвига в выходной регистр.
Тогда да, nOE пусть остаётся как есть. Потому что выход надо "погасить" перед подъёмом RDY и "зажечь" после выставления строки AB.

Гм, оборванный вывод? Это вполне проблема, да... Жаль, что у STM даташиты такие разбросанные. Не случилось ли какой рестрикции из-за конфигов. Но это читать много надо, так не помню, практиковался совсем мало  :-\

Ну трындец какой-то. Я тутпро RDY вещаю, а на входе матрицы этой фигни нет. В общем, RDY - это ST на микросхемах, формируется как-то автоматом. Давай я завтра, как время будет, возьму и на основе уже этой схемы нарисую циклограммы, как там вообще должно быть. А то я по памяти всё, и... промахиваюсь...

и,да... OE по схеме не задействован, так что совсем печалька...
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

Давай называть пины так, как я их задефайнил, а то запутаемся.
nOE, PinA, PinB, SCLK - ногодрыг и SPI ноги - CLK, MOSI (PA5/PA7).
У F103 камня управление третьей ногой SS аппаратное реализовано как-то не верно, никто им не пользуется, только две ноги хардварного SPI у всех, не вдавался в подробности почему.
В принципе и у F0 делал также.
https://github.com/minamonra/

Slabovik

#22
Скорее пока буду смотреть на исходное изображение



Сигналы 'A' и 'B' - выбор строки. Фактически - это разряды двоичного числа в диапазоне 0-3 (A - разряд 0, B - разряд 1)
Несмотря на то, что строк на дисплее 16 длиной по 32 пикселя, электрически их только 4 длиной по 128 пикселей, что составляет 16 байт.

Электрически сигналы 'A' и 'B' не зависят ни от чего и могут меняться в любое время, однако для правильной работы индикатора устанавливать их надо непосредственно перед отображением новой строки.

Сигнал 'OE' (Output Enable) - включение отображения строки (или индикатора). Активный уровень - высокий. Может использоваться для управления яркостью индикатора при помощи ШИМ.

'R' - информационные биты, отображаемые строкой. Инвертированные: '0' - точка горит, '1' - точка погашена. Биты задвигаются в регистры строки в количестве, соответствующем физической длине строки (т.е. 128 бит или 16 байт для нашего случая).

'CKL' - строб (Clock, CLK и т.п.) для данных 'R'. Активный переход от низкого уровня к верхнему - в этот момент то, что было на 'R' попадёт в сдвиговый регистр строки. CKL - наверное опечатка

'SCLK' - строб для переноса накопленных в сдвиговом регистре данных на выход (он же Rdy, DataReady, Sync и т.п.) Активный переход от низкого уровня к верхнему
↓ спойлер ↓
тут могут быть нюансы т.к. микросхем с аналогичных функционалом много и бывает, что у некоторых типов на выходе использован не регистр-защёлка, а регистр хранения - у него при низком уровне сигнала данных на выходе 'хранятся', а при высоком он 'прозрачен', т.е. на его выходах ровно то же, что и на входах

Вот как-то было: https://anklab.ru/forum/index.php?msg=220
[свернуть]

Синонимы.
'A','B' = A0, A1, SA0, SA1...
'CLK' = Clk, Clock, BitLock, BitShift, Shift...
'SCLK' = Ready, Rdy, DataLock, DataReady...
'R' = Data, DataBit, DB...
'OE' = On...

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

Самое главное. Как работать.
Развёртка индикатора должна быть весьма пунктуальна. Поэтому не обойтись без хардверной синхронизации от таймера. В самом простом случае, вывод на индикатор делается внутри прерывания от таймера - см. картинку. Это не очень хорошо т.к. последовательный вывод отнимает много времени, но для учебной цели пойдёт
↓ спойлер ↓
в более серьёзном проекте в прерывании от таймера необходимо делать только включение вывода новой строки (OE и RDY) и можно расчёт байт новой строки, а затем выход и запуск SPI со своими прерываниями - так не надо будет мудрить с вложенными прерываниями и не будет блокировки прерываний надолго (что и есть не очень хорошо)[/b] Ну а пока одно прерывание, SPI можно сделать софтверный
[свернуть]

Циклограмма-вывода-на-светодиодные-матрицы.png
картинка очень широкая, поэтому лучше правым кликом мыши...

В прерывании первое - опускаем OE
Второе - устанавливаем AB текущей строки
Третье - поднимаем RDY (SCLK)
Четвёртое - рассчитываем биты/байты следующей (!) строки, складываем в буфер (ОЗУ)

Пятое - опускаем RDY (SCLK), передаём  рассчитанные биты/байты следующей строки.
Выходим из прерывания.

Повторюсь - пятое не обязательно делать внутри прерывания по таймеру (лучше не делать). Если используется хардверный SPI, то подготовленный на четвёртом буфер должен быть доступен и процедуре обработки SPI, а пятый пункт заключается в запуске прерываний SPI, после чего выход из прерываний по таймеру.
По прерыванию от SPI смотрим на буфер и засовываем в SPI следующий из буфера байт. Если байта нету - останавливаем SPI.

Вот, нарисовал то, что я бы сам делал, будь у меня только проц и ни одной микросхемой более

Циклограмма-вывода-правильная.png

Такое построение позволяет не сидеть долго в прерывании, блокируя их (это моветон, почему - узнаете, когда жахнет).
2,5 мс между строками - это соответствует 100 Гц развертки на экране. Нормально, чтобы не обращать внимание на мерцания.

Лучше всего выделить ОЗУ, в которой формировалось бы изображение, выводимое на экран.
Изменять изображение программе разрешить только когда будут показаны все строки, например, формировать сигнал после вывода 4-й строки, запуская процедуру обновления. Иначе будут видны "перекосяки". Процедура обновит содержимое экранного ОЗУ и новый кадр пойдёт уже обновлённым.

Да, скорость SPI слишком задирать не надо. Например, при 1МГц вывод 128 бит будет всего по длительности ~0,13мс, так что времени довольно много. Другое дело, если экран будет большим, но там просто посчитать.

Надо будет оценить (тем же осциллограформ), сколько по времени займёт исполнение прерывания от таймера, но не думаю, что много. Особенно, если изображение уже в "экранной" области ОЗУ, то оно уже готово, надо только выбрать нужную строчку. Если выводить из памяти программ, то там конечно дольше выходит т.к. каждый раз каждую строчку считать по-новой. Это непроизводительно.

А, да. RDY, OE, AB сделать программно управляемыми (ногодрыг). Data, CLK - хардверными, пусть блок SPI ими дрыгает. По циклограмме вроде понятно, в каком порядке всем этим дрыгать. AB если назначить на биты 0 и 1 какого-нибудь порта, будет проще их туда выгонять (хотя...)
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

Ну у меня же есть SySTick, он же подходит?, - зашли, проверили миллисекунды, - надо выполнили задачу, нет - вышли.
Можно и меньше 1 мсек его настроить.
https://github.com/minamonra/

Slabovik

Это немного другая организация процесса, но в принципе подходит. Основной цикл крутит круги, в которых вызываются все процедуры. А процедуры уже смотрят, пора им или ещё нет. Тут проблема может быть в том, что вдруг возможен какой-то длительный процесс/процедура, а эта штука его прерывать не сможет. Прерывания помогают отделить процессы друг от друга.
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.

zenon

#25
Случайно удалил свой пост.
Предделитель для 1Гц будет такой:
72000000/7200 = 10000Гц
Предзагрузка 10000.
Прерывание по переполнению счётчика:

↓ спойлер ↓
void TIM13_init(void){
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // разрешить тактирование таймера
  TIM3->PSC = 7200 - 1; // предделитель
  TIM3->ARR = 10000 - 1; // предзагрузка
  TIM3->DIER |= TIM_DIER_UIE; // прерывания будем ловить по переполнению счетчика
  TIM3->CR1 |= TIM_CR1_CEN;
  NVIC_EnableIRQ(TIM3_IRQn);
}

void TIM3_IRQHandler (void) {
  if ((TIM3->SR & TIM_SR_UIF) == TIM_SR_UIF) { //  проверяем, что прерывание произошло по событию переполнения счетчика stm32f10x.h
    TIM3->SR &= ~TIM_SR_UIF; // флаг сбросить, иначе при выходе из обработчика прерываний мы тут же попадем туда снова
    LEDTOGGLE; // моргаем
  }
}
[свернуть]
---
Но, у нас ещё есть собственное прерывание на SPI: void SPI1_IRQHandler() :)
https://github.com/minamonra/

Slabovik

Смотрю, озадачил я тебя   ::) Но увы, такова цена многозадачности. Мы ещё реентерабельность ни разу не рассматривали  ;) Впрочем, здесь она не нужна, я полагаю...
Общением на форуме подпитываю свою эгоистичную, склонную к самолюбованию сущность.