Wrapping up the Alarm Clock Project

It has been a long while since the last post. Amongst other things, the clock has been a work-in-progress. Each time I made some progress, I found some new reason to create a revision. The initial revisions where based on issues and oversights. I am finding that as the project matures, the nature of the revisions are changing. Earlier on I was focused on just seeing things working i.e. how to program the micro with the ISP, how to get the modules to communicate. The earlier boards were either bound to the original dev-board, bread board or both. Now, I have the display module and the main-board untethered from the bread board and they are happily working with each other. Each step of the way I learn something new and those earlier issues are no longer the obstacles that they were. So much so that the problems and challenges I face now are more functional and mechanical.

I now have a basic board layout for the controller and the display that I am happy to progress with. These are certainly not the cheapest options, but as I may have mentioned before, they offer a way for me to learn about and demonstrate inter processor communication as well as dealing with multiple voltages in the one application. My focus now was to get the job finished. I see two basic challenges. 1. Getting everything into the case and 2. Getting the alarm working!

Low Profile 7-Segment Display

img_0268e

The seven segment displays I had been using would not allow me to mount the display in the case. It was time to search for a better solution. I discovered some thin profile seven segment displays. They are perfect for the job, though they are a bit tricky to solder since they do not have any leads. I worked around that with a piece of lead wire inserted in two of the holes in my board. This enabled my to apply light pressure on the display in the direction of the leads to hold them firm in position for soldering. Then allowed all the displays to be identical.

Alarm

The alarm buzzer then became my biggest challenge and something new to learn about.The clock originally had a Piezo buzzer. Since the goal is to restore the clock, I was hoping to use a Piezo again. However the results from testing were not what I had expected. It was really difficult to get any sort of appreciable sound. Admittedly, the simple Piezo need to be properly mounted in order to resonate correctly. This I could not really achieve with my test set-up.

Testing the Piezo and looking generally at buzzers was opening up a new avenue of concepts to learn. I found the theory simple enough and meant I still had some design decisions to make. The first thing was to understand what direction to take. Since this was new territory, I saw no other avenue but to order some different types and just try them out. The basic criteria I set was capable of handling at least 5V and in around the 90dB range. I have to admit, I had no idea what 90dB was going to give me.

Description Manufacturer Part Number Digi-Key part Number
Zero-Peak Signal Buzzer Single Tone 2.67kHz Magnetic 0~5V 88dB @ 3V, 10cm TDK Corporation CSQG703BP 445-4832-1-ND
Zero-Peak Signal Buzzer Single Tone 2kHz Magnetic 2~4V 85dB @ 3V, 5cm CUI Inc. SDR08540M3-01 102-1286-ND
Zero-Peak Signal Buzzer Single Tone 2.4kHz Magnetic 3~8V 87dB @ 5V, 10cm CUI Inc. CT-1205-SMT-TR 102-1199-1-ND

In choosing, I had the choice to use a device that need no external driver or to drive the buzzer myself. I opted for the second to also learn how to integrate the PWM feature of the micro into the solution. In testing the buzzers, I could mount the CSQG703BP directly on my bread board. For the other two I created a (rough) test harness and used a Gabotronics Xminilab as my signal source – I don’t possess a bench signal generator yet.

img_0270e

The CSQG703BP tested OK but the tone was quite weak. I could not get a tone out of the SDR08540M3-01 at all but that could be related to the set-up I had. Although the  CT-1205-SMT-TR was quite bulky in comparison to the others, it delivered the best results.

I made the final revision to the board to take the CT-1205-SMT-TR on the underside over the place where the Piezo was originally. The case had a moulding that gave more than enough space for this part, so I was lucky there.

In “bringing up” the buzzer, I had to learn about PWM control and what that meant. I created a test program to only operate the buzzer and not worry about the whole clock functionality yet. In the end I thought it would be cute if the alarm would not simply make the traditional chirps but send  the message “WAKE UP” in Morse code.wakeup

Buzzer Alias Portb.1
Config Buzzer = Output
' CTC-Mode for ~ 2.5kHz
Config Timer1 = Timer , Compare A = Toggle , Prescale = 1 , Clear Timer = 1

Const Timer0_startvalue = 100                               ' 0.001 seconds
Config Timer0 = Timer , Prescale = 64
Timer0 = Timer0_startvalue
On Timer0 Timer0_isr
Enable Timer0
Start Timer0
Enable Interrupts

Heartbeat Alias Portc.3 ' LED indicator
Config Heartbeat = Output : Heartbeat = 0
Const Tone_pitch = 200

Dim Tone As Byte
Dim Tone_length As Integer
Dim Tone_idx As Byte
Dim Song(40) As Byte
Dim Songlen As Byte
Dim Song_finished As Bit

Const Base_length = 7

' Load the song - Songlen should be used to know the length afterwards.
Wait 5
Songlen = 0
Restore Melody
Do
   Read Tone
   If Tone <> &HFF Then
      Incr Songlen
      Song(songlen) = Tone
   End If
Loop Until Tone = &HFF
Tone_length = 1

' A wake up signal. Illuminate the LED for one second.
Set Heartbeat
Wait 1
Reset Heartbeat

' Play the "song" every 10 seconds
Do
   If Song_finished = 1 Then
      Wait 10
      Tone_idx = 0
      Reset Song_finished
   End If
Loop
End

Buzzer_on:
   Compare1a = Tone_pitch
   Tccr1a.6 = 1
