8x8 LED matrix/Using it/09. The first picture
Using it · 09 of 10

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

Five wires
Your board
Wires
5
VCC
5V
Logic
5 V
GND to GND and VCC to 5V: the chip needs 5 V. CS, DIN and CLK go to D10, D11 and D13, the sketch's pins. NC, between DIN and CLK, stays empty: it is connected to nothing.

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 boardCSDINCLK
Arduino UnoD10D11D13
ESP32GPIO 5GPIO 23GPIO 18
ESP32-S3GPIO 10GPIO 11GPIO 12
Raspberry Pi PicoGP17GP19GP18

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
heart

If 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.

matrix_led.ino
/*
  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.2

When it does not work

Nothing lights and the sketch runs.

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.

The serial monitor stays empty on my ESP32-S3.

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.

The heart is on its side or upside down.

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.

It works in Arduino and not in MicroPython.

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.

Where this goes next

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

Community

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.

Browse Modules and blocks on the forum →