Maker.io main logo

RGB LED Matrices with CircuitPython

2022-04-21 | By Adafruit Industries

License: See Original Project

Courtesy of Adafruit

Guide by Jeff Epler, Phillip Burgess, Lady Ada, Melissa LeBlanc-Williams

Overview

Bring a little bit of Times Square into your home with our RGB LED matrix panels. ‎These panels are normally used to make video walls — here in New York we see ‎them on the sides of buses and on bus stops — to display animations or short ‎video clips. We thought they looked really cool, so we picked up a few boxes from ‎the factory. They come in a variety of sizes from 16x32 pixels and up.‎

panels_1

Using the new RGBMatrix library, CircuitPython can blast pixels to these displays ‎really quickly. Use it with DisplayIO for showing text, bitmaps, animations, and ‎more. Not familiar with DisplayIO? There's a guide for that.‎

This guide is for select CircuitPython boards — ones based on the SAMD51 ‎‎(Feather M4, ItsyBitsy M4, Metro M4 etc) and nRF52840 (Feather nRF52840, ‎ItsyBitsy nRF52840, etc).‎

We have a different guide for Raspberry Pi and Arduino.‎

CircuitPython and Arduino share the same basic code for driving these matrices. ‎In CircuitPython, we call it RGBMatrix. In Arduino, it's named Protomatter.‎

rgb_2

pro_3

These panels require 12 or 13 digital pins (6 bit data, 6 or 7 bit control) and a ‎good 5V power supply, at least a couple amps per panel. We suggest our 2A (or ‎larger) regulated 5V adapters and either a terminal block DC jack or solder a jack ‎from our DC extension cord. Please read the rest of our tutorial for more details! ‎

Keep in mind that these displays are normally designed to be driven by FPGAs or ‎other high-speed processors; they do not have built in PWM control of any kind. ‎Instead, you're supposed to redraw the screen over and over to 'manually' PWM ‎the whole thing. RGBMatrix takes care of that for you, offering up to thousands ‎of bright colors. Depending on settings (width, height, and color depth) and ‎microcontroller, RGBMatrix takes from 10% to 60% of the processing power ‎away from CircuitPython.‎

display_4

Of course, we wouldn't leave you with a datasheet and a "good luck!" We have a ‎full wiring diagrams and working CircuitPython code.‎

Connecting with Feather M4 Express & FeatherWing

connect_5

The easiest way to get started with RGBMatrix is with the RGB Matrix ‎FeatherWing. Now you can quickly and easily create projects featuring your ‎favorite 16 or 32-pixel tall matrix boards.‎

Please note: This wing is only tested/designed to work with the SAMD51 M4 ‎Feather or the nRF52840 Feather. It may be possible to use the extra holes as a ‎prototyping area to adapt it to other Feathers, but that's beyond the scope of this ‎guide.‎

wing_6

This wing can be assembled in one of two ways. You can either solder in a 2x8 IDC ‎shrouded header on the top, then plug in the IDC cable that came with your ‎matrix. This makes it easy to stack on top of your Feather. Or you can solder in the ‎‎2x10 socket header on the bottom of the Wing, and then stack your Feather on ‎top. That way you can plug it directly into the back of the matrix *mind blown*.‎

wing_7

This FeatherWing will work great with any of our 16x32, 32x32, or 64x32 RGB ‎matrices, and is definitely the easiest way to glow and go.‎

wing_8

Either way you decide to go, you can plug a 5V DC power pack into the 2.1mm DC ‎jack. That 5V is polarity protected and then output on the other side to a 5.08mm ‎terminal block. An onboard regulator will provide 3.3V power to your Feather, so ‎you don't need a separate USB or battery. This makes for a very compact build!‎

Each 'Wing kit comes with one FeatherWing PCB with surface mount parts ‎attached, a 2x8 IDC header, a 2x10 female socket, 2.1mm DC jack, 5.08mm ‎terminal block, and some male header. You may also want some Feather stacking ‎headers or female headers depending on how you plan to attach/stack your ‎Feather.‎

Use the following block of code to initialize a 64x32 matrix.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. In this mode, you ‎may not use pin A2 unless you cut the trace connecting it to the header, because ‎it is connected to GND on the RGB matrix. ‎

Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix)

Connecting with Feather RP2040 & FeatherWing

connecting_9

The easiest way to get started with RGBMatrix is with the RGB Matrix ‎FeatherWing. Now you can quickly and easily create projects featuring your ‎favorite 16 or 32-pixel tall matrix boards.‎

Please note: This wing is only tested/designed to work with the SAMD51 M4 ‎Feather or the nRF52840 Feather. It may be possible to use the extra holes as a ‎prototyping area to adapt it to other Feathers, but that's beyond the scope of this ‎guide.‎

proto_10

This wing can be assembled in one of two ways. You can either solder in a 2x8 IDC ‎shrouded header on the top, then plug in the IDC cable that came with your ‎matrix. This makes it easy to stack on top of your Feather. Or you can solder in the ‎‎2x10 socket header on the bottom of the Wing, and then stack your Feather on ‎top. That way you can plug it directly into the back of the matrix *mind blown*.‎

assemble_11

This FeatherWing will work great with any of our 16x32, 32x32, or 64x32 RGB ‎matrices, and is definitely the easiest way to glow and go.‎

plug_12

Either way you decide to go, you can plug a 5V DC power pack into the 2.1mm DC ‎jack. That 5V is polarity protected and then output on the other side to a 5.08mm ‎terminal block. An onboard regulator will provide 3.3V power to your Feather, so ‎you don't need a separate USB or battery. This makes for a very compact build!‎

Each 'Wing kit comes with one FeatherWing PCB with surface mount parts ‎attached, a 2x8 IDC header, a 2x10 female socket, 2.1mm DC jack, 5.08mm ‎terminal block, and some male header. You may also want some Feather stacking ‎headers or female headers depending on how you plan to attach/stack your ‎Feather.‎

Use the following block of code to initialize a 64x32 matrix.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.D25, board.D24, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. In this mode, you ‎may not use pin A2 unless you cut the trace connecting it to the header, because ‎it is connected to GND on the RGB matrix. ‎

Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.D25, board.D24, board.A3],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix)

With the RP2040, it is normal for the display to flicker while writing to the ‎CIRCUITPY drive, such as when updating your code.py file. It will not harm the ‎display.‎

Complete example: RP2040 Feather Scroller

