Skip to content

Commit

Permalink
Merge pull request #98 from fpistm/prediv
Browse files Browse the repository at this point in the history
harden prediv management and add parameter to set binary mode
  • Loading branch information
fpistm authored Sep 25, 2023
2 parents a703c0f + 344114d commit 5f53d03
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 217 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ _RTC hours mode (12 or 24)_

_RTC clock source_
* **`Source_Clock getClockSource(void)`** : get current clock source.
* **`void setClockSource(Source_Clock source)`** : this function must be called before `begin()`.
* **`void setClockSource(Source_Clock source, uint32_t predivA, uint32_t predivS)`** : set the clock source (`LSI_CLOCK`, `LSE_CLOCK` or `HSE_CLOCK`) and (a)synchronous prescaler values. This function must be called before `begin()`. Use `(PREDIVA_MAX + 1)` and `(PREDIVS_MAX +1)` to reset value and use computed ones. Those values have to match the following conditions: **_1Hz = RTC CLK source / ((predivA + 1) * (predivS + 1))_**

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

_SubSeconds management_
* **`uint32_t getSubSeconds(void)`**
Expand Down
51 changes: 33 additions & 18 deletions examples/RTCReset/RTCReset.ino
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ typedef struct {
bool alarm_a;
} cb_data_t;

static cb_data_t atime = { 2222, true};
static cb_data_t atime = { 2222, true };
#ifdef RTC_ALARM_B
static cb_data_t btime = { 3333, false};
static cb_data_t btime = { 3333, false };
#endif
static byte seconds = 0;
static byte minutes = 0;
Expand All @@ -64,7 +64,7 @@ static uint8_t conv2d(const char* p) {
}

