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.

MSP430FR4133: Wakeup State from LPM3.5

Part Number: MSP430FR4133

I am trying to understand how everything works when the device wakes up from LPM3.5.  My setup is basically reading data from a sensor and displaying that data on the LCD, using an RTC to take readings from the sensor every 10 minutes.  For most of the time, the unit will be in LPM3.5 with the RTC and LCD operational using the XT1 crystal.  Also, during this time in LPM3.5, I have all the GPIO that are not associated with the LCD/XT1 crystal set as an output and driven low for low power.  When I wakeup from LPM3.5, I want to setup some IO ports and timers to get my sensor reading, write the value to the LCD memory, and then go back to LPM 3.5. 

Reading the userguide, it seems when LOCKLPM5 is set (by entering LPM3.5), it locks the pin states AND the configurations of the RTC and LCD.  From the userguide: "After wakeup from LPMx.5, the state of the I/Os and the modules connected to the RTC LDO are locked and remain unchanged until you clear the LOCKLPM5 bit in the PM5CTL0 register."  The datasheet indicates that the RTC and LCD are in the "LPM3.5 domain". 

Since I have all the GPIO not used in LPM3.5 set as output and low, if I want to set some IO for the sensor operation, I obviously need to change the port mapping, and thus clear the LOCKLPM5 bit.  When I clear the LOCKLPM5 bit, this forces me to have to reinitialize the XT1, RTC, and LCD controller, correct? The portion from the user guide below seems to indicate I do have to reinitialize pretty much everything since a wakeup is a BOR.  EDIT:  It seems the RTC and LCD settings do persist after an LPM3.5 wakeup and I do not have to reinitialize them.  I found an example where they didn't reinit these, and it is working fine, so that is a little confusing....

The user guide also mentions in "Wake Up From LPM3.5" "

1.4.3.3 Wake up From LPM3.5
Do the following steps after a wakeup from LPM3.5:
1. Initialize the registers of the modules connected to the RTC LDO exactly the same way as they were
configured before the device entered LPM3.5 but do not enable the interrupts.
2. Initialize the port registers exactly the same way as they were configured before the device entered
LPM3.5 but do not enable port interrupts.
3. If the LF-crystal-oscillator was used in LPM3.5 the corresponding I/Os must be configured as LFXIN
and LFXOUT. The LF-crystal-oscillator must be enabled in the clock system (see the clock system CS
chapter).
4. Clear the LOCKLPM5 bit in the PM5CTL0 register.
5. Enable port interrupts as necessary.
6. Enable module interrupts.
7. After enabling the port and module interrupts, the wake-up interrupt is serviced as a normal interrupt.

