The piece of self-modifying machine code can be quite small. You define a 4-byte array in RAM, as in Listing 10. This machine code represents a tiny C-callable function that executes the
WAIT instruction and returns to the caller. In the background loop, you modify this code and call it using a pointer-to-function, as in Listing 11.
View the full-size image
View the full-size image
You must disable the transition in every interrupt to wait mode by replacing the WAIT instruction at Wait_code[0], as in Listing 12. With this design, an interrupt can occur at any machine instruction between FSET I (enabling interrupts) and executing the instruction at Wait_code[0]. Any such interrupt will replace the code in Wait_code[0] with the RTS,NOP instruction pair that immediately returns to the background loop, so the WAIT instruction won't survive to the point when the background loop actually comes around to execute it. Thus, any interrupt that preempts the idle loop disables the wait mode, which accomplishes the goal of an interrupt-safe transition to idle mode.
View the full-size image
Atomic low-power states
Running the MCU at full-speed all the time will never lead to a truly low-power design, even if you use the lowest-power MCU available. The biggest power savings are only possible by frequently switching the MCU to a low-power sleep state under the software control.
The simplest foreground/background software design requires that the transition to a low-power state be atomic, or at least interrupt-safe. This requirement does not apply when you use a more sophisticated architecture, such as a preemptive kernel or a real-time operating system. A preemptive kernel executes a special idle task when no other tasks are ready to run because all are blocked waiting for events.
Most kernels provide a way to customize the idle task (using callback functions or macros), so that you can conveniently implement the transition to a low-power state inside the idle task. The main difference between a preemptive kernel and a foreground/background system is that as long as tasks are ready to run, the kernel doesn't switch the context back to the idle task. Consequently the transition to a low-power mode is much simpler, because it doesn't need to occur with interrupts disabled.9 Unfortunately, a preemptive RTOS isn't always an option for a low-end MCU, which simply might not have enough RAM to accommodate a preemptive RTOS.
Miro Samek is the president of Quantum Leaps, LLC, a provider of lightweight, open-source, state machine-based application frameworks for embedded systems. He is the author of Practical Statecharts in C/C++ (CMP Books, 2002), has written numerous articles for magazines, and is a regular speaker at the Embedded Systems Conferences. He welcomes contact at miro@quantum-leaps.com.
Endnotes:
1. Freescale Semiconductors, MC68HC908QY4/D datasheet, 2003.
Back
2. Texas Instruments, MSP430x1xx Family User's Guide, 2006.
Back
3. Atmel, ATmega169 Datasheet, 2005.
Back
4. Atmel, AT91SAM7S32 Datasheet, 2005.
Back
5 ARM Ltd., ARM v7-M Architecture Application Level Reference Manual, 2006.
Back
6 ARM Ltd., Cortex-M3 Technical Reference Manual, 2006.
Back
7. Luminary Micro, LM3S811 Microcontroller datasheet, 2006.
Back
8. Renesas, M16C/62 Group (M16C/62P) Hardware Manual, 2003.
Back
9. Samek, Miro and Robert Ward, "Build a Super Simple Tasker," Embedded Systems Design, July 2006, p. 18.
http//:www.embedded.com/columns/technicalinsights/190302110.
Back