// sample input: date = "Dec 26 2009", time = "12:34:56"
void initDateTime (void) {
void initDateTime(void) {
Serial.printf("Build date & time %s, %s\n", mydate, mytime);

year = conv2d(mydate + 9);
Expand All @@ -89,15 +89,15 @@ void initDateTime (void) {
seconds = conv2d(mytime + 6);
}

void setup()
{
void setup() {
pinMode(USER_BTN, INPUT_PULLUP);
int32_t default_state = digitalRead(USER_BTN);

Serial.begin(9600);
while (!Serial);
Serial.begin(115200);
while (!Serial)
;
// Wait user input to start
while (digitalRead(USER_BTN) == default_state);
while (digitalRead(USER_BTN) == default_state)
;
// Convenient function to init date and time variables
initDateTime();

Expand All @@ -110,7 +110,7 @@ void setup()
#ifdef RTC_ALARM_B
rtc.attachInterrupt(alarmMatch, &btime, STM32RTC::ALARM_B);
#endif
rtc.begin(); // Initialize RTC 24H format
rtc.begin(); // Initialize RTC 24H format
if (!rtc.isTimeSet()) {
Serial.printf("RTC time not set\n Set it.\n");
// Set the time
Expand All @@ -129,6 +129,10 @@ void setup()
} else {
// RTC already initialized
time_t epoc, alarm_epoc;
rtc.getTime(&hours, &minutes, &seconds, &subSeconds, &period);
year = rtc.getYear();
month = rtc.getMonth();
day = rtc.getDay();
if (rtc.isAlarmEnabled()) {
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
alarm_epoc = rtc.getAlarmEpoch();
Expand Down Expand Up @@ -156,16 +160,28 @@ void setup()
#endif
Serial.printf("RTC time already set\n");
}
Serial.printf("Alarm A enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_A)) ? "True" : "False");
// For STM32F1xx series, alarm is always disabled after a reset.
bool alarmA = rtc.isAlarmEnabled(STM32RTC::ALARM_A);
Serial.printf("Alarm A enable status: %s\n", (alarmA) ? "True" : "False");
if (!alarmA) {
rtc.setAlarmDay(day);
rtc.setAlarmTime(hours, minutes, seconds + 5, 567);
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
}
#ifdef RTC_ALARM_B
Serial.printf("Alarm B enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_B)) ? "True" : "False");
bool alarmB = rtc.isAlarmEnabled(STM32RTC::ALARM_B);
Serial.printf("Alarm B enable status: %s\n", (alarmB) ? "True" : "False");
if (!alarmB) {
rtc.setAlarmDay(day, STM32RTC::ALARM_B);
rtc.setAlarmTime(hours, minutes, seconds + 5, 567, STM32RTC::ALARM_B);
rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B);
}
#else
Serial.println("Alarm B not available.");
#endif
}

void loop()
{
void loop() {
rtc.getTime(&hours, &minutes, &seconds, &subSeconds, &period);
// Print current date & time
Serial.printf("\n%02d/%02d/%02d %02d:%02d:%02d.%03d\n", rtc.getDay(), rtc.getMonth(), rtc.getYear(), hours, minutes, seconds, subSeconds);
Expand All @@ -177,13 +193,12 @@ void loop()
delay(1000);
}

void alarmMatch(void *data)
{
void alarmMatch(void* data) {
time_t epoc;
uint32_t epoc_ms;
uint32_t sec = 0;
uint32_t _millis = 1000;
cb_data_t cbdata = {.next = 1000, .alarm_a = true};
cb_data_t cbdata = { .next = 1000, .alarm_a = true };
if (data != NULL) {
cbdata.next = ((cb_data_t*)data)->next;
cbdata.alarm_a = ((cb_data_t*)data)->alarm_a;
Expand All @@ -204,7 +219,7 @@ void alarmMatch(void *data)
// Update epoch_ms - might need to add a second to epoch
epoc_ms += _millis;
if (epoc_ms >= 1000) {
sec ++;
sec++;
epoc_ms -= 1000;
}
#endif
Expand Down
82 changes: 43 additions & 39 deletions src/STM32RTC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -103,7 +104,7 @@ void STM32RTC::begin(bool resetTime, Hour_Format format)
*/
void STM32RTC::end(void)
{
RTC_DeInit();
RTC_DeInit(true);
_timeSet = false;
}

Expand All @@ -117,74 +118,77 @@ STM32RTC::Source_Clock STM32RTC::getClockSource(void)
}

/**
* @brief set the RTC clock source. By default LSI clock is selected. This
* method must be called before begin().
* @brief set the RTC clock source and user (a)synchronous prescalers values.
* @note By default LSI clock is selected. This method must be called before begin().
* @param source: clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK
* @param predivA: Asynchronous prescaler value.
* @note Reset value: RTC_AUTO_1_SECOND for STM32F1xx series, else (PREDIVA_MAX + 1)
* @param predivS: Synchronous prescaler value.
* @note Reset value: (PREDIVS_MAX + 1), not used for STM32F1xx series.
* @retval None
*/
void STM32RTC::setClockSource(Source_Clock source)
void STM32RTC::setClockSource(Source_Clock source, uint32_t predivA, uint32_t predivS)
{
if (IS_CLOCK_SOURCE(source)) {
_clockSource = source;
RTC_SetClockSource((_clockSource == LSE_CLOCK) ? ::LSE_CLOCK :
(_clockSource == HSE_CLOCK) ? ::HSE_CLOCK : ::LSI_CLOCK);
}
RTC_setPrediv(predivA, predivS);
}

#if defined(STM32F1xx)
/**
* @brief get user asynchronous prescaler value for the current clock source.
* @param predivA: pointer to the current Asynchronous prescaler value
* @param dummy : not used (kept for compatibility reason)
* @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::getPrediv(uint32_t *predivA, int16_t *dummy)
void STM32RTC::setBinaryMode(Binary_Mode mode)
{
UNUSED(dummy);
RTC_getPrediv(predivA);
_mode = mode;
}
#else

/**
* @brief get user (a)synchronous prescaler values if set else computed
* ones for the current clock source.
* @param predivA: pointer to the current Asynchronous prescaler value
* @param predivS: pointer to the current Synchronous prescaler value
* @param predivS: pointer to the current Synchronous prescaler value,
* not used for STM32F1xx series.
* @retval None
*/
void STM32RTC::getPrediv(int8_t *predivA, int16_t *predivS)
void STM32RTC::getPrediv(uint32_t *predivA, uint32_t *predivS)
{
if ((predivA != nullptr) && (predivS != nullptr)) {
if ((predivA != nullptr)
#if !defined(STM32F1xx)
&& (predivS != nullptr)
#endif /* STM32F1xx */
) {
RTC_getPrediv(predivA, predivS);
}
}
#endif /* STM32F1xx */

#if defined(STM32F1xx)
/**
* @brief set user asynchronous prescalers value.
* @brief set user (a)synchronous prescalers values.
* @note This method must be called before begin().
* @param predivA: Asynchronous prescaler value. Reset value: RTC_AUTO_1_SECOND
* @param dummy : not used (kept for compatibility reason)
* @param predivA: Asynchronous prescaler value.
* @note Reset value: RTC_AUTO_1_SECOND for STM32F1xx series, else (PREDIVA_MAX + 1)
* @param predivS: Synchronous prescaler value.
* @note Reset value: (PREDIVS_MAX + 1), not used for STM32F1xx series.
* @retval None
*/
void STM32RTC::setPrediv(uint32_t predivA, int16_t dummy)
void STM32RTC::setPrediv(uint32_t predivA, uint32_t predivS)
{
UNUSED(dummy);
RTC_setPrediv(predivA);
setClockSource(_clockSource, predivA, predivS);
}
#else
/**
* @brief set user (a)synchronous prescalers value.
* @note This method must be called before begin().
* @param predivA: Asynchronous prescaler value. Reset value: -1
* @param predivS: Synchronous prescaler value. Reset value: -1
* @retval None
*/
void STM32RTC::setPrediv(int8_t predivA, int16_t predivS)
{
RTC_setPrediv(predivA, predivS);
}
#endif /* STM32F1xx */

/**
* @brief enable the RTC alarm.
Expand Down Expand Up @@ -827,7 +831,7 @@ void STM32RTC::setAlarmSubSeconds(uint32_t subSeconds, Alarm name)
#ifdef RTC_ALARM_B
if (name == ALARM_B) {
_alarmBSubSeconds = subSeconds;
}
} else
#else
UNUSED(name);
#endif
Expand All @@ -850,7 +854,7 @@ void STM32RTC::setAlarmSeconds(uint8_t seconds, Alarm name)
#ifdef RTC_ALARM_B
if (name == ALARM_B) {
_alarmBSeconds = seconds;
}
} else
#else
UNUSED(name);
#endif
Expand All @@ -873,7 +877,7 @@ void STM32RTC::setAlarmMinutes(uint8_t minutes, Alarm name)
#ifdef RTC_ALARM_B
if (name == ALARM_B) {
_alarmBMinutes = minutes;
}
} else
#else
UNUSED(name);
#endif
Expand Down
26 changes: 17 additions & 9 deletions src/STM32RTC.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ 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_SS = SS_MSK, // Every Minute
Expand Down Expand Up @@ -126,7 +132,12 @@ class STM32RTC {
void end(void);

Source_Clock getClockSource(void);
void setClockSource(Source_Clock source);
void setClockSource(Source_Clock source, uint32_t predivA = (PREDIVA_MAX + 1), uint32_t predivS = (PREDIVS_MAX + 1));
void getPrediv(uint32_t *predivA, uint32_t *predivS);
void setPrediv(uint32_t predivA, uint32_t predivS);

Binary_Mode getBinaryMode(void);
void setBinaryMode(Binary_Mode mode);

void enableAlarm(Alarm_Match match, Alarm name = ALARM_A);
void disableAlarm(Alarm name = ALARM_A);
Expand Down Expand Up @@ -212,13 +223,6 @@ class STM32RTC {
void setAlarmEpoch(time_t ts, Alarm_Match match, Alarm name);
void setAlarmEpoch(time_t ts, Alarm_Match match = MATCH_DHHMMSS, uint32_t subSeconds = 0, Alarm name = ALARM_A);

#if defined(STM32F1xx)
void getPrediv(uint32_t *predivA, int16_t *dummy = nullptr);
void setPrediv(uint32_t predivA, int16_t dummy = 0);
#else
void getPrediv(int8_t *predivA, int16_t *predivS);
void setPrediv(int8_t predivA, int16_t predivS);
#endif /* STM32F1xx */
bool isConfigured(void)
{
return RTC_IsConfigured();
Expand All @@ -232,11 +236,15 @@ class STM32RTC {
friend class STM32LowPower;

private:
STM32RTC(void): _clockSource(LSI_CLOCK) {}
STM32RTC(void): _mode(MODE_BCD), _clockSource(LSI_CLOCK)
{
setClockSource(_clockSource);
}

static bool _timeSet;

Hour_Format _format;
Binary_Mode _mode;
AM_PM _hoursPeriod;
uint8_t _hours;
uint8_t _minutes;
Expand Down
Loading

0 comments on commit 5f53d03

Please sign in to comment.