if (Model.NotificationsEnabled) { }
Maker.io main logo

RGB Matrix Panels with Raspberry Pi 5

2025-03-04 | By Adafruit Industries

License: See Original Project Displays LED Matrix Raspberry Pi SBC

Courtesy of Adafruit

Guide by Tim C

Overview

 

Each new generation of the Raspberry Pi brings improvements over the last, and the ‎Raspberry Pi 5 is no exception. However, along with the great new features and enhanced ‎performance can also come some incompatibility with the way things were done on prior ‎versions of the hardware. One such incompatibility with the Pi 5 was the ability to drive ‎HUB75 compatible RGB Matrices like the older Pi's could.‎

The new Adafruit Blinka Raspberry Pi5 PioMatter library brings this capability to the ‎Raspberry Pi 5 by way of the PIO peripherals. ‎

This guide and library support the Raspberry Pi 5 only. They cannot be used with older ‎Raspberry Pi devices.‎

Hardware Requirements

You'll need a Raspberry Pi 5, we recommend the official Raspberry Pi 5V power supply for it. ‎There are a variety of matrix panels and power supplies to choose from depending on how ‎big or small your project will be.‎

Each panel requires up to 4A of power at max brightness with all pixels on. Keeping things a ‎bit dimmer, or not using all the pixels at once will save power. I've had success running 2 ‎panels off of one 4A power adapter, the matrices are still plenty bright for indoor projects.‎

If you're driving more than 2 panels, you'll need another 4A adapter. The female DC power ‎adapter makes it easy to power additional matrices separate from the two that can be ‎powered from the Bonnet's terminal blocks.‎

The library supports both the RGB Matrix Bonnet, and the RGB Matrix HAT. Only one is ‎needed though, choice is up to you.‎

Parts

Raspberry Pi 5 Setup

We recommend you use the latest Raspberry Pi OS flashed onto one of the official ‎Raspberry Pi SDCards. The Raspberry Pi Imager app makes it easy to prepare your SD ‎Card. ‎

  • Click Choose Device then select the Raspberry Pi 5.‎

  • Click Choose OS then select Raspberry Pi OS (64-bit).

  • Click Choose Storage then select your SDCard adapter. The name will depend on ‎your device, and it may differ from the screenshot.‎

Once all 3 values are selected you should see them filled in to the appropriate areas of the ‎main screen.

values_1

values_2

values_3

When everything has been set, click the Next button. You'll be asked if you'd like to apply ‎OS customization settings. This step is optional, it allows you to put in username, WiFi ‎credentials, and SSH public key which will get baked into the image that is flashed to the SD ‎Card.‎

Enter your details and click Yes if you'd like to do it, otherwise click No. Next, you'll be ‎warned that the storage device you've select is going to be erased. Make certain it's the drive ‎you're intending to flash and then click Yes to start the writing process.

‎A pop-up will be shown once the writing has completed successfully.‎

popup_4

popup_5

popup_6

Boot & Update

If you did enter your network credentials and SSH key to the OS customization step, and you ‎can use nmap or some other tool to locate the Pi 5 on the network and then you can do this ‎step entirely "headless". If not, you can temporarily plug in an HDMI display and USB ‎keyboard to do it.‎

Plug in the Pi 5, let it boot up, then update the software on it using the following commands.‎

Download File

Copy Code
sudo apt update
sudo apt upgrade

Create a Virtual Environment

The best practice for installing Python libraries is to use virtual environments to keep things ‎isolated and minimize conflicts between different versions of libraries that might be ‎required for different projects or purposes. You can name your virtual environment ‎anything, but it's best to use something you'll remember and associate with the project your ‎working on. I use the name blinka_venv for the environment containing Adafruit Blinka and ‎all associated libraries on my Pi's.‎

It's easy to create one with the following command.‎

Download File

Copy Code
python -m venv ~/venvs/blinka_venv

For more info about virtual environments see this guide.‎

Install Requirements

Next you need to activate the new virtual environment and then install the required libraries ‎within it.‎

Download File

Copy Code
source ~/venvs/blinka_venv/bin/activate
pip install adafruit-blinka
pip install pillow
pip install numpy
pip install Adafruit-Blinka-Raspberry-Pi5-Piomatter