Save the below file (called rp2040.py to CIRCUITPY as code.py and also save the ‎bitmap image file pi-logo32b.bmp to CIRCUITPY. The 64x32 matrix will scroll the ‎text "RP2040 Feather" over a Raspberry Pi logo.‎

‎Download Project Bundle‎

Copy Code
# SPDX-FileCopyrightText: 2021 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
from math import sin
import board
import displayio
import rgbmatrix
import framebufferio
import adafruit_imageload
import terminalio
from adafruit_display_text.label import Label

displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=6,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.D25, board.D24, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1,
    doublebuffer=True)
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)

g = displayio.Group()
b, p = adafruit_imageload.load("pi-logo32b.bmp")
t = displayio.TileGrid(b, pixel_shader=p)
t.x = 20
g.append(t)

l = Label(text="Feather\nRP2040", font=terminalio.FONT, color=0xffffff, line_spacing=.7)
g.append(l)

display.show(g)

target_fps = 50
ft = 1/target_fps
now = t0 = time.monotonic_ns()
deadline = t0 + ft

p = 1
q = 17
while True:
    tm = (now - t0) * 1e-9
    x = l.x - 1
    if x < -40:
        x = 63
    y =  round(12 + sin(tm / p) * 6)
    l.x = x
    l.y = y
    display.refresh(target_frames_per_second=target_fps, minimum_frames_per_second=0)
    while True:
        now = time.monotonic_ns()
        if now > deadline:
            break
        time.sleep((deadline - now) * 1e-9)
    deadline += ft

‎View on GitHub

Connecting Using a Proto Shield

Your LED matrix display needs 12 or 13 digital pins, and only specific combinations ‎will work. If this much custom wiring worries you, choose the Feather M4 Express ‎with an RGB Matrix Featherwing Kit, because just by connecting the headers you ‎get everything in the right place!‎

If you hold a ribbon cable flat — no folds — and with both connectors facing you, ‎keys pointed the same direction — there’s is a 1:1 correlation between the pins. ‎The top-right pin on one plug links to the top-right on the other plug, and so forth. ‎This holds true even if the cable has a doubled-over strain relief. As long as the ‎keys point the same way and the plugs face the same way, pins are in the same ‎positions at both ends.

ribbon_13

Either end of the ribbon cable can be plugged into the matrix INPUT socket.‎

The free end of the ribbon can point toward the center of the matrix or hang off ‎the side…the pinout is still the same. Notice below the direction of the “key” ‎doesn’t change.‎

free_14

A dual-row header gets installed on the prototyping area, similar to the connector ‎on the matrix. Just like the ribbon cable lying flat, as long as these two headers ‎are aligned the same way, they’ll match pin-for-pin.‎

pin_15

Wires are then soldered from the header to specific microcontroller pins. Try to ‎keep wire lengths reasonably short to avoid signal interference.‎

Using color-coded wires helps a lot! If you don’t have colored wires, that’s okay, ‎just pay close attention where everything goes. Our goal is a proto shield ‎something like this (but this is just an example; refer to the following pages for ‎specific information for your board):‎

color_16

You can also use a plain 2x8-pin male header, or two 1x8 sections installed side-‎by-side (as in the photo above). Since there’s no alignment key with this setup, ‎you might want to indicate it with some tape or a permanent marker.‎

Depending on the make and model of proto shield, some pins are designed to ‎connect in short rows. Others don’t. For the latter, strip a little extra insulation ‎and bend the wire to wrap around the leg of the socket from behind, then solder.‎

shield_17

Connect Ground Wires

32x32 and 64x32 matrices require three ground connections. 32x16 matrices ‎have four.‎‎ ‎

Most proto shields have tons of grounding points, so you shouldn’t have trouble ‎finding places to connect these.‎

wires_18

Upper RGB Data

Pins R1, G1, and B1 (labeled R0, B0 and G0 on some matrices) deliver data to ‎the top half of the display.‎ ‎

upper_19

Lower RGB Data

Pins R2, G2, and B2 (labeled R1, G1 and B1 on some matrices) deliver data to ‎the bottom half of the display. ‎

lower_20

Row Select Lines

Pins A, B, C, and D select which two rows of the display are currently lit. (32x16 ‎matrices don’t have a “D” pin — it’s connected to ground instead.)‎

select_21

LAT Wire

The LAT (latch) signal marks the end of a row of data.‎

lat_22

OE Wire

OE (output enable) switches the LEDs off when transitioning from one row to the ‎next.‎

oe_23

CLK Wire

Last one!‎

The CLK (clock) signal marks the arrival of each bit of data.‎

clk_24

Want to use a breadboard? We've got you covered too. With the Breakout ‎Helper, the 16-pin header can straddle that big gap in the middle.‎

Feather M4 Express

The easiest way to connect a LED matrix to the Feather M4 Express is using the ‎RGB Matrix FeatherWing kit. This board works only with the Feather M4 Express, ‎not other Feather boards like the nRF Feathers. If you've got the ‎FeatherWing, jump over to this page. Otherwise, read on and get wiring!‎

To hook an LED matrix to the Feather M4 Express, make the connections on the ‎left. Remember that for a 16-line matrix, connect 4 GND wires and address wires ‎A, B, and C. For a 32-line matrix, connect 3 GND wires and address wires A, B, C, ‎and D.‎

matrix_25

Use the following block of code to initialize a 64x32 matrix. Remember to connect ‎all 4 address pins: A, B, C, and D.‎

Don't forget you have to provide a separate 5V @ 2 ~ 10Amp power supply to the ‎panels thick power cables.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. Remember to connect just 3 address pins: A, B, and C. Hook a fourth GND wire instead of A3.

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix)

Feather nRF52840‎

This suggested pinout was revised on 2020-06-03‎.

To hook an LED matrix to the Feather nRF52840 Express or Sense, make the ‎connections on the left. Remember that for a 16-line matrix, connect 4 GND wires ‎and address wires A, B, and C. For a 32-line matrix, connect 3 GND wires, and ‎address wires A, B, C, and D.‎

hook_26

Use the following block of code to initialize a 64x32 matrix. Remember to connect ‎all 4 address pins: A, B, C, and D.‎

Don't forget you have to provide a separate 5V @ 2 ~ 10Amp power supply to the ‎panels thick power cables.‎‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.D6, board.A5, board.A1, board.A0, board.A4, board.D11],
    addr_pins=[board.D10, board.D5, board.D13, board.D9],
    clock_pin=board.D12, latch_pin=board.RX, output_enable_pin=board.TX)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. Remember to connect ‎just 3 address pins: A, B, and C. Hook a fourth GND wire instead of A3.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.D6, board.A5, board.A1, board.A0, board.A4, board.D11],
    addr_pins=[board.D10, board.D5, board.D13],
    clock_pin=board.D12, latch_pin=board.RX, output_enable_pin=board.TX)
display = framebufferio.FramebufferDisplay(matrix)

ItsyBitsy M4‎

