This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR2433: Low power mode 3.5 until a button is pushed or the RTC wakes it up (GPIO or RTC interrupt).

Part Number: MSP430FR2433

Hi Guys,

We need your help. 

Our customer is using an MSP430FR2433 with the development board from TI and want to use its low power mode 3.5 so that they can wake it up from a GPIO pin or the RTC. They are using one of the LPM3.5 example codes in the resource explorer in Code Composer studio as a reference.

Kindly check the attached file for the full inquiry.

TI question.txt

I am using an MSP430FR2433 with the development board from TI and want to use its low power mode 3.5 so that I can wake it up from a GPIO pin or the RTC. I am using one of the LPM3.5 example codes in the resource explorer in CodeComposer studio as a reference. My goal is:

1.     To keep the microcontroller in a low power mode until a button is pushed or the RTC wakes it up (GPIO or RTC interrupt).
2.    To activate the associated interrupt service routing (ISR)
3.    Set a variable "interrupt_type" to "1" or "2" depending on which ISR is activated
4.    Return to main() after the ISR and perform specific functions depending on the value of "interrupt_type".

I am able to do 1,2, and 3, but I am not able to change the value of "interrupt_type" in the PORT interrupt ISR. I am able to do it in the RTC ISR. In the port ISR, it is always the initialized value that was declared before main(). I have read that declaring it as a global (volatile) variable should make it work but it doesnt. Here is the relatively simple code in question:

#include <msp430.h>
void initGpio(void);
void initCrystalclk(void);
void GPIOfunction(void);
void RTCfunction(void);
volatile int interrupt_type = 0;
void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;               // stop watchdog timer
    initGpio();                             // Configure GPIO
    initCrystalclk();                       // Initialize XT1 32kHz crystal
    P1OUT |= BIT1;
    if (SYSRSTIV == SYSRSTIV_LPM5WU)        // If MCU wakes up from LPM3.5.
    {
           __enable_interrupt();               // The RTC interrupt should trigger now...
           __no_operation();         
          
           if(interrupt_type==1){
            GPIOfunction();
            }
           if(interrupt_type==2){
            RTCfunction();
           }
    }
    else {                  //waking up from cold start
        static int const Offtime=30;        //time in seconds to stay in LPM
        RTCMOD = 32*Offtime-1;              //forcing LPM3.5 (i.e. run RTC module)
        RTCCTL = RTCSS__XT1CLK | RTCSR |RTCPS__1024| RTCIE; //clock control bits
    }
    P2IES |= BIT3;                          // P2.3 low/high interrupt edge select for button
    P2IE |= BIT3;                           // P2.2 Interrupt enable  P1IE |= BIT6;  for MP
    P2IFG &=~BIT3;                          // in case PxIES set the interrupt flag
    PMMCTL0_H = PMMPW_H;                    // Open PMM Registers for write
    PMMCTL0_L |= PMMREGOFF;                 // and set PMMREGOFF
    __bis_SR_register(LPM3_bits | GIE); // enter LPM 3.5 with interrupts enabled
    __no_operation();
}

#pragma vector=PORT2_VECTOR                 //Interrupt routine when switch closes
__interrupt void Port_2()
{
    __disable_interrupt();          //this is to prevent RTC from interrupting (not tested)
    interrupt_type=1;		//DOESNT WORK
    P2IFG &=~BIT3;
}

#pragma vector = RTC_VECTOR
__interrupt void RTC_ISR(void)
{
    switch(__even_in_range(RTCIV, RTCIV_RTCIF))
    {
        case RTCIV_NONE : break;            // No interrupt pending
        case RTCIV_RTCIF:                   // RTC Overflow
            interrupt_type=2;		//WORKS
            break;
        default:          break;
    }
}

void GPIOfunction(void)
{
 //do something eg. blink led
}

void RTCfunction()
{
    //do something else
}

void initGpio(void)                         //initialize ports
{
    P1DIR = 0xFF; P2DIR = 0xFF; P3DIR = 0xFF;
    P2DIR &= ~BIT3;                         //Set P2.3 as input
    P2REN |= BIT3;                          //Enable Resistor
    P2OUT |= BIT3;                          //Configure P2.3 as pulled-up for debug purpose using button
    PM5CTL0 &= ~LOCKLPM5;                   //Turn ON digital I/O 
}
void initCrystalclk(void)                   //note: crystal clock needs to be connected on Dev board
{
    P2SEL0 |= BIT0 | BIT1;                  // set XT1 pin as second function (for crystal as clock)
       do
       {
           CSCTL7 &= ~(XT1OFFG | DCOFFG);   // Clear XT1 and DCO fault flag
           SFRIFG1 &= ~OFIFG;
       } while (SFRIFG1 & OFIFG);           // Test oscillator fault flag
}

If I put the GPIOfunction() or RTCfunction() inside the ISR, it works, but they are quite lengthy and have their own interrupts, which apparently is not good practice. Please let me know if there is a way to modify the variable value inside the ISR and have it readable by the main() after the ISR. Essentially I am hoping to set a flag inside the ISR that indicates which ISR was called so that I can run a specific subroutine in main(). Thanks in advance!

I can read the P2IFG vector at the beginning of main() to set the variable in main() instead of the ISR, but not sure this is a recommended way.

Thank you in advance for the support. 

Best regards,

Jonathan

  • Before go into the code, could you tell if any obvious problem there? 

  • The P2.3 IE bit needs to be enabled in order to trigger the PORT2 interrupt. This includes the case after the LPM3.5 wakeup. initGpio() is probably a reasonable place to do this. There are a couple of subtleties:

    1) initGpio() shouldn't clear the IFG, since it might be important. This should be done in the "else" part of the wakeup check.

    2) Setting the IES could trigger the IFG, but only if P2IN=0. But the REN will set P2IN=1 when LOCKLPM5 is cleared. So the sequence should be:

        P2IES |= BIT3;                          // P2.3 low/high interrupt edge select for button
        PM5CTL0 &= ~LOCKLPM5;                   //Turn ON digital I/O
        P2IE |= BIT3;                           // P2.2 Interrupt enable  P1IE |= BIT6;  for MP
    

  • Hi Bruce,

    Thank you for the response, however upon checking our customer, there are no problems with triggering the interrupt service routine when the port2 button is pressed. The issue is that after the port2 interrupt triggers, the associated Port2 ISR is not able to modify the global variable "interrupt_type". So as a workaround, they are checking the P2IFG vector in main() to modify the value. They would like to know if this workaround is advisable and is a good programming practice or there is a better way to do it.

    Best regards,

    Jonathan

  • Maybe I need to ask what it means to be "not able to modify..interrupt_type". What happens after the assignment?

    When I ran this code it didn't modify interrupt_type=1 since the ISR wasn't called since the IE wasn't enabled. When I fixed that, it did the assignment properly. Are they running the same code as posted above?

    [Full disclosure: I didn't have a 32kHz crystal, so I ran the RTC from VLOCLK. As far as I know that's the only thing I changed.]

  • Hi Jonathan

    Any more information about the Port2 ISR not able to modify the global variable "interrupt_type"?

    How about not add volatile to define the global variable "interrupt_type"?

  • Hi Gao and Bruce, 

    I will update you once our customer have the feedback. Thank you. 

    Best regards,

    Jonathan

  • Any update about this issue?

  • Hi Gary, 

    Sorry. I am still waiting for the update but none so far. If our customer have feedback I will surely update you. 

    Best regards,

    Jonathan

**Attention** This is a public forum