SLAU533D September 2013 – April 2017
Developing low-power applications is not just about finding the MCU with the lowest-current low-power modes, although that is an important step. The software also must be written to effectively control the circuitry and make good use of the low-power modes that are available.
In an application based on a main loop, one way to do this is to have a single location in the loop where a low-power mode is conditionally entered. Various events can wake it from this sleep and allow the main loop to resume execution, check flags, and handle any waiting events, and then eventually loop back and sleep again.
The primary low-power modes are for MSP430 MCUs are LPM0, LPM3, and LPM4 (see Table 9 for a brief description of these modes). Lower numbers represent "lighter" sleep, while higher numbers generally mean "heavier" sleep. When the MCU is not in an LPM mode, it is considered to be in "active mode", which means that all clocks are enabled and the CPU is executing code. (See the MSP430 family user's guides for complete descriptions of these modes.)
The developer's choice of low-power mode is based on what functionality the MCU needs to keep alive while sleeping. In the case of USB, the MSP430 can enter LPM0 while the USB connection is active (not suspended by the USB host), but this is the deepest possible sleep state. When suspended, it can go into LPM3, which is significantly lower power than LPM0.
With this in mind, refer back to the flowchart in Figure 28. The main loop begins by trying to enter LPM0, but to do so it evaluates several conditions: the return value of USBMSC_poll(), the number of characters waiting to be typed to the host, and whether a LaunchPad development kit pushbutton has been pressed. This code was shown in the previous section.
If USBMSC_poll() returns kUSBMSC_processbuffer, it means the API is waiting for the application to finish the READ or WRITE operation, and thus it is important to skip LPM0 and proceed to mscProcessBuffer().
Similarly, code checks for these other interrupt-driven events that may have occurred after the main loop checked their flags. If execution enters sleep while these flags are set, they are not handled until yet another interrupt occurs. This could cause the device to be unresponsive.
For similar reasons, interrupts are disabled prior to evaluating any of these flags. It takes several cycles to evaluate these conditions, and because these events can occur at any time, the status of the early flags could potentially change before LPM0 is actually entered. If LPM0 were then entered, they would get missed. Disabling interrupts prevents that from happening; the events are simply queued up. When interrupts are reenabled, any interrupts that came in take effect immediately.
Therefore, the code simultaneously enters LPM0 and reenables interrupts by setting the GIE bit:
_bis_SR_register(LPM0_bits + GIE);
If an interrupt had come in while interrupts were disabled, the CPU will wake again in the very next cycle after entry.