To hook an LED matrix to the ItsyBitsy M4, make the connections on the left. ‎Remember that for a 16-line matrix, connect 4 GND wires and address wires A, B, ‎and C. For a 32-line matrix, connect 3 GND wires and address wires A, B, C, and D.‎

led_27

Use the following block of code to initialize a 64x32 matrix. Remember to connect ‎all 4 address pins: A, B, C, and D.‎

Don't forget you have to provide a separate 5V @ 2 ~ 10Amp power supply to the ‎panels thick power cables.‎

Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.MOSI, board.SCK, board.A5, board.A4, board.A0, board.A1],
    addr_pins=[board.D5, board.D7, board.D9, board.D10],
    clock_pin=board.D13, latch_pin=board.D12, output_enable_pin=board.D11)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. Remember to connect ‎just 3 address pins: A, B, and C. Hook a fourth GND wire instead of A3.‎

Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.MOSI, board.SCK, board.A5, board.A4, board.A0, board.A1],
    addr_pins=[board.D5, board.D7, board.D9],
    clock_pin=board.D13, latch_pin=board.D12, output_enable_pin=board.D11)
display = framebufferio.FramebufferDisplay(matrix)

ItsyBitsy nRF52840‎

To hook an LED matrix to the ItsyBitsy nRF52840, make the connections on the ‎left. Remember that for a 16-line matrix, connect 4 GND wires and address wires ‎A, B, and C. For a 32-line matrix, connect 3 GND wires and address wires A, B, C, ‎and D.‎

make_28

Use the following block of code to initialize a 64x32 matrix. Remember to connect ‎all 4 address pins: A, B, C, and D.‎

Don't forget you have to provide a separate 5V @ 2 ~ 10Amp power supply to the ‎panels thick power cables.‎‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.A3, board.A2, board.A1, board.RX, board.TX, board.D5],
    addr_pins=[board.D7, board.D9, board.D10, board.D12],
    clock_pin=board.D2, latch_pin=board.D11, output_enable_pin=board.MISO)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. Remember to connect ‎just 3 address pins: A, B, and C. Hook a fourth GND wire instead of A3.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.A3, board.A2, board.A1, board.RX, board.TX, board.D5],
    addr_pins=[board.D7, board.D9, board.D10],
    clock_pin=board.D2, latch_pin=board.D11, output_enable_pin=board.MISO)
display = framebufferio.FramebufferDisplay(matrix)

Metro M4 Express

To hook an LED matrix to the Metro M4 Express or Metro M4 Airlift Lite, make the ‎connections on the left. Remember that for a 16-line matrix, connect 4 GND wires ‎and address wires A, B, and C. For a 32-line matrix, connect 3 GND wires and ‎address wires A, B, C, and D.‎

hooked_29

Use the following block of code to initialize a 64x32 matrix. Remember to connect ‎all 4 address pins: A, B, C, and D.‎

Don't forget you have to provide a separate 5V @ 2 ~ 10Amp power supply to the ‎panels thick power cables.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.D8, board.D9, board.D10, board.D11, board.D12, board.D13],
    addr_pins=[board.D4, board.D5, board.D6, board.D7],
    clock_pin=board.D1, latch_pin=board.D3, output_enable_pin=board.D2)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. Remember to connect ‎just 3 address pins: A, B, and C. Hook a fourth GND wire instead of A3.‎

Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.D8, board.D9, board.D10, board.D11, board.D12, board.D13],
    addr_pins=[board.D4, board.D5, board.D6],
    clock_pin=board.D1, latch_pin=board.D3, output_enable_pin=board.D2)
display = framebufferio.FramebufferDisplay(matrix)

Shields Up

If you're using the RGB Matrix Shield with the Metro M4 Express, you will need to ‎make a hardware modification.‎

shields_30

The RGB Matrix Shield is designed so that you can customize it to the ‎requirements of your board. We need to change which pin is used for the "CLK" ‎‎(clock) signal.‎

There is a small copper trace between the two larger pads. Using a razor blade, ‎cut or scrape away this trace. (Young people, please have an adult do this ‎step!) Then, use your multimeter in continuity mode to verify that there is no ‎connection between the two rectangular pads.‎

Next, make a connection from the A4 pin to the CLK pin by soldering in a new wire ‎as shown. The wire can be on the top or on the bottom.‎

rgb_32

rgb_31

Once that's done, use the following block of code to initialize a 64x32 matrix:‎

Download File

Copy Code
matrix = rgbmatrix.RGBMatrix(
    width=64,
    height=32,
    bit_depth=1,
    rgb_pins=[board.D2, board.D3, board.D4, board.D5, board.D6, board.D7],
    addr_pins=[board.A0, board.A1, board.A2, board.A3],
    clock_pin=board.A4,
    latch_pin=board.D10,
    output_enable_pin=board.D9,
)

Use the following block of code to initialize a 32x16 matrix:‎

Download File

Copy Code
matrix = rgbmatrix.RGBMatrix(
    width=32,
    height=16,
    bit_depth=1,
    rgb_pins=[board.D2, board.D3, board.D4, board.D5, board.D6, board.D7],
    addr_pins=[board.A0, board.A1, board.A2],
    clock_pin=board.A4,
    latch_pin=board.D10,
    output_enable_pin=board.D9,
)

Feather STM32F405‎

Support for this Feather is experimental, and you need to use CircuitPython 6.0.0-‎beta.3 or newer! If you get an ImportError, make sure you're using the right ‎version.‎

To hook an LED matrix to the Feather STM32F405, make the connections on the ‎left. Remember that for a 16-line matrix, connect 4 GND wires and address wires ‎A, B, and C. For a 32-line matrix, connect 3 GND wires and address wires A, B, C, ‎and D.‎

feather_33

Use the following block of code to initialize a 64x32 matrix. Remember to connect ‎all 4 address pins: A, B, C, and D.‎

Don't forget you have to provide a separate 5V @ 2 ~ 10Amp power supply to the ‎panels thick power cables.‎

‎Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[board.D13, board.D12, board.D11, board.A4, board.A5, board.D6],
    addr_pins=[board.A0, board.A1, board.A2, board.A3],
    clock_pin=board.D5, latch_pin=board.D9, output_enable_pin=board.D10)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. Remember to connect ‎just 3 address pins: A, B, and C. Hook a fourth GND wire instead of A3.‎

‎Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[board.D13, board.D12, board.D11, board.A4, board.A5, board.D6],
    addr_pins=[board.A0, board.A1, board.A2],
    clock_pin=board.D5, latch_pin=board.D9, output_enable_pin=board.D10)
display = framebufferio.FramebufferDisplay(matrix)

Metro ESP32S2‎

metro_34

