diff --git a/examples/mixRTCAlarm/mixRTCAlarm.ino b/examples/mixRTCAlarm/mixRTCAlarm.ino new file mode 100644 index 0000000..02ea167 --- /dev/null +++ b/examples/mixRTCAlarm/mixRTCAlarm.ino @@ -0,0 +1,97 @@ +/* + mode Mix RTC alarm + + This sketch shows how to configure the alarm A & B of the RTC in MIX mode + + Creation 12 Dec 2017 + by Wi6Labs + Modified 03 Jul 2020 + by Frederic Pillon for STMicroelectronics + Modified 03 Jul 2023 + by Francois Ramu for STMicroelectronics + + This example code is in the public domain. + + https://github.com/stm32duino/STM32RTC +*/ + +#include + +/* Get the rtc object */ +STM32RTC& rtc = STM32RTC::getInstance(); + +/* Change these values to set the current initial time */ +const byte seconds = 06; +const byte minutes = 22; +const byte hours = 16; + +/* Change these values to set the current initial date */ +const byte day = 25; +const byte month = 6; +const byte year = 23; + +uint32_t timeout; + +void setup() +{ + Serial.begin(115200); + + // Select RTC clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK. + rtc.setClockSource(STM32RTC::LSE_CLOCK); + + /* Configure the MIX mode */ + rtc.setBinaryMode(STM32RTC::MODE_MIX); + + rtc.begin(true, STM32RTC::HOUR_24); + + rtc.setTime(hours, minutes, seconds); + rtc.setDate(day, month, year); + + /* wait for a while */ + delay(200); + + Serial.printf("Start at %02d:%02d:%02d.%03d\r\n", + rtc.getHours(), rtc.getMinutes(), rtc.getSeconds(), rtc.getSubSeconds()); + + /* Attach the callback function before enabling Interrupt */ + rtc.attachInterrupt(alarmAMatch); + + /* Program the AlarmA in a 12 seconds */ + rtc.setAlarmDay(day); + rtc.setAlarmTime(hours, minutes, seconds + 12); + rtc.enableAlarm(rtc.MATCH_DHHMMSS); + Serial.printf("Set Alarm A in 12s (at %02d:%02d:%02d)\r\n", + rtc.getAlarmHours(), rtc.getAlarmMinutes(), rtc.getAlarmSeconds()); + +#ifdef RTC_ALARM_B + /* Program ALARM B in 400ms ms from now (keep timeout < 1000ms) */ + timeout = rtc.getSubSeconds() + 400; + + rtc.attachInterrupt(alarmBMatch, STM32RTC::ALARM_B); + rtc.setAlarmSubSeconds(timeout, STM32RTC::ALARM_B); + rtc.enableAlarm(rtc.MATCH_SUBSEC, STM32RTC::ALARM_B); + Serial.printf("Set Alarm B (in %d ms) at %d ms\r\n", 400, + rtc.getAlarmSubSeconds(STM32RTC::ALARM_B)); +#endif + +} + +void loop() +{ + +} + +void alarmAMatch(void *data) +{ + UNUSED(data); + Serial.printf("Alarm A Match at %02d:%02d:%02d\r\n", + rtc.getHours(), rtc.getMinutes(), rtc.getSeconds()); +} + +void alarmBMatch(void *data) +{ + UNUSED(data); + Serial.printf("Alarm B Match at %d ms\r\n", rtc.getSubSeconds()); +} + + diff --git a/src/STM32RTC.cpp b/src/STM32RTC.cpp index 0c8bf9d..3799109 100644 --- a/src/STM32RTC.cpp +++ b/src/STM32RTC.cpp @@ -63,6 +63,7 @@ void STM32RTC::begin(bool resetTime, Hour_Format format) _format = format; reinit = RTC_init((format == HOUR_12) ? HOUR_FORMAT_12 : HOUR_FORMAT_24, + (_mode == MODE_MIX) ? ::MODE_BINARY_MIX : ((_mode == MODE_BIN) ? ::MODE_BINARY_ONLY : ::MODE_BINARY_NONE), (_clockSource == LSE_CLOCK) ? ::LSE_CLOCK : (_clockSource == HSE_CLOCK) ? ::HSE_CLOCK : ::LSI_CLOCK , resetTime); @@ -131,6 +132,26 @@ void STM32RTC::setClockSource(Source_Clock source) } } +/** + * @brief get the Binary Mode. + * @retval mode: MODE_BCD, MODE_BIN or MODE_MIX + */ +STM32RTC::Binary_Mode STM32RTC::getBinaryMode(void) +{ + return _mode; +} + +/** + * @brief set the Binary Mode. By default MODE_BCD is selected. This + * method must be called before begin(). + * @param mode: the RTC mode: MODE_BCD, MODE_BIN or MODE_MIX + * @retval None + */ +void STM32RTC::setBinaryMode(Binary_Mode mode) +{ + _mode = mode; +} + #if defined(STM32F1xx) /** * @brief get user asynchronous prescaler value for the current clock source. @@ -216,6 +237,21 @@ void STM32RTC::enableAlarm(Alarm_Match match, Alarm name) RTC_StopAlarm(::ALARM_A); } break; + case MATCH_SUBSEC: + /* force _alarmday to 0 to go to the right alarm config in MIX mode */ +#ifdef RTC_ALARM_B + if (name == ALARM_B) { + RTC_StartAlarm(::ALARM_B, 0, 0, 0, 0, + _alarmBSubSeconds, (_alarmBPeriod == AM) ? HOUR_AM : HOUR_PM, + static_cast(31UL)); + } else +#endif + { + RTC_StartAlarm(::ALARM_A, 0, 0, 0, 0, + _alarmSubSeconds, (_alarmPeriod == AM) ? HOUR_AM : HOUR_PM, + static_cast(31UL)); + } + break; case MATCH_YYMMDDHHMMSS://kept for compatibility case MATCH_MMDDHHMMSS: //kept for compatibility case MATCH_DHHMMSS: @@ -611,7 +647,7 @@ uint8_t STM32RTC::getAlarmYear(void) /** * @brief set RTC subseconds. - * @param subseconds: 0-999 + * @param subseconds: 0-999 milliseconds * @retval none */ void STM32RTC::setSubSeconds(uint32_t subSeconds) @@ -1246,6 +1282,7 @@ bool STM32RTC::isAlarmEnabled(Alarm name) void STM32RTC::syncTime(void) { hourAM_PM_t p = HOUR_AM; + RTC_GetTime(&_hours, &_minutes, &_seconds, &_subSeconds, &p); _hoursPeriod = (p == HOUR_AM) ? AM : PM; } diff --git a/src/STM32RTC.h b/src/STM32RTC.h index b8be12b..4789d62 100644 --- a/src/STM32RTC.h +++ b/src/STM32RTC.h @@ -85,8 +85,15 @@ class STM32RTC { PM = HOUR_PM }; + enum Binary_Mode : uint8_t { + MODE_BCD = MODE_BINARY_NONE, /* not used */ + MODE_BIN = MODE_BINARY_ONLY, + MODE_MIX = MODE_BINARY_MIX + }; + enum Alarm_Match : uint8_t { MATCH_OFF = OFF_MSK, // Never + MATCH_SUBSEC = SUBSEC_MSK, // Every Subsecond MATCH_SS = SS_MSK, // Every Minute MATCH_MMSS = SS_MSK | MM_MSK, // Every Hour MATCH_HHMMSS = SS_MSK | MM_MSK | HH_MSK, // Every Day @@ -128,6 +135,9 @@ class STM32RTC { Source_Clock getClockSource(void); void setClockSource(Source_Clock source); + Binary_Mode getBinaryMode(void); + void setBinaryMode(Binary_Mode mode); + void enableAlarm(Alarm_Match match, Alarm name = ALARM_A); void disableAlarm(Alarm name = ALARM_A); @@ -237,6 +247,7 @@ class STM32RTC { static bool _timeSet; Hour_Format _format; + Binary_Mode _mode; AM_PM _hoursPeriod; uint8_t _hours; uint8_t _minutes; diff --git a/src/rtc.c b/src/rtc.c index 903ca7c..ef41ec4 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -56,7 +56,6 @@ extern "C" { /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ -static RTC_HandleTypeDef RtcHandle = {0}; static voidCallbackPtr RTCUserCallback = NULL; static void *callbackUserData = NULL; #ifdef RTC_ALARM_B @@ -66,9 +65,10 @@ static void *callbackUserDataB = NULL; static voidCallbackPtr RTCSecondsIrqCallback = NULL; static sourceClock_t clkSrc = LSI_CLOCK; +static uint32_t clkVal = 0; static uint8_t HSEDiv = 0; #if !defined(STM32F1xx) -/* predividers values */ +/* predividers values (-1 means not initialised values) */ static uint8_t predivSync_bits = 0xFF; static int8_t predivAsync = -1; static int16_t predivSync = -1; @@ -76,21 +76,75 @@ static int16_t predivSync = -1; static uint32_t prediv = RTC_AUTO_1_SECOND; #endif /* !STM32F1xx */ +static uint32_t fqce_apre; + static hourFormat_t initFormat = HOUR_FORMAT_12; +static binaryMode_t initMode = MODE_BINARY_NONE; /* Private function prototypes -----------------------------------------------*/ static void RTC_initClock(sourceClock_t source); #if !defined(STM32F1xx) static void RTC_computePrediv(int8_t *asynch, int16_t *synch); #endif /* !STM32F1xx */ +#if defined(RTC_BINARY_NONE) +static void RTC_BinaryConf(binaryMode_t mode); +#endif static inline int _log2(int x) { return (x > 0) ? (sizeof(int) * 8 - __builtin_clz(x) - 1) : 0; } +/* Exported variable --------------------------------------------------------*/ +RTC_HandleTypeDef RtcHandle = {0}; + /* Exported functions --------------------------------------------------------*/ +/* HAL MSP function used for RTC_Init */ +void HAL_RTC_MspInit(RTC_HandleTypeDef *rtcHandle) +{ +#if defined(STM32WLxx) + /* Only the STM32WLxx series has a TAMP_STAMP_LSECSS_SSRU_IRQn */ + if (rtcHandle->Instance == RTC) + { + if (HAL_RTCEx_SetSSRU_IT(rtcHandle) != HAL_OK) { + Error_Handler(); + } + /* Give init value for the RtcFeatures enable */ + rtcHandle->IsEnabled.RtcFeatures = 0; + + /* RTC interrupt Init */ + HAL_NVIC_SetPriority(TAMP_STAMP_LSECSS_SSRU_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TAMP_STAMP_LSECSS_SSRU_IRQn); + + } +#else + UNUSED(rtcHandle); +#endif /* STM32WLxx */ + /* RTC_Alarm_IRQn is enabled when enabling Alarm */ +} + +void HAL_RTC_MspDeInit(RTC_HandleTypeDef *rtcHandle) +{ + + if (rtcHandle->Instance == RTC) + { + /* USER CODE BEGIN RTC_MspDeInit 0 */ + + /* USER CODE END RTC_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_RTC_DISABLE(); + __HAL_RCC_RTCAPB_CLK_DISABLE(); + + /* RTC interrupt Deinit */ + HAL_NVIC_DisableIRQ(TAMP_STAMP_LSECSS_SSRU_IRQn); + HAL_NVIC_DisableIRQ(RTC_Alarm_IRQn); + /* USER CODE BEGIN RTC_MspDeInit 1 */ + + /* USER CODE END RTC_MspDeInit 1 */ + } +} + /** * @brief Set RTC clock source * @param source: RTC clock source: LSE, LSI or HSE @@ -134,6 +188,7 @@ static void RTC_initClock(sourceClock_t source) Error_Handler(); } clkSrc = LSE_CLOCK; + clkVal = LSE_VALUE; } else if (source == HSE_CLOCK) { /* Enable the clock if not already set by user */ enableClock(HSE_CLOCK); @@ -192,6 +247,7 @@ static void RTC_initClock(sourceClock_t source) Error_Handler(); } clkSrc = HSE_CLOCK; + clkVal = HSE_VALUE / HSEDiv; } else if (source == LSI_CLOCK) { /* Enable the clock if not already set by user */ enableClock(LSI_CLOCK); @@ -202,6 +258,7 @@ static void RTC_initClock(sourceClock_t source) Error_Handler(); } clkSrc = LSI_CLOCK; + clkVal = LSI_VALUE; } else { Error_Handler(); } @@ -237,8 +294,11 @@ void RTC_setPrediv(int8_t asynch, int16_t synch) } else { RTC_computePrediv(&predivAsync, &predivSync); } + predivSync_bits = (uint8_t)_log2(predivSync) + 1; } + + #endif /* STM32F1xx */ #if defined(STM32F1xx) @@ -285,29 +345,17 @@ void RTC_getPrediv(int8_t *asynch, int16_t *synch) static void RTC_computePrediv(int8_t *asynch, int16_t *synch) { uint32_t predivS = PREDIVS_MAX + 1; - uint32_t clk = 0; /* Get user predividers if manually configured */ if ((asynch == NULL) || (synch == NULL)) { return; } - /* Get clock frequency */ - if (clkSrc == LSE_CLOCK) { - clk = LSE_VALUE; - } else if (clkSrc == LSI_CLOCK) { - clk = LSI_VALUE; - } else if (clkSrc == HSE_CLOCK) { - clk = HSE_VALUE / HSEDiv; - } else { - Error_Handler(); - } - /* Find (a)synchronous prescalers to obtain the 1Hz calendar clock */ for (*asynch = PREDIVA_MAX; *asynch >= 0; (*asynch)--) { - predivS = (clk / (*asynch + 1)) - 1; + predivS = (clkVal / (*asynch + 1)) - 1; - if (((predivS + 1) * (*asynch + 1)) == clk) { + if (((predivS + 1) * (*asynch + 1)) == clkVal) { break; } } @@ -318,27 +366,61 @@ static void RTC_computePrediv(int8_t *asynch, int16_t *synch) */ if ((predivS > PREDIVS_MAX) || (*asynch < 0)) { *asynch = PREDIVA_MAX; - predivS = (clk / (*asynch + 1)) - 1; + predivS = (clkVal / (*asynch + 1)) - 1; } if (predivS > PREDIVS_MAX) { Error_Handler(); } *synch = (int16_t)predivS; + + fqce_apre = clkVal / (*asynch + 1); } #endif /* !STM32F1xx */ +#if defined(RTC_BINARY_NONE) +static void RTC_BinaryConf(binaryMode_t mode) +{ + RtcHandle.Init.BinMode = (mode == MODE_BINARY_MIX) ? RTC_BINARY_MIX : ((mode == MODE_BINARY_ONLY) ? RTC_BINARY_ONLY : RTC_BINARY_NONE); + if (RtcHandle.Init.BinMode == RTC_BINARY_MIX) { + /* Configure the 1s BCD calendar increment */ + + uint32_t inc = 1 / (1.0 / ((float)clkVal / (float)(predivAsync + 1.0))); + if (inc <= 256) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_0; + } else if (inc < (256 << 1)) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_1; + } else if (inc < (256 << 2)) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_2; + } else if (inc < (256 << 3)) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_3; + } else if (inc < (256 << 4)) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_4; + } else if (inc < (256 << 5)) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_5; + } else if (inc < (256 << 6)) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_6; + } else if (inc < (256 << 7)) { + RtcHandle.Init.BinMixBcdU = RTC_BINARY_MIX_BCDU_7; + } else { + Error_Handler(); + } + } +} +#endif /* RTC_BINARY_NONE */ + /** * @brief RTC Initialization * This function configures the RTC time and calendar. By default, the * RTC is set to the 1st January 2001 * Note: year 2000 is invalid as it is the hardware reset value and doesn't raise INITS flag * @param format: enable the RTC in 12 or 24 hours mode + * @param mode: enable the RTC in BCD or Mix or Binary mode * @param source: RTC clock source: LSE, LSI or HSE * @param reset: force RTC reset, even if previously configured * @retval True if RTC is reinitialized, else false */ -bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) +bool RTC_init(hourFormat_t format, binaryMode_t mode, sourceClock_t source, bool reset) { bool reinit = false; hourAM_PM_t period = HOUR_AM, alarmPeriod = HOUR_AM; @@ -360,6 +442,7 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) #endif initFormat = format; + initMode = mode; 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 */ @@ -387,10 +470,12 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) /* Let HAL calculate the prescaler */ RtcHandle.Init.AsynchPrediv = prediv; RtcHandle.Init.OutPut = RTC_OUTPUTSOURCE_NONE; + // Init RTC clock + RTC_initClock(source); #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.HourFormat = (format == HOUR_FORMAT_12) ? RTC_HOURFORMAT_12 : RTC_HOURFORMAT_24; RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE; RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; @@ -400,14 +485,15 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) #if defined(RTC_OUTPUT_REMAP_NONE) RtcHandle.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE; #endif /* RTC_OUTPUT_REMAP_NONE */ -#if defined(RTC_BINARY_NONE) - RtcHandle.Init.BinMode = RTC_BINARY_NONE; -#endif - RTC_getPrediv((int8_t *) & (RtcHandle.Init.AsynchPrediv), (int16_t *) & (RtcHandle.Init.SynchPrediv)); -#endif // STM32F1xx // Init RTC clock RTC_initClock(source); + RTC_getPrediv((int8_t *) & (RtcHandle.Init.AsynchPrediv), (int16_t *) & (RtcHandle.Init.SynchPrediv)); +#if defined(RTC_BINARY_NONE) + RTC_BinaryConf(mode); +#endif /* RTC_BINARY_NONE */ +#endif // STM32F1xx + 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 @@ -446,11 +532,7 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) // 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 (isAlarmASet) { RTC_GetAlarm(ALARM_A, &alarmDay, &alarmHours, &alarmMinutes, &alarmSeconds, &alarmSubseconds, &alarmPeriod, &alarmMask); } @@ -462,6 +544,12 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) // Init RTC clock RTC_initClock(source); +#if defined(STM32F1xx) + RTC_getPrediv(&asynch); +#else + RTC_getPrediv(&asynch, &sync); +#endif // STM32F1xx + // Restore config RTC_SetTime(hours, minutes, seconds, subSeconds, period); RTC_SetDate(years, month, days, weekDay); @@ -483,6 +571,7 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) // Init RTC clock RTC_initClock(source); + #if defined(STM32F1xx) memcpy(&RtcHandle.DateToUpdate, &BackupDate, 4); /* Update date automatically by calling HAL_RTC_GetDate */ @@ -494,7 +583,11 @@ bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset) // This initialize variables: predivAsync, predivSync and predivSync_bits RTC_getPrediv(NULL, NULL); #endif // STM32F1xx +#if defined(RTC_BINARY_NONE) + RTC_BinaryConf(mode); +#endif /* RTC_BINARY_NONE */ } + } #if defined(RTC_CR_BYPSHAD) @@ -542,14 +635,14 @@ bool RTC_IsConfigured(void) * @param hours: 0-12 or 0-23. Depends on the format used. * @param minutes: 0-59 * @param seconds: 0-59 - * @param subSeconds: 0-999 + * @param subSeconds: 0-999 (not used) * @param period: select HOUR_AM or HOUR_PM period in case RTC is set in 12 hours mode. Else ignored. * @retval None */ void RTC_SetTime(uint8_t hours, uint8_t minutes, uint8_t seconds, uint32_t subSeconds, hourAM_PM_t period) { RTC_TimeTypeDef RTC_TimeStruct; - UNUSED(subSeconds); + UNUSED(subSeconds); /* not used (read-only register) */ /* Ignore time AM PM configuration if in 24 hours format */ if (initFormat == HOUR_FORMAT_24) { period = HOUR_AM; @@ -615,7 +708,16 @@ void RTC_GetTime(uint8_t *hours, uint8_t *minutes, uint8_t *seconds, uint32_t *s } #if defined(RTC_SSR_SS) if (subSeconds != NULL) { - *subSeconds = ((predivSync - RTC_TimeStruct.SubSeconds) * 1000) / (predivSync + 1); + if (initMode == MODE_BINARY_MIX) { + /* The subsecond is the free-running downcounter, to be converted in milliseconds */ + *subSeconds = (((UINT32_MAX - RTC_TimeStruct.SubSeconds + 1) & UINT32_MAX) + * 1000) / fqce_apre; /* give one more to compensate the 3.9ms uncertainty */ + *subSeconds = *subSeconds % 1000; /* nb of milliseconds */ + /* predivAsync is 0x7F with LSE clock source */ + } else { + /* the subsecond register value is converted in millisec */ + *subSeconds = ((predivSync - RTC_TimeStruct.SubSeconds) * 1000) / (predivSync + 1); + } } #else UNUSED(subSeconds); @@ -683,7 +785,7 @@ void RTC_GetDate(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *wday) * @param hours: 0-12 or 0-23 depends on the hours mode. * @param minutes: 0-59 * @param seconds: 0-59 - * @param subSeconds: 0-999 + * @param subSeconds: 0-999 milliseconds * @param period: HOUR_AM or HOUR_PM if in 12 hours mode else ignored. * @param mask: configure alarm behavior using alarmMask_t combination. * See AN4579 Table 5 for possible values. @@ -691,18 +793,19 @@ void RTC_GetDate(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *wday) */ void RTC_StartAlarm(alarm_t name, uint8_t day, uint8_t hours, uint8_t minutes, uint8_t seconds, uint32_t subSeconds, hourAM_PM_t period, uint8_t mask) { - RTC_AlarmTypeDef RTC_AlarmStructure; + RTC_AlarmTypeDef RTC_AlarmStructure = {0}; /* Ignore time AM PM configuration if in 24 hours format */ if (initFormat == HOUR_FORMAT_24) { period = HOUR_AM; } + /* Use alarm A by default because it is common to all STM32 HAL */ + RTC_AlarmStructure.Alarm = name; + if ((((initFormat == HOUR_FORMAT_24) && IS_RTC_HOUR24(hours)) || IS_RTC_HOUR12(hours)) && IS_RTC_DATE(day) && IS_RTC_MINUTES(minutes) && IS_RTC_SECONDS(seconds)) { /* Set RTC_AlarmStructure with calculated values*/ - /* Use alarm A by default because it is common to all STM32 HAL */ - RTC_AlarmStructure.Alarm = name; RTC_AlarmStructure.AlarmTime.Seconds = seconds; RTC_AlarmStructure.AlarmTime.Minutes = minutes; RTC_AlarmStructure.AlarmTime.Hours = hours; @@ -717,7 +820,12 @@ void RTC_StartAlarm(alarm_t name, uint8_t day, uint8_t hours, uint8_t minutes, u { RTC_AlarmStructure.AlarmSubSecondMask = predivSync_bits << RTC_ALRMASSR_MASKSS_Pos; } - RTC_AlarmStructure.AlarmTime.SubSeconds = predivSync - (subSeconds * (predivSync + 1)) / 1000; + if (initMode == MODE_BINARY_MIX) { + /* the subsecond is the millisecond to be converted in a subsecond downcounter value */ + RTC_AlarmStructure.AlarmTime.SubSeconds = UINT32_MAX - ((subSeconds * fqce_apre) / 1000 + 1); + } else { + RTC_AlarmStructure.AlarmTime.SubSeconds = predivSync - (subSeconds * (predivSync + 1)) / 1000; + } } else { RTC_AlarmStructure.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL; } @@ -758,6 +866,41 @@ void RTC_StartAlarm(alarm_t name, uint8_t day, uint8_t hours, uint8_t minutes, u UNUSED(mask); #endif /* !STM32F1xx */ + /* Set RTC_Alarm */ + HAL_RTC_SetAlarm_IT(&RtcHandle, &RTC_AlarmStructure, RTC_FORMAT_BIN); + HAL_NVIC_SetPriority(RTC_Alarm_IRQn, RTC_IRQ_PRIO, RTC_IRQ_SUBPRIO); + HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn); +#if defined(RTC_ICSR_BIN) + } else if (RtcHandle.Init.BinMode != RTC_BINARY_NONE) { + /* We have an SubSecond alarm to set in RTC_BINARY_MIX or RTC_BINARY_ONLY mode */ +#else + } else { +#endif /* RTC_ICSR_BIN */ +#if defined(RTC_SSR_SS) + { +#if defined(RTC_ALRMASSR_SSCLR) + RTC_AlarmStructure.BinaryAutoClr = RTC_ALARMSUBSECONDBIN_AUTOCLR_NO; +#endif /* RTC_ALRMASSR_SSCLR */ + RTC_AlarmStructure.AlarmMask = RTC_ALARMMASK_ALL; + +#ifdef RTC_ALARM_B + if (name == ALARM_B) + { + /* Expecting RTC_ALARMSUBSECONDBINMASK_NONE for the subsecond mask on ALARM B */ + RTC_AlarmStructure.AlarmSubSecondMask = mask << RTC_ALRMBSSR_MASKSS_Pos; + } else +#endif + { + /* Expecting RTC_ALARMSUBSECONDBINMASK_NONE for the subsecond mask on ALARM A */ + RTC_AlarmStructure.AlarmSubSecondMask = mask << RTC_ALRMASSR_MASKSS_Pos; + } + /* The subsecond in ms is converted in ticks unit 1 tick is 1000 / fqce_apre */ + RTC_AlarmStructure.AlarmTime.SubSeconds = UINT32_MAX - (subSeconds * fqce_apre) / 1000; + } + +#else + UNUSED(subSeconds); +#endif /* RTC_SSR_SS */ /* Set RTC_Alarm */ HAL_RTC_SetAlarm_IT(&RtcHandle, &RTC_AlarmStructure, RTC_FORMAT_BIN); HAL_NVIC_SetPriority(RTC_Alarm_IRQn, RTC_IRQ_PRIO, RTC_IRQ_SUBPRIO); @@ -848,7 +991,15 @@ void RTC_GetAlarm(alarm_t name, uint8_t *day, uint8_t *hours, uint8_t *minutes, } #if defined(RTC_SSR_SS) if (subSeconds != NULL) { - *subSeconds = ((predivSync - RTC_AlarmStructure.AlarmTime.SubSeconds) * 1000) / (predivSync + 1); + if (initMode == MODE_BINARY_MIX) { + /* + * The subsecond is the bit SS[14:0] of the ALARM SSR register (not ALARMxINR) + * to be converted in milliseconds + */ + *subSeconds = (((0x7fff - RTC_AlarmStructure.AlarmTime.SubSeconds + 1) & 0x7fff) * 1000) / fqce_apre; + } else { + *subSeconds = ((predivSync - RTC_AlarmStructure.AlarmTime.SubSeconds) * 1000) / (predivSync + 1); + } } #else UNUSED(subSeconds); diff --git a/src/rtc.h b/src/rtc.h index bad868b..75e1c8c 100644 --- a/src/rtc.h +++ b/src/rtc.h @@ -55,6 +55,12 @@ typedef enum { HOUR_FORMAT_24 } hourFormat_t; +typedef enum { + MODE_BINARY_NONE, /* BCD only */ + MODE_BINARY_ONLY, + MODE_BINARY_MIX +} binaryMode_t; + typedef enum { HOUR_AM, HOUR_PM @@ -70,7 +76,9 @@ typedef enum { /* NOTE: STM32 RTC can't assign a month or a year to an alarm. Those enum are kept for compatibility but are ignored inside enableAlarm(). */ M_MSK = 16, - Y_MSK = 32 + Y_MSK = 32, + SUBSEC_MSK = 48, + ALL_MSK = 0xFF } alarmMask_t; typedef enum { @@ -173,7 +181,7 @@ void RTC_getPrediv(int8_t *asynch, int16_t *synch); void RTC_setPrediv(int8_t asynch, int16_t synch); #endif /* STM32F1xx */ -bool RTC_init(hourFormat_t format, sourceClock_t source, bool reset); +bool RTC_init(hourFormat_t format, binaryMode_t mode, sourceClock_t source, bool reset); void RTC_DeInit(void); bool RTC_IsConfigured(void);