cancel
Showing results for 
Search instead for 
Did you mean: 

The RTC on my STM32L476RG MCU does not reliably cause a repetitive interrupt.

Clark Sann
Senior

I just had a problem where my RTC timer did not fire the callback as it should. Most of the time it works fine, but yesterday on a customers system, it did not. The log shows the callback occurred, then the callback reinitialized the timer (in Start_RTC_Wakeup_Timer) just as it has thousands of times before. But after it was restarted this time, the callback never fired again. The log showed the system continued doing other things just as it should. The system was not locked up. The only problem was the RTC never fired again.

This failure was rather catastrophic because the RTC was supposed to kick off a number of important processes.

What would cause this? Do I need to have a timer to monitor the RTC and restart the system if this happens again. Doesn't seem like I should need to do this...

Clark

My RTC code is this:

// initialization
static void MX_RTC_Init(void)
{
 
 /* USER CODE BEGIN RTC_Init 0 */
 
 /* USER CODE END RTC_Init 0 */
 
 RTC_TimeTypeDef sTime = {0};
 RTC_DateTypeDef sDate = {0};
 
 /* USER CODE BEGIN RTC_Init 1 */
 
 /* USER CODE END RTC_Init 1 */
 /** Initialize RTC Only
 */
 hrtc.Instance = RTC;
 hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
 hrtc.Init.AsynchPrediv = 127;
 hrtc.Init.SynchPrediv = 255;
 hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
 hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
 hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
 hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
 if (HAL_RTC_Init(&hrtc) != HAL_OK)
 {
  Error_Handler();
 }
 
Initialize in main like this:
	rtcWakeUpCounter = 29;		// wakeup every 30 seconds
	Start_RTC_Wakup_Timer();
 
void Start_RTC_Wakup_Timer(void)
{
	/* Enable wakeup source for analog scan */
	HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
	HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, rtcWakeUpCounter, RTC_WAKEUPCLOCK_RTCCLK_DIV16  RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
	SaveLogToSD("Reset / start RTC wakeup timer");
}
 
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) {      // fires every 30 seconds
	SaveLogToSD("**********  RTC wakeup  **********");
 
// Do a few things here.....
 
	Start_RTC_Wakup_Timer();
}

1 ACCEPTED SOLUTION

Accepted Solutions
Piranha
Chief II

Why are you disabling/enabling the wakeup feature after each event? That feature is periodic!

And, if you call HAL_RTC...() functions from several threads or interrupts, which can interrupt each other, then it will inevitably fail because of the broken HAL_LOCK logic inside those functions.

View solution in original post

5 REPLIES 5
Piranha
Chief II

Why are you disabling/enabling the wakeup feature after each event? That feature is periodic!

And, if you call HAL_RTC...() functions from several threads or interrupts, which can interrupt each other, then it will inevitably fail because of the broken HAL_LOCK logic inside those functions.

Clark Sann
Senior

@Piranha​ 

To answer your question, I have no idea why I did that! I just looked at an example and you are right, ST does not call those functions from inside the callback. Obviously it is totally unnecessary and probably harmful. Thank you for your assistance!!!!

Regarding where to call HAL_RTC functions...once I remove Start_RTC_Wakeup_Timer from the callback, the only place I am calling those functions if from main.

Again, I think you just saved me a lot of time. Thank you!

Clark

Piranha
Chief II

By the way, just noticed another potential problem! You are calling SaveLogToSD() from interrupt context. Make sure it's allowed to call it from interrupts at all. If it uses FatFS or something like that, then most likely it's not allowed. Also using any blocking read/write calls or printf() in interrupt context can delay interrupt for a long time. It depends on a specific use case whether such delays can be tolerated.

In other words, it's generally a bad idea. The recommended approach is to do only quick things in interrupt and do long ones in main/thread context. For debugging purposes one can use LEDs, flags, counters, arrays of flags/counters etc. But, if you really need those human readable texts to be logged from interrupts, then consider, for example, making a table of those texts and passing an ID/index (and timestamp, if necessary) as a message to a queue, from which they are read later by a log processing task and formatted and written out to SD or whatever.

Clark Sann
Senior

Thank you again. I will fix this. I use the RTC callback to acquire ADC data and transmit it via cellular. I have queued the cellular transmission but I figured the write to FatFS would be ok. But I will fix this. What about acquiring data from an analog input whose data is acquired by I2C? How can I determine if this is disallowed?

Clark Sann
Senior

I think it will be easy to move almost everything out of the RTC callback to the main thread. Right now I read the new values in the callback, pass them to cellular in the main thread, and log to SD in the callback. That’s absurd. It would be just as easy to use the RTC as nothing more than a method to accurately set a flag at a precise interval. Then in the main thread when the flag is seen - acquire, transmit, and log. You have really helped me.