012 - MicroPython TechNotes: 8x8 Dot Matrix Display (SPI)

Introduction

In this tutorial, we will learn on how to use an 8×8 Dot Matrix Display with SPI protocol as communication interface. For this tutorial, I will be using the 8×8 Dot Matrix Display module with SPI protocol from GorillaCell ESP32 development kit.

Pinout

  1. GND – for the ground pin.
  2. VCC – for the supply voltage.
  3. DIN – for the SPI serial data input.
  4. CLK – for the SPI serial clock pin.
  5. CS – for the SPI chip select pin.

Bill Of Materials

  1. ESP32 development board.
  2. Gorillacell ESP32 shield (optional).
  3. 5-pin female-female dupont jumper wires.
  4. 8×8 dot matrix display (SPI).

Hardware Instruction

  1. First, attach the ESP32 dev board on top the ESP32 shield making sure that both USB port is on the same side.
  2. Next, attach the dupont wires to the 8×8 dot matrix display by following the a color coding which is black for the ground, red for the VCC, and etc.
  3. Next, attach the other side of the dupont wires to the ESP32 shield with the following pin assignment which is black to the GND, red to the VCC, yellow to GPIO 23, white to GPIO 19, and blue to GPIO 18.
  4. Next, power the ESP32 shield with an external power supply with a USB type-C connector and make sure that the power switch is slide to ON state.
  5. Next, connect the ESP32 to the computer by connecting a micro-USB cable. Our demo circuit is now ready.

Software Instruction

  1. Copy the max7219.py and paste it to Thonny IDE.
  2. Save it to ESP32 MicroPython device root directory by clicking the File menu and select Save As.
  3. Give it a name as max7219.py and click Ok.
  4. Play with your dot matrix display using the example # 1 and example # 2. Please feel free to modify it according to your needs. And if you have any concern, just send me a message by writing in the comment box provided.

Video Demonstration

Call To Action

For any concern, write your message in the comment section.

You might also like to support my journey on Youtube by Subscribing. Click this to Subscribe to TechToTinker.

Thank you and have a good days ahead.

See you,

– George Bantique | tech.to.tinker@gmail.com

Source Code

1. Example # 1, exploring the basics:

 1from machine import Pin, SPI
 2from max7219 import Max7219
 3
 4spi = SPI(1,
 5          baudrate=10000000,
 6          polarity=1,
 7          phase=0,
 8          sck=Pin(19),
 9          mosi=Pin(23))
10cs = Pin(18, Pin.OUT)
11display = Max7219(8, 8, spi, cs, True)
12
13
14# The following codes should be tested using the REPL:
15# 1. To display a character:
16display.text('A',0,0)
17display.show()
18# 2. To clear the display:
19# display.fill(0)
20# 3. To modify the default brightness:
21# display.brightness(0)  # minimum brightness
22display.brightness(15) # maximum brightness
23# 4. To display a scrolling message:
24# display.marquee('Hello world')
25# ****************************************************
26# Other graphic primitives:
27# 5. To display a single pixel:
28# display.pixel(x, y[, c])
29# 6. To display a horizontal line:
30# display.hline(x, y, w, col)
31# 7. To display a vertical line:
32# display.vline(x, y, h, col)
33# 8. To display a line:
34# display.line(x1, y1, x2, y2, col)
35# 9. To display a rectangle:
36# display.rect(x, y, w, h, col)
37# 10. To display a filled rectangle:
38# display.fill_rect(x, y, w, h, col)
39# 11. To scroll the display:
40# display.scroll(dx, dy)
41# 12. To display custom character:
42# display.blit(fbuf, x, y[, key])

2. Example # 2, count up then count down:

 1from machine import Pin, SPI
 2from max7219 import Max7219
 3from time import sleep_ms
 4
 5spi = SPI(1,
 6          baudrate=10000000,
 7          polarity=1,
 8          phase=0,
 9          sck=Pin(19),
10          mosi=Pin(23))
11cs = Pin(18, Pin.OUT)
12display = Max7219(8, 8, spi, cs, True)
13
14counter = 0
15isCountUp = True
16
17while True:
18    # count up
19    if isCountUp:
20        if counter < 9:
21            counter += 1
22            if counter == 9:
23                isCountUp = False
24    # count down
25    else:
26        if counter > 0:
27            counter -= 1
28            if counter == 0:
29                isCountUp = True
30
31    display.fill(0)
32    display.text(str(counter),0,0)
33    display.show()
34    
35    sleep_ms(500)

