mega88 clock divisor not reliable??
2006-10-01 by larry barello
Anyone use the clock divisor on the m88? Below is my code. Every so often
the reset to normal speed fails. Interrupts are disabled during the ISR()
In short my "system" has a 50hz clock and I divide the CPU clock by 128 when
I want low power and the timer wakes me up 2.56 seconds later. Every so
often I get a 5 second delay. If I put the reset inside the "bDeepSleep"
clause, it works a couple times and eventually gets stuck in low speed mode.
I have tried a variety of approaches: Sleep, no sleep, put into a while()
loop until the CLKPR is equal to what I want (of course it is, but the
clock is still slow), etc. The resulting assembly code is good: ldi, sts,
ldi, sts. The one that fails is "ldi, sts, sts" (storing a zero comes out
of a register that the C compiler maintains).
while(1)
{
if (bDeepSleep)
{
SLEEP(TRUE); // Radio sleep
CloseSerialIO(); // Disable serial interrupts
cli();
CLKPR = 0x80;
CLKPR = 0x07; // Divide system clock by 128.
}
else
{
ProtocolTask(); // Communications with MCS via zibee
WGRMTask(); // Handles overall state of the machine
&
}
sei();
asm ("sleep");
}
// We rely upon slow clocks for low power in the mega88
// The timer interrupt restores the clock to full speed
// then lets the logic run. The logic enables the radio
// and waits for a transaction (x ms) going back to sleep
// if nothing happens.
//void TIMER1_CAPT_vect (void) __attribute__ ((interrupt));
//void TIMER1_CAPT_vect (void);
ISR(TIMER1_CAPT_vect)
{
CLKPR = 0x80; // Set clock back to full speed
CLKPR = 0x00;
if (bDeepSleep) // 1/2.56 hz!
{
InitSerialIO(BAUD115200);
SLEEP(FALSE); // Wake radio up
bDeepSleep = FALSE;
}
else
SystemTimer++;
}
[Non-text portions of this message have been removed]