Return

Buzzer_off:
   Tccr1a.6 = 0
Return

' ISR for timer 0. This will traverse the "melody" playing each tone, and pause
' in turn until the end of the song.
' The Melody is a series of data values. Since there is only one tone from the 
' buzzer, only the length is given. There is a base length and the tone length is
' a multiple of that. Basically this comes from Morse code that the dots are three
' units long and the dashes are seven. Anything greater than &H80 is considered 
' a pause.
Timer0_isr:
   Timer0 = Timer0_startvalue
   If Tone_length > 0 Then
      Decr Tone_length
      If Tone_length <= Base_length Then
         Gosub Buzzer_off
      End If
   Else
      Toggle Heartbeat
      If Tone_idx < Songlen Then          Incr Tone_idx                            ' Get the next tone          Tone = Song(tone_idx)          Tone_length = Tone And &H0F              ' Get the tone length          Tone_length = Base_length * Tone_length  ' Factor the tone buy the base length          Tone_length = Tone_length + Base_length  ' Build in a unit gap at the end          If Tone > &H80 Then
            Gosub Buzzer_off
         Else
            Gosub Buzzer_on
         End If
      Else
         Set Song_finished
      End If
   End If
Return

Melody:                                             ' Wake up - Morse code
Data &H01 , &H03 , &H03 , &H83 , &H01 , &H03 , &H83 , &H03 , &H01 , 
     &H03 , &H83 , &H01 , &H87 , &H01 , &H01 , &H03 , &H83 , &H01 , 
     &H03 , &H03 , &H01 , &HFF

Alarm Integration

It was easy enough to integrate the alarm-tone code into the main-board code since since the 16-bit Timer0 was not in use. I could configure the Timer0 for CTC-Mode (Clear Timer on Compare) to deliver the 2.5kHz which produced the best results. I did attempt other PWM configurations but the results were not what I was expecting or wanted.

Config Timer1 = Timer , Compare A = Toggle , Prescale = 1 , Clear Timer = 1
Const Tone_pitch = 200

In my original design, I had anticipated to utilise the alarm interrupt (address $E) that the RTC-DFC supports – or is meant to support. I actually found that this does not work. When the alarm is programmed, it can be seen to be fired since the indicator LED on the module will illuminate. However, the Alarm Interrupt line is not brought low and therefore not detected in my code. I have two modules to try this out on and neither would pull the interrupt line low – even after upgrading to the latest firmware.

After chatting with my tutor, Chris Gammell from Contextual Electronics, I came to realise the workaround. In addition to the Interrupt line, it is possible to detect the alarm in the interrupt status register. This works. So I modified the code not to rely on the interrupt line but to, instead, query the Interrupt Status Register and invoke the alarm if the alarm bit is set.

Read_dfc_interrupt_flag:
   Reset Dfc_ss
   Mosi(1) = &HCE
   Spiout Mosi(1) , 1
   Spiin Mosi(1) , 1
   Set Dfc_ss
   Interrupt_register = Mosi(1)

   If Alarm_disabled = 0 Then
      Temp = Interrupt_register And &B00000100
      If Temp = &B00000100 Then
         Set Alarm_fired
      End If
   End If
Return

Wrapping up

I was keen to get this project into a finished state. The enabling of the alarm was one of the last stages. All was needed then was to clean up the code a bit and implement an “alarm cancel”. There is a push-button on one of the front feet so that the alarm can be cancelled by tapping the top of the clock.

img_0274eSo here it is, the renovated clock. I utilised the BOM feature of KiCad to perform a cost analysis of the two modules. The Clock module comes to a BOM cost of 41.46€ (including the RTC-DFC from ELV) and the display module comes to a BOM cost of 35.14€. I have already mentioned that this implementation is a bit over the top in terms of components etc. but it is more about the learning exercise rather than making a cost effective clock and display module.

Just to recap on what I have learned in this exercise:

  • Circuit design
  • PCB layout
  • PCB Manufacturing
  • Assembly
    • Improved through-hole soldering
    • SMD
  • Programming through an ISP (to a development board and my own board)
  • Inter module programming using I²C and SPI
  • Trouble shooting using a logic analyser and oscilloscope

img_0275e

When I set out on this project, I anticipated to learn a bit about UML – SysML in particular. I did start out that way but with everything else I had to learn on the way, it sort of went by the way. However the block diagrams that I created ended up being an valuable reference of what I had intended the pin allocations to be. That is something will try to utilise more for the next project.

Addendum

Now that the clock has been running a week or so, I was thinking about how it is able to pick up the time signal better in some places than others. I was made think about this further when the ELV Journal showcased an external antenna for the RTC-DCF. I realised that all this time, I have been treating the DFC-RTF as a black box an literally taking it for granted. That approach certainly helped to get the job done. It was time to take a closer look. The RTC-DFC is a module in two parts. A DCF77 receiver module and a micro based RTC. It turns out that I really had a bit of luck with the positioning of the antenna on the main board. In certain locations the clock can (eventually) receive a signal, in others not at all. Looking at the data signal from the DCF77, I could clearly see the one second pulses when the antenna was about 5cm from the board. Bring the antenna closer and the signal is disrupted as the images below show.

It was not a light decision to take to add the external antenna to the clock as I had to make a slight modification to the case for the antenna cable. The performance of the clock as improved immensely. It now sits, as a trophy, on my Lab windowsill.