3. max7219.py dot matrix display library:

  1from machine import Pin, SPI
  2from micropython import const
  3import framebuf, utime
  4
  5_DIGIT_0 = const(0x1)
  6
  7_DECODE_MODE = const(0x9)
  8_NO_DECODE = const(0x0)
  9
 10_INTENSITY = const(0xa)
 11_INTENSITY_MIN = const(0x0)
 12
 13_SCAN_LIMIT = const(0xb)
 14_DISPLAY_ALL_DIGITS = const(0x7)
 15
 16_SHUTDOWN = const(0xc)
 17_SHUTDOWN_MODE = const(0x0)
 18_NORMAL_OPERATION = const(0x1)
 19
 20_DISPLAY_TEST = const(0xf)
 21_DISPLAY_TEST_NORMAL_OPERATION = const(0x0)
 22
 23_MATRIX_SIZE = const(8)
 24
 25# _SCROLL_SPEED_NORMAL is ms to delay (slow) scrolling text.
 26_SCROLL_SPEED_NORMAL = 100
 27
 28class Max7219(framebuf.FrameBuffer):
 29    """
 30    Driver for MAX7219 8x8 LED matrices
 31    https://github.com/vrialland/micropython-max7219
 32    Example for ESP8266 with 2x4 matrices (one on top, one on bottom),
 33    so we have a 32x16 display area:
 34    >>> from machine import Pin, SPI
 35    >>> from max7219 import Max7219
 36    >>> spi = SPI(1, baudrate=10000000)
 37    >>> screen = Max7219(32, 16, spi, Pin(15))
 38    >>> screen.rect(0, 0, 32, 16, 1)  # Draws a frame
 39    >>> screen.text('Hi!', 4, 4, 1)
 40    >>> screen.show()
 41    On some matrices, the display is inverted (rotated 180°), in this case
 42     you can use `rotate_180=True` in the class constructor.
 43    """
 44
 45    def __init__(self, width, height, spi, cs, rotate_180=False):
 46        # Pins setup
 47        self.spi = spi
 48        self.cs = cs
 49        self.cs.init(Pin.OUT, True)
 50
 51        # Dimensions
 52        self.width = width
 53        self.height = height
 54        # Guess matrices disposition
 55        self.cols = width // _MATRIX_SIZE
 56        self.rows = height // _MATRIX_SIZE
 57        self.nb_matrices = self.cols * self.rows
 58        self.rotate_180 = rotate_180
 59        # 1 bit per pixel (on / off) -> 8 bytes per matrix
 60        self.buffer = bytearray(width * height // 8)
 61        format = framebuf.MONO_HLSB if not self.rotate_180 else framebuf.MONO_HMSB
 62        super().__init__(self.buffer, width, height, format)
 63
 64        # Init display
 65        self.init_display()
 66
 67    def _write_command(self, command, data):
 68        """Write command on SPI"""
 69        cmd = bytearray([command, data])
 70        self.cs(0)
 71        for matrix in range(self.nb_matrices):
 72            self.spi.write(cmd)
 73        self.cs(1)
 74
 75    def init_display(self):
 76        """Init hardware"""
 77        for command, data in (
 78                (_SHUTDOWN, _SHUTDOWN_MODE),  # Prevent flash during init
 79                (_DECODE_MODE, _NO_DECODE),
 80                (_DISPLAY_TEST, _DISPLAY_TEST_NORMAL_OPERATION),
 81                (_INTENSITY, _INTENSITY_MIN),
 82                (_SCAN_LIMIT, _DISPLAY_ALL_DIGITS),
 83                (_SHUTDOWN, _NORMAL_OPERATION),  # Let's go
 84        ):
 85            self._write_command(command, data)
 86
 87        self.fill(0)
 88        self.show()
 89
 90    def brightness(self, value):
 91        # Set display brightness (0 to 15)
 92        if not 0 <= value < 16:
 93            raise ValueError('Brightness must be between 0 and 15')
 94        self._write_command(_INTENSITY, value)
 95
 96    def marquee(self, message):
 97        start = 33
 98        extent = 0 - (len(message) * 8) - 32
 99        for i in range(start, extent, -1):
100            self.fill(0)
101            self.text(message, i, 0, 1)
102            self.show()
103            utime.sleep_ms(_SCROLL_SPEED_NORMAL)
104
105    def show(self):
106        """Update display"""
107        # Write line per line on the matrices
108        for line in range(8):
109            self.cs(0)
110
111            for matrix in range(self.nb_matrices):
112                # Guess where the matrix is placed
113                row, col = divmod(matrix, self.cols)
114                # Compute where the data starts
115                if not self.rotate_180:
116                    offset = row * 8 * self.cols
117                    index = col + line * self.cols + offset
118                else:
119                    offset = 8 * self.cols - row * (8 - line) * self.cols
120                    index = (7 - line) * self.cols + col - offset
121
122                self.spi.write(bytearray([_DIGIT_0 + line, self.buffer[index]]))
123
124            self.cs(1)

References And Credits

  1. Purchase the kits at:
  1. MAX7219 Driver Library of Jeff Brown: https://github.com/jgbrown32/ESP8266_MAX7219


Posts in this series



No comments yet!

GitHub-flavored Markdown & a sane subset of HTML is supported.