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.
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:
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)
Our initialization function:
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); ConvertFromUTCTimeType(&currTimeBuf, timeBuf); SetConfigRegisterTimeStamp(&currTimeBuf); //2. Initialize Port registers, without enabling interrupts GPIO_Init(); //3. LF Crystal Clk_Init(); //4. Clear the LOCKLPM bit PM5CTL0 &= ~LOCKLPM5; //5. Enable port interrupts as necessary GPIO_EnableInterrupts(); //6. Enable module interrupts ADC_Init(); RTC_enableInterrupt(RTC_BASE, RTC_OVERFLOW_INTERRUPT); Hardware_Version hwVersion = ReadHardwareVersion(); //7. After enabling the port and module interrupts, the wakeup interrupt is serviced as normal interrupt __enable_interrupt(); ... }
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:
RTC_start(RTC_BASE, RTC_CLOCKSOURCE_XT1CLK);
Our RTC ISR:
/* * 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 case 2: //RTC overflow/interrupt pending // ISR is called every minute and will store the 60s in utcTimeStamp if (GetStatusRegister().ContinuousMode_EN){ secSince1970value += RTC_INT_SECONDS; // FRAM must not be edited, as RAM is not lost during continuous mode operation }else{ currTimeBuf = GetConfigRegister().Timestamp; ConvertToUTCTimeType(&secTimeBuf, &currTimeBuf); if(GetStatusRegister().DeepSleep_EN){ secTimeBuf += RTC_INT_DEEP_SLEEP_SECONDS; RTC_ADC_ISR(); // This is called every wake up during LPM3.5, as rtc_minuteDiv is lost }else{ secTimeBuf += RTC_INT_SECONDS; secSince1970value += RTC_INT_SECONDS; } ConvertFromUTCTimeType(&currTimeBuf, secTimeBuf); SetConfigRegisterTimeStamp(&currTimeBuf); } rtc_temperatureFlag = true; rtc_lightFlag = true; rtc_minuteDiv++; if (rtc_minuteDiv >= RTC_INT_ADC_MIN) // this part is called every hour, during LPM3 { rtc_minuteDiv = 0; RTC_ADC_ISR(); } // Wake-up controller __bic_SR_register_on_exit(LPM3_bits); break; default: FRAM_SetErrorCode(ERR_RTC_ISR_NOT_HANDLED); GPIO_ToggleDebugPin(DEBUG_ERROR_3); break; } }
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:
// 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) }
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
// 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;
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