The operating mode of the MSP430 is controlled with four different bits in the status register. These bits are called CPUOFF, OSCOFF, SCG0, and SCG1. The first two are fairly self-evident; the first of these controls the power to the CPU of the MSP430. The second controls the power to the external oscillator (ie. crystal usually). In addition, these bits turn on/off MCLK and ACLK respectively, since those are associated with the CPU and LFXTL. The other two bits add more control over SMCLK, the DCO, and the DC generator.
|Page from the x2xx Family Guide describing|
the low power modes.
the _BIS_SR() function we saw earlier is perhaps the easiest method of using the LPMs. The header files define a set of names called LPMx_bits to help with the bit management. To enter a low power mode, simply issue the command _BIS_SR(LPMx_bits); with x replaced by the LPM number you've chosen. Keep in mind that if you want to use interrupts, you will also have to add GIE to the argument, or at least _enable_interrupt(); before going into the LPM.
Another good thing to keep in mind is that the LPMs are distinct; you don't need to include LPM0 to use LPM1. In fact, doing so (eg. using a command such as _BIS_SR(LPM0_bits + LPM1_bits + GIE);) would have undesirable side effects by adding the binary values that the header file definitions provide together.
One of the features of the MSP430 architecture is that you don't need to tell the CPU to wake up on the interrupt, nor do you need to put it back in the LPM manually. All of this is done automatically; when an interrupt is triggered, the Status Register is saved to memory (pushed onto the stack) and reset, waking up the CPU. Once the ISR has been satisfied, the original Status Register (including the LPM setting) is popped off the stack back into its place, and the MSP430 returns to the low power state. If you require your program to wake up the chip and stay awake, you will need to include a line in your ISR to do so:
_BIC_SR(LPMx_bits); // clears the bits corresponding to LPMx and exits the low power mode
Note the different function name; _BIS_SR() is Bit Set Status Register (ie. set to 1) while _BIC_SR() is Bit Clear Status Register (ie. clear to 0).
Example using the Low Power Modes
As an example, I've coded up a simple program that plays a tone on an 8Ω speaker. The speaker I have has two pins with 0.2" separation, and so it plugs right into the headers on the LaunchPad. To accommodate the spacing, I'm using P1.0 and P1.2 to drive the speaker. If you don't have a speaker available, you can simulate the same idea using the two LEDs on the LaunchPad; just follow the instructions in the code and change SOUT to BIT6 and adjust the frequency accordingly.
The idea is simple; we start with P1.0 high, P1.2 low, and switch each at a given frequency. This method provides a square wave, not a pure tone, but it does work. Keep in mind that audible frequencies are generally in the 100's and 1000's of Hz. It might be interesting to see how low of a frequency you can hear (clicking doesn't count; listen for an actual tone) and how high you can hear. Also, you can keep one pin constantly low and switch only the other if you want to reduce the volume.
There's more to explore with the low power modes, and next time we'll start playing with the low frequency oscillator to drop into the deeper sleep modes.
Reader Exercise: This tutorial's code uses LPM0. Try out the other low power modes by using LPMx_bits in place of LPM0_bits. What happens if you try to use LPM1? LPM2? LPM3? LPM4? Can you explain why some of these work and others don't? Those that work, is there any actual difference between the modes as implemented for this program? As you answer these questions, think about what clock is sourcing the timer and what oscillator is used for the clock.