Rickta59 589 Posted January 26, 2013 Share Posted January 26, 2013 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. -rick Quote Link to post Share on other sites
Rickta59 589 Posted January 26, 2013 Share Posted January 26, 2013 ... 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. -rick Quote Link to post Share on other sites
roadrunner84 466 Posted January 26, 2013 Share Posted January 26, 2013 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. Quote Link to post Share on other sites
Rickta59 589 Posted January 26, 2013 Share Posted January 26, 2013 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(); __attribute__((interrupt(WDT_VECTOR))) void WDT_ISR(void) { static uint16_t counter; if ( ++counter > 8000 ) { P1OUT ^= BIT6; // blink green led once and a while counter = 0; } return; } __attribute__((interrupt(PORT1_VECTOR))) 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 #endif 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 __enable_interrupt(); IE1 |= WDTIE; // enable watchdog interval loop(); 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*/ to #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. -rick roadrunner84 1 Quote Link to post Share on other sites
roadrunner84 466 Posted January 26, 2013 Share Posted January 26, 2013 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. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.