The first picture
Five wires and a sketch with no library to install. It wakes the chip, sets brightness 4, and draws a heart and an arrow in turn, a second each. The picture is written as rows you can read, and the sketch turns it into the columns the chip wants.
Five wires
GND to GND. VCC to 5V, or VBUS on a Pico, whatever your board's logic voltage. CS, DIN and CLK to three output pins:
| Your board | CS | DIN | CLK |
|---|---|---|---|
| Arduino Uno | D10 | D11 | D13 |
| ESP32 | GPIO 5 | GPIO 23 | GPIO 18 |
| ESP32-S3 | GPIO 10 | GPIO 11 | GPIO 12 |
| Raspberry Pi Pico | GP17 | GP19 | GP18 |
Those are each board's hardware SPI pins. The sketch drives them by hand, so any three pins would do, but these leave the wiring right for the SPI library later. NC stays empty.
The sketch
send() is one message: CS low, the register's address, the data, CS high.
show() walks the eight columns, builds each column's byte from the picture,
and sends it to registers 1 to 8.
setup() sends the five messages from
Sixteen bits and a latch:
test off, decoding off, all eight columns, brightness 4, and wake up. Then
loop() shows the heart, then the arrow, a second each.
What you should see
A red heart, then an arrow pointing up at the matrix's top edge, back and forth. At 115200 the serial monitor prints each name as it goes up:
heart
arrow
heartIf the arrow points left, right or down, set TURN and upload again. If the
matrix stays dark, the next article is the list to check.
The code
No library to install: shiftOut comes with every board. send() is one message, show() turns a picture into eight column bytes, and setup() sends the five messages every MAX7219 needs before its first picture.
/*
8x8 LED Matrix - the first picture TK52 / /p/tk52
Wiring. Matrix up, header at the bottom, the pins read
GND VCC CS DIN NC CLK from the left. There is no square pad
on this board: count from GND, printed on both sides.
GND -> GND
VCC -> 5V (VBUS on a Pico). The MAX7219 needs 4.0 to 5.5 V,
so never 3V3.
CS -> D10 on an Uno, GPIO 5 on an ESP32, GPIO 10 on an
ESP32-S3, GP17 on a Raspberry Pi Pico
DIN -> D11 on an Uno, GPIO 23 on an ESP32, GPIO 11 on an
ESP32-S3, GP19 on a Raspberry Pi Pico
NC -> nothing: no trace on the board reaches it
CLK -> D13 on an Uno, GPIO 18 on an ESP32, GPIO 12 on an
ESP32-S3, GP18 on a Raspberry Pi Pico
Arduino IDE
Tools > Board your board, e.g. Arduino Uno
Tools > Port the one that appears when you plug in
Tools > USB CDC On Boot Enabled (ESP32-S3 only)
No library to install: shiftOut comes with every board.
Serial Monitor at 115200.
*/
// Uno pins. ESP32: 5, 23, 18. ESP32-S3: 10, 11, 12. Pico: 17, 19, 18.
const int CS_PIN = 10;
const int DIN_PIN = 11;
const int CLK_PIN = 13;
// If the picture comes out on its side, try 1, 2 or 3 quarter
// turns. If it comes out mirrored, set FLIP to true.
const int TURN = 0;
const bool FLIP = false;
// Pictures: the top row first, the leftmost pixel in the top bit.
const uint8_t HEART[8] = {
0b00000000, 0b01100110, 0b11111111, 0b11111111,
0b11111111, 0b01111110, 0b00111100, 0b00011000,
};
const uint8_t ARROW[8] = {
0b00011000, 0b00111100, 0b01111110, 0b11011011,
0b00011000, 0b00011000, 0b00011000, 0b00011000,
};
// One 16-bit message: the register's address, then its data,
// top bit first. CS going back HIGH is what makes it take effect.
void send(uint8_t reg, uint8_t data) {
digitalWrite(CS_PIN, LOW);
shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, reg);
shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, data);
digitalWrite(CS_PIN, HIGH);
}
// Is the picture's pixel at (x, y) lit? x from the left, y down.
bool lit(const uint8_t *pic, int x, int y) {
if (FLIP) x = 7 - x;
for (int t = 0; t < TURN; t++) {
int s = x;
x = y;
y = 7 - s;
}
return pic[y] & (0x80 >> x);
}
// On the TK52, register d + 1 lights column d from the left, and
// bit b of it lights the pixel b rows down from the top.
void show(const uint8_t *pic) {
for (int d = 0; d < 8; d++) {
uint8_t column = 0;
for (int b = 0; b < 8; b++) {
if (lit(pic, d, b)) column |= 1 << b;
}
send(1 + d, column);
}
}
void setup() {
Serial.begin(115200);
pinMode(CS_PIN, OUTPUT);
pinMode(DIN_PIN, OUTPUT);
pinMode(CLK_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH);
send(0x0F, 0); // display test off
send(0x09, 0); // no decoding: every bit is one LED
send(0x0B, 7); // scan all eight columns, never fewer
send(0x0A, 4); // brightness 4 of 15
send(0x0C, 1); // wake up: it powers up in shutdown
}
void loop() {
show(HEART);
Serial.println("heart");
delay(1000);
show(ARROW);
Serial.println("arrow");
delay(1000);
}TURN and FLIP are there because the column order is worked out from the matrix's datasheet rather than seen on a lit board. Leave them at 0 and false unless the heart comes out turned or mirrored.
View on GitHub · blocks/tk52-matrix-led/arduino/matrix_led/matrix_led.ino @ v1.2The same sketch in MicroPython, for an ESP32, an ESP32-S3 or a Pico. send() clocks the sixteen bits out by hand, top bit first, the same way shiftOut does.
# 8x8 LED Matrix - the first picture TK52 / /p/tk52
#
# Wiring. Matrix up, header at the bottom, the pins read
# GND VCC CS DIN NC CLK from the left. There is no square pad
# on this board: count from GND, printed on both sides.
#
# GND -> GND
# VCC -> 5V (VBUS on a Pico). Never 3V3: the MAX7219 needs
# 4.0 to 5.5 V.
# CS -> GPIO 5 on an ESP32, GPIO 10 on an ESP32-S3,
# GP17 on a Raspberry Pi Pico
# DIN -> GPIO 23 on an ESP32, GPIO 11 on an ESP32-S3,
# GP19 on a Raspberry Pi Pico
# NC -> nothing: no trace on the board reaches it
# CLK -> GPIO 18 on an ESP32, GPIO 12 on an ESP32-S3,
# GP18 on a Raspberry Pi Pico
#
# Save it to the board with Thonny and run it. No library needed.
from machine import Pin
import time
# ESP32: 5, 23, 18. ESP32-S3: 10, 11, 12. Pico: 17, 19, 18.
cs = Pin(5, Pin.OUT, value=1)
din = Pin(23, Pin.OUT, value=0)
clk = Pin(18, Pin.OUT, value=0)
# If the picture comes out on its side, try 1, 2 or 3 quarter
# turns. If it comes out mirrored, set FLIP to True.
TURN = 0
FLIP = False
# Pictures: the top row first, the leftmost pixel in the top bit.
HEART = (0b00000000, 0b01100110, 0b11111111, 0b11111111,
0b11111111, 0b01111110, 0b00111100, 0b00011000)
ARROW = (0b00011000, 0b00111100, 0b01111110, 0b11011011,
0b00011000, 0b00011000, 0b00011000, 0b00011000)
def send(reg, data):
# One 16-bit message: address, then data, top bit first.
# CS going back high is what makes it take effect.
word = (reg << 8) | data
cs.value(0)
for i in range(15, -1, -1):
din.value((word >> i) & 1)
clk.value(1)
clk.value(0)
cs.value(1)
def lit(pic, x, y):
# Is the picture's pixel at (x, y) lit? x from the left, y down.
if FLIP:
x = 7 - x
for _ in range(TURN):
x, y = y, 7 - x
return pic[y] & (0x80 >> x)
def show(pic):
# On the TK52, register d + 1 lights column d from the left,
# and bit b of it lights the pixel b rows down from the top.
for d in range(8):
column = 0
for b in range(8):
if lit(pic, d, b):
column |= 1 << b
send(1 + d, column)
send(0x0F, 0) # display test off
send(0x09, 0) # no decoding: every bit is one LED
send(0x0B, 7) # scan all eight columns, never fewer
send(0x0A, 4) # brightness 4 of 15
send(0x0C, 1) # wake up: it powers up in shutdown
while True:
show(HEART)
print("heart")
time.sleep(1)
show(ARROW)
print("arrow")
time.sleep(1)The three Pin numbers at the top are the ESP32's. Change them for your board from the line above them; nothing else changes.
View on GitHub · blocks/tk52-matrix-led/micropython/matrix_led.py @ v1.2When it does not work
Check VCC is on 5V (VBUS on a Pico), not 3V3. Then check the three signal pins match the ones at the top of the sketch: the Uno's are D10, D11 and D13, and each other board's are in the comment above them.
Set Tools > USB CDC On Boot to Enabled and upload again. Without it the S3's USB port does not bring up a serial port at boot. The matrix still works; only the printing is missing.
Set TURN to 1, 2 or 3 near the top of the sketch and upload again. The book works out which way up the columns run from drawings, not from a lit board, and TURN is there in case yours disagrees.
The pin numbers at the top of the MicroPython script are the ESP32's: 5, 23 and 18. On an ESP32-S3 use 10, 11 and 12; on a Pico, 17, 19 and 18. There is no Uno version: an Uno cannot run MicroPython.
A dark matrix, random dots, every LED on, a picture on its side, and a board that resets.
When it stays dark →Edit this page — content/books/matrix-led/the-first-picture.mdx
Questions about this product
See what other owners have asked, and read their solutions.
This page covers several products. Choose yours to see the right discussions.
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.