Add PIO Subsystem Rule Configuration

By default, one requires root privilege to access the PIO hardware peripherals. We'll setup a ‎rule that makes it so that the standard user can do it. We need to edit the ‎file /etc/udev/rules.d/99-com.rules.‎

Download File

Copy Code
sudo nano /etc/udev/rules.d/99-com.rules

Add a new empty line or two at the top of the file by pressing enter. Then add this to one of ‎the empty lines.‎

Download File

Copy Code
SUBSYSTEM=="*-pio", GROUP="gpio", MODE="0660"

‎To save the file press Ctrl-S on the keyboard. Then press Ctrl-X to exit. After you've done ‎this, reboot the Pi with sudo reboot.

Accessing Console

At present time, the python scripts that drive the matrices work best when run from the ‎console context rather than the desktop UI context. There are a few ways you can achieve ‎this and depending on whether your Pi is dedicated to this usage or not you may want to set ‎it up to boot directly to the console.‎

Temporary

If you don't want to make any config changes then you can simply press Ctrl-Alt-F1 on a ‎keyboard connected to the Pi to change from the desktop context to the console. The HDMI ‎screen will go from showing the desktop to just the basic terminal prompt. At this prompt ‎you can activate your virtual environment as shown above, and then run Python scripts that ‎draw to the matrix. To go back to the desktop context, you can press Ctrl-Alt-F7.‎

SSH

If you access the Pi over SSH then it already counts as the console so you can activate your ‎virtual environment and run the matrix scripts with nothing further needed.‎

Auto Boot to Console

If you intend to keep using the same Pi for RGB Matrix projects, and you typically use a ‎keyboard and HDMI screen to interact with the Pi directly, rather than SSH, then it may be ‎convenient to configure your Pi to automatically boot directly to the console rather than the ‎desktop.‎

To enter the config utility run this command.‎

Download File

Copy Code
sudo raspi-config
  • Ensure System Options is highlighted, and press enter.‎

  • Arrow down to highlight Boot / Auto Login and press enter.‎

  • Highlight either B1 Console, or B2 Console Autologin and press enter.‎

  • After the setting is applied, you'll be taken back to the main raspi-config screen

  • Arrow right until Finish is highlighted and press enter.‎

  • When prompted to reboot now highlight Yes and press enter.‎

When the Pi boots up, you'll be ready to activate your virtual environment and run the python ‎scripts that interact with the RGB Matrix.‎

system_7

system_8

system_9

Wiring

wiring_10

The RGB Matrix Bonnet and RGB Matrix HAT make it easy to wire up the RGB Matrix and ‎required power supply.‎

It is best to make all of these connections with the power unplugged, and then once ‎everything is connected and you've double-checked that it's all correct, plug in the power to ‎turn everything on. I've found that the Pi can complain about low power if its USB C power is ‎not plugged in prior to the DC jack power on the Bonnet or Hat. So be sure to plug in the USB ‎C power adapter first, then the adapters powering the Bonnet and any additional panels.‎

For more info see this guide page.‎

Pi 5 & Bonnet Connections

  • Attach the Matrix Bonnet or Hat to the Raspberry Pi 5 GPIO pin rows.‎

  • Connect the USB C power cable to the USB C jack to power the Pi.‎

  • Connect the barrel jack of the DC 5V 4A power adapter into the barrel jack ‎connector on the Matrix Bonnet or Hat.‎

  • Connect the fork on the end of GND (black wire) lead on the matrix power cable to ‎the - terminal block on the Matrix Bonnet or Hat.‎

  • Connect the fork on the end of the 5V (red wire) lead on the matrix power cable to ‎the + terminal block on the Matrix Bonnet or Hat.‎

  • Connect one end of a 2x8 IDC ribbon cable to the 2x8 pin connector on the Matrix ‎Bonnet or Hat.‎

connect_11

Matrix Panel Connections

  • Connect one end of the 4-pin matrix power cable connector to the 4 pin power ‎input connector on the back of the matrix panel.‎

  • Connect the other end of the 2x8 IDC ribbon cable to the input 2x8 pin ‎connector on the back of the matrix panel. The input connector is the one that the ‎arrows in the long direction point away from.‎

matrix_12

Basic Test

test_13

