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:
- To keep the microcontroller in a low power mode until a button is pushed or the RTC wakes it up (GPIO or RTC interrupt).
- To activate the associated interrupt service routing (ISR)
- Set a variable "interrupt_type" to "1" or "2" depending on which ISR is activated
- 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 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;
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;
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!
UPDATE: I can confirm now that the RTCfunction() does get called and the ISR for the RTC is able to modify the interrupt_type variable. THe GPIO ISR however cannot.