2014-10-29 07:24 AM
Good afternoon, I have deal with STM32L152ZD RTC in alarm mode( alarm B), I need to make it interrupt every rtc_period seconds. Clocking source is LSE with frequency 32768 Hz, RTC working good, but interrupts not generated. Can your help me with it? Maybe some stupid mistake has place?
Appreciate your help, Daniil./*
* Each 15 seconds our RTC would make an event and interrupt.
*
* */
#define rtc_period 15
void
sw_irtc_initialization()
{
/// [000] �?а�?тройка ча�?ов реального времени.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/// Enable the PWR clock.
PWR_RTCAccessCmd(ENABLE);
/// Allow access to RTC.
RCC_RTCResetCmd(ENABLE);
/// Reset RTC Domain.
RCC_RTCResetCmd(DISABLE);
RCC_LSEConfig(RCC_LSE_ON);
/// Enable the LSE OSC.
while
(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}
/// Wait till LSE is ready.
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/// Select the RTC Clock Source.
RTC_InitTypeDef RTC_InitStructure;
/// Configure the RTC data register and RTC prescaler.
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStructure.RTC_AsynchPrediv = 0x7F;
RTC_InitStructure.RTC_SynchPrediv = 0xFF;
RTC_Init(&RTC_InitStructure);
RCC_RTCCLKCmd(ENABLE);
/// Enable the RTC Clock.
RTC_WaitForSynchro();
/// Wait for RTC APB registers synchronisation.
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
/// Enable the RTC Wakeup Interrupt.
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RTC_TimeTypeDef RTC_TimeStruct;
RTC_AlarmTypeDef RTC_AlarmStruct;
uint32_t current_time = 0;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
/// [0] Get current time.
current_time = RTC_TimeStruct.RTC_Hours*3600 +
/// [1] Go all to the seconds.
RTC_TimeStruct.RTC_Minutes*60 +
RTC_TimeStruct.RTC_Seconds;
current_time = current_time + rtc_period;
// [2] Add rtc_period seconds.
if
( current_time>864000 )
/// [3] If current time with addition seconds more then seconds in a one day:
{
RTC_TimeStruct.RTC_H12 = RTC_HourFormat_24;
// New day begins, so count from null.
RTC_TimeStruct.RTC_Hours = 0;
RTC_TimeStruct.RTC_Minutes = 0;
RTC_TimeStruct.RTC_Seconds = current_time - 864000;
}
else
{
RTC_TimeStruct.RTC_H12 = RTC_HourFormat_24;
// Still the same day, so convert time in seconds back to hours,minutes,seconds
RTC_TimeStruct.RTC_Hours = current_time/3600;
RTC_TimeStruct.RTC_Minutes = (current_time - RTC_TimeStruct.RTC_Hours*3600)/60;
RTC_TimeStruct.RTC_Seconds = (current_time - RTC_TimeStruct.RTC_Hours*3600 - RTC_TimeStruct.RTC_Minutes*60);
}
RTC_AlarmStruct.RTC_AlarmTime = RTC_TimeStruct;
// [4] Assign recalculated time to Alarm time structure.
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_Seconds;
// [5] Turn on alarm mask, RTC will make an event each time it count to the seconds value in RTC_AlarmTime.
RTC_AlarmCmd(RTC_Alarm_B, DISABLE);
// [6] Disable alarm b peripherial, need to make available SetAlarm function.
RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_B, &RTC_AlarmStruct);
// [7] SetAlarm with predefined parameters.
RTC_ITConfig(RTC_IT_ALRB, ENABLE);
// [7] Make RTC alarm B interrupt available.
RTC_ClearFlag(RTC_FLAG_ALRBF);
// [8] Clear alarm flag
RTC_AlarmCmd(RTC_Alarm_B, ENABLE);
// [9] Make alarm available
}
void
RTC_Alarm_IRQHandler()
{
if
(RTC_GetITStatus(RTC_IT_ALRB) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_ALRB);
RTC_TimeTypeDef RTC_TimeStruct;
RTC_AlarmTypeDef RTC_AlarmStruct;
uint32_t current_time = 0;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
/// [0] Get current time.
current_time = RTC_TimeStruct.RTC_Hours*3600 +
/// [1] Go all to the seconds.
RTC_TimeStruct.RTC_Minutes*60 +
RTC_TimeStruct.RTC_Seconds;
current_time = current_time + rtc_period;
// [2] Add rtc_period seconds.
if
( current_time>864000 )
/// [3] If current time with addition seconds more then seconds in a one day:
{
RTC_TimeStruct.RTC_H12 = RTC_HourFormat_24;
// New day begins, so count from null.
RTC_TimeStruct.RTC_Hours = 0;
RTC_TimeStruct.RTC_Minutes = 0;
RTC_TimeStruct.RTC_Seconds = current_time - 864000;
}
else
{
RTC_TimeStruct.RTC_H12 = RTC_HourFormat_24;
// Still the same day, so convert time in seconds back to hours,minutes,seconds
RTC_TimeStruct.RTC_Hours = current_time/3600;
RTC_TimeStruct.RTC_Minutes = (current_time - RTC_TimeStruct.RTC_Hours*3600)/60;
RTC_TimeStruct.RTC_Seconds = (current_time - RTC_TimeStruct.RTC_Hours*3600 - RTC_TimeStruct.RTC_Minutes*60);
}
RTC_AlarmStruct.RTC_AlarmTime = RTC_TimeStruct;
// [4] Assign recalculated time to Alarm time structure.
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_Seconds;
// [5] Turn on alarm mask, RTC will make an event each time it count to the seconds value in RTC_AlarmTime.
RTC_AlarmCmd(RTC_Alarm_B, DISABLE);
// [6] Disable alarm b peripherial, need to make available SetAlarm function.
RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_B, &RTC_AlarmStruct);
// [7] SetAlarm with predefined parameters.
RTC_ITConfig(RTC_IT_ALRB, ENABLE);
// [7] Make RTC alarm B interrupt available.
RTC_ClearFlag(RTC_FLAG_ALRBF);
// [8] Clear alarm flag
RTC_AlarmCmd(RTC_Alarm_B, ENABLE);
// [9] Make alarm available
}
}
#stm32l152 #rtc #rtc-alarm
2014-10-29 09:37 AM
Hi
Im no expert because I have not actually used the RTC myself (yet). Looking at your line and comment ''NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
/// Enable the RTC Wakeup Interrupt.
''
This could be the wrong IRQ.
The RTC has 2 different IRQs - 1 for wakeup which is used for the low power modes
1 for Alarm A/B - 'RTC_Alarm_IRQHandler' I think this is the one you want to use.
2014-10-29 09:51 AM
The RTC has 4 different IRQ, but they are routed through the EXTI controller, thus they have to be enabled not only in NVIC, but also in EXTI.
Read ch.19.5 ''RTC interrupts'' in RM0038. JW2014-10-29 09:53 AM
Hi
OK, I said I was not an expert. I just had a look around the code and defines. You have the right NVIC IRQ number and the ISR name should be correct. So it is just your comment that is wrong. Still do not know why you are not getting the IRQ.2014-10-30 12:11 AM
Ok, EXTI line 17 initialization has been added. EXTI 17 in interrupt mode, sensetive to rising edge.
2014-10-30 12:28 AM
Problem has been detected: ^)
// [5] Turn on alarm mask, RTC will make an event each time it count to the seconds value in RTC_AlarmTime.
// RTC_AlarmMask_Seconds not working - right way is to use RTC_AlarmMask_DateWeekDay;
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay;
Now interrupt is working, but I have a problem to reset interrupt... still dig deep.
2014-10-30 02:35 AM
One problem has been detected, we have to use some kit of masks,
RTC_AlarmMask_DateWeekDay
make interrups available.
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay;
Now interrupt is working in one second mode, but I need to make one interrupt in 32 sec, for example!!! No any reaction on RTC_AlarmStructvalues!!! I have changed code for better understanding:void
sw_irtc_initialization()
{
/// === [RTC global variables init. ][begin] =====================================================================
sw_irtc_alarm_b_counter = 0;
/// [0] initial value of alarm b counter. global variable.
sw_irtc_measured_frequency = 3276;
/// [1] measured frequency of LSE osc. - RTC clock source.
/// === [RTC global variables init. ][end ] =====================================================================
/// === [RTC hardware initialization][begin] =====================================================================
RTC_WriteProtectionCmd(DISABLE);
/// [2] remove RTC registers write protection
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/// [3] Enable the PWR clock.
PWR_RTCAccessCmd(ENABLE);
/// [4] Allow access to RTC.
RCC_RTCResetCmd(ENABLE);
/// [5] Reset RTC Domain.
RCC_RTCResetCmd(DISABLE);
RCC_LSEConfig(RCC_LSE_ON);
/// [6] Enable the LSE OSC. Nominal frequency is 768 kHz.
while
(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}
/// [7] Wait untill LSE is ready.
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/// [8] Select LSE as RTC Clock Source.
RTC_InitTypeDef RTC_InitStructure;
/// [9] Configure the RTC data register and RTC prescaler.
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStructure.RTC_AsynchPrediv = 0x7F;
RTC_InitStructure.RTC_SynchPrediv = 0xFF;
RTC_Init(&RTC_InitStructure);
RCC_RTCCLKCmd(ENABLE);
/// [10] Enable the RTC Clock.
RTC_WaitForSynchro();
/// [11] Wait for RTC APB registers synchronisation.
/// Just formal without error handler
/// === [RTC hardware initialization][end] =======================================================================
/// === [RTC interrupt settings ][begin] =====================================================================
EXTI_InitTypeDef exti;
/// [12] According to manual RTC Alarm interrupt works
EXTI_ClearITPendingBit(EXTI_Line17);
/// in pair with external interrupt controller line
exti.EXTI_Line = EXTI_Line17;
exti.EXTI_Mode = EXTI_Mode_Interrupt;
/// Mode is interrupt, not event.
exti.EXTI_Trigger = EXTI_Trigger_Rising;
/// Interrupt sensetive to rising edge.
exti.EXTI_LineCmd = ENABLE;
/// Make line available.
EXTI_Init(&exti);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
/// [13] Enable the RTC Alarm Interrupt.
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// Interruption priority does not matter, time period near 32 seconds.
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/// === [RTC interrupt settings ][end ] =====================================================================
DBGMCU_APB1PeriphConfig(DBGMCU_RTC_STOP, ENABLE);
/// [14] Should stop RTC in debug state when the core is halted.
/// Without it hard to follow code execution in breakpoints.
sw_irtc_alarm_set();
/// [15] Self wrote function for alarm set
}
void
sw_irtc_alarm_set(
void
)
{
RTC_TimeTypeDef RTC_TimeStruct;
RTC_AlarmTypeDef RTC_AlarmStruct;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
/// [0] Get current time.
uint32_t current_time = RTC_TimeStruct.RTC_Hours*3600 +
/// [1] Go all to the seconds.
RTC_TimeStruct.RTC_Minutes*60 +
RTC_TimeStruct.RTC_Seconds +
rtc_period ;
/// [2] Add rtc_period seconds.
if
( current_time>864000 )
/// [3] If current time with addition seconds more then seconds in a one day:
{
RTC_TimeStruct.RTC_H12 = RTC_HourFormat_24;
/// New day begins, so count from null.
RTC_TimeStruct.RTC_Hours = 0;
RTC_TimeStruct.RTC_Minutes = 0;
RTC_TimeStruct.RTC_Seconds = current_time - 864000;
}
else
{
RTC_TimeStruct.RTC_H12 = RTC_HourFormat_24;
/// Still the same day, let's convert time in seconds back to hours:minutes:seconds.
RTC_TimeStruct.RTC_Hours = current_time/3600;
RTC_TimeStruct.RTC_Minutes = (current_time - RTC_TimeStruct.RTC_Hours*3600)/60;
RTC_TimeStruct.RTC_Seconds = (current_time - RTC_TimeStruct.RTC_Hours*3600 - RTC_TimeStruct.RTC_Minutes*60);
}
RTC_AlarmStruct.RTC_AlarmTime = RTC_TimeStruct;
/// [4] Assign recalculated time to Alarm time structure.
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay|RTC_AlarmMask_Seconds;
/// [5] Turn on alarm mask, RTC will make an event each time.
/// [!!!] How do the masks would work? One or more then one? Just need in periodic interrupts,
/// [!!!] one interrupt every 32 seconds.
RTC_WriteProtectionCmd(DISABLE);
RTC_AlarmCmd(RTC_Alarm_B, DISABLE);
/// [6] Disable alarm b peripherial, need to make available SetAlarm function.
RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_B, &RTC_AlarmStruct);
// [8] SetAlarm with predefined parameters.
RTC_ITConfig(RTC_IT_ALRB, ENABLE);
// [9] Make RTC alarm B interrupt available.
RTC_AlarmCmd(RTC_Alarm_B, ENABLE);
// [10] Make alarm available.
RTC_ClearFlag(RTC_FLAG_ALRBF);
// [11] Clear alarm flag.
}
void
RTC_Alarm_IRQHandler()
{
CoEnterISR();
/// [0] CooCox OS used, don't take attention, not so important.
if
(RTC_GetITStatus(RTC_IT_ALRB) != RESET)
/// [1] If alarm b interrupt status not reset...
{
RTC_ClearITPendingBit(RTC_IT_ALRB);
/// [2] Clear RTC alarm b interrupt bit.
EXTI_ClearITPendingBit(EXTI_Line17);
/// [3] Clear EXTI l17 interrupt bit.
sw_irtc_alarm_b_counter++;
/// [4] Each time we are here, another second has spent.
if
(sw_irtc_alarm_b_counter==32)
/// [5] If number of done interrupts equal to 32, 32 seconds has spent
{
// To compensate LSE temperature drift every 32 seconds we have to make recalibration of frequency. Self wrote func.
sw_irtc_make_colibration(sw_meteo_Data.Temperature, sw_irtc_measured_frequency);
sw_irtc_alarm_b_counter=0;
/// [7] reset alarm interrup counter.
}
}
CoExitISR();
/// [0] CooCox OS used, don't take attention, not so important.
}