Jump to content

Low Power Mode

Recommended Posts

If the WDT triggers while in another ISR, it will save the SR at the time, which will be Active Mode, because all ISR's run in Active Mode.  When the WDT ISR exits, it will only change the SR that was pushed onto the stack when the WDT was called. Control then returns back to the user's ISR. When that ISR exits, it will restore the SR that it saved at the time it was called, putting the system back into LPM. Consequently the call to __bic_status_register_on_exit in the WDT cannot restore the system to active mode.


I don't think other ISR routines, like the watchdog, can interrupt  your ISR unless you enable GIE inside your ISR. I could be wrong but that is my impression. In slau144i, page 38 it talks about the GIE being cleared


"6. The SR is cleared. This terminates any low-power mode. Because the GIE bit is cleared, further interrupts are disabled."


In slaa294a, page 3 it says something along those lines also:


"Given this ability to change the power mode from the ISR, the developer can choose to implement the full

functionality of the ISR within the routine itself, or use the ISR to wake up the processor and let the main
loop handle all or part of the resulting functionality. Handling within the ISR ensures that the response to
the interrupt event is immediate, provided that interrupts are enabled at the time of the event. However,
while handling an ISR, interrupts are not enabled and will not be enabled until the ISR is completed. As a
result, long ISRs may decrease system responsiveness. The developer must choose which of these
options best fits the application."
In a simple test I verified that if I put a blocking loop in my port ISR nothing else happens until the loop exits.
Link to post
Share on other sites
... Personally, I think the Port_1 & Port_2 functions should have a call to  __bic_status_register_on_exit(LPM4_bits). Otherwise if whatever is currently causing the return to active mode gets fixed, there is no way to ensure a return to active mode from a pin interrupt. ...


This might be a reasonable approach.  For the next release of Energia it might make sense to try and focus on some low power optimizations like this.  You are all welcome to take a stab at it.



Link to post
Share on other sites

No interrupt can break into another interrupt, unless you enable GIE as you say. The WDT/NMI are the only exception to this statement; these will interrupt any running routine (isr or loop). The only easy to prevent this is to explicitly disable the WDT/NMI through their dedicated flags WDTIE/NMIE. Those will themselves clear this bit, a user must manually enable again if these routines are entered.

Link to post
Share on other sites

In the code below the green led only blinks when you aren't holding down SW2.


 * lpmfoo.cpp - low power mode testing with ISR tests
 * Desc: simple test to see if ISRS block other ISR execution
 * Uses: P1.0 - RED LED
 *       P1.6 - GREEN LED
 *       P1.3 - SW2 push button
 * Compiled with:
 *    msp430-gcc -DF_CPU=1002400 -mmcu=msp430g2553 -mdisable-watchdog \
 *      -Os -g -fdata-sections -ffunction-sections -Wl,--gc-sections lpmfoo.cpp
 *    mspdebug rf2500 "prog a.out"
 * Author: rick@kimballsoftware.com
 * Date: 01-26-2013 Created

#include <msp430.h>
#include <stdint.h>
#include <stdlib.h>

void loop();

void WDT_ISR(void)
  static uint16_t counter;

  if ( ++counter > 8000 ) {
    P1OUT ^= BIT6; // blink green led once and a while
    counter = 0;


void PORT1_ISR(void)
#if 0 /* enable this code to allow the WDT_ISR to run at the same time as this ISR*/
    __bis_status_register(GIE); // enter scary zone, ISR running inside of other ISRS

    P1IFG &= ~BIT3;
    P1OUT ^= BIT0; // turn on red led

    // block anything else from running until I let go of the button
    while(!(P1IN & BIT3));

    P1OUT ^= BIT0; // turn off red led

int main(void)
    // compile with -mdisable-watchdog

    WDTCTL = WDT_MDLY_0_064;   /* trigger WDT_ISR every 64usecs */

    // enable leds for display
    P1OUT &= ~(BIT0|BIT6);
    P1DIR |= BIT0 | BIT6;

    // sw2 , configure as input_pullup
    P1DIR &= ~BIT3;
    P1OUT |= BIT3;
    P1REN |= BIT3;

    // sw2, enabled trigger PORT1 ISR
    P1IE |= BIT3;
    P1IES |= BIT3;  // Bit = 1: The PxIFGx flag is set with a high-to-low transition
    P1IFG &= ~BIT3; //

    // output SMCLK clock so I can watch it with a scope probe
    P1SEL |= BIT4; P1DIR |= BIT4; // in LPM3, LPM4 will only oscillate while SW2 is held down


    IE1 |= WDTIE;                     // enable watchdog interval


    return 0;

void loop() {

    LPM1; /* WDT will work */
    //LPM3; /* WDT will never work */
    //LPM4; /* WDT will never work */

    while(1) {
if you change:


#if 0 /* enable this code to allow the WDT_ISR to run at the same time as this ISR*/



#if 1 /* enable this code to allow the WDT_ISR to run at the same time as this ISR*/

then the green led will blink even when the button is being held down.



Link to post
Share on other sites

Interesting, I thought this behaviour is contrary to what the family guide tells about this. Thanks for this new insight!


I've been browsing the family guide a little bit more. The WDT will generate a normal interrupt, not a nmi, that is, if you're using it in timer mode. In watchdog mode out will still trigger during an interrupt routine, though the msp will reset then instead of running an isr.

The NMI (which can be set up as the isr for the reset pin) on the other hand seems to be executed in higher priority and can even override any other running isr.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...