Skip to content

Commit 1710d2d

Browse files
committed
Proper subsecond management
Signed-off-by: Frederic Pillon <[email protected]>
1 parent bf74a2c commit 1710d2d

File tree

3 files changed

+41
-29
lines changed

3 files changed

+41
-29
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ _RTC clock source_
3434
* **`void setClockSource(Source_Clock source)`** : this function must be called before `begin()`.
3535

3636
_RTC Asynchronous and Synchronous prescaler_
37-
* **`void getPrediv(int8_t *predivA, int16_t *predivS)`** : get user (a)synchronous prescaler values if set else computed ones for the current clock source.
38-
* **`void setPrediv(int8_t predivA, int16_t predivS)`** : set user (a)synchronous prescaler values. This function must be called before `begin()`. Use -1 to reset value and use computed ones.
37+
* **`void getPrediv(int8_t *predivA, int16_t *predivS)`** : get (a)synchronous prescaler values if set else computed ones for the current clock source.
38+
* **`void setPrediv(int8_t predivA, int16_t predivS)`** : set (a)synchronous prescaler values. This function must be called before `begin()`. Use -1 to reset value and use computed ones. Those values have to match the following conditions: **_1Hz = RTC CLK source / ((predivA + 1) * (predivS + 1))_**
3939

4040
_SubSeconds management_
4141
* **`uint32_t getSubSeconds(void)`**
@@ -62,6 +62,10 @@ _Time and date configuration (added for convenience)_
6262

6363
_SubSeconds alarm management_
6464

65+
Important note:
66+
- STM32F1 and STM32L1xx (Ultra Low Power Medium (ULPM) density) series do not support subsecond.
67+
- Subsecond “resolution” depends on synchronous prescaler value. Bigger than this value is, better resolution will get for subsecond.
68+
6569
* **`void setAlarmSubSeconds(uint32_t subSeconds)`**
6670

6771
* **Updated API:**

src/STM32RTC.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939

4040
#include "Arduino.h"
4141
#if defined(STM32_CORE_VERSION) && (STM32_CORE_VERSION > 0x01090000)
42-
#include "rtc.h"
42+
#include "rtc.h"
4343
#endif
4444
// Check if RTC HAL enable in variants/board_name/stm32yzxx_hal_conf.h
4545
#ifndef HAL_RTC_MODULE_ENABLED
46-
#error "RTC configuration is missing. Check flag HAL_RTC_MODULE_ENABLED in variants/board_name/stm32yzxx_hal_conf.h"
46+
#error "RTC configuration is missing. Check flag HAL_RTC_MODULE_ENABLED in variants/board_name/stm32yzxx_hal_conf.h"
4747
#endif
4848

4949
/**

src/rtc.c

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
*/
3636

3737
#include "rtc.h"
38+
#include <math.h>
3839

3940
#if defined(STM32_CORE_VERSION) && (STM32_CORE_VERSION > 0x01090000) &&\
4041
defined(HAL_RTC_MODULE_ENABLED) && !defined(HAL_RTC_MODULE_ONLY)
@@ -62,9 +63,10 @@ static void *callbackUserData = NULL;
6263
static sourceClock_t clkSrc = LSI_CLOCK;
6364
static uint8_t HSEDiv = 0;
6465
#if !defined(STM32F1xx)
65-
/* Custom user values */
66-
static int8_t userPredivAsync = -1;
67-
static int16_t userPredivSync = -1;
66+
/* predividers values */
67+
static uint8_t predivSync_bits = 0xFF;
68+
static int8_t predivAsync = -1;
69+
static int16_t predivSync = -1;
6870
#endif /* !STM32F1xx */
6971

