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.

MSP430FR2476: Waking up from LPM3.5 mode via RTC interrupt does not always work

Part Number: MSP430FR2476

Hi,

We have designed a board with the MSP430FR2476, which operates most of the time in a low power mode. The RTC interrupt wakes up the controller every minute from LPM3 mode or every 30 min if the controller is in LPM3.5 mode to update date and time. The controller enters LPM3.5 after two hours of inactivity. Normally the firmware works fine and date/time are correct. But sometimes (after a few days) the controller does not wake up from LPM3.5. Only a reset could start the controller again. Their shouldn't be a problem with the power supply, because the battery is full and after resetting, the controller is working fine again. Unfortunately, the problem cannot be traced in a defined way. Sometimes it occurs after one day and sometimes after several days.

Our code for entering LPM3.5:

Fullscreen
1
2
3
4
5
WDT_A_hold(WDT_A_BASE); // Disable Watchdog
PMMCTL0_H = PMMPW_H; // Open PMM Registers for write
PMMCTL0_L |= PMMREGOFF; // Disable power regulator
__bis_SR_register(LPM3_bits + GIE); // Enter LPM3.5, with interrupts enabled
__no_operation(); // Do nothing (just for debugging)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Our initialization function:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void BL_Init()
{
// Configure FRAM write protection
SYSCFG0 = PFWP | DFWP | FRWPPW | FRWPOA5 | FRWPOA4 | FRWPOA3 | FRWPOA2 | FRWPOA1 | FRWPOA0;
SysCtl_enableFRAMWrite(SYSCTL_FRAMWRITEPROTECTION_DATA | SYSCTL_FRAMWRITEPROTECTION_PROGRAM);
// Wake up routine according to datasheet section 1.4.3.3 (Wake up from LPM3.5)
// 1. Init RTC, but do not enable interrupts
// Get current time from ConfigReg
rtcTime_t currTimeBuf = GetConfigRegister().Timestamp;
__time64_t timeBuf;
ConvertToUTCTimeType(&timeBuf, &currTimeBuf);
// Initialize RTC with Deep Sleep Timings
RTC_init(RTC_BASE, (uint16_t) RTC_INT_DEEP_SLEEP_SECONDS * RTC_FREQUENCY, RTC_CLOCKPREDIVIDER_1024);
// Add current time in rtccnt
uint16_t time = RTCCNT + FRAM_GetRTCDivError();
timeBuf += time / RTC_FREQUENCY;
FRAM_SetRTCDivError(time % RTC_FREQUENCY);
// Start and reset RTC
RTC_start(RTC_BASE, RTC_CLOCKSOURCE_XT1CLK);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Is there a way to find out why the wake up is blocked?


Best regards

Christian

  • Hi Christian, 

    Just to narrow the possibilities since it seems a bit odd that you are unable to reproduce the error consistently, have you tried to run this same code on a another FR2476? 

    What behavior have you seen from clock source? Any inconsistencies? 

    regards, 

    Henok

  • Hi Henok,

    Yes, we have this issue on several boards with the same firmware. The odd thing is that if I add further debug outputs to narrow down the error, the error does not occur. But that is not a solution, because the error could occur after a longer period of time. Thus, we must find the error.

    I also thought the clock source could be a possible source of error. I caused severe temperature fluctuations on the board with a cooling spray and a hot-air gun, but the error does not occur.

    Thanks for your suggestions!

    Christian

  • Christian, 

    Hmm okay there must be something wrong with the code then. An issue like this is a bit unfamiliar to me, I will reach out to teammates. 

    Are you using VLOCLK or XT1CLK?

    In the meantime, can you share your RTC Interrupt service routine? I would like to see how it is being implemented.

    regards, 

    Henok

  • Hi Henok,

    I made further tests on Friday and the wake-up issue occurs also with the actual debug version after about three hours. It was the first time that it occurs after the first entry of LPM3.5.

    We are using XT1CLK for the RTC:

    Fullscreen
    1
    RTC_start(RTC_BASE, RTC_CLOCKSOURCE_XT1CLK);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Our RTC ISR:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /*
    * RTC-overflow after every minute -> add 60 seconds to utcTimestamp
    * Overflow after RTC_INT_SECONDS in LPM3
    * Overflow after RTC_INT_DEEP_SLEEP_SECONDS in LPM3.5
    */
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=RTC_VECTOR
    __interrupt
    #elif defined(__GNUC__)
    __attribute__((interrupt(RTC_VECTOR)))
    #endif
    void RTC_ISR(void)
    {
    rtcTime_t currTimeBuf;
    __time64_t secTimeBuf;
    static uint8_t rtc_minuteDiv = 0;
    switch (__even_in_range(RTCIV, 2))
    {
    case 0:
    break; //No interrupt pending
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Thanks for your help!

    Christian

  • Hi Christian, 

    Thanks for sharing. Will get back to you within 24 hours. 

    regards, 

    Henok

  • Hi Christian, apologies for the delay, very busy week. 

    Nothing in the code pops out at me so here is an option.

    Can you scale your RTC to a much faster time? for example instead of having to wait 3 hrs lets make the wakeup increments much sooner. Lets see if we catch where the fault is. Assuming you scale everything to the same extent (for example 10x shorter periods) we should see the same behavior just at a much quicker time. 

    regards, 

    Henok

  • Hi Henok,

    Sorry, I forgot to mention that we have already scaled everything with a factor of 10. I also thought that it will occur more often, but the issue never occurred with the faster version.

    We did some more measurements on the crystal, but the clock signal was always stable.

    I have found one deviation from the User’s Guide for entering LPM3.5. In section 1.4.3.1 is stated that the general interrupt enable (GIE) shall be cleared before entering LPM3.5. Thus, I changed the code as follows:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // Enter LPM3.5
    while (1)
    {
    WDT_A_hold(WDT_A_BASE); // Disable Watchdog
    __bic_SR_register(GIE); // clear the GIE bit
    PMMCTL0_H = PMMPW_H; // Open PMM Registers for write
    PMMCTL0_L |= PMMREGOFF; // Disable power regulator
    __bis_SR_register(LPM3_bits | GIE); // Enter LPM3.5, with interrupts enabled
    __no_operation(); // Do nothing (just for debugging)
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Is that so ok?

    Strangely, if I do not enable GIE again, the controller still wakes up by GPIO or RTC interrupts. Is that a correct behaviour?

    Regards,

    Christian

  • Hi Christian, 

    I don't believe if line 5 is necessary. I am looking at one of the RTC examples we have and I don't see it there. 

    Are you working off of this example? https://dev.ti.com/tirex/explore/node?node=AHHV7PMTsKxeoPY6Yj2nEA__IOGqZri__LATEST

    Also is it necessary to have these initializations in the while loop? These typically are in the main set up.

    regards, 

    Henok

  • I don't know the answer to your original question, but for your other questions:

    1) The disable (Sec 1.4.3.1 Step (8)) is as far as I know just to avoid being interrupted during the LPM setup (the next 3 lines). That said, I suppose forgetting to do it could cause an intermittent failure if you have many stray interrupts.

    2) GIE is inoperative while in LPMx.5, since the CPU is powered off. Setting the GIE on the LPM line is for a pin wakeup, and comes from Sec 8.3.3 (b) "Note", to avoid a race where the wakeup pin transitions during the previous 3 code lines, and thus the transition isn't recognized later. The enable allows the ISR to run (at the last-moment) before LPM. I haven't seen an analogous note for the RTC wakeup, so I suppose that doesn't apply.

    [Edit: I forgot to ask: How do you know that it doesn't wake up? Is it (e.g.) possible it did wake up, but then malfunctioned? This distinction helps to know in which direction to look.]

  • Hi Henok,

    As Bruce mentioned, I want to avoid being interrupted during the LPM setup. I will test if it could be a problem when an interrupt occurs during entering LPM setup today.

    Yes, I know this example and it is pretty the same sequence as we use. The only difference is that we do not distinguish between coming out of an LPM3.5 or a regular reset. The device won’t be reset in normal case.

    The while loop is not necessary. It is only there to ensure entering LPM3.5 if it should go wrong the first time. But you are right. If there is a problem entering LPM3.5, the second, third, ... time could also fail. That results in an infinite loop. I will remove the while loop. I could measure the current consumption curve if there is really a problem entering the LPM3.5.

    Thanks

    Christian

  • Hi Bruce,

    Thank you very much for your answers.

    Our board can communicate via SPI interface. Therefore, we have a GPIO pin to wake-up the controller and hold it in a continuous mode. If the problem occurs, then the wake-up also does not work via GPIO pin and the SPI communication fails.

    I am also measuring the current consumption curve to analyse if the controller is in LPM3, LPM3.5 or normal mode. But the problem occurs so rarely that I don’t have a measurement of it yet.

    Regards,

    Christian

  • Christian, 

    As Bruce mentioned, I want to avoid being interrupted during the LPM setup. I will test if it could be a problem when an interrupt occurs during entering LPM setup today.

    I would like to see what you find from this as well. This looks like where the issue may be.

    If there is a problem entering LPM3.5, the second, third, ... time could also fail. That results in an infinite loop. I will remove the while loop.

    Agreed, this was my concern with the while loop.

    Let me know what you find. I will keep looking as well.

    regards, 

    Henok

  • Hi Henok,

    I tried to reproduce the issue with the while loop by triggering several interrupts during entering LPM3.5, but it did not occur. I have removed the while loop and started a long-term test. One setup is running over a week with no problems. We will repeat this test with several setups to ensure that the issue is solved.

    I have one further question: I want to trigger a software reset if the controller fails to enter LPM3.5. What is the best solution for that? I clear the LPM3 bits to wake up the controller and set the Software POR bit in the PMMCTL0 register (see code below). Is that ok, or do you have a better solution?

    Regards,

    Christian

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Enter LPM3.5
    WDT_A_hold(WDT_A_BASE); // Disable Watchdog
    __bic_SR_register(GIE); // Clear the GIE bit
    PMMCTL0_H = PMMPW_H; // Open PMM Registers for write
    PMMCTL0_L |= PMMREGOFF; // Disable power regulator
    __bis_SR_register(LPM3_bits + GIE); // Enter LPM3.5, with interrupts enabled
    __no_operation(); // Do nothing (just for debugging)
    // The following code shall not be reached in normal cases, only if entering LPM3.5 mode fails
    __bic_SR_register(LPM3_bits);
    // Trigger a reset by software
    PMMCTL0 = PMMPW|PMMSWPOR;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Hi Christian, 

    Great! looks like we are getting somewhere.

    So there are a few ways, you can use the PMM like you are or implement a watchdog timer. 

    With the watchdog, a PUC reset occurs when it does not get fed by the CPU. Since you get to set your interval here it may actually be quicker than doing a POR. 

    regards, 

    Henok

**Attention** This is a public forum