Further testing the μController Display Module

In the last post, I was able to get the μController version of the display module working with a basic test routine that proved that 1. the controller could be programmed and 2. the display was being driven correctly. The next stage is to flesh this out to replicate the MAX2771 API. The purpose here is not to simply create a duplicate of the MAX2771 which does a great job on its own. This approach means that I can re-use the code I created for the MAX2771 display module project. The additional goal of this small project was to gain experience in creating a SPI slave! Interfacing with the MAX2771 was simple since that is already a SPI slave unit. All I needed was to just create the master.

Connecting things together

I still have things set up from the previous tests so it was just a matter of connecting things back up again. Though this time I had two units to program instead of just one. I still have the main controller board for the clock to complete so I used the myAVR Dev board as a provisional main controller. Luckly, the myAVR dev board comes with its own programmer. I had to program this via the myAVR ProgTool since the BASCOM-AVR IDE was in use with programming the display module via the AVRISP mkII. It sounds more awkward than what it turned out to be. The part that was awkward was that the AVRISP mkII had trouble programming the display module while the SPI connection was still made to the myAVR dev board (my provisional mainboard). I had to disconnect the /SS, MOSI and CLK from the display module before being able to program. This would be a point of research to work out what is involved to be able to program the display module while still connected!

μControlled Display Driver Integration Test
μControlled Display Driver Integration Test

Once the infrastructure of programmers and connections was sorted, it was just then a matter of piecing together the code to enable the slave unit to start servicing the requests of the master i.e to start displaying the time. With the Real Time Clock still connected (via an I2C bus) I had a neat source of test data.

Getting thing up and running was rewarded with a red blinking LED on the dev board. This was my signal that the communication with the Real Time Clock was functioning. The next was the display module itself.To keep things simple,  I am opting to use the basic BASCOM constructs for SPI. The logic analyzer was useful for seeing that the SPI messages were being sent. Though my particular logic analyzer only shows that there was activity. It lacks the sophistication of being able to see exactly what was being sent. Thankfully, I have been able to get things working without that level of sophistication.


Creating the Slave

Dim Rbit As Bit
Config Pinb.4 = Output                    ' MISO
Config Spi = Hard , Interrupt = On , Data Order = Msb , 
       Master = No , Polarity = Low , Phase = 0 , Clockrate = 128

On Spi Spi_isr Nosave

Enable Timer0
Enable Timer1
Enable Interrupts

The snippet above shows how the slave was defined. Basically I used the same construct in the master. The “Master = yes” property is the only difference. Once data is available for the slave to read, the spi_isr interrupt routine is executed. Here I just grab the data into a Regisiter array. The API I was wanting to implement was to read a two byte command i.e. a register address and then a value. I was not sure on how this is to be done since BASCOM-AVR documentation only really talks about receiving one byte at a time for slave. In comparison, sending multiple bytes from the master is not difficult at all.

   PUSH r24    ; save used register
   IN r24, SREG; save SREG
   PUSH r24
   Set Rbit                         ' we received something
      If Spi_idx = 0 Then
         Idx = SPDR
         Set Spi_idx
         Register(idx) = SPDR
         Reset Spi_idx
      End If
   POP r24
   !OUT SREG, r24 ; restore sreg
   POP r24       ; and the used register

Here I had a variable to track which element of the command was being received spi_idx. When reset, then the first value from the master is expected and therefore that value is recorded as an index value i.e the register address. When spi_idx is set, then it is expected that the value from the master is the register value and that is then directly recorded in the Register array.

With the register address and value for the register obtained from the master, then it was a matter of interpreting the newly arrived information. I implemented this using a case construct.

   If Spi_idx = 0 Then
      Select Case Idx
         Case Hours_10:
            Digits(1) = Register(idx)
         Case Hours_unit:
             Digits(2) = Register(idx)
         Case Minutes_10:
            Digits(3) = Register(idx)
         Case Minutes_unit:
            Digits(4) = Register(idx)
         Case Colon:
            Digits(5) = Register(idx)
         Case Indicators:
            Digits(6) = Register(idx)
         ' Case Intensity:
         ' Case Power_mode:
         Case Digit_blink:
             Blink_mask = Register(idx)
         ' Case Blink_rate:
         Case Test_mode:
            If Register(idx) = Enabled Then
               Digits(1) = 8
               Digits(2) = 8
               Digits(3) = 8
               Digits(4) = 8
               Digits(5) = 8
               Digits(6) = 8
               Digits(1) = 0
               Digits(2) = 0
               Digits(3) = 0
               Digits(4) = 0
               Digits(5) = 0
               Digits(6) = 0
            End If
         Case Else
      End Select
      End If
   End If

The idea here is to simply  react if there is a new value arrived. Based on the value of idx (the register address) to then assign the value from the register to a variable that will result in the desired behaviour. i.e. setting a digit value etc.

One feature I have implemented that is not part of the MAX2771 API is a Blink feature. i.e. to enable a digit or colon to blink. I managed this with a mask with one bit for each element of the display. This seems to work quite well.

   Timer0 = Timer0_count
   Incr Position
   If Position > 5 Then
      Position = 0
   End If

   Digit = Position + 1
   PORTD = &H0A          ' Set all segments off
   PORTC = Makebcd(position)

   Blink_test = &B00000001
   Shift Blink_test , Left , Position
   Blink_test = Blink_test And Blink_mask
   If blink_flag = 1 and blink_test > 0 Then
      Value = Digit_off
      Value = Digits(digit)
   End If
   PORTD = Value

Next Steps

The μController version of the display module is working, I have to admit, in principle. There is still a bit more work to do to clean up its behaviour and possibly implement more tests and features i.e. the indicators on the top and bottom left of the display.

The actual main board still needs to be done. This will be presented in future posts. There are some considerations to be done with that in terms of its physical size for the existing casing. Another task that is outstanding is the interfacing of the Real Time Clock with SPI rather than I2C. I have been using I2C since that is what I used on the very first trial. My goal is to have a multiple slave SPI implementation. This too can be prototyped with my current set up before finalising on the actual main controller board.

The advantage I have with the current approach is that the firmware for the main board is progressively being done with the testing of the modules. It is just missing the implementation of the various push buttons. Even this can be implemented in the myAVR Development board.


Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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