7072
static hourFormat_t initFormat = HOUR_FORMAT_12;
@@ -208,10 +210,14 @@ static void RTC_initClock(sourceClock_t source)
208210
void RTC_setPrediv(int8_t asynch, int16_t synch)
209211
{
210212
#if !defined(STM32F1xx)
211-
if ((asynch >= -1) && (synch >= -1)) {
212-
userPredivAsync = asynch;
213-
userPredivSync = synch;
213+
if ((asynch >= -1) && ((uint32_t)asynch <= PREDIVA_MAX) && \
214+
(synch >= -1) && ((uint32_t)synch <= PREDIVS_MAX)) {
215+
predivAsync = asynch;
216+
predivSync = synch;
217+
} else {
218+
RTC_computePrediv(&predivAsync, &predivSync);
214219
}
220+
predivSync_bits = (uint8_t)log2(predivSync) + 1;
215221
#else
216222
UNUSED(asynch);
217223
UNUSED(synch);
@@ -228,14 +234,14 @@ void RTC_setPrediv(int8_t asynch, int16_t synch)
228234
void RTC_getPrediv(int8_t *asynch, int16_t *synch)
229235
{
230236
#if !defined(STM32F1xx)
231-
if ((userPredivAsync == -1) || (userPredivSync == -1)) {
232-
RTC_computePrediv(asynch, synch);
233-
} else {
234-
if ((asynch != NULL) && (synch != NULL)) {
235-
*asynch = userPredivAsync;
236-
*synch = userPredivSync;
237-
}
237+
if ((predivAsync == -1) || (predivSync == -1)) {
238+
RTC_computePrediv(&predivAsync, &predivSync);
238239
}
240+
if ((asynch != NULL) && (synch != NULL)) {
241+
*asynch = predivAsync;
242+
*synch = predivSync;
243+
}
244+
predivSync_bits = (uint8_t)log2(predivSync) + 1;
239245
#else
240246
UNUSED(asynch);
241247
UNUSED(synch);
@@ -361,7 +367,7 @@ void RTC_DeInit(void)
361367
}
362368

363369
/**
364-
* @brief Check wether time is already set
370+
* @brief Check if time is already set
365371
* @retval True if set else false
366372
*/
367373
bool RTC_IsTimeSet(void)
@@ -375,13 +381,13 @@ bool RTC_IsTimeSet(void)
375381
* @param minutes: 0-59
376382
* @param seconds: 0-59
377383
* @param subSeconds: 0-999
378-
* @param period: select HOUR_AM or HOUR_PM period in case RTC is set in 12 hours mode. Else ingored.
384+
* @param period: select HOUR_AM or HOUR_PM period in case RTC is set in 12 hours mode. Else ignored.
379385
* @retval None
380386
*/
381387
void RTC_SetTime(uint8_t hours, uint8_t minutes, uint8_t seconds, uint32_t subSeconds, hourAM_PM_t period)
382388
{
383389
RTC_TimeTypeDef RTC_TimeStruct;
384-
390+
UNUSED(subSeconds);
385391
/* Ignore time AM PM configuration if in 24 hours format */
386392
if (initFormat == HOUR_FORMAT_24) {
387393
period = HOUR_AM;
@@ -399,15 +405,13 @@ void RTC_SetTime(uint8_t hours, uint8_t minutes, uint8_t seconds, uint32_t subSe
399405
RTC_TimeStruct.TimeFormat = RTC_HOURFORMAT12_AM;
400406
}
401407
#if !defined(STM32F2xx) && !defined(STM32L1xx) || defined(STM32L1_ULPH)
402-
RTC_TimeStruct.SubSeconds = subSeconds;
403-
RTC_TimeStruct.SecondFraction = 0;
404-
#else
405-
UNUSED(subSeconds);
408+
/* subSeconds is read only, so no need to set it */
409+
/*RTC_TimeStruct.SubSeconds = subSeconds;*/
410+
/*RTC_TimeStruct.SecondFraction = 0;*/
406411
#endif /* !STM32F2xx && !STM32L1xx || STM32L1_ULPH */
407412
RTC_TimeStruct.DayLightSaving = RTC_STOREOPERATION_RESET;
408413
RTC_TimeStruct.StoreOperation = RTC_DAYLIGHTSAVING_NONE;
409414
#else
410-
UNUSED(subSeconds);
411415
UNUSED(period);
412416
#endif /* !STM32F1xx */
413417

@@ -444,7 +448,7 @@ void RTC_GetTime(uint8_t *hours, uint8_t *minutes, uint8_t *seconds, uint32_t *s
444448
}
445449
#if (!defined(STM32F2xx) && !defined(STM32L1xx)) || defined(STM32L1_ULPH)
446450
if (subSeconds != NULL) {
447-
*subSeconds = RTC_TimeStruct.SubSeconds;
451+
*subSeconds = ((predivSync - RTC_TimeStruct.SubSeconds) * 1000) / (predivSync + 1);
448452
}
449453
#else
450454
UNUSED(subSeconds);
@@ -530,8 +534,12 @@ void RTC_StartAlarm(uint8_t day, uint8_t hours, uint8_t minutes, uint8_t seconds
530534
RTC_AlarmStructure.AlarmTime.Hours = hours;
531535
#if !defined(STM32F1xx)
532536
#if !defined(STM32F2xx) && !defined(STM32L1xx) || defined(STM32L1_ULPH)
533-
RTC_AlarmStructure.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_SS14_10;
534-
RTC_AlarmStructure.AlarmTime.SubSeconds = subSeconds;
537+
if (subSeconds < 1000) {
538+
RTC_AlarmStructure.AlarmSubSecondMask = predivSync_bits << RTC_ALRMASSR_MASKSS_Pos;
539+
RTC_AlarmStructure.AlarmTime.SubSeconds = predivSync - (subSeconds * (predivSync + 1)) / 1000;
540+
} else {
541+
RTC_AlarmStructure.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
542+
}
535543
#else
536544
UNUSED(subSeconds);
537545
#endif /* !STM32F2xx && !STM32L1xx || STM32L1_ULPH */
@@ -624,7 +632,7 @@ void RTC_GetAlarm(uint8_t *day, uint8_t *hours, uint8_t *minutes, uint8_t *secon
624632
}
625633
#if !defined(STM32F2xx) && !defined(STM32L1xx) || defined(STM32L1_ULPH)
626634
if (subSeconds != NULL) {
627-
*subSeconds = RTC_AlarmStructure.AlarmTime.SubSeconds;
635+
*subSeconds = ((predivSync - RTC_AlarmStructure.AlarmTime.SubSeconds) * 1000) / (predivSync + 1);
628636
}
629637
#else
630638
UNUSED(subSeconds);

0 commit comments

Comments
 (0)