An ongoing question on many Arduino forums is how to modify software to suit the different types of matrix modules available. Usually the poster has tried some LED matrix software and the display is reversed or upside down, or animations are disjointed across the module boundaries.
There are clear reasons this happens, and the Parola library has software configuration parameters that allow you to adapt how the software operates to suit your hardware module.
Why is there a problem?
The first thing to understand is why there is a problem at all.
The MAX7219 control IC was originally designed to control up to 8 digits of 7 segment display. Each digit has 7 LED segments (named a to g) and a decimal point (dp) connected through a common cathode. The MAX7221 does the same thing but with less EMI emissions. The IC multiplexes the display of the segments sequentially across all the digits to be displayed.
Basically, the IC capable of controlling 64 individual LEDs (8 digits x (7 seg + 1 dp)) and there are 64 LEDs in a LED matrix.
However, unlike the mapping to digits/segments, there is no standard mapping of the 64 LEDs to matrix rows and columns. So there are a number of hardware configurations that can (and do!) result, depending on how the hardware designer has wired up the MAX7219 to the LED module:
- ‘Rows’ can be wired as ‘digits’ or ‘segments’ increasing left to right or right to left
- ‘Columns’ can be wired as ‘segments’ or ‘digits’ increasing top to bottom or bottom to top.
So, any matrix can be physically wired so that the matrix orientation (in physical space) can have rows or columns in either direction and in any order. This means that writing a library like Parola, where the code must assume a standard coordinate system for it to work, requires a mapping between the physical pixels (LEDs) and this standard coordinate system.
A Brief Word on Coordinate Systems
Two Cartesian coordinate systems are used in the library. One defines the pixels seen (display coordinates), and the other is an underlying hardware coordinate system based on digits and segments mapping to the MAX72xx hardware control registers.
In Parola, display coordinates always have their origin in the top right corner of a display and by convention
- Column numbers (and therefore module numbers) increment to the left
- Row numbers (0..7) increment top to bottom
All user functions consistently use display coordinates to make animations independent of underlying hardware changes. It is the job of the hardware control library functions to map display coordinates to hardware coordinates.
Adapting the Library
The coordinate system mapping is a function of the hardware library (MD_MAX72xx). From the above discussion, the hardware library needs to know if
- ‘Digits’ are mapped to rows or columns. This also fixes ‘segments’ to the other axis.
- The order in which each axis is wired (up/down and left/right). A simplifying assumption (which has been valid so far!) is that the LEDs are wired sequentially and not in random order.
The MD_MAX72xx library needs to be informed of the the following parameters to direct the hardware coordinate mapping:
- HW_DIG_ROWS – set to 1 if MAX72xx digits are mapped to rows in the matrix
- HW_REV_COLS – set to 0 for normal orientation with col 0 on the right, set to 1 if reversed
- HW_REV_ROWS – set to 0 for normal orientation with row 0 at the top set to 1 if reversed
In practice, there seems to be four common types of matrix modules on the market, and so it is convenient to define ‘canned’ combinations for those matrix types:
- Parola style modules that are now manufactured as kits by ElectroDragon. The library was originally developed for this module type.
- Generic Modules commonly available from many suppliers (eg, eBay) at reasonable cost. They are characterized by IN and OUT connectors at the short ends of the rectangular PCB.
- ICStation kit module available as kits from ICStation.
- FC-16 modules identifiable by the FC-16 designation silk-screened on the PCB. Many of the ‘4-joined-up’ module systems are made up of individual FC-16 modules.
In MD_MAX72xx prior to version 3.0.0, the type of module being used for the library is defined by editing the appropriate #define in the MD_MAX72xx header file. For most users, this was be the only action necessary if they always used the same type of display module.
From version 3.0.0 onwards, the module type is specified in the application as one of the parameters to the class constructor. This eliminates the need to edit the library header file for the different module types.
Determining New Hardware Configurations
The library example code includes a utility called MD_MAX72xx_HW_Mapper. This test software maps display hardware rows and columns. It uses a generic SPI interface and only one MAX72xx/8×8 LED module is needed for testing.
It is independent of the libraries as the code is used to directly map the display orientation by setting pixels on the display and printing to the serial monitor which MAX72xx hardware component (segment and digit) is being exercised.
By observing the LED display and the serial monitor you can build a map like the one below. It is worth noting the direction in which the rows and columns are scanned by the utility, as this is the easiest way to work out the row/column reversal values.
The result of these observations is a grid definition that looks somewhat like:
DIG0 D1 D2 D3 D4 D5 D6 D7 Seg G Seg F Seg E Seg D Seg C Seg B Seg A Seg DP
From this example mapping it is clear
- MAX72xx digits map to the columns, HW_DIG_ROWS is 0.
- DIG0 is on the left (columns were also scanned left to right), so HW_REV_COLS should be set to 1 to reverse it to the standard 0 on the right.
- Seg G is at the top (rows were also top to bottom), so HW_REV_ROWS should be set to 0, as it is already standard with 0 on top.
Note that in some situations using the module ‘upside down’ will result in a better configuration than would otherwise be the case. An example of this is the generic module mapping. Also remember that the modules are daisy chained from right to left.
Having determined the values for the defines, the mapping can be matched to an existing hardware type or a new type defined.