I'm looking into developing battery-powered software using the EFM Gekko controllers (http://energymicro.com/) and would like the controller to be asleep whenever there's nothing useful for it to be doing. The WFI (Wait For Interrupt) instruction is used for this purpose; it will put the processor to sleep until an interrupt occurs.
If sleep were engaged by storing something someplace, one could use load-exclusive/store-exclusive operations to do something like:
// dont_sleep gets loaded with 2 any time something happens that // should force the main loop to cycle at least once. If an interrupt // occurs that causes it to be reset to 2 during the following statement, // behavior will be as though the interrupt happened after it. store_exclusive(load_exclusive(dont_sleep) >> 1); while(!dont_sleep) { // If interrupt occurs between next statement and store_exclusive, don't sleep load_exclusive(SLEEP_TRIGGER); if (!dont_sleep) store_exclusive(SLEEP_TRIGGER); }
If an interrupt were to occur between the load_exclusive and store_exclusive operations, the effect would be to skip the store_exclusive, thus causing the system to run through the loop one more time (to see if the interrupt had set dont_sleep). Unfortunately, the Gekko uses a WFI instruction rather than a write address to trigger sleep mode; writing code like
if (!dont_sleep) WFI();
would run the risk that an interrupt could occur between the 'if' and the 'wfi' and set dont_sleep, but the wfi would go ahead and execute anyway. What's the best pattern to prevent that? Set PRIMASK to 1 to prevent interrupts from interrupting the processor just before executing the WFI, and clear it immediately after? Or is there some better trick?
EDIT
I'm wondering about the Event bit. By the general description, it woulds like it's intended for multi-processor support, but was wondering whether something like the following might work:
if (dont_sleep) SEV(); /* Will make following WFE clear event flag but not sleep */ WFE();
Every interrupt that sets don't_sleep should also execute an SEV instruction, so if the interrupt happens after the "if" test, the WFE would clear the event flag but not go to sleep. Does that sound like a good paradigm?