2023-10-31 11:44 AM
Hello !
I've been practicing how RTC works in STM32 Nucleo and I've used a code from this website tutorials.
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) {
z ++;
RTC_AlarmTypeDef sAlarm;
HAL_RTC_GetTime(hrtc, &RTC_TimeStruct, FORMAT_BIN);
HAL_RTC_GetDate(hrtc, &RTC_DateStruct, FORMAT_BIN);
HAL_RTC_GetAlarm(hrtc,&sAlarm,RTC_ALARM_A,FORMAT_BIN);
if(sAlarm.AlarmTime.Seconds>54) {
sAlarm.AlarmTime.Seconds=0;
}else{
sAlarm.AlarmTime.Seconds=sAlarm.AlarmTime.Seconds+5;
}
while(HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, FORMAT_BIN)!=HAL_OK){}
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
if (z == 2)
{
printf("y =%d\n", RTC_TimeStruct.Minutes);
printf("x =%d\n", RTC_TimeStruct.Seconds);
z = 0;
}
}
I don't understand how HAL_RTC_SetAlarm_IT in this while().
I've seen that HAL_RTC_SetAlarm_IT returns either a HAL_OK or HAL_TIMEOUT. So I've checked what happens if the code jumps to this while() expression. At the end HAL_RTC_SetAlarm_IT returned HAL_OK so why it does what is inside of this while() instruction ???
I mean that HAL_RTC_SetAlarm_IT returns the HAL_OK and the expression was that HAL_RTC_SetAlarm_IT != HAL_OK but it is HAL_OK so why it does once the instruction inside of while() ??
It doesn't make sense to me. Also why HAL_RTC_SetAlarm_IT must be putted into while with HAL_OK requirement and other HAL like HAL_GetTime or HAL_GetDate doesn't need this verification ???
2023-11-01 01:51 AM
You also asked the same question on the Edaboard, but let's answer it here:
If you look at the function HAL_RTC_SetAlarm_IT() in stm32xxx_hal_rtc.c, you will find places where the function can be exited with a timeout. The background is the query of the flags ALRAWF and ALRBWF, which can take some time This timeout is intercepted with:
while(HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, FORMAT_BIN)!=HAL_OK){}
(btw: this is also just an example and could be further improved to capture the theoretically possible permanent condition that HAL_RTC_SetAlarm_IT is permanently unequal to HAL_OK)
As for HAL_RTC_GetTime and HAL_RTC_GetDate, these functions do not access ALRAWF and ALRBWF and therefore do not have the potential timeout problem, which is why a comparable while(!=HAL_OK) is not necessary when calling them.
Does this answer your question?
Regards
/Peter
2023-11-01 04:30 AM
Does this answer your question? - Partly
I have 2 questions if I can ask :) :
- In this example when I've putted the breakpoint on this while statement I've checked what happens with HAL_RTC_SetAlarm_IT() and I was looking step by step, at the end it returned HAL_OK but it still executed what was in while() which is toggeling the diode and printing the time which is weird because HAL_OK is equal to HAL_OK so it should not execute what was in while()
- Second question is that in while(), if I put the same data to be set twice (because that what happens if the while is once executed and again checks the condition putting the same data inside the HAL_RTC_SetAlarm_IT() function) doesn't it mean it sets the alarm twice which should in result put again the same situation like in the first try ? Which is the timeout ? It doesn't have the time to finish it in while condition. Or perhaps ALRAWF block from putting new data ? I haven't understood exactly fully the code which wonders if there is ALRAWF then calling againHAL_RTC_SetAlarm_IT() with new data are ignored ?
2023-11-01 06:42 AM
while(HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, FORMAT_BIN)!=HAL_OK
{
}
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
hrtc->Instance->ALRMAR = (uint32_t)tmpreg;
/* Configure the Alarm A Subseconds register */
hrtc->Instance->ALRMASSR = subsecondtmpreg;
/* Configure the Alarm state: Enable Alarm */
__HAL_RTC_ALARMA_ENABLE(hrtc);
/* Configure the Alarm interrupt */
__HAL_RTC_ALARM_ENABLE_IT(hrtc, RTC_IT_ALRA);??
The timeout is set with RTC_TIMEOUT_VALUE (in stm32xxx_hal_rtc.h) and counted down with the variable count.
2023-11-01 01:48 PM
@Peter BENSCH wrote:
- I don't really understand your problem: the while loop itself doesn't contain any code except for the call to HAL_RTC_SetAlarm_IT(), and it doesn't toggle any LED. The toggling of the LED takes place after the while loop, which after some reformatting can be read as:
while(HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, FORMAT_BIN)!=HAL_OK
{
}
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
Ok my bad now I see that the instruction is out of while, which I thought the toggle and other stuff was inside the while. Well I understand my mistake here, thank you for pointing it out :>.
@Peter BENSCH wrote:
- It is not a problem to execute the function several times, because the alarm is not really set until there has been no timeout anymore. To do this, first a tmpreg is assembled and only after a successfully set ALRAWF or ALRBWF the respective alarm register is set, as can be seen in the example of F4:
hrtc->Instance->ALRMAR = (uint32_t)tmpreg;
/* Configure the Alarm A Subseconds register */
hrtc->Instance->ALRMASSR = subsecondtmpreg;
/* Configure the Alarm state: Enable Alarm */
__HAL_RTC_ALARMA_ENABLE(hrtc);
/* Configure the Alarm interrupt */
__HAL_RTC_ALARM_ENABLE_IT(hrtc, RTC_IT_ALRA);??
The timeout is set with RTC_TIMEOUT_VALUE (in stm32xxx_hal_rtc.h) and counted down with the variable count.
Here as I understand tmpreg contains all the setting for the RTC and is then passed to the ALRMAR which sets the alarm but only after the flag is set, otherwise it will exit and executing again this function will do everything all over again.
I think that's how it works although the SetAlarm function is pretty complex ... If I am right then I also wondered how to read this part :
tmpreg = (((uint32_t)RTC_ByteToBcd2(sAlarm->AlarmTime.Hours) << RTC_ALRMAR_HU_Pos) | \
((uint32_t)RTC_ByteToBcd2(sAlarm->AlarmTime.Minutes) << RTC_ALRMAR_MNU_Pos) | \
((uint32_t)RTC_ByteToBcd2(sAlarm->AlarmTime.Seconds)) | \
((uint32_t)(sAlarm->AlarmTime.TimeFormat) << RTC_TR_PM_Pos) | \
((uint32_t)RTC_ByteToBcd2(sAlarm->AlarmDateWeekDay) << RTC_ALRMAR_DU_Pos) | \
((uint32_t)sAlarm->AlarmDateWeekDaySel) | \
((uint32_t)sAlarm->AlarmMask));
This tmpreg is a single 32 bit int variagle so how it contains all information when other variables are also 32 bits ? They are weirdly shifted and ORed but each of them are 32 bits and they contain the alarm mask, hours, minutes etc. only the subseconds are loaded seperatelly in ALRMASSR as I understood.
2023-11-02 01:14 AM
Correct, the alarm setting is assembled in tmpreg, which requires some shift operations, whereby the OR operations are used to superimpose the individual partial values.
In the current example, 32bit variables are used to link them via OR, so they remain 32bit. The other values, such as RTC_ALRMAR_HU_Pos (position of the hour bits) are not variables, but are specified by a #DEFINE, which can be found in the device-specific Device Peripheral Access Layer Header File (Drivers\CMSIS\Device\ST\STM32xxxx\Include).