Update: (10/5/2013) I’ve now included more pictures at the bottom.
This clock has been nearly 6 months in the making for me. It uses the phenomenon known as persistence of vision (also found in CRT TVs, some LED displays, and more) to “draw” an image from individual pulses of light. These pulses of light occur so fast that our eyes cannot distinguish them individually and they become an image (such as how the individual pixels on a TV make up the overall image, however phosphor plays a part in it but thats a completely different topic). Now this concept has been around for a long time however it’s still fun to create something new with this idea.
I’ve seen hard drive clocks before, where a slit has been cut in the platter and multi-colored LEDs shine below as the disc rotates, pulsing at just the right time to make “hands” appear at specific locations around the face. This is a fun little trick and generally makes good use of an otherwise dead hard drive, however I wanted to try something different. You always hear of hard drive (POV) clocks but you never hear of CD-ROM (POV) clocks. It’s essentially the same idea, instead of the platter, you have a compact disc. The only problem is that people using the hard drive make use of the still functional motor and driver to rotate this platter as 5600RPM or even 7200RPM. This is great because you know that you have a constant speed (thanks to the motor driver) so thats one variable taken care of. What about driving a CD? Simply applying power to a CD-ROM drive doesn’t make it spin, so you got to get creative and thats what I did.
If you are just now learning about my progress in this POV clock, then you can get caught up on my previous posts covering the ideas, progress, and issues that got me to where I am now: The idea and design, Update 2, Update 3 and Update 4. I wanted to try this POV clock for three reasons: one, was to try something new (no hard drive); two, cut down on noise; and three, because its cool. Have you ever heard how noisy a hard drive can be in a quiet room? You don’t complain of a CD player being too loud (not one of those 52x drives mind you). My ultimate goal was to create something that both looks nice and is functional. There’s no point in spending your time to create a clock thats too noisy to use!
The hardware of the clock consists of a microcontroller (ATMEGA168) which handles all the work. It is clocked from the internal RC oscillator at 8MHz, leaving the external crystal (32.768KHz) free to handle the time keeping. The RGB LED strip that makes up the display element is driven by three transistor drivers (one for each color). The three transistors are then connected to a single transistor to enable blanking, or dimming by PWM.
The motor that drives the CD was taken from a CD-ROM drive. Rather than use the spindle motor (which I had seriously considered) I decided to use the tray ejection motor instead. If I were to use the spindle motor, I would need to use a driver IC (which I could have taken from the control board) but the control signal would have been a bit difficult to work with. It requires a voltage whose amplitude correlates to the desired speed, but producing a specific voltage from a microcontroller would have been too difficult. Instead, a control algorithm is providing a PWM signal to allow a desired speed to be set and maintained using the tray motor. The driver for the motor is simply another transistor with a reverse diode added across the motor for protection. I am using 3.3v to power the motor as it takes very little voltage to spin up and maintain the disc speed.
To measure the rotational speed and provide an index for the display, I used an IR photodiode and phototransistor which detects a reference mark on the disc. The IR photodiode continuously shines on the CD and reflects back to an IR phototransistor which is buffered by NPN transistor and signals the micro controller. The buffer ensures that the signal to the microcontroller is clean and has the proper voltage levels. When the index marker is lined up with the IR beam, the reflection is broken, signaling the start of the disc. I encountered several problems when working with the IR pair, mostly due to the wrong wavelength range and poor index sensing. Again, those are covered in depth in the posts above.
To allow control of the clock and user input, I wanted to include a rotary encoder. I was able to find one which also encorported a RGB LED inside. This allowed me to give feedback without changing the display (such as the selected mode). I also encountered numerous problems with the rotary encoder relating to poor quality. Basically, inside, there are contacts which touch tracks to close the circuit. As the knob is rotated, the contacts (two of them) make contact with the tracks in different patterns that make up a grey code seen on the output of the pins. Well this worked great, however the shaft that the knob is on also has divots that allow it to “click” into a position and continue to make contact with the tracks. The problem is that the divots don’t match up with the tracks so as the knob “clicks” into place, the contacts are in an indeterminate position. Sometimes they are contacting the tracks, other times they don’t. In order for a rotary encoder to function correctly and for the software to detect the direction, as well as the position, the grey code must be output correctly. The thing with grey code is that only one bit changes at a time, allowing for both direction and position sensing through software. Well as the shaft “clicks” into the divot, the output of the two bits no longer represents a valid position so the software (and developer) gets confused. After scratching my head for a few days, I discovered that the divots were the root of my problem. Luckily, there was a small copper collar inside the rotary encoder that was responsible for the shaft “clicking” into position on the plastic housing and providing pressure so that the contacts make contact with the tracks. By simply flipping the collar around, I was still able to maintain the pressure on the contacts and I no longer had erroneous output but I also lost that satisfying “clicking” noise as it was rotated. To interface the rotary encoder to the microcontroller, I required a few components. Since we’re dealing with contacts, they have a certain amount of bounce so I needed to filter that out, along with the push switch. I essentially used the debouncing circuit that was recommended in the datasheet. To drive the LEDs I simply used three resistors connected directly to the microcontroller pins.
Now that the input and output has been covered, the only thing remaining is the power. Since this is a clock and I’m not using a RTC (real time clock), I didn’t want to set the time every time it was unplugged or lost power. I decided to use a small 3V coin cell to power the AVR (and only the AVR) when power has been lost. Since the LED strip required 12V, I found a 12V 1A switching power supply “wall wart” style from an old router. This gets fed into a 7805 linear regulator and then the N.O. side of a relay where the 12V goes directly to the coil. The N.C. side goes to the 3V coin cell. Finally, the common side of the relay goes to the AVR’s VCC. This way, when 12V is applied, the relay activates and switches the AVR power source from the 3V battery to the regulated 5V. There is also a resistor connecting the 12V supply to one of the microcontroller pins (the internal diodes on the input pin pull the 12v to a proper 5V-ish while the resistor limits the current as not to damage the input diodes). This will allow it to sense when power has been lost and enter a sleep mode.
The software controlling the clock is almost entirely interrupt driven. What should have been the easiest part ended up taking me the most time. I ran into many problems which caused me to rewrite the entire code (twice). My goal in terms of software was to have something that would be easy to use and reliable. There are three timers which control most of the critical items with pin-change interrupts taking care of the remaining inputs.
TIMER0 is used solely for the PWM handling of the motor and the dimming of the LEDs. Since there are two PWM channels associated to TIMER0, both are in use. TIMER1 controls all of the display elements, including measuring the rotational speed of the CD, synchronizing the hands to the index marker, and displaying the individual hands. TIMER2 handles all of the time keeping and as such, is clocked from an external 32.768KHz watch crystal. It also handles the timeout of the menu, where after 7 seconds of no input, the menu is disabled.
Pin-change interrupts handle the rotary encoder input and the power loss input. Because the ATMEGA168 has three pin-change interrupts covering a third of the pins each, I use one interrupt routine to handle the rotary encoder position (called when the position has changed). This allows the code to be a bit cleaner since I know that only the rotary encoder is attached (and mask bits set) for those pins. The rotary encoder’s push button switch is attached to another pin-change interrupt routine and like the position pins, only the switch is attached to this set of pins and interrupt mask bit set. Finally, like the first two, the third pin-change interrupt is driven by the power loss input.
Time keeping is completely handled by TIMER2 with the help of an external 32.768KHz crystal. Since TIMER2 is 8-bit and its clocked from this external source, I set the prescaler to 128. This means that every time it overflows, 1 second has passed. I don’t bother with clearing the counter or touching it for that matter as that would or could cause the clock to run slow. Instead, when the timer overflows the ‘seconds’ variable gets incremented and a flag gets set. This flag notifies the main loop that it should call a function to adjust the time. All this function does is adjust the time so that there are never 60 seconds, or 60 minutes, or 13 hours (its a 12-hour clock). There is another function (or interrupt) associated with TIMER2 which counts down from 7 every second when activated. This provides the menu with a 7 second timeout.
The rotational speed is measured using the input compare hardware which loads a register with the value of TIMER1 when the input signal is sensed (setup to look for the falling edge). The timer is then reset and this recorded value is saved for use later. The interrupt also considers this the index mark and prepares other functions (variables) for drawing the hands. The hands are drawn by a routine which is called 60 times a rotation. The exact time the routine is called is calculated from the period (obtained when the input compare occurred) divided by 60. The interrupt routine checks if it should draw a hand or leave it blank, which if it should draw the hand, it draws it in the correct color (red for hour, green for minute and blue for second). This may seem wasteful to call the routine every time even if there is nothing to do. That was my thinking originally, which is why I wrote it differently before. At first I called the routine only when it needed to draw a hand. This worked great, except for when I tried to rotate the clock face by introducing a bias. This is when things backfired and the routine wasn’t being called sometimes (or rather the interrupt wasn’t being triggered). As a last measure fix, I switched to the current method which works and I’m able to rotate the clock face so I kept it. There is an overflow interrupt for TIMER1 which should never be called unless something bad happens (the CD isn’t rotating fast enough and the 16-bit TIMER1 value has overflowed). In this case the interrupt signals that it has overflowed and gives the motor controller a kick in the pants. In actuality, this only should occur during startup.
There is a second (compare match) interrupt available for TIMER1 which I haven’t used yet but I had experimented with drawing a background. I ran into some timing issues where drawing the background took too many processor cycles and the motor control function (I’ll explain that later) wasn’t able to complete a calculation before the next period was found. I also found that the clock was loosing time by as much as an hour a day. Okay well I finally got the background to work (using the second compare match interrupt) without any problems. The TIMER2 interrupt has priority over TIMER1 interrupts so its not that TIMER2 interrupts weren’t being handled. It may be because the function that adjusts the time (when to change from 60 seconds to 0 and increment the minutes) is delayed because of the motor control function. The TIMER1 interrupt for drawing the background was called 240 times per a rotation (4 times per a “hand” position) to keep the hands from blending in with the background. I may revisit the idea of drawing a background by reduction the number of slices to perhaps 120.
The motor controller function is the other exception where it is not interrupt driven. This is called when the flag indicating a new period has been captured (from the input capture interrupt of TIMER1) is set. This function uses a PID formula to maintain the speed of the CD as close as possible to the desired speed. Since the hands are drawn dynamically and their positions aren’t hardcoded, the clock is fairly resilient to speed fluctuations. The PID function overall does a really good job at maintaining the speed with very little variation, however if I had more time to better tune the Kp, Ki and Kd constants, I’m sure I could have done better. The function takes approximately 3ms to compute the PID and return a value. In this case, the value returned is the new PWM value in the range of 0-255.
The menu for the clock (accessed by the rotary encoder) steps through the various functions: Brightness – Hour – Minute – Second – Face Bias – Speed – Background. There is a different color for the rotary encoder with each function (white for Brightness, red for Hour, green for Minute, blue for Second, magenta for Face Bias, teal for Speed, and yellow for Background). The first four are self explanatory whereas the Face Bias lets you rotate the clock face so that the 12 o’clock position can be anywhere. This is handy if you want to turn the clock on its side or even upside down. Speed lets you adjust the CD speed so that it either spins faster or slower. Faster means the hands look better and don’t “flicker”; slower is quieter. Background does just that, it chooses between six different styles: “crazy”, yellow, teal, magenta, white, and black (default).
The power loss mode is activated when the input detects a loss on the 12v side. When this happens, all the non-essential hardware parts of the microcontroller are shutdown: TIMER0, TIMER1, inputs, etc. The only parts left active is TIMER2 and the pin-change interrupt for the power loss pin. The microcontroller then enters a sleep and wakes only to increment the seconds and adjust the time. I thought about changing the TIMER2 prescaler to interrupt once ever 8 seconds instead of every second while in power down mode but in doing so the prescaler would need to be cleared which would result in the loss of up to 8 seconds when powered back on and 1 second when powered off. Granted, this wouldn’t happen very often but I just decided to leave it out.
For an enclosure, I decided to go with a boxed 4″x6″ picture frame I found for a few dollars. I then bought a piece of plexiglass and cut it down to size then drilled a hole toward the bottom for the rotary encoder. To hide all the guts of the clock, I painted the plexiglass black (from the outside view). I did this by first carefully placing a CD on the plexiglass and giving it a few coats of plastic primer followed by the black coat. I finished it off with a coat of white so that the LEDs inside the box will reflect back and make the display brighter (or so that was my thinking). With the paint dry I carefully lifted up the CD and I had a perfect front cover.
To make the CD inside the clock, I did the same process but I first placed a small strip of kapton tape from the inner radius to the outer. The CD I used was one of those blank clear ones that come in a 25 pack of DVD-R media. Its thinner than a real CD but works great, just be careful as they break easily. A few coats of primer, then black, then white and the kapton mask came off and it was done. The index marker was made by drawing a box next to where the kapton tape was with a permanent marker. This seemed to work really well and contrasted nicely with the white CD back side.
The picture frame came with a wooden rectangle piece to separate the glass from the back. I cut this down to make a 4″x4″ compartment for the CD and a 2″x2″ compartment for the electronics. I coated the 4″x4″ compartment in white paint, again thinking that it would help reflect more light outward. With a generous application of hot glue, I put the plexiglass into the frame, followed by the support piece I cut down earlier, and then the LED strip. I had originally ordered a 1m (or 3 feet, can’t remember) piece but luckily you can cut them down to a smaller size if you find the right place to cut them. For me, it was right in the middle.
After that, I started to assemble the circuit from what I had first been testing on – a bread board. I used a chunk of pert board as I hand’t yet mastered making my own boards at home yet. To mount the motor and IR pair, I fell back to 3D printing it. I drew something up with measurements I had made, printed it and test fit it. It looked good, but when I went to remove the motor, I broke it so I had to reinforce it some. The second print was much sturdier, but I forgot to adjust the mounting holes and it wouldn’t fit. The third print worked perfectly. This holds the IR LED and phototransistor, as well as the motor and is attached to the back of the picture frame with machine screws.
As I began test fitting everything, I realized that I needed a way to update the firmware (I hadn’t yet gotten the clock completely working at this point) so I made a small board that housed a 6-pin programming header, coin cell holder and a reset button. I then attached it to the back of the picture frame and made a cutout so they were all accessible. With the clock completely assembled, I was able to finish up writing the code without the fear of bumping something and wasting hours searching for the software bug (ask me how I know).
This video shows the clock in action. Yeah, I know I got a little carried away with the effects but it does do a good job at demonstrating what it can do.
I am extremely happy with how the clock turned out, however there is still a lot more that can be done.
As I said, I experimented with drawing a background on the clock which looked really nice and everybody liked it but I noticed that the motor controller function was getting starved for cycles and wasn’t able to complete the PID calculations (FLOAT mind you) before the next rotation. Backgrounds work now! There was one background I really liked where the various colors where rotating backwards (counter clockwise) as the clock hands were moving forward. I may experiment with taming down my background art and seeing what happens. I also wish I could have better tuned the PID constants more however it is still very functional.
Although the clock is very quiet at lower speeds of about 1320 RPMs (22 rotations a second) it does get a little noisy as I ramp the speed up to 1920 RPMs (32 rotations a second). I blame the way the motor is mounted for this. I should have made a gasket to sandwich between the clock back and the motor mount to help absorb the vibrations. Still, at 1320 RPMs, its still very usable.
So I received a few requests to post pictures of the inside of the clock. So here they are (click to enlarge them!):
Download source code here