Once you're Pi 5 is all set up and you've got the RGB Matrix panels all wired you're ready to ‎test it out!‎

As always, you need to activate the virtual environment before running the example. If you ‎haven't already then activate it like this.‎

Download File

Copy Code
source ~/venvs/blinka_venv/bin/activate

Next you can run the single_panel_simpletest.py script.‎

Download File

Copy Code
python single_panel_simpletest.py

The code for this example is embedded below. You can download it, or copy/paste the text ‎into a file.‎

Download Project Bundle

Copy Code
#!/usr/bin/python3
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Display a simple test pattern of 3 shapes on a single 64x32 matrix panel.

Run like this:

$ python simpletest.py

"""

import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import numpy as np
from PIL import Image, ImageDraw

width = 64
height = 32

geometry = piomatter.Geometry(width=width, height=height, n_addr_lines=4,
                                                     rotation=piomatter.Orientation.Normal)

canvas = Image.new('RGB', (width, height), (0, 0, 0))
draw = ImageDraw.Draw(canvas)

framebuffer = np.asarray(canvas) + 0  # Make a mutable copy
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed,
                             pinout=piomatter.Pinout.AdafruitMatrixBonnet,
                             framebuffer=framebuffer,
                             geometry=geometry)

draw.rectangle((2, 2, 10, 10), fill=0x008800)
draw.circle((18, 6), 4, fill=0x880000)
draw.polygon([(28, 2), (32, 10), (24, 10)], fill=0x000088)

framebuffer[:] = np.asarray(canvas)
matrix.show()

input("Press enter to exit")

View on GitHub

Code Explanation

After initializing the matrix, this example uses the Pillow library (PIL) to draw 3 basic shapes ‎and colors. It can serve as a good test to ensure your wiring and software are all setup ‎properly.‎

Initialization Config

Initializing matrix panels to display things onto requires 3 main steps: ‎

  • Create a Geometry object to define the size and shape of the panel(s)‎

  • Create a framebuffer to hold display data

  • Create the PioMatter instance.‎

Geometry

The Geometry object defines the size and shape of the panel(s) that will serve as the ‎display. There 6 arguments that can be passed to configure it.‎

  • width - The total width of the panel(s) in pixels.‎

  • height - The total height of the panel(s) in pixels.‎

  • n_addr_lines - The number of connected address lines. The number of pixels in the ‎shift register is automatically computed from these values. Many panels use 4 as a ‎standard. The 64x64 panels that we stock use 5 address lines. Set this value ‎according to which panels you're using. Note that using 5 addr lines also requires ‎soldering a jumper as described on this guide page.‎

  • serpentine - Controls the arrangement of multiple panels when they are stacked in ‎rows. If it is True, then each row goes in the opposite direction of the previous row. ‎Default is True.‎

  • rotation - controls the orientation of the panel(s). Must be one of ‎the Orientation constants. Default is Orientation.Normal. Over valid values ‎are Orientation.R180, Orientation.CW, and Orientation.CCW

  • n_planes - Controls the color depth of the panel. This is separate from the ‎framebuffer layout. Decreasing n_planes can increase FPS at the cost of reduced ‎color fidelity. The default, 10, is the maximum value.‎

Framebuffer

Next you need a framebuffer, this is a numpy array that will contain pixel data in the ‎appropriate colorspace. When refreshed the matrix will show the data that is in this ‎framebuffer on the display. Depending on what you're displaying it can be created in a few ‎different ways.‎

Download File

Copy Code
# For displaying an image from PIL, canvas is the PIL.Image instance
framebuffer = np.asarray(canvas) + 0

# For displaying arbitrary data, start with zeros
framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)

PioMatter

Now the PioMatter instance can be initialized. Aside from the Geometry, and Framebuffer ‎created above, it also accepts arguments for colorspace and pinout.‎

  • colorspace - Controls the colorspace that will be used for data to be displayed. It must be one of the Colorspace constants. Which to use depends on what data you’re displaying and how it is processed before copying into the framebuffer. Many ‎of the examples use Colorspace.RGB888Packed. Other valid values ‎are Colorspace.RGB565 and Colorspace.RGB888‎.

  • pinout - Defines which pins the panels are wired to. Different pinouts can support ‎different hardware breakouts and panels with different color order. The value must ‎be one of ‎the Pinout constants Pinout.AdafruitMatrixBonnet, Pinout.AdafruitMatrixBonnetBGR, Pinout.AdafruitMatrixHat, or Pinout.AdafruitMatrixHatBGR.‎

  • framebuffer - A numpy.array buffer as noted above.‎

  • geometry - A Geometry instance as noted above.‎

Example Initialization Code

Download File

Copy Code
geometry = piomatter.Geometry(width=64, height=32, n_addr_lines=4, rotation=piomatter.Orientation.Normal)

matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)

matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=piomatter.Pinout.AdafruitMatrixBonnet, framebuffer=matrix_framebuffer, geometry=geometry)

Multiple Matrix Panels

Is one panel too small to contain your epic ideas? No problem, you can chain multiple ‎panels together in a serpentine configuration to assemble a larger total display size. When ‎wiring multiple panels, be sure to pay attention to the arrows on the silkscreen of the back ‎of the matrix panels. The arrows in the long direction point away from the input 2x8 IDC ‎connector and point towards the output 2x8 IDC connector.‎

Various possible configurations are illustrated below.

panels_14

Horizontal Layouts

‎2 x 1 panel layout with a total size of 128x32 pixels. ‎

layouts_15

‎4 x 1 panel layout with a total size of 256x32 pixels.‎

layouts_16

‎2 x 2 panel layout with a total size of 128x64 pixels.‎

layouts_17

layouts_18

Vertical Layouts

‎1 x 2 panel layout with a total size of 64x64 pixels.‎

layouts_19

‎1 x 4 panel layout with a total size of 64x128 pixels.‎

layouts_20

Once your panels are properly wired up be sure to update the width and height values used ‎in the code when the matrices are initialized.‎

Animated GIF

led_matrices_animated_gif_scaled

As always, you need to activate the virtual environment before running the example. If you ‎haven't already then activate it like this.‎

Download File

Copy Code
source ~/venvs/blinka_venv/bin/activate

Next you can run the play_gif.py script.‎

Download File

Copy Code
python play_gif.py

The code for this example is embedded below. You can download it, or copy/paste the text ‎into a file.‎

Download Project Bundle

Copy Code
#!/usr/bin/python3
"""
Display an animated gif

