A chain of four MAX7219 8×8 modules makes a 32×8 scrolling sign. MicroPython’s framebuf draws the text; the Pico W’s SPI0 shifts it out — no library to install.
The matrix is a 5 V part: power it from VBUS, and pass DIN, CS and CLK through a 74AHCT125 buffer so the MAX7219 sees proper 5 V logic levels.
Wiring
| Raspberry Pi Pico W | MAX7219 8×8 LED matrix (4-in-1 FC-16 module) | Wire | Notes |
|---|---|---|---|
| VBUS | VCC | red | VBUS (pin 40) is USB 5 V. Keep brightness low on USB — four modules can draw several hundred mA. |
| GND | GND | black | |
| GP19 | DIN | green | Via 74AHCT125 buffer — GP19 (pin 25, SPI0 TX) → 74AHCT125 1A; 1Y → DIN. Buffer VCC = VBUS (5 V), GND = GND, all OE pins = GND. |
| GP17 | CS | orange | Via 74AHCT125 buffer — GP17 (pin 22) → 2A; 2Y → CS. |
| GP18 | CLK | yellow | Via 74AHCT125 buffer — GP18 (pin 24, SPI0 SCK) → 3A; 3Y → CLK. |
5 V part, 3.3 V board. The MAX7219 runs on 5 V and expects a HIGH of at least 3.5 V. A 3.3 V board (ESP32, Pico) often works, but not reliably — for a dependable build, buffer DIN, CS and CLK with a 74HCT125 or 74AHCT125 powered from 5 V.
Board quirks
- The MAX7219 needs at least 3.5 V for a logic HIGH. Straight from 3.3 V GPIOs it often works on the bench and then glitches; the 5 V-powered 74AHCT125 makes it dependable. Nothing flows back into the Pico, so there is no damage risk either way.
- The driver is about 20 lines inside
main.py: aframebuf32×8 canvas, sent row by row to all four chips in one chip-select window. - Most 4-in-1 boards are “FC-16” style. If text runs backwards or each 8×8 block is rotated, you have a different module layout — reverse the module order in
show(). - Brightness register
0x0Ais set to 2 of 15: plenty indoors and gentle on USB power.
Code
# MAX7219 4-in-1 8x32 LED matrix (FC-16 style) on a Raspberry Pi Pico W (MicroPython).
# Wiring: VCC -> VBUS (pin 40, USB 5 V), GND -> GND. DIN, CS and CLK go through a 74AHCT125
# buffer powered from 5 V (the MAX7219 wants at least 3.5 V for a HIGH):
# GP19 (pin 25, SPI0 TX) -> buffer -> DIN, GP17 (pin 22) -> buffer -> CS, GP18 (pin 24, SPI0 SCK) -> buffer -> CLK.
# The small driver below is written for FlashReady (MIT) from the MAX7219 datasheet.
from machine import Pin, SPI
import framebuf
import time
MODULES = 4 # 8x8 blocks in the chain
MESSAGE = "Namaste from Pico W "
spi = SPI(0, baudrate=5_000_000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19))
cs = Pin(17, Pin.OUT, value=1)
buf = bytearray(8 * MODULES)
fb = framebuf.FrameBuffer(buf, 8 * MODULES, 8, framebuf.MONO_HLSB)
def write_all(reg, value):
cs(0)
spi.write(bytes([reg, value]) * MODULES)
cs(1)
def show():
w = MODULES # bytes per row in MONO_HLSB
for row in range(8):
cs(0)
for m in range(MODULES):
spi.write(bytes([row + 1, buf[row * w + m]])) # first module written = far end of the chain
cs(1)
for reg, val in ((0x0F, 0), (0x0C, 1), (0x0B, 7), (0x09, 0), (0x0A, 2)):
write_all(reg, val) # test off, wake, scan all 8 rows, no BCD decode, brightness 2/15
print("MAX7219 x{} - scrolling: {}".format(MODULES, MESSAGE.strip()))
width = len(MESSAGE) * 8
while True:
for x in range(8 * MODULES, -width, -1):
fb.fill(0)
fb.text(MESSAGE, x, 0, 1)
show()
time.sleep_ms(40)# MAX7219 4-in-1 8x32 LED matrix (FC-16 style) on a Raspberry Pi Pico W (MicroPython).
# Wiring: VCC -> VBUS (pin 40, USB 5 V), GND -> GND. DIN, CS and CLK go through a 74AHCT125
# buffer powered from 5 V (the MAX7219 wants at least 3.5 V for a HIGH):
# GP19 (pin 25, SPI0 TX) -> buffer -> DIN, GP17 (pin 22) -> buffer -> CS, GP18 (pin 24, SPI0 SCK) -> buffer -> CLK.
# The small driver below is written for FlashReady (MIT) from the MAX7219 datasheet.
from machine import Pin, SPI
import framebuf
import time
MODULES = 4 # 8x8 blocks in the chain
MESSAGE = "Namaste from Pico W "
spi = SPI(0, baudrate=5_000_000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19))
cs = Pin(17, Pin.OUT, value=1)
buf = bytearray(8 * MODULES)
fb = framebuf.FrameBuffer(buf, 8 * MODULES, 8, framebuf.MONO_HLSB)
def write_all(reg, value):
cs(0)
spi.write(bytes([reg, value]) * MODULES)
cs(1)
def show():
w = MODULES # bytes per row in MONO_HLSB
for row in range(8):
cs(0)
for m in range(MODULES):
spi.write(bytes([row + 1, buf[row * w + m]])) # first module written = far end of the chain
cs(1)
for reg, val in ((0x0F, 0), (0x0C, 1), (0x0B, 7), (0x09, 0), (0x0A, 2)):
write_all(reg, val) # test off, wake, scan all 8 rows, no BCD decode, brightness 2/15
print("MAX7219 x{} - scrolling: {}".format(MODULES, MESSAGE.strip()))
width = len(MESSAGE) * 8
while True:
for x in range(8 * MODULES, -width, -1):
fb.fill(0)
fb.text(MESSAGE, x, 0, 1)
show()
time.sleep_ms(40)Expected serial output
MAX7219 x4 - scrolling: Namaste from Pico WMAX7219 x4 - scrolling: Namaste from Pico W
Common errors
Random dots or only the first module works
Weak 3.3 V logic or a loose DOUT→DIN joint between modules. Add the buffer and press the module headers in firmly.
Pico resets when everything lights up
Too much current from USB. Lower brightness or power the matrix from its own 5 V supply with a common GND.