Driving 8x8 Dot Matrices with MAX7219

Not only to drive 7-segment displays, MAX7219 is also commonly used in driving 8x8 dot matrices. In this tutorial, we'll show how to use one MAX7219 to drive one 8x8 dot matrix and how to daisy-chain multiple MAX7219s to drive multiple 8x8 dot matrices. For ease of wiring, we use the 8x8 dot matrix module (with MAX7219 built-in) as the component used in this article.

Table of Contents

Mapping 7-segment Display to 8x8 Dot Matrix

Although a 7-segment display and a 8x8 got matrix are quite different in form factor, they are actually with the same structure: a display module with a group of LEDs. One 7-segment display consists of 8 LEDs (7 LEDs for digit segments and one LED for the decimal point), and as mentioned in the previous tutorial, one MAX7219 can drive up to 8 seven-segment displays. This means MAX7219 can drive up to 8x8 = 64 LEDs, which is exactly the number of LEDs on a 8x8 dot matrix. As a result, by using the non-decode (raw data) mode of MAX7219, it can be used to drive a 8x8 dot matrix. The next question is, how to map the LED position between a 7-segment display and a 8x8 dot matrix? Let's explain it with the following figure.

By using the non-decode display mode of MAX7219 (if you're not familiar with it, check the previous MAX7219 tutorial), each column of the matrix is mapped to one digit control register. It means Digit 0 is mapped to Column 0, Digit 1 is mapped to Column 1 and so on. And each row of a column is mapped to different segments of a 7-segment display. Starting from the top dot, which is mapped to the LSB of the data fed to the Digit data register, the mapping goes down sequentially to the last row mapped to the MSB of the Digit register. Here we show an example to define the bitmap of "7" on the matrix.

According to the figure, the bitmap pattern of "7" is defined as:

const byte bitmap_7[] =
{
  // define the dot pattern from column 0 ~ column 7
  B00000000, B00000000, B01100001, B00010001, B00001001, B00000111, B00000000, B00000000
};

Hardware Setup

5 pins are needed from the LinkIt 7697:

  • 5V

  • GND

  • P15

  • P16

  • P17

And they are wiring to pins

  • VCC

  • GND

  • CLK

  • CS

  • DIN

of the display module, respectively.

By setting up the hardware wiring, next we give an example to show different bitmaps on the display.

1-matrix Example

Following the bitmap definition mentioned above, the first example in this tutorial uses one 8x8 dot matrix to display characters. This sketch code displays "Hello, LinkIt7697" repeatedly and the demo video is:

The source codes are based on the previous tutorial of MAX7219 and we modify it for working with the dot matrix:

Explanation

When using MAX7219 with a dot matrix, the targets to be driven are columns, not digits. So we re-define the Digit data register to Column data register for better readability of the code:

And some basic properties of the matrix and data to be displayed are defined:

To display a bitmap, MAX7219 needs to be set to non-decode (raw data) mode for all columns:

and the code needs to update Column data registers for constructing a complete bitmap:

Due to a 4x8 bitmap is used on a 8x8 matrix, the code starts the updating position from column 2 to make the bitmap centered-aligned and updates data for BYTE_PER_MAP columns. Moreover, because 1 column consumes 1 byte data of the bitmap, when jumping to the next bitmap in the char_pattern array, the starting address of a different character would be a multiple of BYTE_PER_MAP.

Chained-matrix Example

MAX7219 supports to daisy-chain several MAX7219s to make one combined display. For chained MAX7219s, the data fed into the first IC would be output to the next IC after 16 cycles, which is the same cycle counts as the time consumed in sending one command. That's why it's called shift register: it takes 16 cycles to fill up the internal 16-bit data storage and starts to push bits out from the oldest bit in it when there are more data to be fed in. Therefore, for correctly sending commands to all chained MAX7219s, you need to send the command for the farthest node (from the main MCU) first and send the command for the nearest node last. Here is an illustrative animation for that:

In this video, 3 MAX7219s are used and it means total 16x3 = 48 cycles are needed to send commands to all MAX7219s. Initially, the LOAD pin is set to LOW and the command of node #2 (the farthest MAX7219) is sent in the first 16 cycles. For the next 16 cycles, the command of node #1 is sent and this makes the command of node #2 stored in node #0 pushed out and propagated to the next node. Finally, for the last 16 cycles, the command of node #0 is sent and the commands previously stored in node #0 and #1 are pushed to the final destination. After all commands are set to their correct position, the LOAD pin is set to HIGH and commands take effect for MAX7219 operations. This is the case where all MAX7219s need a new command and how the data flow is going. What if only one MAX7219 needs a new command and others don't need to change their states?

There is a special register called No-Op register with address 0 (ref: table 2 in the datasheet) is defined in MAX7219. When the LOAD pin is set to HIGH and MAX7219 receives a No-Op command, it will do nothing and its internal states won't be changed. Here we show another animation which deals with this case: only node #1 takes a new command and rest of the nodes on the chain keep un-touched.

In the following chained-matrix example, we extend the previous 1-matrix example to a 5-matrix configuration. And use the No-Op command to display the same pattern on each 8x8 dot matrix sequentially as in the 1-matrix example:

Hardware Setup

The DOUT pin of each module is connected to the DIN pin on the next module. For rest of the pins, they are wiring to the counterpart on the next module.

Based on the source of the 1-matrix example, some modifications are made to support the chained matrices. First, the No-Op command is defined:

And for updating commands to all chained MAX7219s, the set_register() API is extends to set_all_register() (all MAX7219 is set to the same command) and set_single_register() (only one MAX7219 receives a new command and others don't):

By using this 2 APIs to replace the set_register() API used in the 1-matrix example, the complete example is shown below:

This example uses 5-matrix configuration and you can use a different number of matrices to run this example by modifying the definition in Line 34:

Recap

  • For commands applied to all MAX7219s, use the set_all_registers() API. Like the case in init_max7219() and clear_matrix().

  • For commands only applied to a specific MAX7219, use the set_single_register() API. It will keeps rest of the matrices un-touched.

Scrolling-string Example

With the basics mentioned above, the last example is further extended to give a demonstration about how to use 5 matrices to do a commonly-seen scrolling string effect:

The complete sketch codes of this example are:

Summary

Accompanying with the previous 7-segment display tutorial, this tutorial gives a complete view of different MAX7219 applications. Not only to dive 7-segment displays, the non-decode mode can also be used to drive multiple LEDs or a LED matrix. By using a shift register like MAX7219, the control and wiring complexities of building a LED display application can be greatly reduced.

Last updated