A great way to get started with RGBMatrix is with the RGB Matrix Shield and ‎the Metro ESP32-S2. Now you can quickly and easily create projects featuring ‎your favorite 16 or 32-pixel tall matrix boards.‎

For a small panel, you can use the screw terminals on the Adafruit RGB Matrix ‎Shield together with an appropriate DC power adapter on the Metro. For a larger ‎panel, you'll need an independent 5V supply at several amps.‎

In any case, using USB power alone is not recommended, as the RGB Matrix can ‎draw a lot of current.‎

Each Shield kit comes with one Shield PCB, a 2x8 IDC header, 5.08mm terminal ‎block, and some male header.‎

Use the following block of code to initialize a 64x32 matrix.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32,
    bit_depth=6,
    rgb_pins=[board.IO7, board.IO8, board.IO9, board.IO10, board.IO11, board.IO12],
    addr_pins=[board.A0, board.A1, board.A2, board.A3],
    clock_pin=board.IO13,
    latch_pin=board.IO15,
    output_enable_pin=board.IO14,
)
display = framebufferio.FramebufferDisplay(matrix)

Use the following block of code to initialize a 32x16 matrix. In this mode, you ‎may not use pin A3 unless you cut the trace connecting it to the header, because ‎it is connected to GND on the RGB matrix. ‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32,
    bit_depth=4,
    rgb_pins=[board.IO7, board.IO8, board.IO9, board.IO10, board.IO11, board.IO12],
    addr_pins=[board.A0, board.A1, board.A2],
    clock_pin=board.IO13,
    latch_pin=board.IO15,
    output_enable_pin=board.IO14,
)
display = framebufferio.FramebufferDisplay(matrix)

Connecting Using a MatrixPortal

To hook an LED matrix to the MatrixPortal M4 board, just connect the power ‎wires and press it on. Check out the Prep the MatrixPortal page for more ‎detailed information. You can learn more about using the MatrixPortal in ‎our Adafruit MatrixPortal M4 guide.‎

portal_35

‎64x32 Matrix‎

Use the following block of code to initialize a 64x32 matrix.‎

‎Download File‎

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=4,
    rgb_pins=[
        board.MTX_R1,
        board.MTX_G1,
        board.MTX_B1,
        board.MTX_R2,
        board.MTX_G2,
        board.MTX_B2
    ],
    addr_pins=[
        board.MTX_ADDRA,
        board.MTX_ADDRB,
        board.MTX_ADDRC,
        board.MTX_ADDRD
    ],
    clock_pin=board.MTX_CLK,
    latch_pin=board.MTX_LAT,
    output_enable_pin=board.MTX_OE
)
display = framebufferio.FramebufferDisplay(matrix)

‎32x16 Matrix‎

Use the following block of code to initialize a 32x16 matrix.‎

‎Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=32, bit_depth=4,
    rgb_pins=[
        board.MTX_R1,
        board.MTX_G1,
        board.MTX_B1,
        board.MTX_R2,
        board.MTX_G2,
        board.MTX_B2
    ],
    addr_pins=[
        board.MTX_ADDRA,
        board.MTX_ADDRB,
        board.MTX_ADDRC
    ],
    clock_pin=board.MTX_CLK,
    latch_pin=board.MTX_LAT,
    output_enable_pin=board.MTX_OE
)
display = framebufferio.FramebufferDisplay(matrix)

‎64x64 Matrix‎

Use the following block of code to initialize a 64x64 matrix. Don't forget to close ‎the Address E Line jumper with solder. You'll need to check the datasheet for ‎your matrix to determine whether to connect it to Pin 8 or 16.‎

Don't forget to close the Address E Line jumper first.‎

Download File

Copy Code
displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, height=64, bit_depth=4,
    rgb_pins=[
        board.MTX_R1,
        board.MTX_G1,
        board.MTX_B1,
        board.MTX_R2,
        board.MTX_G2,
        board.MTX_B2
    ],
    addr_pins=[
        board.MTX_ADDRA,
        board.MTX_ADDRB,
        board.MTX_ADDRC,
        board.MTX_ADDRD,
        board.MTX_ADDRE
    ],
    clock_pin=board.MTX_CLK,
    latch_pin=board.MTX_LAT,
    output_enable_pin=board.MTX_OE
)
display = framebufferio.FramebufferDisplay(matrix)

Prep the MatrixPortal

Power Prep

The MatrixPortal supplies power to the matrix display panel via two standoffs. ‎These come with protective tape applied (part of our manufacturing process) ‎which MUST BE REMOVED!‎

Use some tweezers or a fingernail to remove the two amber circles.‎

power_36

power_37

Power Terminals

Next, screw in the spade connectors to the corresponding standoff.‎

  • red wire goes to +5V

  • black wire goes to GND

screw_38

screw_39

Panel Power

Plug either one of the four-conductor power plugs into the power connector pins ‎on the panel. The plug can only go in one way, and that way is marked on the ‎board's silkscreen.‎

panel_40

panel_41

Board Connection

Now, plug the board into the left side shrouded 8x2 connector as shown. The ‎orientation matters, so take a moment to confirm that the white indicator arrow ‎on the matrix panel is oriented pointing up and right as seen here and the ‎MatrixPortal overhangs the edge of the panel when connected. This allows you to ‎use the edge buttons from the front side.‎

Check nothing is impeding the board from plugging in firmly. If there's a plastic ‎nub on the matrix that's keeping the Portal from sitting flat, cut it off with ‎diagonal cutters.‎

board_42

board_43

check_44

check_45

For info on adding LED diffusion acrylic, see the page LED Matrix Diffuser.‎

Example: Simple two-line text scroller

scroll_46

This example creates two lines of scrolling text on a 64x32 matrix ‎using CircuitPython Display Text. It's designed for the FeatherWing M4 Express, ‎but you can adapt it to other boards by changing the lines that create the ‎RGBMatrix object. We've thoroughly commented this example so it's a great place ‎to start if you're not familiar with displayio.‎

For this example, make sure to install the following library:‎

If you want to customize the example to use a different font, you'll also need

Here's how the code will work:‎

  • Create the RGBMatrix and FramebufferDisplay objects

  • Create the two text labels to scroll

  • Put them in a Group, and then show that Group

  • Repeatedly scroll each label to the left, returning it to the far-right hand side ‎when it has gone all the way

‎Download Project Bundle‎

Copy Code
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# This example implements a simple two line scroller using
# Adafruit_CircuitPython_Display_Text. Each line has its own color
# and it is possible to modify the example to use other fonts and non-standard
# characters.

import adafruit_display_text.label
import board
import displayio
import framebufferio
import rgbmatrix
import terminalio

# If there was a display before (protomatter, LCD, or E-paper), release it so
# we can create ours
displayio.release_displays()

