A driver to control one or more MAX7219 / MAX7221 serially interfaced, 8-Digit, LED Display Drivers
MAX7219 / MAX7221 devices are controlled via Serial Peripheral Interface (SPI) and can be cascaded. Follow these steps to use the driver:
spi_bus_initialize()
. Most applications choose SPI2_HOST
however other hosts should work,led_driver_max7219_init()
and providing the number of devices, desired SPI frequency … ,led_driver_max7219_set_xxx
or led_driver_max7219_configure_xxx
functions:
led_driver_max7219_set_chain_mode()
/ led_driver_max7219_set_mode()
to configure the device mode,led_driver_max7219_configure_chain_decode()
/ led_driver_max7219_configure_decode()
to configure decode mode,led_driver_max7219_set_chain_intensity()
/ led_driver_max7219_set_intensity()
to change display intensity,led_driver_max7219_configure_chain_scan_limit()
/ led_driver_max7219_configure_scan_limit
to configure scan limit.led_driver_max7219_set_chain()
/ led_driver_max7219_set_digit()
/ led_driver_max7219_set_digits()
to set all / one / n digits on the chainled_driver_max7219_free()
and optionally shut down the SPI master with spi_bus_free()
.Before using any led_driver_max7219_xxx
function, an SPI master needs to be initialized. This can be achieved as follows:
// SPI Host ID
const spi_host_device_t SPI_HOSTID = SPI2_HOST;
//
// GPIO pins to use for SPI
// NOTE: For maximum performance, prefer IO MUX over GPIO Matrix routing
// * See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html#gpio-matrix-routing
//
const gpio_num_t CS_LOAD_PIN = GPIO_NUM_19;
const gpio_num_t CLK_PIN = GPIO_NUM_18;
const gpio_num_t DIN_PIN = GPIO_NUM_16;
spi_bus_config_t spiBusConfig = {
.mosi_io_num = DIN_PIN,
.miso_io_num = GPIO_NUM_NC,
.sclk_io_num = CLK_PIN,
.data2_io_num = GPIO_NUM_NC,
.data3_io_num = GPIO_NUM_NC,
.max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE,
.flags = SPICOMMON_BUSFLAG_MASTER,
.isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI_HOSTID, &spiBusConfig, SPI_DMA_CH_AUTO));
We initialize SPI2_HOST
as SPI master (SPICOMMON_BUSFLAG_MASTER
) and request ESP-IDF to automatically choose the DMA channel (SPI_DMA_CH_AUTO
).
Next, we initialize the MAX7219 / MAX7221 driver by specifying the SPI master host we just initialized, clock source, frequency (MAX7219 / MAX7221 support a maximum of 10MHz), SPI queue size and chain length. The chain length defines how many physical MAX7219 / MAX7221 devices are cascaded via the DOUT
pin. See data sheet for more information on cascading MAX7219 / MAX7221 devices and for sample schematics. The driver currently supports a maximum of 255 cascaded devices in a single chain. The field .chain_length
must be a uint8_t
in the range [1..255].
// Number of devices MAX 7219 / 7221 in the chain
const uint8_t ChainLength = 3;
// Handle to the MAX 7219 / 7221 driver
led_driver_max7219_handle_t led_max7219_handle = NULL;
max7219_config_t max7219InitConfig = {
.spi_cfg = {
.host_id = SPI_HOSTID,
.clock_source = SPI_CLK_SRC_DEFAULT,
.clock_speed_hz = 10 * 1000000,
.spics_io_num = CS_LOAD_PIN,
.queue_size = 8
},
.hw_config = {
.chain_length = ChainLength
}
};
ESP_ERROR_CHECK(led_driver_max7219_init(&max7219InitConfig, &led_max7219_handle));
The driver allows users to control all MAX7219 / MAX7221 devices on the chain at once or control a specific MAX7219 / MAX7221 device. Functions named led_driver_max7219_chain_xxx
(aka led_driver_max7219_set_chain_mode()
) operate on all devices at once while functions accepting a uint8_t chainId
(aka led_driver_max7219_set_mode()
) target a specific MAX7219 / MAX7221 device. The chain is one based. The first device in the chain has chainId = 1
, the second device chainId = 2
and so on.
A MAX7219 / MAX7221 device can operate in three distinct modes:
At power on, all MAX7219 / MAX7221 devices enter shutdown mode. The chain is typically configured (set scan limit, intensity, decode …) in shutdown mode. When one-time configuration is complete, MAX7219 / MAX7221 devices are then put in normal mode to display digits. Alternatively, MAX7219 / MAX7221 devices can be switched to test mode until there is data ready to display.
The mode of operation is configured as follows:
// Configure Normal mode for all MAX7219 / MAX7221 devices in the chain
ESP_ERROR_CHECK(led_driver_max7219_set_chain_mode(led_max7219_handle, MAX7219_NORMAL_MODE));
...
// Configure Normal mode for the second (2) MAX7219 / MAX7221 device on the chain
ESP_ERROR_CHECK(led_driver_max7219_set_mode(led_max7219_handle, 2, MAX7219_NORMAL_MODE));
There are three steps to turning on LEDs on a given MAX7219 / MAX7221 device:
uint8_t
describing which LED is on. This value is decode mode dependent.MAX7219 / MAX7221 devices support two different decoding modes:
Each MAX7219 / MAX7221 device controls up to eight groups of eight LEDs. These LEDs are typically arranged as eight digits each composed of seven segments and a decimal point as shown in the picture below:
However, LEDs can be arranged in any shape or form. Other popular arrangements include a matrix of 64 LEDs or Sixteen-segment displays. Each digit (a group of nine LEDs) can be configured for either Code-B or Direct Addressing.
The desired decode mode is set by combining (or’ing together) one or more MAX7219_CODE_B_DECODE_DIGIT_x
constant. For instance configure digit 1 and digit 3 for Code-B and all other digits for direct addressing with MAX7219_CODE_B_DECODE_DIGIT_1 | MAX7219_CODE_B_DECODE_DIGIT_3
. The following constants make it easier to configure all digits for Code-B or direct addressing:
MAX7219_CODE_B_DECODE_ALL
configures all digits as Code-B,MAX7219_CODE_B_DECODE_NONE
configures all digits as direct addressing.The code to configure decode mode is as follows:
// Configure Code-B decode for all digits on all MAX7219 / MAX7221 devices in the chain
led_driver_max7219_configure_chain_decode(led_max7219_handle, MAX7219_CODE_B_DECODE_ALL)
...
// Configure Code-B decode for digits 1, 2 and 5 on all MAX7219 / MAX7221 devices in the chain
led_driver_max7219_configure_chain_decode(led_max7219_handle, MAX7219_CODE_B_DECODE_DIGIT_1 | MAX7219_CODE_B_DECODE_DIGIT_2 | MAX7219_CODE_B_DECODE_DIGIT_5)
...
// Configure Code-B decode for digits 1, 2 and 5 on the second (2) MAX7219 / MAX7221 device on the chain
ESP_ERROR_CHECK(led_driver_max7219_configure_decode(led_max7219_handle, 2, MAX7219_CODE_B_DECODE_DIGIT_1 | MAX7219_CODE_B_DECODE_DIGIT_2 | MAX7219_CODE_B_DECODE_DIGIT_5));
The driver header file offers convenient constants for both Code-B symbols and direct addressing symbols:
MAX7219_CODE_B_0
to MAX7219_CODE_BLANK
. To enable the decimal point, combine a character with MAX7219_CODE_B_DP_MASK
as in MAX7219_CODE_B_0 | MAX7219_CODE_B_DP_MASK
MAX7219_SEGMENT_A
to MAX7219_SEGMENT_G
with MAX7219_SEGMENT_DP
as the mask for the decimal point,MAX7219_CUSTOM_0
to MAX7219_CUSTOM_BLANK
with MAX7219_SEGMENT_DP
as the mask for the decimal point.Once a decode mode has been chosen, symbol codes can be sent to the chain as follows:
// Assume Code-B decode for all digits and set digit 1 to 'E' on all on all MAX7219 / MAX7221 devices in the chain
ESP_ERROR_CHECK(led_driver_max7219_set_chain(led_max7219_handle, 1, MAX7219_CODE_B_E));
...
// Assume Code-B decode for all digits and set digit 1 to 'E' on the second (2) MAX7219 / MAX7221 device
ESP_ERROR_CHECK(led_driver_max7219_set_digit(led_max7219_handle, 2, 1, MAX7219_CODE_B_E));
...
// Assume direct addressing for all digits and set digit 1 to 'E' on all on all MAX7219 / MAX7221 devices in the chain
ESP_ERROR_CHECK(led_driver_max7219_set_chain(led_max7219_handle, 1, MAX7219_DIRECT_ADDRESSING_E));
...
// Assume direct addressing for all digits and set digit 1 to 'E' on the second (2) MAX7219 / MAX7221 device
ESP_ERROR_CHECK(led_driver_max7219_set_digit(led_max7219_handle, 2, 1, MAX7219_DIRECT_ADDRESSING_E));
It is also possible to set several digits across one or more devices on the chain as follows:
const uint8_t symbolsCount = 5;
const uint8_t symbols[] = { MAX7219_DIRECT_ADDRESSING_H, MAX7219_DIRECT_ADDRESSING_E, MAX7219_DIRECT_ADDRESSING_L, MAX7219_DIRECT_ADDRESSING_L, MAX7219_DIRECT_ADDRESSING_0 };
// Assume direct addressing for all digits and display 'HELL0' starting at digit 3 of the second (2) MAX7219 / MAX7221 device
ESP_ERROR_CHECK(led_driver_max7219_set_digits(led_max7219_handle, 2, 3, symbols, symbolsCount));
Finally, a specific segment / LED can be turned on as follows:
// Assume direct addressing for all digits and turn on segment 'A' and decimal point on all MAX7219 / MAX7221 devices in the chain
ESP_ERROR_CHECK(led_driver_max7219_set_chain(led_max7219_handle, 1, MAX7219_SEGMENT_A | MAX7219_SEGMENT_DP));
MAX7219 / MAX7221 devices allow LEDs brightness control. The brightness is always set for all LEDs and is a two-step operation:
The driver enables digital brightness control. Digital display intensity can be changed at any time. It is also possible to create a fade effect by reducing or increasing intensity over a short period of time. Intensity PWM is programmatically controlled as follows:
// Configure PWM to 2/16 for all MAX7221 devices in the chain
ESP_ERROR_CHECK(led_driver_max7219_set_chain_intensity(led_max7219_handle, MAX7219_INTENSITY_DUTY_CYCLE_STEP_2));
...
// Configure PWM to 5/32 for the second (2) MAX7221 device on the chain
ESP_ERROR_CHECK(led_driver_max7219_set_intensity(led_max7219_handle,2, MAX7219_INTENSITY_DUTY_CYCLE_STEP_3));
MAX7219 / MAX7221 devices allow configuring how many digits are displayed from 1 to 8. If the scan limit is set for three digits or less, individual digit drivers will dissipate excessive amounts of power. Consequently, the value of the RSET resistor must be adjusted according to the number of digits displayed, to limit individual digit driver power dissipation. Scan limit should not be used for leading ‘0’ suppression. Refer to the data sheet for additional information.
It is possible to configure scan limit per device on a chain. However, the data sheet recommends configuring all MAX7219 / MAX7221 devices with the same scan limit.
Scan limit can be configured as follows:
// Configure scan limit to 4 digits for all MAX7221 devices in the chain
ESP_ERROR_CHECK(led_driver_max7219_configure_chain_scan_limit(led_max7219_handle, 4));
...
// Configure scan limit to 4 digits for the second (2) MAX7221 device on the chain
ESP_ERROR_CHECK(led_driver_max7219_configure_scan_limit(led_max7219_handle, 2, 4));
MAX7219 / MAX7221 devices include a test mode. In test mode, all LEDs are turned on by overriding, but not altering, all controls and digits (including the shutdown mode). In test mode, 8 digits are scanned and the duty cycle is 31/32 (15/16 for MAX7221).
Test mode can be entered as follows:
// Configure Test mode for all MAX7219 / MAX7221 devices in the chain
ESP_ERROR_CHECK(led_driver_max7219_set_chain_mode(led_max7219_handle, MAX7219_TEST_MODE));
...
// Configure Test mode for the second (2) MAX7219 / MAX7221 device on the chain
ESP_ERROR_CHECK(led_driver_max7219_set_mode(led_max7219_handle, 2, MAX7219_TEST_MODE));
All driver functions are thread safe with the exception of led_driver_max7219_init()
and led_driver_max7219_free()
. Internally, each instance of the driver has a global semaphore which is acquired after validating arguments and before accessing any SPI function.
The driver supports multiple instances of led_driver_max7219_handle_t
. Currently, all led_driver_max7219_handle_t
instances must be accessed by the same FreeRTOS task.
Several samples are located under examples
. This section lists samples and capabilities demonstrated. Refer to a sample README.md
file for more details.
max_7219_7221_basic
demonstrates how to initialize, configure a single MAX7219 / MAX7221 device and display symbols. This is a good starting point for new users,max_7219_7221_cascade
demonstrates how to initialize, configure a chain of three MAX7219 / MAX7221 cascaded devices and display symbols,max_7219_7221_decode
demonstrates how to initialize, configure a single MAX7219 / MAX7221 device and set per digit decode mode,max_7219_7221_intensity
demonstrates how to control display intensity,max_7219_7221_scanlimit
demonstrates how to control scan limit (how many digits are active on a given MAX7219 / MAX7221 device),max_7219_7221_temperature
demonstrates how to display the current ESP32 device temperature, minimum and maximum,max_7219_7221_testmode
demonstrates how to control test mode.