MAX7221 Driven Display Module

It is now time to put some theory into action. This entry will talk about the implementation of the clock display module driven by the MAX7221. This chip was selected for the first version of the display module as it provided a one-stop solution for driving seven segment displays. It also SPI compatible and provided some additional features like program selectable intensity.
The assembly of the board went without any issues. In a previous blog, I had calculated a Rset as 50KΩ in order to limit the segment current to 10mA. In the end, I only used what I had on-hand, so I used a 56KΩ. I was unsure about this and prepared to change the resistor if the intensity was not adequate.


Once assembled, the display module was connected to the myAVR development board that I am using. I used ATMega88-PinOutthe pre-defined pins for the SPI interface. From a previous test, the Real Time Clock (RTC) was connected with the I²C interface, also using the pre-defined pins. To keep thing simple for this test, I left this the way it was. Even though, in the final implementation, i will be using SPI for both the RTC and the display module.

The RTC is driven by 3.3V and therefore needs a couple of level shifters (shown in the photo) to convert the 5V signal to the 3.3V. I already had those on-hand from previous trials.



With everything connected and double checked, it was time to start creating some code. This would  be my first attempt at programming the SPI so I was a bit unsure how it would go. The RTC and I²C was a known quantity so I decided to start with that first and create a heart-beat pulse. This would prove that the program is being written to the micro controller correctly and that the basic infrastructure was in place.

This was achieved by configuring the Pin Change Interrupt (PCINT) 16 and 17 for the one second pulse and the DFC complete signal respectively. The one second pulse enables the micro controller concentrate on orchestrating the information between the RTC and display module and does not have to implement any internal timers. This also means I don’t need any special crystal circuitry for additional accuracy. PCINT16 and PCINT17 are part of the Pin Change Mask Register 2 (PCMSK2) at bits 0 and 1 of the mask register. The set up for these is shown in BASCOM below. In this case, PORTB.0 is configured to be connected to the LED to provide the heart-beat.

On Pcint2 Pcint2_isr
Pcmsk2.0 = 1 ' PCINT16 - 1 Second pulse
Pcmsk2.1 = 1 ' PCINT17 - DCF message

Enable Pcint2
Enable Interrupts


Config Pind.0 = Input
Second_interrupt Alias Pind.0
Dim New_second As Bit

Config Pind.1 = Input
Dcf_interrupt Alias Pind.1

Config Portb.0 = Output
Heartbeat Alias Portb.0


Do ' Main control loop


 If Second_interrupt = 0 Then New_second = 1
 If Dcf_interrupt = 0 Then Time_dcf = 0

For the full source, see the GitHub repo for simpleCheck.bas

The MAX7221 was programmed first by setting up the SPI interface, using the config spi instruction. Before the main control loop, the initialisation subroutine is called. This sets the initial parameters for the MAX7221 and also runs a two second lamp check. The MAX7221 can drive up to 8 digits. I am technically only using four digits, so in order to avoid any flicker on the display, the duty cycle needs to be configured not drive the digits that are not needed. In actual fact,  from the original design, I am using 6 digits. The segments A and B of the fifth and sixth digits are used for the colon and indicators respectively.

Config Spi = Hard , Master = Yes , Data_order = Msb

' Display

Const Intensity_register = &H0A
Const Intensity_max = &H0F
Const Intensity_med = &H07
Const Intensity_min = &H00

Const Shutdown_register = &H0C
Const Normal_mode = &H01

Const Display_test_register = &H0F
Const Display_test_on = &H01
Const Display_test_off = &H00

' Scan Lmit 0xXB
Const Scan_limit_addr = &H0B
Const Scan_limit_value = &H05 ' Display digits 0 1 2 3 4 5

' Decode mode 0xX9
Const Decode_mode_addr = &H09
Const Decode_mode_value = &H0F ' Code B decode for digits 3-0 No decode for digits 7-4

Const Digit1_addr = &H01
Const Digit2_addr = &H02
Const Digit3_addr = &H03
Const Digit4_addr = &H04
Const Colon_addr = &H05
Const Signal_addr = &H06

Dim Spi_data(2) As Byte


Gosub Init_display


' Subroutines =================================================================


' Put the MAX7221 into normal operation mode.
   Spi_data(1) = Shutdown_register
   Spi_data(2) = Normal_mode
   Spiout Spi_data(1) , 2

' Run the test mode for 2 seconds.
   Spi_data(1) = Display_test_register
   Spi_data(2) = Display_test_on
   Spiout Spi_data(1) , 2

   Wait 2

   Spi_data(1) = Display_test_register
   Spi_data(2) = Display_test_off
   Spiout Spi_data(1) , 2

' Set the display intensity to maximum
   Spi_data(1) = Intensity_register
   Spi_data(2) = Intensity_max
   Spiout Spi_data(1) , 2

' Set the scan limit i.e. the number of digits to support
   Spi_data(1) = Scan_limit_addr
   Spi_data(2) = Scan_limit_value
   Spiout Spi_data(1) , 2

' Set the decode level - which digits to be treated as
' numbers and which will be custom driven
   Spi_data(1) = Decode_mode_addr
   Spi_data(2) = Decode_mode_value
   Spiout Spi_data(1) , 2

' Turn off the indicators
   Spi_data(1) = Signal_addr
   Spi_data(2) = 0
   Spiout Spi_data(1) , 2

' Turn off the colon
   Spi_data(1) = Colon_addr
   Spi_data(2) = 0
   Spiout Spi_data(1) , 2


Setting the device into normal operation was the real trick. Before I did that, it remained in an off state. So by default, it is configured to be in a shutdown mode. I had mentioned I was concerned about the resistor and the intensity of the display. It turns out that the 56KΩ is more than adequate, in fact, I can imagine that in the final implementation, a lower intensity will be required.

With the heart-beat functioning and the correct initial values being displayed, then it was only a matter of waiting for the RTC to receive its DCF77 signal for the correct time to be displayed. This eventually occurred after a minute or so. Then I started with the enhancements such as driving the colon also from the heart-beat pulse.


In conclusion, since the assembly and testing went largely without any issues, I can only sing the praises for the MAX7221. Though it is quite pricey, it certainly saves time and space for any other type of display driver. I am now curious about the next driver I intend to trial where I have to create my own firmware.

One extra thought I have is regarding the layout of the board. For this board the SPI pin header is in the bottom right hand corner. For the next board I will be working on, for no good reason, the SPI pin header is in the middle. It would have made more sense to make them compatible so that I could also be working on the main board and then interchange the display modules as needed. Hind-sight is a wonderful thing.


One thought on “MAX7221 Driven Display Module

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s