# This next call creates the RGB Matrix object itself. It has the given width
# and height. bit_depth can range from 1 to 6; higher numbers allow more color
# shades to be displayed, but increase memory usage and slow down your Python
# code. If you just want to show primary colors plus black and white, use 1.
# Otherwise, try 3, 4 and 5 to see which effect you like best.
#
# These lines are for the Feather M4 Express. If you're using a different board,
# check the guide to find the pins and wiring diagrams for your board.
# If you have a matrix with a different width or height, change that too.
# If you have a 16x32 display, try with just a single line of text.
matrix = rgbmatrix.RGBMatrix(
    width=64, height=32, bit_depth=1,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)

# Associate the RGB matrix with a Display so that we can use displayio features
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)

# Create two lines of text to scroll. Besides changing the text, you can also
# customize the color and font (using Adafruit_CircuitPython_Bitmap_Font).
# To keep this demo simple, we just used the built-in font.
# The Y coordinates of the two lines were chosen so that they looked good
# but if you change the font you might find that other values work better.
line1 = adafruit_display_text.label.Label(
    terminalio.FONT,
    color=0xff0000,
    text="This scroller is brought to you by CircuitPython RGBMatrix")
line1.x = display.width
line1.y = 8

line2 = adafruit_display_text.label.Label(
    terminalio.FONT,
    color=0x0080ff,
    text="Hello to all CircuitPython contributors worldwide <3")
line2.x = display.width
line2.y = 24

# Put each line of text into a Group, then show that group.
g = displayio.Group()
g.append(line1)
g.append(line2)
display.show(g)

# This function will scoot one label a pixel to the left and send it back to
# the far right if it's gone all the way off screen. This goes in a function
# because we'll do exactly the same thing with line1 and line2 below.
def scroll(line):
    line.x = line.x - 1
    line_width = line.bounding_box[2]
    if line.x < -line_width:
        line.x = display.width

# This function scrolls lines backwards.  Try switching which function is
# called for line2 below!
def reverse_scroll(line):
    line.x = line.x + 1
    line_width = line.bounding_box[2]
    if line.x >= display.width:
        line.x = -line_width

# You can add more effects in this loop. For instance, maybe you want to set the
# color of each label to a different value.
while True:
    scroll(line1)
    scroll(line2)
    #reverse_scroll(line2)
    display.refresh(minimum_frames_per_second=0)

View on GitHub

Example: Two-line colorful text scroller

example_47

This example creates two lines of scrolling text on a 64x32 matrix. It's designed for ‎the FeatherWing M4 Express, but you can adapt it to other boards by changing ‎the lines that create the RGBMatrix object.‎

Because each letter is set to a different color, this example doesn't use the ‎adafruit_display_text library.‎

To customize the text, simply make sure you keep the lines in pairs of equal length, ‎and don't miss the comma at the end of each line.‎

Download Project Bundle‎

Copy Code
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# This example implements a rainbow colored scroller, in which each letter
# has a different color. This is not possible with
# Adafruit_Circuitpython_Display_Text, where each letter in a label has the
# same color
#
# This demo also supports only ASCII characters and the built-in font.
# See the simple_scroller example for one that supports alternative fonts
# and characters, but only has a single color per label.

import array

from rainbowio import colorwheel
import board
import displayio
import framebufferio
import rgbmatrix
import terminalio
displayio.release_displays()

matrix = rgbmatrix.RGBMatrix(
    width=64, height=32, bit_depth=3,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)

# Create a tilegrid with a bunch of common settings
def tilegrid(palette):
    return displayio.TileGrid(
        bitmap=terminalio.FONT.bitmap, pixel_shader=palette,
        width=1, height=1, tile_width=6, tile_height=14, default_tile=32)

g = displayio.Group()

