Hi,
I'm concerned that there is a race condition when entering sleep mode (PM1-3) where the MCU should be woken up by an interrupt. I have read the applicable sections of the CC2430 data sheet many times without finding an answer. Here is the situation, which is a pretty standard mode of operation (and thus a standard problem to solve):
Suppose we want to be woken up from sleep by a falling edge on a GPIO pin, say P0.1. So we set up the P0 pin change interrupt handler to be called, and that works fine while we're awake. However, suppose we now want to sleep in PM2 until an interrupt occurs to wake the MCU. Furthermore, let's assume that the port 0 ISR sets a global flag "triggered" to 1 to indicate that the event of interest (P0.1 falling edge) has occurred. We might have code like this:
// [Pseudocode]
bool triggered; // Flag to indicate that the event has occurred.
interrupt my_isr()
{
triggered = 1;
// Signal the sleep-entry code not to finish entering sleep mode,
// in the case that this ISR was called between the last flag check and
// actually entering sleep mode.
SLEEP.MODE = 0;
}
void sleep()
{
// Otherwise, sleep until it is triggered.
SLEEP.MODE = 2; // Set MODE for PM2.
ASM NOP; // [I have seen this "3xNOP" technique
ASM NOP; // w/ MODE double-check trick mentioned from people,
ASM NOP; // but see no reference in the data sheet.]
// (Probably the 3xNOP/MODE double-check is not useful since we've already
// disabled interrupts.)
if (SLEEP.MODE == 0)
return; // Interrupt was triggered.
EA = 1; // Enable interrupts.
// (Note: Race condition! We hope our interrupt does not occur here.)
PCON.IDLE = 1; // Sleep.
ASM NOP; // First instruction after wake-up.
}
void wait_for_trigger()
{
while (1)
{
EA = 0; // Disable interrupts to safely check flag.
if (triggered)
break; // The event of interest has occurred.
sleep(); // Wait for interrupt.
}
EA = 1;
triggered = 0; // Clear the triggered flag, it has been handled.
}
I have two questions which I do not believe the data sheet (or any other document in the "Technical Documents" section of the TI CC2430 product page) addresses:
(1) Where is the NOP x 3 + ISR-SLEEP.MODE-double-check trick documented? I think the TIMAC library implements it, and I've seen mention of it for other TI chip models, but no official mention for the CC2430 (is it in the data sheet?).
(2) Is there a race condition when enabling interrupts immediately before entering sleep mode? How does the CC2430 make this a safe operation? That is, we *must not* miss an interrupt and sleep anyway, since then we could sleep forever. Therefore, enabling interrupts and entering sleep mode must be an atomic operation. See this article by Miro Samek for examples of the problem and solution for other MCU architecures (HC08, MSP430, AVR, ARM), as well as a solution for 8051 which uses a "shadow copy" of the PCON SFR to avoid race conditions. Is this necessary on the CC2430?
Regards,
Colin