2 * "Copyright (c) 2005 Stanford University. All rights reserved.
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose, without fee, and without written
6 * agreement is hereby granted, provided that the above copyright
7 * notice, the following two paragraphs and the author appear in all
8 * copies of this software.
10 * IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE TO ANY PARTY FOR
11 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
12 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
13 * IF STANFORD UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * STANFORD UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
19 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND STANFORD UNIVERSITY
20 * HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
21 * ENHANCEMENTS, OR MODIFICATIONS."
26 * Implementation of TEP 112 (Microcontroller Power Management) for
27 * the MSP430. Code for low power calculation copied from older
28 * msp430hardware.h by Vlado Handziski, Joe Polastre, and Cory Sharp.
31 * @author Philip Levis
32 * @author Vlado Handziski
33 * @author Joe Polastre
35 * @date October 26, 2005
36 * @see Please refer to TEP 112 for more information about this component and its
41 module McuSleepC @safe() {
44 interface McuPowerState;
47 interface McuPowerOverride;
52 mcu_power_t powerState = MSP430_POWER_ACTIVE;
54 /* Note that the power values are maintained in an order
55 * based on their active components, NOT on their values.*/
56 // NOTE: This table should be in progmem.
57 const uint16_t msp430PowerBits[MSP430_POWER_LPM4 + 1] = {
60 SR_SCG0+SR_CPUOFF, // LPM1
61 SR_SCG1+SR_CPUOFF, // LPM2
62 SR_SCG1+SR_SCG0+SR_CPUOFF, // LPM3
63 SR_SCG1+SR_SCG0+SR_OSCOFF+SR_CPUOFF, // LPM4
66 mcu_power_t getPowerState() {
67 mcu_power_t pState = MSP430_POWER_LPM3;
68 // TimerA, USART0, USART1 check
69 if ((((TACCTL0 & CCIE) ||
72 ((TACTL & TASSEL_3) == TASSEL_2))
73 #ifdef __MSP430_HAS_UART0__
74 || ((ME1 & (UTXE0 | URXE0)) && (U0TCTL & SSEL1))
76 #ifdef __MSP430_HAS_UART1__
77 || ((ME2 & (UTXE1 | URXE1)) && (U1TCTL & SSEL1))
79 #ifdef __MSP430_HAS_I2C__
80 // registers end in "nr" to prevent nesC race condition detection
81 || ((U0CTLnr & I2CEN) && (I2CTCTLnr & SSEL1) &&
82 (I2CDCTLnr & I2CBUSY) && (U0CTLnr & SYNC) && (U0CTLnr & I2C))
85 pState = MSP430_POWER_LPM1;
87 #ifdef __MSP430_HAS_ADC12
88 // ADC12 check, pre-condition: pState != MSP430_POWER_ACTIVE
89 if (ADC12CTL0 & ADC12ON){
90 if (ADC12CTL1 & ADC12SSEL_2){
91 // sample or conversion operation with MCLK or SMCLK
92 if (ADC12CTL1 & ADC12SSEL_1)
93 pState = MSP430_POWER_LPM1;
95 pState = MSP430_POWER_ACTIVE;
96 } else if ((ADC12CTL1 & SHS0) && ((TACTL & TASSEL_3) == TASSEL_2)){
97 // Timer A is used as sample-and-hold source and SMCLK sources Timer A
98 // (Timer A interrupts are always disabled when it is used by the
99 // ADC subsystem, that's why the Timer check above is not enough)
100 pState = MSP430_POWER_LPM1;
108 void computePowerState() {
109 powerState = mcombine(getPowerState(),
110 call McuPowerOverride.lowestState());
113 async command void McuSleep.sleep() {
119 temp = msp430PowerBits[powerState] | SR_GIE;
120 __asm__ __volatile__( "bis %0, r2" : : "m" (temp) );
121 // All of memory may change at this point...
122 asm volatile ("" : : : "memory");
123 __nesc_disable_interrupt();
126 async command void McuPowerState.update() {
130 default async command mcu_power_t McuPowerOverride.lowestState() {
131 return MSP430_POWER_LPM4;