Run like this:

$ python play_gif.py

The animated gif is played repeatedly until interrupted with ctrl-c.
"""

import time

import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import numpy as np
import PIL.Image as Image

width = 64
height = 32

gif_file = "nyan.gif"

canvas = Image.new('RGB', (width, height), (0, 0, 0))
geometry = piomatter.Geometry(width=width, height=height,
                              n_addr_lines=4, rotation=piomatter.Orientation.Normal)
framebuffer = np.asarray(canvas) + 0  # Make a mutable copy
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed,
                             pinout=piomatter.Pinout.AdafruitMatrixBonnet,
                             framebuffer=framebuffer,
                             geometry=geometry)

with Image.open(gif_file) as img:
    print(f"frames: {img.n_frames}")
    while True:
        for i in range(img.n_frames):
            img.seek(i)
            canvas.paste(img, (0,0))
            framebuffer[:] = np.asarray(canvas)
            matrix.show()
            time.sleep(0.1)

View on GitHub

Code Explanation

After initializing the matrix panel, this example loads a GIF file using PIL. Within the main ‎loop it iterates over the frames of the GIF, pasting each one into the canvas image. ‎The framebuffer gets filled with data from the canvas image and then shown on the matrix ‎panel.‎

Scrolling Text

led_matrices_quote_scroller_scaled

As always, you need to activate the virtual environment before running the example. If you ‎haven't already then activate it like this.‎

Download File

Copy Code
source ~/venvs/blinka_venv/bin/activate

Next you can run the quote_scroller.py script.‎

Download File

Copy Code
python quote_scroller.py

The code for this example is embedded below. You can download it, or copy/paste the text ‎into a file.‎

Download Project Bundle

Copy Code
#!/usr/bin/python3
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Display quote from the Adafruit quotes API as text scrolling across the
matrices.

Requires the requests library to be installed.

Run like this:

$ python quote_scroller.py

"""

import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import numpy as np
import requests
from PIL import Image, ImageDraw, ImageFont