# We only use the built in font which we treat as being 7x14 pixels
linelen = (64//7)+2

# prepare the main groups
l1 = displayio.Group()
l2 = displayio.Group()
g.append(l1)
g.append(l2)
display.show(g)

l1.y = 1
l2.y = 16

# Prepare the palettes and the individual characters' tiles
sh = [displayio.Palette(2) for _ in range(linelen)]
tg1 = [tilegrid(shi) for shi in sh]
tg2 = [tilegrid(shi) for shi in sh]

# Prepare a fast map from byte values to
charmap = array.array('b', [terminalio.FONT.get_glyph(32).tile_index]) * 256
for ch in range(256):
    glyph = terminalio.FONT.get_glyph(ch)
    if glyph is not None:
        charmap[ch] = glyph.tile_index

# Set the X coordinates of each character in label 1, and add it to its group
for idx, gi in enumerate(tg1):
    gi.x = 7 * idx
    l1.append(gi)

# Set the X coordinates of each character in label 2, and add it to its group
for idx, gi in enumerate(tg2):
    gi.x = 7 * idx
    l2.append(gi)

#  These pairs of lines should be the same length
lines = [
    b"This scroller is brought to you by    CircuitPython & PROTOMATTER",
    b"        .... . .-.. .-.. --- / .--. .-. --- - --- -- .- - - . .-.",
    b"Greetz to ...          @PaintYourDragon      @v923z  @adafruit         ",
    b"  @danh        @ladyada  @kattni      @tannewt    all showers & tellers",
    b"New York Strong                       Wash Your Hands                  ",
    b"                  Flatten the curve                   Stronger Together",
]

even_lines = lines[0::2]
odd_lines = lines[1::2]

# Scroll a top text and a bottom text
def scroll(t, b):
    # Add spaces to the start and end of each label so that it goes from
    # the far right all the way off the left
    sp = b' ' * linelen
    t = sp + t + sp
    b = sp + b + sp
    maxlen = max(len(t), len(b))
    # For each whole character position...
    for i in range(maxlen-linelen):
        # Set the letter displayed at each position, and its color
        for j in range(linelen):
            sh[j][1] = colorwheel(3 * (2*i+j))
            tg1[j][0] = charmap[t[i+j]]
            tg2[j][0] = charmap[b[i+j]]
        # And then for each pixel position, move the two labels
        # and then refresh the display.
        for j in range(7):
            l1.x = -j
            l2.x = -j
            display.refresh(minimum_frames_per_second=0)

# Repeatedly scroll all the pairs of lines
while True:
    for e, o in zip(even_lines, odd_lines):
        scroll(e, o)

‎View on GitHub

Example: (Ada)Fruit Machine

 

 

simulate_48

This example simulates a "fruit machine", similar to a slot machine, using emoji ‎from the Adafruit Discord server. It's designed for the FeatherWing M4 Express, ‎but you can adapt it to other boards by changing the lines that create the ‎RGBMatrix object. The code is also designed for the 64x32 LED displays.‎

You'll also need the emoji.bmp file on your CIRCUITPY drive.‎

Download Project Bundle‎

Copy Code
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import random
import time

import board
import displayio
import framebufferio
import rgbmatrix

displayio.release_displays()

matrix = rgbmatrix.RGBMatrix(
    width=64, height=32, bit_depth=3,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)

# This bitmap contains the emoji we're going to use. It is assumed
# to contain 20 icons, each 20x24 pixels. This fits nicely on the 64x32
# RGB matrix display.

filename = "emoji.bmp"

# CircuitPython 6 & 7 compatible
bitmap_file = open(filename, 'rb')
bitmap = displayio.OnDiskBitmap(bitmap_file)
pixel_shader = getattr(bitmap, 'pixel_shader', displayio.ColorConverter())

# # CircuitPython 7+ compatible
# bitmap = displayio.OnDiskBitmap(filename)
# pixel_shader = bitmap.pixel_shader

# Each wheel can be in one of three states:
STOPPED, RUNNING, BRAKING = range(3)

# Return a duplicate of the input list in a random (shuffled) order.
def shuffled(seq):
    return sorted(seq, key=lambda _: random.random())

# The Wheel class manages the state of one wheel. "pos" is a position in
# scaled integer coordinates, with one revolution being 7680 positions
# and 1 pixel being 16 positions. The wheel also has a velocity (in positions
# per tick) and a state (one of the above constants)
class Wheel(displayio.TileGrid):
    def __init__(self):
        # Portions of up to 3 tiles are visible.
        super().__init__(bitmap=bitmap, pixel_shader=pixel_shader,
                         width=1, height=3, tile_width=20, tile_height=24)
        self.order = shuffled(range(20))
        self.state = STOPPED
        self.pos = 0
        self.vel = 0
        self.y = 0
        self.x = 0
        self.stop_time = time.monotonic_ns()

    def step(self):
        # Update each wheel for one time step
        if self.state == RUNNING:
            # Slowly lose speed when running, but go at least speed 64
            self.vel = max(self.vel * 9 // 10, 64)
            if time.monotonic_ns() > self.stop_time:
                self.state = BRAKING
        elif self.state == BRAKING:
            # More quickly lose speed when braking, down to speed 7
            self.vel = max(self.vel * 85 // 100, 7)

        # Advance the wheel according to the velocity, and wrap it around
        # after 7680 positions
        self.pos = (self.pos + self.vel) % 7680

        # Compute the rounded Y coordinate
        yy = round(self.pos / 16)
        # Compute the offset of the tile (tiles are 24 pixels tall)
        yyy = yy % 24
        # Find out which tile is the top tile
        off = yy // 24

        # If we're braking and a tile is close to midscreen,
        # then stop and make sure that tile is exactly centered
        if self.state == BRAKING and self.vel == 7 and yyy < 4:
            self.pos = off * 24 * 16
            self.vel = 0
            self.state = STOPPED

        # Move the displayed tiles to the correct height and make sure the
        # correct tiles are displayed.
        self.y = yyy - 20
        for i in range(3):
            self[i] = self.order[(19 - i + off) % 20]

    # Set the wheel running again, using a slight bit of randomness.
    # The 'i' value makes sure the first wheel brakes first, the second
    # brakes second, and the third brakes third.
    def kick(self, i):
        self.state = RUNNING
        self.vel = random.randint(256, 320)
        self.stop_time = time.monotonic_ns() + 3_000_000_000 + i * 350_000_000

# Our fruit machine has 3 wheels, let's create them with a correct horizontal
# (x) offset and arbitrary vertical (y) offset.
g = displayio.Group()
wheels = []
for idx in range(3):
    wheel = Wheel()
    wheel.x = idx * 22
    wheel.y = -20
    g.append(wheel)
    wheels.append(wheel)
display.show(g)

# Make a unique order of the emoji on each wheel
orders = [shuffled(range(20)), shuffled(range(20)), shuffled(range(20))]

# And put up some images to start with
for si, oi in zip(wheels, orders):
    for idx in range(3):
        si[idx] = oi[idx]

# We want a way to check if all the wheels are stopped
def all_stopped():
    return all(si.state == STOPPED for si in wheels)

# To start with, though, they're all in motion
for idx, si in enumerate(wheels):
    si.kick(idx)

# Here's the main loop
while True:
    # Refresh the display (doing this manually ensures the wheels move
    # together, not at different times)
    display.refresh(minimum_frames_per_second=0)
    if all_stopped():
        # Once everything comes to a stop, wait a little bit and then
        # start everything over again.  Maybe you want to check if the
        # combination is a "winner" and add a light show or something.
        for idx in range(100):
            display.refresh(minimum_frames_per_second=0)
        for idx, si in enumerate(wheels):
            si.kick(idx)

    # Otherwise, let the wheels keep spinning...
    for idx, si in enumerate(wheels):
        si.step()

‎View on GitHub

Example: Conway's "Game of Life"‎

 

 

According to Wikipedia, "John Horton Conway was an English mathematician ‎active in the theory of finite groups, knot theory, number theory, combinatorial ‎game theory, and coding theory. He also made contributions to many branches of ‎recreational mathematics, most notably the invention of the cellular automaton ‎called the Game of Life."‎

Web comic XKCD memorialized his passing with a comic which showed a stick ‎person turning into a "glider", a construct in the Game of Life which will continue ‎moving indefinitely into empty space.‎

This example opens with a recreation of XKCD's tribute to Conway, then from ‎time to time refreshes the display with a random state. It's designed for the ‎FeatherWing M4 Express, but you can adapt it to other boards by changing the ‎lines that create the RGBMatrix object. The code is also designed for the 64x32 ‎LED displays. Unlike the other demos, it will adapt to other display sizes like 16x32 ‎by changing the lines that create the RGBMatrix object.‎

Download Project Bundle‎

Copy Code
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import random
import time

import board
import displayio
import framebufferio
import rgbmatrix

displayio.release_displays()

# Conway's "Game of Life" is played on a grid with simple rules, based
# on the number of filled neighbors each cell has and whether the cell itself
# is filled.
#   * If the cell is filled, and 2 or 3 neighbors are filled, the cell stays
#     filled
#   * If the cell is empty, and exactly 3 neighbors are filled, a new cell
#     becomes filled
#   * Otherwise, the cell becomes or remains empty
#
# The complicated way that the "m1" (minus 1) and "p1" (plus one) offsets are
# calculated is due to the way the grid "wraps around", with the left and right
# sides being connected, as well as the top and bottom sides being connected.
#
# This function has been somewhat optimized, so that when it indexes the bitmap
# a single number [x + width * y] is used instead of indexing with [x, y].
# This makes the animation run faster with some loss of clarity. More
# optimizations are probably possible.

def apply_life_rule(old, new):
    width = old.width
    height = old.height
    for y in range(height):
        yyy = y * width
        ym1 = ((y + height - 1) % height) * width
        yp1 = ((y + 1) % height) * width
        xm1 = width - 1
        for x in range(width):
            xp1 = (x + 1) % width
            neighbors = (
                old[xm1 + ym1] + old[xm1 + yyy] + old[xm1 + yp1] +
                old[x   + ym1] +                  old[x   + yp1] +
                old[xp1 + ym1] + old[xp1 + yyy] + old[xp1 + yp1])
            new[x+yyy] = neighbors == 3 or (neighbors == 2 and old[x+yyy])
            xm1 = x

# Fill 'fraction' out of all the cells.
def randomize(output, fraction=0.33):
    for i in range(output.height * output.width):
        output[i] = random.random() < fraction


# Fill the grid with a tribute to John Conway
def conway(output):
    # based on xkcd's tribute to John Conway (1937-2020) https://xkcd.com/2293/
    conway_data = [
        b'  +++   ',
        b'  + +   ',
        b'  + +   ',
        b'   +    ',
        b'+ +++   ',
        b' + + +  ',
        b'   +  + ',
        b'  + +   ',
        b'  + +   ',
    ]
    for i in range(output.height * output.width):
        output[i] = 0
    for i, si in enumerate(conway_data):
        y = output.height - len(conway_data) - 2 + i
        for j, cj in enumerate(si):
            output[(output.width - 8)//2 + j, y] = cj & 1

# bit_depth=1 is used here because we only use primary colors, and it makes
# the animation run a bit faster because RGBMatrix isn't taking over the CPU
# as often.
matrix = rgbmatrix.RGBMatrix(
    width=64, height=32, bit_depth=1,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.A5, board.A4, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)
SCALE = 1
b1 = displayio.Bitmap(display.width//SCALE, display.height//SCALE, 2)
b2 = displayio.Bitmap(display.width//SCALE, display.height//SCALE, 2)
palette = displayio.Palette(2)
tg1 = displayio.TileGrid(b1, pixel_shader=palette)
tg2 = displayio.TileGrid(b2, pixel_shader=palette)
g1 = displayio.Group(scale=SCALE)
g1.append(tg1)
display.show(g1)
g2 = displayio.Group(scale=SCALE)
g2.append(tg2)

# First time, show the Conway tribute
palette[1] = 0xffffff
conway(b1)
display.auto_refresh = True
time.sleep(3)
n = 40

while True:
    # run 2*n generations.
    # For the Conway tribute on 64x32, 80 frames is appropriate.  For random
    # values, 400 frames seems like a good number.  Working in this way, with
    # two bitmaps, reduces copying data and makes the animation a bit faster
    for _ in range(n):
        display.show(g1)
        apply_life_rule(b1, b2)
        display.show(g2)
        apply_life_rule(b2, b1)

    # After 2*n generations, fill the board with random values and
    # start over with a new color.
    randomize(b1)
    # Pick a random color out of 6 primary colors or white.
    palette[1] = (
        (0x0000ff if random.random() > .33 else 0) |
        (0x00ff00 if random.random() > .33 else 0) |
        (0xff0000 if random.random() > .33 else 0)) or 0xffffff
    n = 200

‎View on GitHub

Advanced: Multiple Panels

The features on this page require CircuitPython 6.2 or later (including 6.2.0-‎alpha.1)‎

If you have multiple identical panels, you can extend a single display across them, ‎vertically, horizontally, or both.‎

back_49

Back view of four 64x32 panels in a 2x2 arrangement. The MatrixPortal controller ‎is at top left.‎

Inspect the rear of your panel. There are two 10-pin connectors. You can "chain" ‎multiple displays by using a ribbon cable to hook the "OUT" of one panel to the ‎‎"IN" of the next panel.‎

Many of Adafruit's panels include a ribbon cable; check the description.‎

panels_50

Next, you'll need to power all your panels. Each panel has a 4-pin power ‎connector, and most of Adafruit's panels include a Y-splitter power cable which ‎can be connected to 2 panels. The power supply current requirement increases ‎according to the number of panels, but the voltage requirement is always 5V. ‎Remember that we recommend a 5V 4A supply for a single 64x32 pixel panel, so ‎our recommendation becomes 4×2=8A for 2 panels and 4×4=16A for 4 panels. ‎By using dimmer colors and avoiding big solid areas on the display, you may be ‎able to get by with a smaller power supply.‎

An insufficient power supply is frequent problem and can lead to flickering and ‎jumbled displays.‎

More displays also mean more memory (RAM) usage. Using bit_depth=6, ‎approximate RAM usage is as follows:‎

  • one 64×32 panel uses 17kB

  • two 64×32 panels use 33kB

  • four 64×32 panels use 65kB

Using bit_depth=3, approximate RAM usage is as follows:‎

  • one 64×32 panel uses 11kB

  • two 64×32 panels use 21kB

  • four 64×32 panels use 42kB

Using bit_depth=1, approximate RAM usage is as follows:‎

  • one 64×32 panel uses 7kB

  • two 64×32 panels use 13kB

  • four 64×32 panels use 25kB

The total number of panels is limited by RAM usage, CPU usage, and refresh rate. ‎Other arrangements than those shown, such as 1×3, 3×1, 2x3, 3x2, etc., are ‎possible.‎

Chaining and Tiling

This script for MatrixPortal will be used to demonstrate the different chaining and ‎tiling options:‎

Download File‎

Copy Code
import displayio
import board
import rgbmatrix
import framebufferio

bit_depth = 1
base_width = 64
base_height = 32
chain_across = 1
tile_down = 1
serpentine = True

width = base_width * chain_across
height = base_height * tile_down

addr_pins = [board.MTX_ADDRA, board.MTX_ADDRB, board.MTX_ADDRC, board.MTX_ADDRD]
rgb_pins = [
    board.MTX_R1,
    board.MTX_G1,
    board.MTX_B1,
    board.MTX_R2,
    board.MTX_G2,
    board.MTX_B2,
]
clock_pin = board.MTX_CLK
latch_pin = board.MTX_LAT
oe_pin = board.MTX_OE

displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
                width=width,
                height=height,
                bit_depth=bit_depth,
                rgb_pins=rgb_pins,
                addr_pins=addr_pins,
                clock_pin=clock_pin,
                latch_pin=latch_pin,
                output_enable_pin=oe_pin,
                tile=tile_down, serpentine=serpentine,
            )
display = framebufferio.FramebufferDisplay(matrix)

We'll focus on the effect of these 3 settings:‎

  • chain_across

  • tile_down

  • serpentine

Note how chain_across is used to calculate the width from the base_width and ‎similarly that tile_down is used to calculate the height from the base_height.‎

The total number of displays is chain_across * tile_down.‎

The top-right panel (before rotation) is always the one that has the MatrixPortal, ‎or incoming ribbon cable attached to it.‎

Purely horizontal arrangements

  • chain_across = 1

  • tile_down = 1

  • serpentine doesn't matter

Uses a single panel, size is 64x32.‎

arrange_51

  • chain_across = 2

  • tile_down = 1

  • serpentine doesn't matter

Uses two panels, total display size is 128x32.‎

arrange_52

 

  • chain_across = 4

  • tile_down = 1

  • serpentine doesn't matter

Uses four panels, total display size is 256x32.‎

arrange_53

Purely vertical arrangements

The value called "serpentine" controls whether every alternate row of panels is ‎rotated 180 degrees. This is generally more convenient, due to the positions of ‎the connectors. The approximate path of the ribbon cables is shown with the ‎arrows.‎

  • chain_across = 1‎

  • tile_down = 4

  • serpentine = True

Uses four panels, total display size is 64x128. Notice how displays 2 and 4 are ‎rotated 180 degrees to minimize the length of ribbon cables required.‎

vert_54

  • chain_across = 1

  • tile_down = 4‎

  • serpentine = False

Uses four panels, total display size is 64x128. Note how the ribbon cables are ‎longer than with serpentine=True. This is usually less convenient.‎

vert_55

Rectangular arrangements

  • chain_across = 2

  • tile_down = 2‎

  • serpentine = True

Uses four panels, total display size is 128x64. Note how displays 3 and 4 are ‎rotated 180 degrees to minimize the length of ribbon cables required.‎

rec_56

  • chain_across = 2

  • tile_down = 2‎

  • serpentine = False

Uses four panels, total display size is 128x64.‎

Note how long the ribbon cable is from panel 2 to 3. This is why the "serpentine" ‎arrangement is usual preferable to the non-serpentine arrangement.‎

rec_57

The effect of display rotation

All of the above examples show a display with rotation=0. You can change the ‎rotation of a screen by passing in a rotation= parameter to ‎the FramebufferDisplay constructor, or by setting the .rotation property of ‎the display object at any time.‎

This rotation, which can be any of 0, 90, 180, or 270 degrees counterclockwise, ‎affects the whole display rather than the individual panels.‎

display.rotation = 90‎

display_58

display.rotation = 180‎

display_59

display.rotation = 270

display_60

Advanced Example: Big, big flag of Wales

dragon_61

This example uses 4 64×32 matrices attached to a single MatrixPortal using the ‎‎"serpentine" wiring style.‎

Place the code below on CIRCUITPY (as code.py) and the bitmap ‎image (as wales.bmp). You can change the bitmap to any other file that works ‎with OnDiskBitmap, up to 128x64 pixels. No additional libraries are required. You ‎can adapt it to other boards by changing the lines that create ‎the RGBMatrix object.‎

object_62

object_63

Download Project Bundle

Copy Code
# SPDX-FileCopyrightText: 2021 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# Minimal example displaying an image tiled across multiple RGB LED matrices.
# This is written for MatrixPortal and four 64x32 pixel matrices, but could
# be adapted to different boards and matrix combinations.
# No additional libraries required, just uses displayio.
# Image wales.bmp should be in CIRCUITPY root directory.

import board
import displayio
import framebufferio
import rgbmatrix

displayio.release_displays() # Release current display, we'll create our own

# Create RGB matrix object for a chain of four 64x32 matrices tiled into
# a single 128x64 pixel display -- two matrices across, two down, with the
# second row being flipped. width and height args are the combined size of
# all the tiled sub-matrices. tile arg is the number of rows of matrices in
# the chain (horizontal tiling is implicit from the width argument, doesn't
# need to be specified, but vertical tiling must be explicitly stated).
# The serpentine argument indicates whether alternate rows are flipped --
# cabling is easier this way, downside is colors may be slightly different
# when viewed off-angle. bit_depth and pins are same as other examples.
MATRIX = rgbmatrix.RGBMatrix(
    width=128, height=64, bit_depth=6, tile=2, serpentine=True,
    rgb_pins=[board.MTX_R1,
              board.MTX_G1,
              board.MTX_B1,
              board.MTX_R2,
              board.MTX_G2,
              board.MTX_B2],
    addr_pins=[board.MTX_ADDRA,
               board.MTX_ADDRB,
               board.MTX_ADDRC,
               board.MTX_ADDRD],
    clock_pin=board.MTX_CLK, latch_pin=board.MTX_LAT,
    output_enable_pin=board.MTX_OE)

# Associate matrix with a Display to use displayio features
DISPLAY = framebufferio.FramebufferDisplay(MATRIX, auto_refresh=False,
                                           rotation=0)

# Load BMP image, create Group and TileGrid to hold it
FILENAME = "wales.bmp"

# CircuitPython 6 & 7 compatible
BITMAP = displayio.OnDiskBitmap(open(FILENAME, "rb"))
TILEGRID = displayio.TileGrid(
    BITMAP,
    pixel_shader=getattr(BITMAP, 'pixel_shader', displayio.ColorConverter()),
    tile_width=BITMAP.width,
    tile_height=BITMAP.height
)

# # CircuitPython 7+ compatible
# BITMAP = displayio.OnDiskBitmap(FILENAME)
# TILEGRID = displayio.TileGrid(
#     BITMAP,
#     pixel_shader=BITMAP.pixel_shader,
#     tile_width=BITMAP.width,
#     tile_height=BITMAP.height
# )

GROUP = displayio.Group()
GROUP.append(TILEGRID)
DISPLAY.show(GROUP)
DISPLAY.refresh()

# Nothing interactive, just hold the image there
while True:
    pass

View on GitHub

制造商零件编号 3036
RGB MATRIX FEATHERWING KIT M0 M4
Adafruit Industries LLC
制造商零件编号 4702
ADAFRUIT RGB MATRIX FEATHERWING
Adafruit Industries LLC
制造商零件编号 2830
FEATHER STACKING HEADERS FML
Adafruit Industries LLC
制造商零件编号 2886
FEATHER HEADER KIT FML
Adafruit Industries LLC
制造商零件编号 2104
IDC BREAKOUT HELPER - 2X8 (16 PI
Adafruit Industries LLC
制造商零件编号 4775
METRO ESP32-S2
Adafruit Industries LLC
制造商零件编号 2601
RGB MATRIX SHIELD FOR ARDUINO
Adafruit Industries LLC
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum