As a starter exercise, I have decided to put a new life into an old digital alarm clock that stopped working. I received this in 1980 and it worked reliably well until late 2012 when if finally stopped displaying the time. It is amazing that it lasted as long as it did. The tone was not a tone but rather an annoying screech. The remarkable thing I found about this device of this age was that it was almost capable of memory. When the power was pulled, and the plug re-inserted within 5 seconds, it would not loose time. More than 5 seconds and it would give a dying squeak. Re-inserting the plug and the time reset mode would be enabled i.e. blinking display but the time would be close to the time the plug was pulled. Most clocks of the era (and today) will simply flash 12:00.
So why this exercise?
It has already been pointed out to me that I can go down the street and get a $5.00 replacement. There are many reasons to begin with this as a kick off project
- It has a function
- It will have inputs (alarm setting buttons, sleep mode)
- It has more than one output – display and sound
- These fit in with using a micro controller
- All have to fit into a pre-prescribed casing adding another dimension to the board design
- There will be a sense of achievement getting this thing working again
The original is based on a MM5402N from National Semiconductor. Rather than replacing the passives and or the clock chip, I thought this could be an opportunity to learn about simple controller programming and IO. To be honest, I did try replacing the components. But with my level of soldering rework practice and the age of the board, I gave up and decided a whole new approach was needed.
To keep things simple, I will be starting with a the proof of concept using an existing example. This uses the myAVR MkII development board for the Atmel range of chips. This is a dev board I have started with and would like to continue to gain a bit of proficiency. I will be using an Atmega88 and the Real-Time-Clock with DCF77-Empfang as per the existing example. I like to consider the RTC-DCF for the final project also as this delegates the management of time to the Read-Time-Clock, for instance, setting and firing of alarms. This device as additional features of receiving the actual time transmitted from Frankfurt, Germany and also provides an alarm function. This leaves the device controller to manage the UI i.e. alarm setting buttons and the display. The device is a bit of an over-kill in that it also provides a number of communication possibilities. The communication mechanism that I will be using for this will be I2C – only to get some experience in this mechanism. The first problem I had was that the MyAVR operates at the nominal 5V. The RTC-DCF operates on 3.3V. So my first lesson in I2C was a level shifter to convert the signal voltage from 5V to 3.3V. This was easily solved as there are plenty of resources on line to explain this. I came up with the following based on the information in the RTC-DCF documentation and using a set of pin headers that I can then easily interface with the MyAVR. I created a GitHub project and created the schematics and board layout using KiCad. I had the boards created through OshPark. This was the simplest part so far!
The boards arrived and assembled the parts onto the board. The next stage was to connect them all together. This is the part that made me look at the documentation a bit closer to realise that in the sample application I was modelling, they used a couple of interrupts from the clock module to help with the timing and display of the correct time. These signals also went via a level shifter. Thankfully Oshpark always supply a minimum of three boards and my boards will handle two signals each. So I assembled another board to cater for the interrupts. The final assembly of the test setup is shown below. I used a hand held logic analyser to observe some of the signals and there I notice an anomaly. Even after getting the sample working i.e. displaying the correct time, there are a couple of things that don’t quite add up when compared with the sample and documentation.
The first issue I found was that there is supposed to be a interrupt fired every second. I have since found out that that won’t happen until there is a firmware update needed on the real-time-clock (this will be another challenge to add to the repertoire). To work around this, I implemented my own one-second pulse with one of the in-built timers of the Atmega88. This was an area where I actually had quite a bit of trouble. In another sample program, I had created and tested a display driver. But creating a “time-counter” sample was very difficult. By having to drive the 7-Segment LEDs manually and compute the time, there seemed to be some odd clash with memory that I am no longer familiar with after so many years of using higher level languages. Rather than counting up, sequentially, the display was displaying seemingly random numbers. I really could not solve this issue. Since, in principle, the display driver was working, I turned back to the problem of the clock implementation, I found a couple of rules that need to be adhered to. These rules are not exhaustive or conclusive. Just a couple of points I noticed from this exercise.
- Keep the Interrupt Service Routine (ISR) as short as possible. I.e any additional or fancy computations in the 7-Segment display driver could be clearly detected in the refresh rate of the display segments.
- Any computation that an ISR depends on should also be contained in an ISR – or something equivalent to make the computation atomic.
Adhering to these rules, the ISR for the display driver did only that – Display the time. The one-second pulse timer was used to build the string to display. Attempting to build that string anywhere else caused strange things to be displayed. By setting the display string in the one-second pulse timer ISR effectively made that operation atomic.
Aside from the display issue, what else I found odd was with the second interrupt used by the sample – a “DCF time-receipt complete interrupt”. The interrupt routine for this interrupt was being fired seemingly randomly regardless of when the DCF time-receipt actually fired. The small logic analyser output shows I2 as the input from the DCF time-receipt and I4 is connected to a LED that is toggled whenever the ISR is fired. It can be seen that I4 is toggled twice before the receipt of the interrupt on I2. This really needs a closer examination of the IO settings and interrupt usage. i.e. Read-the-manual.
The proof-of-concept is basically done. To complete the exercise, the firmware update should be done on the RTC-DCF do demonstrate the RTC sourced heart-beat rather than the timer-driven pulse. I have also learned from this that I need to include a 3.3V regulator in order to use this RTC-DCF module.
One of my goals is to also learn SysML so it will be (back) to the drawing board to start to model what it is that I want from this device and what it needs to contain. i.e. Should this be using such an all-inclusive module for the time or go directly to the DCF77? Should a simple display module be used? and spare me the resource issues when manually driving four seven segment displays plus colon and alarm indicators. These and more questions will be subjects for further posts.