STM32L151 RTC Alarm interrupt

13,139

Solution 1

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.

Solution 2

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
   }
}
Share:
13,139
uv_utna
Author by

uv_utna

Updated on June 04, 2022

Comments

  • uv_utna
    uv_utna almost 2 years

    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

  • Kennet Celeste
    Kennet Celeste about 5 years
    is this a legitimate approach ? or it's a workaround ?
  • Kennet Celeste
    Kennet Celeste about 5 years
    how can one make this every 5 seconds for instance?
  • Bence Kaulics
    Bence Kaulics about 5 years
    @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.
  • Mohammad Kholghi
    Mohammad Kholghi over 2 years
    You MUST use HAL_RTC_GetDate after HAL_RTC_GetTime. Otherwise, it's locked.
  • Mohammad Kholghi
    Mohammad Kholghi over 2 years
    @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
    Mohammad Kholghi over 2 years
    @KennetCeleste it's a workaround. RTC generates an alarm every second automatically.