3

I am having problem with RTC alarm interrupt of STM32L151. I want my program to go to RTC alarm interrupt every second but it does not work. My main funtion:

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_IWDG_Init();
  MX_RTC_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();

  __HAL_RTC_ALARM_ENABLE_IT(&hrtc, RTC_IT_ALRA);

  while (1)
  {

  }
}

Function configures RTC: MX_RTC_Init():

void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime;
  RTC_DateTypeDef sDate;
  RTC_AlarmTypeDef sAlarm;

  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.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  HAL_RTC_Init(&hrtc);

  sTime.Hours = 0x14;
  sTime.Minutes = 0;
  sTime.Seconds = 0;
  sTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);

  sDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
  sDate.Month = RTC_MONTH_AUGUST;
  sDate.Date = 0x24;
  sDate.Year = 0x16;

  HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BCD);

    /**Enable the Alarm A 
    */
  sAlarm.AlarmTime.Hours = 0;
  sAlarm.AlarmTime.Minutes = 0;
  sAlarm.AlarmTime.Seconds = 0;
  sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);

}

I created project using CubeMX. Do you have any idea or advice for me? Thank you

uv_utna
  • 41
  • 1
  • 1
  • 3
  • You probably need to enable the interrupt in the NVIC. That may be hidden by some of this code, so it might be done already. Check and see if it is enabled in the NVIC, and if it is, check and see if the RTC interrupt enables are correct (also check and see if there is a pending interrupt). – rjp Sep 06 '16 at 18:17

3 Answers3

8

If a field is masked, then that won't be compared when checking alarm date. So when you mask SECONDS, then only the DAY, HOUR and MINUTE fields will be compared. The proper way of achieving 1 second interrupts with RTC is to use all alarm mask because this way none of the fields are compared and when the RTC increments the SECOND field an alarm interrupt will be generated.

sAlarm.AlarmMask = RTC_ALARMMASK_ALL;

Also all of this are described by ST in their Using the hardware real-time clock (RTC) in STM32 F0, F2, F3, F4 and L1 series of MCUs application note.

enter image description here

This is a very convenient solution as you do not have to reset the alarm after all interrupts.

Bence Kaulics
  • 7,066
  • 7
  • 33
  • 63
  • how can one make this every 5 seconds for instance? – Kennet Celeste Apr 06 '19 at 19:23
  • 2
    @KennetCeleste I am afraid to do that you have to mask everything except the seconds field and reconfigure the alarm at every interrupt. Something like in the other answer. What would simplfy it is moving from HAL to bare register approach because HAl has a huge overhead. – Bence Kaulics Apr 07 '19 at 07:59
  • @KennetCeleste You want a 5 seconds alarm? 1. mask time to every second, then use a variable as 0 and `var++;` till `var==5`. Now, call whatever function you'd like. (Don't forget to reset the variable to 0). 2. use timers. If you set RTC time to 5 seconds, IT WILL INTERRUPT AT `XX:XX:05`, NOT EVERY 5 SECONDS! – Mohammad Kholghi Oct 30 '21 at 20:22
1

As you have set sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS, the RTC will generate an interrupt when the seconds value of the time will match sAlarm.AlarmTime.Seconds which is 0 in your case. So you will have an interrupt every minute here if you leave the code as it is.

If you want an interrupt every second, you will have to set the alarm again with the next second in your interrupt handler. The code in your interrupt handler would look like:

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    RTC_TimeTypeDef sTime;
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    uint8_t next_second = sTime.Seconds++;
    if (next_second > 59) next_second = 0;

    RTC_AlarmTypeDef sAlarm;
    sAlarm.AlarmTime.Hours = 0;
    sAlarm.AlarmTime.Minutes = 0;
    sAlarm.AlarmTime.Seconds = RTC_ByteToBcd2(next_second);
    sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
    sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
    sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS;
    sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
    sAlarm.AlarmDateWeekDay = 1;
    sAlarm.Alarm = RTC_ALARM_A;
    HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);
}

For this to work, you have to make sure that you have set up properly the RTC clock (internal or external 32K).

Alternatively you could use the wake up function of the RTC, it would be more appropriate I think. Or in your main loop, you could use the HAL_GetTick to check that 1 second has elapsed since your last processing, like this:

static uint32_t last_second = 0;
void main(void)
{
   uint32_t current_second = HAL_GetTick();
   if (current_second - last_second > 1000)
   {
       last_second = current_second;

       //1 second has elapsed, do something
   }
}
Guillaume Michel
  • 1,189
  • 8
  • 14
0
  1. Don't call __HAL_RTC_ALARM_ENABLE_IT() directly. It's called by HAL_RTC_SetAlarm_IT().
  2. Enable Alarm B. Why? Because sometimes, as I've experienced, one alarm won't work. You "sometimes" have to enable both alarms.
  3. For masking, you have to mask all bits:
    sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES|RTC_ALARMMASK_SECONDS;

This way, you ask ST to just use seconds. You can also use RTC_ALARMMASK_ALL.

Mohammad Kholghi
  • 533
  • 2
  • 7
  • 21