Backspace Invaders или как подключить светодиодный дисплей 64x64 к Arduino

ac020d905fcf46f8a7458d999c31a514.jpg
4095 светодиодов и все-все-все

Как ни удивительно, с выводом изображения на такой дисплей вполне справляется контроллер ATmega328, что лежит в основе Arduino Uno. Из этого всего получилась «карманная» консоль (весом несколько килограмм), в которую прошита игра по мотивам Space Invaders. В планах придумать что-нибудь ещё, ведь свободной памяти осталось полно.

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

В этот раз хотелось сделать что-то компактное с разрешением на уровне приставок и компьютеров начала 80х. Правда дисплей в 64×64 пикселя не дотягивает до Atari 2600, но зато на целых 64 пикселя больше, чем дисплей Nokia 3310, где игры тоже были. Так что его должно было с запасом должно хватить как минимум для комфортной игры в тетрис или понг.

86bdbc720d954c949f82749a98c1d080.gif


Кроме дисплея я раздобыл плату, совместимую с Arduino Uno, и стал думать как бы теперь со всем этим добром взлететь.

Компания Adafruit продаёт подобные дисплеи и на её сайте можно найти примеры их использования. Там же есть ссылка на библиотеку для работы с ними. Библиотека поддерживает Arduino Uno и Arduino Mega.

Эта библиотека организует видеопамять, где и хранит цвета пикселей. Пользовательская программа перекрашивает эти пиксели, а изображение выводится на дисплей в обработчике прерывания таймера. С маленькими дисплеями это работает неплохо, но в моём случае такой способ не годится. Даже если на каждый пиксель выделять по полбайта (по одному биту на R, G, B и один лишний), то для матрицы 64×64 понадобится 2 килобайта памяти. А это всё что есть у ATmega328P. Можно, конечно, взять процессор помощнее, но это не путь джедая.

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

6a2bd186f3ff491d96f2dfe91a218b92.jpg


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

  • Выставляем на входах дисплея адрес выводимой строки
  • Заполняем массив цветами пикселей спрайтов, которые пересекаются с текущей строкой
  • Задвигаем по очереди все пиксели в сдвиговый регистр, который управляет светодиодами
  • Защёлкиваем полученные данные и подаём их на выходы регистров


В итоге под видеопамять выделен массив размером только в четыре строки экрана. Почему четыре? Всё потому, что одновременно мы задвигаем данные в две строки — ведь у матрицы две группы входов: R1/G1/B1 и R2/G2/B2. Управляют они двумя строками, отстоящими друг от друга на 16 пикселей.

Но тогда почему не две строки, а четыре? Оказывается, что матрица 64×64 состоит из двух независимых матриц 32×64. Можно было бы к каждой подключить отдельные выходы процессора, но у ATmega328 их недостаточно. К счастью, заботливый производитель предусмотрел каскадирование этих матриц — выход сдвигового регистра одной можно подключить ко входу другой. Тогда получится логическая матрица 32×128, которая физически отображается как 64×64. То есть в каждой фазе нам надо задвинуть в регистры две строки по 128 пикселей —, а это и есть 4 строки физического экрана.

7637d6366a1540558e603b704ff247b6.png

Прототип консоли мы сделали во время летней компьютерной школы. Первой игрой стало нечто, отдалённо напоминающее Space Invaders.

В реальности светодиоды очень уж выжигали глаза. Отрегулировать их яркость с помощью ШИМ вряд ли получится — быстродействия ATmega не хватает. Надо брать какой-нибудь ARM или ПЛИС.

Финальный вариант я оформил в деревянном корпусе. Экран защищён зашкуренным оргстеклом. За счёт рассеяния света глаза теперь не выжигаются, но на видео работу приставки теперь снять сложнее — всё изображение становится размытым.

Вся программа использует 1101 байт (53%) ОЗУ и 6432 (19%) байт ПЗУ. Остаётся ещё место, чтобы сделать несколько игр и меню для их выбора.

Ссылки

  1. Исходники проекта: github.com/Dovgalyuk/BackspaceInvaders
  2. Описание работы матрицы на сайте adafruit: learn.adafruit.com/32×16–32×32-rgb-led-matrix
  3. Библиотека от adafruit для управления матрицей: github.com/adafruit/RGB-matrix-Panel
  4. Библиотека от adafruit для рисования графических примитивов: github.com/adafruit/Adafruit-GFX-Library
  5. Похожий проект на более мощном процессоре: learn.adafruit.com/ledgames-beaglebone-black-64×64-led-game/overview
  6. Статья про управление дисплеем меньшего размера: geektimes.ru/post/275548

© Geektimes