# 128px for 2x1 matrices. Change to 64 if you're using a single matrix.
total_width = 128
total_height = 32

bottom_half_shift_compensation = 1

font_color = (0, 128, 128)

# Load the font
font = ImageFont.truetype("LindenHill-webfont.ttf", 26)

quote_resp = requests.get("https://www.adafruit.com/api/quotes.php").json()

text = f'{quote_resp[0]["text"]} - {quote_resp[0]["author"]}'
#text = "Sometimes you just want to use hardcoded strings. - Unknown"

x, y, text_width, text_height = font.getbbox(text)

full_txt_img = Image.new("RGB", (int(text_width) + 6, int(text_height) + 6), (0, 0, 0))
draw = ImageDraw.Draw(full_txt_img)
draw.text((3, 3), text, font=font, fill=font_color)
full_txt_img.save("quote.png")

single_frame_img = Image.new("RGB", (total_width, total_height), (0, 0, 0))

geometry = piomatter.Geometry(width=total_width, height=total_height,
                              n_addr_lines=4, rotation=piomatter.Orientation.Normal)
framebuffer = np.asarray(single_frame_img) + 0  # Make a mutable copy

matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed,
                             pinout=piomatter.Pinout.AdafruitMatrixBonnet,
                             framebuffer=framebuffer,
                             geometry=geometry)

