For my current project, the ICMI Service Status Monitor, I have chosen the Maxim MAX7219 IC to drive the indicator LEDs. This little chip comes with several nice out of the box features such as adjustable LED current, 16 level brightness control, special decode mode for seven segment displays and so on. The main reason I chose it is because it contains a multiplex scan mechanism implemented in hardware. This frees my own code from a lot of additional complexity that I would encounter if I chose to implement multiplex scanning in software (which is not impossible of course and I’ve already done it – check the code samples for my ICMI Seven Segment Board – but it’s nice not having to do it and besides that, the focus of this projects lies more on the PC/Arduino communication).
The downside of using the MAX7219 is the more complex communication with the chip required to make things work. The IC uses various registers to store its configuration state and when sending data, you also have to address the proper register and pass the data in a format specified in the data sheet. To make things easier, I chose to implement this communication in form of an Arduino library that makes using the MAX7219 a whole lot easier by hiding the complexity behind a neat API. Others have implemented such a library before more of course and some of them also offer additional functionality such as multi-chip configuration or CODE B digit decoding. I do not intend to compete with them (at least not yet), I merely took the opportunity of extending my skills.
This section describes the methods available to the user when importing this library. Again: don’t get confused by the uint8_t data type – it is the same as byte in Arduino and can hold an integer value between 0 and 255.
Constructor Max7219(uint8_t dataPin, uint8_t clockPin, uint8_t loadPin, uint8_t digitCount)
This constructor is used to create a new “control instance” for the connected MAX7219 chip. The IC required 3 Arduino pins – the data pin, the clock pin and the load pin (pins 1, 13 and 12 of the MAX7219) that you need to pass to the constructor. In addition, you have to tell it, how many digits (when using seven segment displays) or rows (that’s what we want) are connected to the driver. This value is used internally to verify the parameters of later method calls. Example (Arduino connected with pins 5, 6 and 7):
* This is the MAX7219 control instance that this sketch will use
* to communicate with the LED driver. Configures the library to
* use 4 digits/rows.
Max7219 max7219(5, 6, 7, 4);
Method void enable(boolean enable)
The whole LED driver can be shutdown by disabling it. All its settings and the current state are preserved, the chip just ceases to operate. After a power reset, the chip is disabled by default so you will need to call max7219.enable(true) (assuming the control instance was constructed with the name max7219 as in the constructor example above) if you want it to show something. If you omit this call, all your configuration commands will still configure the chip but you simply won’t see it. Enabling and disabling the driver can also be used to flash the whole display.
Methods void setDigitRaw(uint8_t which, uint8_t value) / void setRow(uint8_t which, uint8_t value)
These two methods are actually only one method with two names. I introduced these names so a user could call whichever method best fits in the context of his program. If your program controls a LED matrix, calls to setDigitRaw() might seem a little strange so you could use setRow() instead.
This is the method that actually tells the driver what to display. You have to specify the index of the row/digit that you want to set (ranging from 0-7, limited by the row/digit count you gave in the constructor) and the value you want to set it to. To make things easier, the method performs a bit level translation of the value from your value to what the MAX7219 expects. This way, the bit order equals the segment or column order. Bit 0 (the rightmost bit, also called the least significant bit) corresponds to segment A (column 1), bit 1 corresponds to segment B (column 2) and so on. To display the number 7 on the fourth digit of a seven segment display, you would pass 3 as the index and B00000111 (segment A-C lit).
Although the MAX7219 supports it, the library currently does not offer a way to pass a BCD number to the chip. When using BCD mode, you could display a 7 by actually passing a 7 as value and the chip will take care of the decoding to segments. This feature may be included in future releases. The current lack of this feature is the reason why this method is called setDigitRaw() and not just setDigit() .
Method void setIntensity(uint8_t level)
The MAX7219 offers a built-in brightness control for the display with a 16 step resolution. This method allows you to set the brightness level for the display and accepts value from 1 (darkest) to 16 (brightest). Any value below 1 will be treated as 1, any value above 16 will be treated as 16. It is not possible to switch off the display, even the darkest setting is still visible and does not stand for “off”. If you want to turn of the display, call enable(false) instead. The constructor will set the chip to the highest brightness. This is a sort of safety precaution I created, because the IC’s initial brightness setting defaults to the lowest level. During testing, I wrecked my head trying to figure out why the LEDs were so dim, not realising the brightness settings. For others to avoid this mistake, I reversed the default brightness value in my library implementation.
Method void testDisplay(boolean testDisplay)
This method can be used to toggle the internal test mode of the MAX7219 on and off. When enabling test mode, the IC switches on all LEDs (regardless of the row/digit count passed to the constructor) and sets brightness to maximum. Enabling the test mode will not overwrite any settings made before entering the test mode, which means when switching back to normal mode, the display will revert to the exact setting that it hade before entering test mode. This method is useful for verifying your LED display and to be able to quickly switch to a fully lit LED panel without having to change each row and saving the state of the display in order to return to that state later.
Method void clearDisplay()
This method does exactly what the name promises: it clears the display by turning all LEDs in all rows off. This operation cannot be undone, that means once you clear the display, you have to reprogram it again, you cannot simply switch back to a previous state.
Method uint8_t version()
In order to provide some hint to a users program regarding the compatibility of the library, this method returns the current version number of the library. This can be used to check programmatically, if the user needs to update to a newer version and it can be used to prevent incompatibility issues.
Using the library
Using this library for your own projects is a two-step process. First, you need to install the library to your Arduino IDE and then you need to import it into you sketch.
Installing the library to the Arduino IDE
Use a file manager to navigate to the directory where your Arduino IDE resides (e.g.
D:\Development\Arduino-1.0). Go into the folder called
libraries and create a new folder there called
ICMIMax7219. Copy the
.h files as well as the examples folder into the newly created directory. If your IDE was running at that time, you have to restart it for the changes to take effect. After the restart, go the
File => Examples menu. If everything succeeded, you should see and entry called
ICMIMax7219 and you can open the
BasicFunctionExample from there.
Note: If you have another library for the MAX7219 installed, you may encounter naming clashes when the files of the other library are also named
Max7219.*. When encountering this, remove the other MAX7219 library from your Arduino IDE. I will address this problem in the second release of the library.
Using the library in your code
To use the library in your own sketch, you need to import the header file. Do this by placing the line
at the very top of your sketch. This enables you to access the libraries functionality. In order to do so, you need to create an instance of the Max7219 class somewhere in you project. You can do this by calling the constructor as follows
* the number of the Arduino pin that is connected to the data in pin
const uint8_t PIN_DATA = 5;
* the number of the Arduino pin that is connected to the clock pin
const uint8_t PIN_CLOCK = 6;
* the number of the Arduino pin that is connected to the load pin
const uint8_t PIN_LOAD = 7;
* The number of LED rows/digits connected to the MAX7219.
const uint8_t ROW_COUNT = 8;
* This is the MAX7219 control instance that this sketch will use
* to communicate with the LED driver.
Max7219 max7219(PIN_DATA, PIN_CLOCK, PIN_LOAD, ROW_COUNT);
First, the example defines some integer constants to represents the Arduino pins the IC is connected to and the digit/row count. The last line then creates an instance with the name
max7219 which can subsequently be used to control the IC with calls like
In order to see a full, working sketch that uses the library, please refer to the
BasicFunctionDemo sketch in the examples folder. The video embedded at the start of the post shows you what the output of this sketch will look like on an 8×8 LED matrix.