How to operate STM32L4 to reset the RTC alarm output (Alarm A once per second) as quickly as possible?

2024-01-08

Using a high-precision crystal oscillator as the RTC clock source, we want the 1-second output of the alarm clock to be synchronized with the 1PPS of the GPS. Now we use the rising edge of EXTI to trigger the interrupt to detect the 1PPS second pulse of the GPS. In the interrupt function, use HAL_RTC_SetTime() and HAL_RTC_SetDate( ) write the RTC time and turn off the EXTI interrupt. The subsequent alarm output will be dozens of milliseconds later than 1PPS. How can we make the two outputs as close as possible?
Alternatively, the RTC time can be written in advance. What method can be used to clear the current count when receiving the EXTI interrupt?
CubeMX configuration, PC5 1PPS input, PB2 alarm output.

If you want the 1 second output of the alarm clock to be synchronized with the 1PPS of the GPS, it is recommended to use the periodic wake-up function of the RTC alarm clock instead of using an external interrupt to detect the 1PPS second pulse. Specific steps are as follows:

1. Use HAL_RTC_Init() to initialize the RTC module, set the RTC clock source to a high-precision crystal oscillator, and the RTC clock frequency is LSE (32.768kHz)

2. Use the HAL_RTCEx_SetWakeUpTimer_IT() function to set the periodic wake-up function of the RTC so that the RTC wakes up the system once every second. In the callback function of this function, set the alarm clock and output the alarm clock.

3. Clear the RTC time in the HAL_RTCEx_RTCEventCallback() callback function.

The reference code is as follows:

```c
/*RTC initialization */
void RTC_Init(void)
{
   /* Enable backup access */
   HAL_PWR_EnableBkUpAccess();
   /* Enable LSE */
   __HAL_RCC_LSE_CONFIG(RCC_LSE_ON);
   /* Wait for LSE to stabilize */
   while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET);
   /* Select LSE as the RTC clock source */
   __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
   /* Enable RTC clock */
   __HAL_RCC_RTC_ENABLE();
   /* Initialize RTC */
   hrtc.Instance = RTC;
   hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
   hrtc.Init.AsynchPrediv = 127;
   hrtc.Init.SynchPrediv = 255;
   hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
   HAL_RTC_Init(&hrtc);
}

/* RTC wake-up callback function */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
   /* Turn off the alarm clock */
   HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
   /* Output alarm clock */
   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
   /* Clear time to zero */
   RTC_TimeTypeDef sTime;
   sTime.Hours = 0;
   sTime.Minutes = 0;
   sTime.Seconds = 0;
   HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
}

/* RTC event callback function */
void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc)
{
   /* Clear time to zero */
   RTC_TimeTypeDef sTime;
   sTime.Hours = 0;
   sTime.Minutes = 0;
   sTime.Seconds = 0;
   HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
}

/* Set RTC wake-up time and cycle */
void RTC_SetWakeUpTime(uint32_t WakeUpCounter)
{
   /* Turn off wake-up timer */
   HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
   /* Set wake-up period */
   HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, WakeUpCounter, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
   /* Set the alarm clock, the next wake-up time is 1 second later */
   RTC_TimeTypeDef sTime;
   sTime.Hours = 0;
   sTime.Minutes = 0;
   sTime.Seconds = 1;
   HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
   RTC_AlarmTypeDef sAlarm;
   sAlarm.AlarmTime.Hours = 0;
   sAlarm.AlarmTime.Minutes = 0;
   sAlarm.AlarmTime.Seconds = 1;
   sAlarm.AlarmTime.SubSeconds = 0;
   sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
   sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
   sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
   sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
   sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
   sAlarm.AlarmDateWeekDay = 1;
   sAlarm.Alarm = RTC_ALARM_A;
   HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
}
```

In the main function, you can use the following code to call the function for RTC initialization and setting the wake-up time:

```c
/* Initialize RTC */
RTC_Init();
/* Set wake-up time */
RTC_SetWakeUpTime(32768);
```

After this configuration, the RTC wakes up the system and outputs an alarm clock every second, synchronized with the 1PPS second pulse of the GPS. If you want to output an alarm immediately after receiving an external interrupt, you can use the HAL_RTC_WaitForSynchro() function to make the time setting take effect immediately. The specific code is as follows:

```c
/* External interrupt callback function */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
   if(GPIO_Pin == GPIO_PIN_5){
     /* Set the RTC time to the current time */
     RTC_TimeTypeDef sTime;
     sTime.Hours = your_hours;
     sTime.Minutes = your_minutes;
     sTime.Seconds = your_seconds;
     HAL_RTC_WaitForSynchro(&hrtc);
     HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
     /* Turn off interrupts and output alarm clock */
     HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
     HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
     HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
   }
}
```

Top