The WDT periodic wakeup options are limited to a few intervals that do not suite my needs. I need a wakeup from PM1 or PM2 every 5msec based on the 32KHz ROSC.
My approach was to use the sleeptimer and to set the next sleeptimer compare in the sleeptimer ISR as shown below. This works fine if the change to PM1 or PM2 is not invoked, that is, EnterSleepModeProcessInterruptsOnWakeup() below is commented out. It works if EnterSleepModeProcessInterruptsOnWakeup() is not commented out if using a debugger and a breakpoint is set in the ISR. However, if left to run free it ends up in the weeds.
I'm using TI's code examples in the following for setting the sleeptimer and for invoking sleep mode...
#include "power_mode.h"
#include "ioCC254x_bitdef.h"
#include "ioCC2541.h"
/***********************************************************************************
* LOCAL VARIABLES
*/
// Union for storing 24 bit sleep timer value.
typedef union {
unsigned long value;
unsigned char byte[4];
} union_32bit;
static union_32bit sleep_timer;
static long loop_cnt;
void set_sleeptimer()
{
while(!(SLEEPSTA & SLEEPSTA_CLK32K)); // Wait for positive flank on sleep timer.
sleep_timer.byte[0] = ST0; // ST0 must be read first.
sleep_timer.byte[1] = ST1;
sleep_timer.byte[2] = ST2;
sleep_timer.value += 164;
ST2 = sleep_timer.byte[2];
ST1 = sleep_timer.byte[1];
while( !(STLOAD & STLOAD_LDRDY) );
ST0 = sleep_timer.byte[0];
}
#pragma vector = ST_VECTOR
__interrupt void sleep_isr(void)
{
STIF = 0;
set_sleeptimer();
}
int main(void)
{
STIF = 0; // Clear [IRCON.STIF] (Sleep Timer CPU interrupt flag).
STIE = 1; // Set the individual, interrupt enable bit [IEN0.STIE=1].
EA = 1; // Enable global interrupt by setting the [IEN0.EA=1].
SLEEPCMD = (SLEEPCMD & ~SLEEPCMD_MODE) | SLEEPCMD_MODE_PM1;
set_sleeptimer();
while(1)
{
EnterSleepModeProcessInterruptsOnWakeup();
++loop_cnt;
}
}