Skip to content

fix: ability to set alarm after reset #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions examples/F1RTCDateRetention/F1RTCDateRetention.ino
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ void setup()
// Check if date is valid = read in the backUp reg.
// Note that backup reg only keep the date /time
// and a power off reset the content if not saved by Vbat
// HAL_RTC init date is set to 1st of January 2000
if ((day == 1) && (month == RTC_MONTH_JANUARY) && (year == 0)) {
// Stm32duino RTC init date is set to 1st of January 2001
// https://github.com/stm32duino/STM32RTC/blob/f620b534f7bffe24f031fc5935324027cfe51320/src/rtc.c#L395
if ((day == 1) && (month == RTC_MONTH_JANUARY) && (year == 1)) {
// Set the time
rtc.setHours(INITIAL_HOUR);
rtc.setMinutes(INITIAL_MIN);
Expand Down
51 changes: 11 additions & 40 deletions src/STM32RTC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,26 @@ void STM32RTC::begin(bool resetTime, Hour_Format format)
{
bool reinit;

if (resetTime == true) {
_timeSet = false;
}

_format = format;
reinit = RTC_init((format == HOUR_12) ? HOUR_FORMAT_12 : HOUR_FORMAT_24,
(_clockSource == LSE_CLOCK) ? ::LSE_CLOCK :
(_clockSource == HSE_CLOCK) ? ::HSE_CLOCK : ::LSI_CLOCK
, resetTime);
_timeSet = !reinit;

syncTime();
syncDate();

if (reinit == true) {
_timeSet = false;
syncTime();
syncDate();
// Use current time to init alarm members
if (!IS_RTC_DATE(_alarmDay)) {
// Use current time to init alarm members,
// specially in case _alarmDay is 0 (reset value) which is an invalid value
_alarmDay = _day;
_alarmHours = _hours;
_alarmMinutes = _minutes;
_alarmSeconds = _seconds;
_alarmSubSeconds = _subSeconds;
_alarmPeriod = _hoursPeriod;
} else {
_timeSet = true;
}
}

Expand Down Expand Up @@ -927,38 +924,9 @@ void STM32RTC::configForLowPower(Source_Clock source)
__HAL_RCC_RTCAPB_CLKAM_ENABLE();
#endif

setClockSource(source);
begin();

if (_clockSource != source) {
// Save current config
AM_PM period, alarmPeriod = _alarmPeriod;
uint32_t subSeconds;
uint8_t seconds, minutes, hours, weekDay, day, month, years;
uint8_t alarmSeconds, alarmMinutes, alarmHours, alarmDay;
Alarm_Match alarmMatch = _alarmMatch;

alarmDay = _alarmDay;
alarmHours = _alarmHours;
alarmMinutes = _alarmMinutes;
alarmSeconds = _alarmSeconds;

getDate(&weekDay, &day, &month, &years);
getTime(&seconds, &minutes, &hours, &subSeconds, &period);

end();
_clockSource = source;
// Enable RTC
begin(_format);
// Restore config
setTime(seconds, minutes, hours, subSeconds, period);
setDate(weekDay, day, month, years);
setAlarmTime(alarmHours, alarmMinutes, alarmSeconds, alarmPeriod);
setAlarmDay(alarmDay);
if (RTC_IsAlarmSet()) {
enableAlarm(alarmMatch);
}
}

if (!isTimeSet()) {
// Set arbitrary time for Lowpower; if not already set
setTime(12, 0, 0, 0, AM);
Expand All @@ -984,6 +952,9 @@ void STM32RTC::syncTime(void)
void STM32RTC::syncDate(void)
{
RTC_GetDate(&_year, &_month, &_day, &_wday);
#if defined(STM32F1xx)
RTC_StoreDate();
#endif /* STM32F1xx */
}

/**
Expand Down
120 changes: 93 additions & 27 deletions src/rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,6 @@ static void RTC_initClock(sourceClock_t source)
} else {
Error_Handler();
}
#ifdef __HAL_RCC_RTCAPB_CLK_ENABLE
__HAL_RCC_RTCAPB_CLK_ENABLE();
#endif
__HAL_RCC_RTC_ENABLE();
}

#if defined(STM32F1xx)
Expand Down Expand Up @@ -342,44 +338,47 @@ static void RTC_computePrediv(int8_t *asynch, int16_t *synch)
bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset)
{
bool reinit = false;
hourAM_PM_t period = HOUR_AM, alarmPeriod = HOUR_AM;
uint32_t subSeconds = 0, alarmSubseconds = 0;
uint8_t seconds = 0, minutes = 0, hours = 0, weekDay = 0, days = 0, month = 0, years = 0;
uint8_t alarmMask = 0, alarmDay = 0, alarmHours = 0, alarmMinutes = 0, alarmSeconds = 0;
bool isAlarmSet = false;
#if defined(STM32F1xx)
uint32_t asynch;
#else
int8_t asynch;
int16_t sync;
#endif

initFormat = format;

/* Init RTC clock */
RTC_initClock(source);

RtcHandle.Instance = RTC;

/* Ensure backup domain is enabled before we init the RTC so we can use the backup registers for date retention on stm32f1xx boards */
enableBackupDomain();

if (reset) {
resetBackupDomain();
RTC_initClock(source);
}

#ifdef __HAL_RCC_RTCAPB_CLK_ENABLE
__HAL_RCC_RTCAPB_CLK_ENABLE();
#endif
__HAL_RCC_RTC_ENABLE();

isAlarmSet = RTC_IsAlarmSet();

#if defined(STM32F1xx)
uint32_t BackupDate;
BackupDate = getBackupRegister(RTC_BKP_DATE) << 16;
BackupDate |= getBackupRegister(RTC_BKP_DATE + 1) & 0xFFFF;
if ((BackupDate == 0) || reset) {
// RTC needs initialization
/* Let HAL calculate the prescaler */
RtcHandle.Init.AsynchPrediv = prediv;
RtcHandle.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
HAL_RTC_Init(&RtcHandle);
// Default: saturday 1st of January 2001
// Note: year 2000 is invalid as it is the hardware reset value and doesn't raise INITS flag
RTC_SetDate(1, 1, 1, 6);
reinit = true;
} else {
memcpy(&RtcHandle.DateToUpdate, &BackupDate, 4);
/* and fill the new RTC Date value */
RTC_SetDate(RtcHandle.DateToUpdate.Year, RtcHandle.DateToUpdate.Month,
RtcHandle.DateToUpdate.Date, RtcHandle.DateToUpdate.WeekDay);
}
#else

if (!LL_RTC_IsActiveFlag_INITS(RtcHandle.Instance) || reset) {
// RTC needs initialization
RtcHandle.Init.HourFormat = format == HOUR_FORMAT_12 ? RTC_HOURFORMAT_12 : RTC_HOURFORMAT_24;
RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
Expand All @@ -389,17 +388,87 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset)
#endif /* RTC_OUTPUT_REMAP_NONE */

RTC_getPrediv((int8_t *) & (RtcHandle.Init.AsynchPrediv), (int16_t *) & (RtcHandle.Init.SynchPrediv));
#endif // STM32F1xx
// Init RTC clock
RTC_initClock(source);

HAL_RTC_Init(&RtcHandle);
// Default: saturday 1st of January 2001
// Note: year 2000 is invalid as it is the hardware reset value and doesn't raise INITS flag
RTC_SetDate(1, 1, 1, 6);
reinit = true;
} else {
// This initialize variables: predivAsync, redivSync and predivSync_bits
RTC_getPrediv(NULL, NULL);
// RTC is already initialized
uint32_t oldRtcClockSource = __HAL_RCC_GET_RTC_SOURCE();
oldRtcClockSource = ((oldRtcClockSource == RCC_RTCCLKSOURCE_LSE) ? LSE_CLOCK :
(oldRtcClockSource == RCC_RTCCLKSOURCE_LSI) ? LSI_CLOCK :
#if defined(RCC_RTCCLKSOURCE_HSE_DIVX)
(oldRtcClockSource == RCC_RTCCLKSOURCE_HSE_DIVX) ? HSE_CLOCK :
#elif defined(RCC_RTCCLKSOURCE_HSE_DIV32)
(oldRtcClockSource == RCC_RTCCLKSOURCE_HSE_DIV32) ? HSE_CLOCK :
#elif defined(RCC_RTCCLKSOURCE_HSE_DIV)
(oldRtcClockSource == RCC_RTCCLKSOURCE_HSE_DIV) ? HSE_CLOCK :
#elif defined(RCC_RTCCLKSOURCE_HSE_DIV128)
(oldRtcClockSource == RCC_RTCCLKSOURCE_HSE_DIV128) ? HSE_CLOCK :
#endif
// default case corresponding to no clock source
0xFFFFFFFF);

#if defined(STM32F1xx)
if ((RtcHandle.DateToUpdate.WeekDay == 0)
&& (RtcHandle.DateToUpdate.Month == 0)
&& (RtcHandle.DateToUpdate.Date == 0)
&& (RtcHandle.DateToUpdate.Year == 0)) {
// After a reset for example, restore HAL handle date with values from BackupRegister date
memcpy(&RtcHandle.DateToUpdate, &BackupDate, 4);
}
#endif // STM32F1xx

if (source != oldRtcClockSource) {
// RTC is already initialized, but RTC clock source is changed
// In case of RTC source clock change, Backup Domain is reset by RTC_initClock()
// Save current config before call to RTC_initClock()
RTC_GetDate(&years, &month, &days, &weekDay);
RTC_GetTime(&hours, &minutes, &seconds, &subSeconds, &period);
#if defined(STM32F1xx)
RTC_getPrediv(&asynch);
#else
RTC_getPrediv(&asynch, &sync);
#endif // STM32F1xx
if (isAlarmSet) {
RTC_GetAlarm(&alarmDay, &alarmHours, &alarmMinutes, &alarmSeconds, &alarmSubseconds, &alarmPeriod, &alarmMask);
}

// Init RTC clock
RTC_initClock(source);

// Restore config
RTC_SetTime(hours, minutes, seconds, subSeconds, period);
RTC_SetDate(years, month, days, weekDay);
#if defined(STM32F1xx)
RTC_setPrediv(asynch);
#else
RTC_setPrediv(asynch, sync);
#endif // STM32F1xx
if (isAlarmSet) {
RTC_StartAlarm(alarmDay, alarmHours, alarmMinutes, alarmSeconds, alarmSubseconds, alarmPeriod, alarmMask);
}
} else {
// RTC is already initialized, and RTC stays on the same clock source

// Init RTC clock
RTC_initClock(source);
#if defined(STM32F1xx)
memcpy(&RtcHandle.DateToUpdate, &BackupDate, 4);
/* and fill the new RTC Date value */
RTC_SetDate(RtcHandle.DateToUpdate.Year, RtcHandle.DateToUpdate.Month,
RtcHandle.DateToUpdate.Date, RtcHandle.DateToUpdate.WeekDay);
#else
// This initialize variables: predivAsync, predivSync and predivSync_bits
RTC_getPrediv(NULL, NULL);
#endif // STM32F1xx
}
}
#endif /* STM32F1xx */

#if defined(RTC_CR_BYPSHAD)
/* Enable Direct Read of the calendar registers (not through Shadow) */
Expand Down Expand Up @@ -573,9 +642,6 @@ void RTC_GetDate(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *wday)
*month = RTC_DateStruct.Month;
*day = RTC_DateStruct.Date;
*wday = RTC_DateStruct.WeekDay;
#if defined(STM32F1xx)
RTC_StoreDate();
#endif /* STM32F1xx */
}
}

Expand Down