Общие сведения
В этом проекте мы подключим RGB-светодиодные матрицы 64x64 к Raspberry Pi и выведем на них сначала кадровый буфер, а затем бегущую строку.
Видео
Нам понадобится
Подключение
Для подключения матриц 64x64 необходимо установить джамперы RGB Matrix Hat в следующее положение:
Установим RGB Matrix Hat:
Теперь можно подключить цепочку с матрицами:
Вывод кадрового буфера
При помощи библиотеки RPI-FB-MATRIX возможен вывод кадрового буфера. То, что выводится в hdmi порт, будет выведено на матрицы. Возможно выводить как часть экрана (crop), так и весь экран в масштабе (scale).
Откроем эмулятор терминала
и выполним команду
git clone https://github.com/tremaru/rgb-fb-matrix
Далее необходимо установить библиотеку libconfig++
sudo apt update && sudo apt install libconfig++-dev
После этого можно приступать к сборке. Для этого перейдём в директорию rgb-fb-matrix
cd rgb-fb-matrix
И запустим программу make
make -j
После завершения программы make
в директории появятся две утилиты, первая называется display-test
, вторая rpi-fb-matrix
. Обеим утилитам для работы необходимо передать файл конфигурации. В нём необходимо указать размеры панели, количество панелей и ориентацию панелей. Подробнее об этом можно узнать в примере файла конфигурации matrix.cfg
, который находится в этой же директории.
Рассмотрим пример файла конфигурации.
Рассмотрим на примере подключения двух панелей 128x64:
display_width = 192; // общее количество пикселей в ширину display_height = 128; // общее количество пикселей в длинну panel_width = 64; // количество пикселей одной матрицы в ширину panel_height = 64; // количество пикселей одной матрицы в длинну chain_length = 6; // количество панелей parallel_count = 1; количество паралельных линий. Подробнее о подключении паралельных линий читайте в файле README.md // Геометрия подключения панелей panels = ( // order - порядковый номер панели, 0 - первая панель экрана, // правый верхний угол которой соответствует 0 X и Y экрана. // rotate - угол ориетнации панели 0 или 180 ( {order = 0; rotate = 0;}, {order = 1; rotate = 0; }, {order = 2; rotate = 0; } ), ( {order = 5; rotate = 180;}, {order = 4; rotate = 180; }, {order = 3; rotate = 180; } ) ) // Если раскомментировать строку ниже, то вывод на матрицы будет не масштабирован (scale) // а обрезан (crop) начиная с указанной в скобках координаты (0, 0 - правый верхний угол экарна) // crop_origin = (5, 95)
Для тестирования файла конфигурации воспользуемся утилитой display-test
, передав ей файл конфигурации и дополнительные аргументы:
sudo ./display-test matrix.cfg --led-no-hardware-pulse --led-slowdown-gpio=3
В правом верхнем углу каждой матрицы загорится белым её порядковый номер в массиве матриц.
Выведем кадровый буфер на сборку матриц
Для вывода на матрицы запустим утилиту rgb-fb-matrix и передадим ей файл конфигурации и дополнительные аргументы:
./rgb-fb-matrix matrix.cfg --led-no-hardware-pulse --led-slowdown-gpio=3 --led-pwm-bits=5 --led-pwm-lsb-nanoseconds=60
Скрипт проекта
Далее выведем бегущую строку на матрицы при помощи байдингов для python.
Перейдём в директорию с байдингами для python:
cd rpi-rgb-matrix/bindings/python/samples
В этой папке уже есть демо-скрипты для python, откроем runtext.py
и немного изменим его содержание на следующее:
from samplebase import SampleBase from rgbmatrix import graphics import time text = "Привет мир! Это бегущая строка на матрицах 64x64. " text += "Для установки библиотеки выполните команду: " text += "git clone https://github.com/tremaru/rpi-fb-matrix" pos_y = 55 class RunText(SampleBase): global text global pos_y def __init__(self, *args, **kwargs): super(RunText, self).__init__(*args, **kwargs) self.parser.add_argument("-t", "--text", help="The text to scroll on the RGB LED panel", default=text) def run(self): offscreen_canvas = self.matrix.CreateFrameCanvas() font = graphics.Font() font.LoadFont("../../../fonts/40x60.bdf") textColor = graphics.Color(255, 255, 0) pos = offscreen_canvas.width my_text = self.args.text while True: offscreen_canvas.Clear() len = graphics.DrawText(offscreen_canvas, font, pos, pos_y, textColor, my_text) pos -= 1 if (pos + len < 0): pos = offscreen_canvas.width time.sleep(0.05) offscreen_canvas = self.matrix.SwapOnVSync(offscreen_canvas) # Основная функция if __name__ == "__main__": run_text = RunText() if (not run_text.process()): run_text.print_help()
Сохраним скрипт и запустим его, указав дополнительные аргументы для матриц 64x64:
python3 ./runtext.py --led-no-hardware-pulse=1 --led-cols=64 --led-rows=64 --led-chain=6 --led-slowdown-gpio=3 -t "Привет Мир!"
Описание дополнительных аргументов
Ниже приведён список некоторых аргументов и их краткое описание.
--led-gpio-mapping=<название> | название карты выводов (по умолчанию 'regular') |
--led-rows=цифра | Количество светодиодов по оси Y на каждой панели |
--led-cols=цифра | Количество светодиодов по оси X на каждой панели |
--led-chain=цифра | Количество панелей, соединённых вместе |
--led-pwm-bits=<1..11> | Количество битов для ШИМ (по умолчанию 11) |
--led-scan-mode=<0..1> | Режим развёртки (черезстрочный, прогрессивный) |
--led-show-refresh | Вывести в stdout частоту обновления сборки |
--led-inverse | Обратить цвета |
--led-rgb-sequence | Последовательность цветов субпикселей (RGB, RBG, BGR...) |
--led-no-hardware-pulse | Использовать программное тактирование |
--led-slowdown-gpio | Необходим для более быстрых Raspberry (3, 4), по умолчанию 1 |
Оптимизация вывода
Для оптимизации и ускорения вывода на матрицы можно попробовать следующие шаги:
Выключить встроенный звук Raspberry. Для этого в файле
/boot/config.txt
необходимо добавить строкуdtparam=audio=off
. При этом необходимо запускать скрипты и программы библиотеки с командойsudo
и не использовать ключ--led-no-hardware-pulse
Выключить интерфейсы, которые могут использовать gpio выводы, например SPI и 1-Wire. Сделать это можно при помощи команды
sudo raspi-config
Библиотека использует центральный процессор для вывода (по заявке автора DMA контроллер Rasbperry оказался слишком медленным). На многоядерных Raspberry можно выделить одно ядро исключительно под обработку массива матриц. Для этого в файл
/boot/cmdline.txt
необходимо добавитьisolcpus=3
для четырёхядерных Raspberry. В этом файле должна быть только одна строка и этот параметр следует добавлять в конец этой строки.Дальнейшего быстродействия можно добиться использованием комбинаций из следующих параметров библиотеки:
- --led--pwm-bits=<1..11> - параметр задаёт количесво битов для ШИМ. Меньшее число даёт большее быстродействие и меньшую глубину цвета
- --led-scan-mode=<0..1> - этой командой можно задать черезстрочную или прогрессивную развёртку. Черезстрочная развёртка в два раза быстрее, за счёт ухудшения качества отображения (--led-scan-mode=1)
- --led-pwm-lsb-nanoseconds=<50..300> - этот параметр позволит достичь большего количества кадров в секунду при меньших его значениях. Побочным эффектом может быть гостинг (светодиоды, которые не должны гореть будут неярко светиться)
- --led-pwm-dither-bits - этим параметром можно добиться больших кадров в секунду за счёт яркости. По умолчанию
0
.
Если картинка "дрожит" или "размазана" по панелям, возможно нужно замедлить скорость переключения выводов GPIO Raspberry. Это можно сделать при помощи параметра --led-slowdown-gpio
. Большие значения сильнее замедляют вывод, но дают более стабильную картинку. В случае с Raspberry Pi 3A+ и матрицами 64x64 с адресацией ABCDE
мы использовали --led-slowdown-gpio=3
.
При подборке необходимых значений параметров имеет смысл использовать параметр --led-show-refresh
для мониторинга частоты обновления сборки матриц.
Стоит отметить, что чем больше матриц включает в себя сборка, тем медленнее будет вывод на них. Например, на матрицу размером 32x16 необходимо 32 (ряда) * 16 (колонок) * 11 (бит цвета) * 180 (Гц, частота обновления) - больше 1000000 операций в секунду!
В параметрах, передаваемых скриптам Python необходимо всегда указывать значение, например --led-no-hardware-pulse=1
(в отличии от Си, где можно просто --led-no-hardware-pulse
)
Значения всех параметров можно определять прямо в коде при использовании библиотеки. Все параметры хранятся в объекте rgbmatrix.RGBMatrixOptions
Пример для Python:
from rgbmatrix import RGBMatrix, RGBMatrixOptions options = RGBMatrixOptions() options.rows = 64 options.cols = 64 options.chain_length = 6 # код вывода
Пример для C++:
#include "led-matrix.h" int main(int argc, char** argv) { RGBMatrix::Options options; options.rows = 64; options.cols = 64; options.chain_length = 6; RGBMatrix* matrix = rgb_matrix::CreateMatrixFromFlags(&argc, &argv, &defaults); // код вывода }
Обсуждение