STM32L151 RTC Alarm interrupt

17.1k Views Asked by At

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

3

There are 3 best solutions below

3
Guillaume Michel On

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
   }
}
3
Bence Kaulics On

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 each interrupts.

0
Mohammad Kholghi On
  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.