I never noticed any issues with remembering brightness settings after power loss. My clock was purchased in December 2011.
From examining the Adafruit code and my own personal experience with the clock, I believe the official firmware saves the time and restarts the clock after a power outage. After the restart, the firmware loads the saved time, detects the low power condition, and sleeps, waking once-per-second to update the time. I suspect that, while sleeping, the once-per-second interrupt periodically fails to wake the clock. When this happens, the watchdog timer detects a lockup and resets the clock, sometimes resulting in noticeable time loss. When power is restored, the clock once again saves the time, restarts, loads the saved time, and otherwise runs normally.EDIT:
I was using the term "reset" loosely. What happens is a "software restart" by calling the function "void (*app_start)(void) = 0x0000;" which is defined in iv.h. This simply jumps to the very first instruction, which is like a reset except that registers values may persist.
After writing an alternative Ice Tube Clock firmware with the behavior described by ib123 (no restarting or blinking on power loss), I can say that reliably waking from power save mode with asynchronous timer interrupts is surprisingly tricky. But for those attempting to do so, the following suggestions may help:
First, before sleeping, ensure all timer2 registers have been written. If they have not, the system may not wake.
- Code: Select all
while(ASSR & ( _BV(TCN2UB) | _BV(OCR2AUB) | _BV(OCR2BUB) | _BV(TCR2AUB) | _BV(TCR2BUB) ));
Second, the code in the once-per-second interrupt must take at least one quartz clock cycle to execute (32.768kHz or 30.5 microseconds), or the interrupt may be triggered more than once per second. If in doubt, set one of the timer2 registers in the code, and the while loop above will prevent the system from sleeping before the value is written, which takes more than once quartz clock cycle. For example, the following line could be placed in the once-per-second interrupt handler.
- Code: Select all
OCR2B = 0;
Third---and I found no mention of this in the ATmega168 or ATmega328p datasheets---waking from sleep is unreliable if any
of the timers are disabled in the power reduction register (PRR). So enable and disable timer0 and timer1 with the timer configuration registers (TCCR0A, TCCR0B, TCCR1A, and TCCR1B), and leave all timers enabled in the power reduction register.
Fourth---and this is done correctly in the official firmware---divide the system clock by at least four during sleep as higher clock speeds may prove unstable at lower voltages. Some people recommend dividing the clock by the maximum possible amount to reduce power consumption while running code, but this also forces the microcontroller to spend more time running code and less time sleeping. In my firmware, the microcontroller used less power while sleeping with a faster clock speed. So grab your multimeter, try it both ways and do whatever is more efficient.
- Code: Select all
The datasheet also specifies that "The CPU main clock frequency must be more than four times the Oscillator frequency," so do not divide the system clock by more than 32. The official firmware divides the 8 MHz internal clock by 256 during sleep, resulting in CPU clock of 31.250kHz. This seems to work fine in practice, but violates the datasheet.
Fifth and finally, I do not think there is much need to optimize the power-loss interrupt for speed, as previously suggested. The power supply capacitors are reasonably large and the ATmega168v executes code quickly. My power-down-and-sleep code is rather inefficient, but still seems to work reliably without loosing time...
Well... I hope someone finds this information helpful. Cheers!