print("Ctrl-C to exit")
while True:
    for x_pixel in range(-total_width-1,full_txt_img.width):
        if bottom_half_shift_compensation == 0:
            # full paste
            single_frame_img.paste(full_txt_img.crop((x_pixel, 0, x_pixel + total_width, total_height)), (0, 0))

        else:
            # top half
            single_frame_img.paste(full_txt_img.crop((x_pixel, 0, x_pixel + total_width, total_height//2)), (0, 0))
            # bottom half shift compensation
            single_frame_img.paste(full_txt_img.crop((x_pixel, total_height//2, x_pixel + total_width, total_height)), (bottom_half_shift_compensation, total_height//2))

        framebuffer[:] = np.asarray(single_frame_img)
        matrix.show()

View on GitHub

Code Explanation

This example fetches a quote from the Adafruit Quotes API using the requests library. Once ‎fetched the quote is rendered in its entirety in a single line into a very wide ‎image full_txt_img. This image is too wide to display all at once on the matrix hence the ‎need for scrolling. ‎

The matrix gets initialized and then the code moves to the main loop. Once inside, an inner ‎for loop iterates over horizontal pixel indexes. A matrix sized section of the full_text_img is ‎copied out and pasted into single_frame_img. From there it's copied into ‎the framebuffer and shown on the matrix.‎

Mirror Console

mirror_21

Display Configuration

This example will mirror the console's framebuffer to the matrix panel. In order to make it fit ‎better, and to ensure that the requisite /dev/fb0 exists whether or not an HDMI display is ‎plugged in, there will be a modification to the file /boot/firmware/cmdline.txt that adds a ‎video configuration with the smallest allowed display size.‎

Download File

Copy Code
sudo nano /boot/firmware/cmdline.txt

Scroll to the end of the line by pressing end or holding right arrow for a while.‎

Press space bar to insert a space at the end of the existing line.‎

Add the following after the space at the end of the existing line.‎

Download File

Copy Code
video=HDMI-A-1:640x480M@60D

Press Ctrl-S to save the file.‎

Press Ctrl-X to exit.‎

Then reboot the Pi for it to take effect

Download File

Copy Code
sudo reboot

When the Pi boots back up, the file /dev/fb0 should now exist even if you don't have an HDMI ‎display plugged in. If you do have an HDMI display, you'll notice that the text on it is now ‎scaled bigger since we've overridden the display size to be 640x480‎

Run The Example

As always, you need to activate the virtual environment before running the example. If you ‎haven't already, then activate it like this.‎

Download File

Copy Code
source ~/venvs/blinka_venv/bin/activate

Next you can run the fbmirror_scaled.py script. The script accepts several arguments to ‎configure the panels. The first 3 are specific to the fbmirror examples.‎

  • ‎--scale - a number to scale the full display down by. What is best depends on what ‎you're showing. 2 or 4 are good places to start and then tune it to your content and ‎desired look.‎

  • --x-offset - the number of pixels in the x axis to skip when getting the region to mirror.‎

  • ‎--y-offset - the number of pixels in the y axis to skip when getting the region to mirror.‎

The remaining arguments are of the configuration options described on the Initialization ‎Config page. The first two are required.‎

  • ‎--width - the number of pixels wide the total panel is. 128px is for a 2x2 matrix panel.‎

  • ‎--height - the number of pixels tall the total panel is. 64px is for a 2x2 matrix panel.‎

The rest are optional if you're using default the configuration for everything.‎

  • ‎--orientation - the rotation angle, must be one of Normal, CW, CCW, R180. ‎

  • ‎--pinout - the pinout to use for the panel(s) e.g. AdafruitMatrixBonnet

  • ‎--num-address-lines - the number of address lines. The 64x64 panels we stock ‎use 5, all smaller panels use 4

  • ‎--num-planes - the color depth, defaults to 10. Lower values can improve refresh rate ‎speed.‎

  • ‎--serpentine - the organization of multiple panels, serpentine is default. Use --no-‎serpentine if your panels are wired in the non-serpentine configuration.‎

The command should look as follows with appropriate values filled in for your panel:‎

python fbmirror_scaled.py --scale [scale] --width [width] --height [height] --orientation ‎‎[orientation]‎

The values for a 2x2 matrix panel rotated 180 are shown below, adjust them for your ‎panel(s).‎

Download File

Copy Code
python fbmirror_scaled.py --scale 3 --width 128 --height 64 --orientation R180

panel_22

The code for this example is embedded below. You can download it, or copy/paste the text ‎into a file.‎

Download Project Bundle

Copy Code
#!/usr/bin/python3
"""
Mirror a scaled copy of the framebuffer to RGB matrices,

A portion of the framebuffer is displayed until the user hits ctrl-c.

Control scale, matrix size, and orientation with command line arguments.

Usage: fbmirror_scaled.py [OPTIONS]

Options:
  --x-offset INTEGER              The x offset of top left corner of the
                                  region to mirror
  --y-offset INTEGER              The y offset of top left corner of the
                                  region to mirror
  --scale INTEGER                 The scale factor to reduce the display down
                                  by.
  --num-address-lines INTEGER     The number of address lines used by the
                                  panels
  --num-planes INTEGER            The number of bit planes (color depth. Lower
                                  values can improve refresh rate in frames
                                  per second
  --orientation [Normal|R180|CCW|CW]
                                  The overall orientation (rotation) of the
                                  panels
  --pinout [AdafruitMatrixBonnet|AdafruitMatrixBonnetBGR|AdafruitMatrixHat|AdafruitMatrixHatBGR]
                                  The details of the electrical connection to
                                  the panels
  --serpentine / --no-serpentine  The organization of multiple panels
  --height INTEGER                The panel height in pixels
  --width INTEGER                 The panel width in pixels
  --help                          Show this message and exit.


The `/dev/fb0` special file will exist if a monitor is plugged in at boot time,
or if `/boot/firmware/cmdline.txt` specifies a resolution such as
`...  video=HDMI-A-1:640x480M@60D`.
"""

import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import click
import numpy as np
import PIL.Image as Image
import piomatter_click

with open("/sys/class/graphics/fb0/virtual_size") as f:
    screenx, screeny = [int(word) for word in f.read().split(",")]

with open("/sys/class/graphics/fb0/bits_per_pixel") as f:
    bits_per_pixel = int(f.read())

assert bits_per_pixel == 16

bytes_per_pixel = bits_per_pixel // 8
dtype = {2: np.uint16, 4: np.uint32}[bytes_per_pixel]

with open("/sys/class/graphics/fb0/stride") as f:
    stride = int(f.read())

linux_framebuffer = np.memmap('/dev/fb0',mode='r', shape=(screeny, stride // bytes_per_pixel), dtype=dtype)


@click.command
@click.option("--x-offset", "xoffset", type=int, help="The x offset of top left corner of the region to mirror",  default=0)
@click.option("--y-offset", "yoffset", type=int, help="The y offset of top left corner of the region to mirror", default=0)
@click.option("--scale", "scale", type=int, help="The scale factor to reduce the display down by.", default=3)
@piomatter_click.standard_options
def main(xoffset, yoffset, scale, width, height, serpentine, rotation, pinout, n_planes, n_addr_lines):
    geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, rotation=rotation)
    matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
    matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=matrix_framebuffer, geometry=geometry)

    while True:
        tmp = linux_framebuffer[yoffset:yoffset + height * scale, xoffset:xoffset + width * scale]
        # Convert the RGB565 framebuffer into RGB888Packed (so that we can use PIL image operations to rescale it)
        r = (tmp & 0xf800) >> 8
        r = r | (r >> 5)
        r = r.astype(np.uint8)
        g = (tmp & 0x07e0) >> 3
        g = g | (g >> 6)
        g = g.astype(np.uint8)
        b = (tmp & 0x001f) << 3
        b = b | (b >> 5)
        b = b.astype(np.uint8)
        img = Image.fromarray(np.stack([r, g, b], -1))
        img = img.resize((width, height))
        matrix_framebuffer[:, :] = np.array(img)
        matrix.show()

if __name__ == '__main__':
    main()

‎View on GitHub

Code Explanation

After initializing the matrix panel(s), this example mirrors the /dev/fb0 framebuffer ‎using numpy.memmap. Inside the main loop it copies the current values from the mirrored ‎instance into a PIL Image, scales it down to the specified size, then copies it ‎into matrix_framebuffer to be shown on the panel.‎

MP4 Video

led_matrices_bunny_video_scaled

Playing mp4 video files to the console framebuffer can be done with the VLC application, ‎which is pre-loaded by default in the Raspberry Pi OS. In order to get the video to the matrix ‎panel, we'll use the Mirror Console example from the previous page, so check that out first if ‎you haven't already. The trick is to keep the Mirror Console example running and then play ‎the video so that the video is mirrored to the matrix panels.‎

You can run the fbmirror_scaled.py script via SSH, or directly from the console with a ‎keyboard. If you run it directly from the console, then you'll need to add & to the end of the ‎command to run it in the background so that you can get a new prompt to run the VLC ‎command.‎

Download File

Copy Code
source ~/venvs/blinka_venv/bin/activate
cd ~/Adafruit_Blinka_Raspberry_Pi5_PioMatter/examples

# Via SSH
python fbmirror_scaled.py --scale 16 --width 128 --height 64 --orentation R180

# Direct Console
python fbmirror_scaled.py --scale 16 --width 128 --height 64 --orientation R180 &

If you ran it directly in the console and want to stop the mirroring process you can do so ‎using the ps and kill commands. First run ps and look for the row with "python" in the CMD ‎column, follow that row to the PID column and note the PID number for the process. Then ‎run kill [number] swapping in the pid number of the process.‎

The VLC command must be run directly from the console, not via SSH.‎

Once the display is being mirrored, all that's left is to start up the video. We must use the --‎vout fb argument to tell VLC to send the video output to the framebuffer. It can also be ‎handy to modify the brightness of the video to darken it some if you see lines or other ‎artifacts in the bright regions of your video. That can be done by adding --video-filter=adjust ‎‎--brightness=0.85 to the command before the video is specified. Change the 0.85 to ‎whatever brightness percentage you want.‎

The whole command looks like this.‎

Download File

Copy Code
vlc --vout fb --video-filter=adjust --brightness=0.85 your_video_file.mp4

You can stop the video early by pressing Ctrl-C. If you let the entire video play then it will ‎bring you back to the terminal after it's over, but it will still be waiting for you to exit VLC by ‎pressing Ctrl-C.‎

The code for this is the fbmirror_scaled.py script from the previous page.‎

制造商零件编号 3211
RGB MATRIX BONNET FOR RASPBERRY
Adafruit Industries LLC
制造商零件编号 2345
LED MATRIX RGB HAT RTC RASP PI
Adafruit Industries LLC
制造商零件编号 2279
64X32 RGB LED MATRIX - 3MM PITCH
Adafruit Industries LLC
制造商零件编号 658
AC/DC DESKTOP ADAPTER 5V 50W
Adafruit Industries LLC
制造商零件编号 368
ADAPT TERM BL 2POS TO 2.1MM JCK
Adafruit Industries LLC
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.