In my case, before I entered LPM3.5, I had some of the ports that are used for the sensor reading as output/low for low power.  But when I wakeup to take the measurement, I will want some driven high, and a couple as an input.  Do I need to set the port registers as all output/low (that aren't used for XT1 and LCD) before I then set the ports I need for the sensor reading?

I have been looking at the RTC example that displays a time on the LCD on a Launchpad board.  I guess the reason this example never had to reinitialize anything when it woke up from LPM3.5 is that it never has to clear the LOCKLPM5 bit, since it is only using the RTC and LCD:

int main( void )
{
    WDTCTL = WDTPW | WDTHOLD;                               // Stop watchdog timer

    if (SYSRSTIV == SYSRSTIV_LPM5WU)                        // If LPM3.5 wakeup
    {
        Inc_RTC();                                          // Real clock

        PMMCTL0_H = PMMPW_H;                                // Open PMM Registers for write
        PMMCTL0_L |= PMMREGOFF_L;                           // and set PMMREGOFF
        __bis_SR_register(LPM3_bits | GIE);                 // Re-enter LPM3.5
    }
    else
    {
        // Initialize GPIO pins for low power
        Init_GPIO();

        *Seconds = 0;                                       // Set initial time to 12:00:00
        *Minutes = 0;
        *Hours = 12;

        // Configure XT1 oscillator
        P4SEL0 |= BIT1 | BIT2;                              // P4.2~P4.1: crystal pins
        do
        {
            CSCTL7 &= ~(XT1OFFG | DCOFFG);                  // Clear XT1 and DCO fault flag
            SFRIFG1 &= ~OFIFG;
        }while (SFRIFG1 & OFIFG);                           // Test oscillator fault flag
        CSCTL6 = (CSCTL6 & ~(XT1DRIVE_3)) | XT1DRIVE_2;     // Higher drive strength and current consumption for XT1 oscillator

        // Disable the GPIO power-on default high-impedance mode
        // to activate previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;

        // Configure RTC
        RTCCTL |= RTCSS__XT1CLK | RTCIE;                    // Initialize RTC to use XT1 and enable RTC interrupt
        RTCMOD = 32768;                                     // Set RTC modulo to 32768 to trigger interrupt each second

        // Configure LCD pins
        SYSCFG2 |= LCDPCTL;                                 // R13/R23/R33/LCDCAP0/LCDCAP1 pins selected

        LCDPCTL0 = 0xFFFF;
        LCDPCTL1 = 0x07FF;
        LCDPCTL2 = 0x00F0;                                  // L0~L26 & L36~L39 pins selected

        LCDCTL0 = LCDSSEL_0 | LCDDIV_7;                     // flcd ref freq is xtclk

        // LCD Operation - Mode 3, internal 3.08v, charge pump 256Hz
        LCDVCTL = LCDCPEN | LCDREFEN | VLCD_6 | (LCDCPFSEL0 | LCDCPFSEL1 | LCDCPFSEL2 | LCDCPFSEL3);

        LCDMEMCTL |= LCDCLRM;                               // Clear LCD memory

        LCDCSSEL0 = 0x000F;                                 // Configure COMs and SEGs
        LCDCSSEL1 = 0x0000;                                 // L0, L1, L2, L3: COM pins
        LCDCSSEL2 = 0x0000;

        LCDM0 = 0x21;                                       // L0 = COM0, L1 = COM1
        LCDM1 = 0x84;                                       // L2 = COM2, L3 = COM3

        LCDCTL0 |= LCD4MUX | LCDON;                         // Turn on LCD, 4-mux selected (LCD4MUX also includes LCDSON)

        // Display time
        LCDMEM[pos1] = digit[(*Hours) / 10];
        LCDMEM[pos2] = digit[(*Hours) % 10];
        LCDMEM[pos3] = digit[(*Minutes) / 10];
        LCDMEM[pos4] = digit[(*Minutes) % 10];
        LCDMEM[pos5] = digit[(*Seconds) / 10];
        LCDMEM[pos6] = digit[(*Seconds) % 10];

        // Display the 2 colons
        LCDMEM[7] = 0x04;
        LCDMEM[11] = 0x04;

        PMMCTL0_H = PMMPW_H;                                // Open PMM Registers for write
        PMMCTL0_L |= PMMREGOFF_L;                           // and set PMMREGOFF
    
        __bis_SR_register(LPM3_bits | GIE);                 // Enter LPM3.5
        __no_operation();                                   // For debugger
    }
}

  • Hi Alexander,

    Firstly, I do a summary for your question, please correct me if there any misunderstand:
    You need communocate with sensor via some GPIO when exit from LPM3.5, thus you have to clear LOCKPM5 bit to unlock GPIO.And you would like to learn if you need to re-initialize GPIO for crystal after wake up from LPM3.5 mode.

    I think is yes, you have to re-init LFXT module and clear LOCKPM5 bit, you can refer to this example code:

    https://dev.ti.com/tirex/explore/node?node=AIIst5gLtBM7DVuyhd5.8A__IOGqZri__LATEST

    Thanks!

    Best Regards

    Johnson

  • Thanks for the reply! Yeah, looks like everytime it wakes up I have to reinit the gpio and XT1, but the RTC and LCD configuration persists. 

  • On another related note to wakeup behavior, in my code I have two wakeup sources from lpm3.5, the RTC and I/O.  After the BOR reset when coming out of LPM3.5, I have to check which interrupt was the source of the wakeup so I know which function to call.  The first line in wakeup code is __enable_interrupt(), which should make the RTC or I/O ISR execute.  In the I/O ISR I basically set a flag, and if that flag is true, then I execute function A.  If not, then I know it was an RTC interrupt and I execute function B.  It seems to me that there is a little bit of a delay after it executes __enable_interrupt() and the ISR starts to execute.  In my code it executes the line below _enable_interrupt() before it jumps to the ISR.  Does this seem correct?

    if (SYSRSTIV == SYSRSTIV_LPM5WU)                        // If LPM3.5 wakeup
            {
                __enable_interrupt();
                // The below line will get executed before jumping to the ISR
                display_units = BAKMEM0;  //Get display_units from bakmem
                // Between above line and below line, the ISR will execute. 
                temperature_c = BAKMEM1; // Get temperature displayed from bakmem
              
                if (button_flag)
                {
                    functionA();
                }
                else
                    functionB();

    I can't really find any documentation on how long the ISR takes to execute after enabling interrupts. 

    After thinking about it a little more, I am not sure I even need any ISR's for these wakeup interrupts.  The main function essentially serves as a large ISR for my two wakeup sources.  I could just check the P1IV register upon wakeup to see if it was my I/O (button) that was the source of the wakeup.  (If not, then I know it is the RTC and can read the RTCIV to clear it). 

  • Hi Alexander,

    Your question is that there are some delay between __enable_interrupt() and ISR?

    How much the delay? does this will affect your application?

    I think if you would like to know the source of wake-up, as you describe, you can check the P1IV or RTCIV.

    Thanks!

    Best Regards

    Johnson

**Attention** This is a public forum