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 the 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 ... Loop End ... Pcint2_isr: If Second_interrupt = 0 Then New_second = 1 If Dcf_interrupt = 0 Then Time_dcf = 0 Return
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 Spiinit ... ' 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 ================================================================= Init_display: ' 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 Return
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.