Skip to content

Commit 5f53d03

Browse files
authored
Merge pull request #98 from fpistm/prediv
harden prediv management and add parameter to set binary mode
2 parents a703c0f + 344114d commit 5f53d03

File tree

6 files changed

+301
-217
lines changed

6 files changed

+301
-217
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ _RTC hours mode (12 or 24)_
3131

3232
_RTC clock source_
3333
* **`Source_Clock getClockSource(void)`** : get current clock source.
34-
* **`void setClockSource(Source_Clock source)`** : this function must be called before `begin()`.
34+
* **`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))_**
3535

3636
_RTC Asynchronous and Synchronous prescaler_
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))_**
37+
* **`void getPrediv(uint32_t *predivA, uint32_t *predivS)`** : get (a)synchronous prescaler values if set else computed ones for the current clock source.
38+
* **`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))_**
3939

4040
_SubSeconds management_
4141
* **`uint32_t getSubSeconds(void)`**

examples/RTCReset/RTCReset.ino

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ typedef struct {
3636
bool alarm_a;
3737
} cb_data_t;
3838

39-
static cb_data_t atime = { 2222, true};
39+
static cb_data_t atime = { 2222, true };
4040
#ifdef RTC_ALARM_B
41-
static cb_data_t btime = { 3333, false};
41+
static cb_data_t btime = { 3333, false };
4242
#endif
4343
static byte seconds = 0;
4444
static byte minutes = 0;
@@ -64,7 +64,7 @@ static uint8_t conv2d(const char* p) {
6464
}
6565

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

7070
year = conv2d(mydate + 9);
@@ -89,15 +89,15 @@ void initDateTime (void) {
8989
seconds = conv2d(mytime + 6);
9090
}
9191

92-
void setup()
93-
{
92+
void setup() {
9493
pinMode(USER_BTN, INPUT_PULLUP);
9594
int32_t default_state = digitalRead(USER_BTN);
96-
97-
Serial.begin(9600);
98-
while (!Serial);
95+
Serial.begin(115200);
96+
while (!Serial)
97+
;
9998
// Wait user input to start
100-
while (digitalRead(USER_BTN) == default_state);
99+
while (digitalRead(USER_BTN) == default_state)
100+
;
101101
// Convenient function to init date and time variables
102102
initDateTime();
103103

@@ -110,7 +110,7 @@ void setup()
110110
#ifdef RTC_ALARM_B
111111
rtc.attachInterrupt(alarmMatch, &btime, STM32RTC::ALARM_B);
112112
#endif
113-
rtc.begin(); // Initialize RTC 24H format
113+
rtc.begin(); // Initialize RTC 24H format
114114
if (!rtc.isTimeSet()) {
115115
Serial.printf("RTC time not set\n Set it.\n");
116116
// Set the time
@@ -129,6 +129,10 @@ void setup()
129129
} else {
130130
// RTC already initialized
131131
time_t epoc, alarm_epoc;
132+
rtc.getTime(&hours, &minutes, &seconds, &subSeconds, &period);
133+
year = rtc.getYear();
134+
month = rtc.getMonth();
135+
day = rtc.getDay();
132136
if (rtc.isAlarmEnabled()) {
133137
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
134138
alarm_epoc = rtc.getAlarmEpoch();
@@ -156,16 +160,28 @@ void setup()
156160
#endif
157161
Serial.printf("RTC time already set\n");
158162
}
159-
Serial.printf("Alarm A enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_A)) ? "True" : "False");
163+
// For STM32F1xx series, alarm is always disabled after a reset.
164+
bool alarmA = rtc.isAlarmEnabled(STM32RTC::ALARM_A);
165+
Serial.printf("Alarm A enable status: %s\n", (alarmA) ? "True" : "False");
166+
if (!alarmA) {
167+
rtc.setAlarmDay(day);
168+
rtc.setAlarmTime(hours, minutes, seconds + 5, 567);
169+
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
170+
}
160171
#ifdef RTC_ALARM_B
161-
Serial.printf("Alarm B enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_B)) ? "True" : "False");
172+
bool alarmB = rtc.isAlarmEnabled(STM32RTC::ALARM_B);
173+
Serial.printf("Alarm B enable status: %s\n", (alarmB) ? "True" : "False");
174+
if (!alarmB) {
175+
rtc.setAlarmDay(day, STM32RTC::ALARM_B);
176+
rtc.setAlarmTime(hours, minutes, seconds + 5, 567, STM32RTC::ALARM_B);
177+
rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B);
178+
}
162179
#else
163180
Serial.println("Alarm B not available.");
164181
#endif
165182
}
166183

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

180-
void alarmMatch(void *data)
181-
{
196+
void alarmMatch(void* data) {
182197
time_t epoc;
183198
uint32_t epoc_ms;
184199
uint32_t sec = 0;
185200
uint32_t _millis = 1000;
186-
cb_data_t cbdata = {.next = 1000, .alarm_a = true};
201+
cb_data_t cbdata = { .next = 1000, .alarm_a = true };
187202
if (data != NULL) {
188203
cbdata.next = ((cb_data_t*)data)->next;
189204
cbdata.alarm_a = ((cb_data_t*)data)->alarm_a;
@@ -204,7 +219,7 @@ void alarmMatch(void *data)
204219
// Update epoch_ms - might need to add a second to epoch
205220
epoc_ms += _millis;
206221
if (epoc_ms >= 1000) {
207-
sec ++;
222+
sec++;
208223
epoc_ms -= 1000;
209224
}
210225
#endif

src/STM32RTC.cpp

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ void STM32RTC::begin(bool resetTime, Hour_Format format)
6363

6464
_format = format;
6565
reinit = RTC_init((format == HOUR_12) ? HOUR_FORMAT_12 : HOUR_FORMAT_24,
66+
(_mode == MODE_MIX) ? ::MODE_BINARY_MIX : ((_mode == MODE_BIN) ? ::MODE_BINARY_ONLY : ::MODE_BINARY_NONE),
6667
(_clockSource == LSE_CLOCK) ? ::LSE_CLOCK :
6768
(_clockSource == HSE_CLOCK) ? ::HSE_CLOCK : ::LSI_CLOCK
6869
, resetTime);
@@ -103,7 +104,7 @@ void STM32RTC::begin(bool resetTime, Hour_Format format)
103104
*/
104105
void STM32RTC::end(void)
105106
{
106-
RTC_DeInit();
107+
RTC_DeInit(true);
107108
_timeSet = false;
108109
}
109110

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

119120
/**
120-
* @brief set the RTC clock source. By default LSI clock is selected. This
121-
* method must be called before begin().
121+
* @brief set the RTC clock source and user (a)synchronous prescalers values.
122+
* @note By default LSI clock is selected. This method must be called before begin().
122123
* @param source: clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK
124+
* @param predivA: Asynchronous prescaler value.
125+
* @note Reset value: RTC_AUTO_1_SECOND for STM32F1xx series, else (PREDIVA_MAX + 1)
126+
* @param predivS: Synchronous prescaler value.
127+
* @note Reset value: (PREDIVS_MAX + 1), not used for STM32F1xx series.
123128
* @retval None
124129
*/
125-
void STM32RTC::setClockSource(Source_Clock source)
130+
void STM32RTC::setClockSource(Source_Clock source, uint32_t predivA, uint32_t predivS)
126131
{
127132
if (IS_CLOCK_SOURCE(source)) {
128133
_clockSource = source;
129134
RTC_SetClockSource((_clockSource == LSE_CLOCK) ? ::LSE_CLOCK :
130135
(_clockSource == HSE_CLOCK) ? ::HSE_CLOCK : ::LSI_CLOCK);
131136
}
137+
RTC_setPrediv(predivA, predivS);
132138
}
133139

134-
#if defined(STM32F1xx)
135140
/**
136-
* @brief get user asynchronous prescaler value for the current clock source.
137-
* @param predivA: pointer to the current Asynchronous prescaler value
138-
* @param dummy : not used (kept for compatibility reason)
141+
* @brief get the Binary Mode.
142+
* @retval mode: MODE_BCD, MODE_BIN or MODE_MIX
143+
*/
144+
STM32RTC::Binary_Mode STM32RTC::getBinaryMode(void)
145+
{
146+
return _mode;
147+
}
148+
149+
/**
150+
* @brief set the Binary Mode. By default MODE_BCD is selected. This
151+
* method must be called before begin().
152+
* @param mode: the RTC mode: MODE_BCD, MODE_BIN or MODE_MIX
139153
* @retval None
140154
*/
141-
void STM32RTC::getPrediv(uint32_t *predivA, int16_t *dummy)
155+
void STM32RTC::setBinaryMode(Binary_Mode mode)
142156
{
143-
UNUSED(dummy);
144-
RTC_getPrediv(predivA);
157+
_mode = mode;
145158
}
146-
#else
159+
147160
/**
148161
* @brief get user (a)synchronous prescaler values if set else computed
149162
* ones for the current clock source.
150163
* @param predivA: pointer to the current Asynchronous prescaler value
151-
* @param predivS: pointer to the current Synchronous prescaler value
164+
* @param predivS: pointer to the current Synchronous prescaler value,
165+
* not used for STM32F1xx series.
152166
* @retval None
153167
*/
154-
void STM32RTC::getPrediv(int8_t *predivA, int16_t *predivS)
168+
void STM32RTC::getPrediv(uint32_t *predivA, uint32_t *predivS)
155169
{
156-
if ((predivA != nullptr) && (predivS != nullptr)) {
170+
if ((predivA != nullptr)
171+
#if !defined(STM32F1xx)
172+
&& (predivS != nullptr)
173+
#endif /* STM32F1xx */
174+
) {
157175
RTC_getPrediv(predivA, predivS);
158176
}
159177
}
160-
#endif /* STM32F1xx */
161178

162-
#if defined(STM32F1xx)
163179
/**
164-
* @brief set user asynchronous prescalers value.
180+
* @brief set user (a)synchronous prescalers values.
165181
* @note This method must be called before begin().
166-
* @param predivA: Asynchronous prescaler value. Reset value: RTC_AUTO_1_SECOND
167-
* @param dummy : not used (kept for compatibility reason)
182+
* @param predivA: Asynchronous prescaler value.
183+
* @note Reset value: RTC_AUTO_1_SECOND for STM32F1xx series, else (PREDIVA_MAX + 1)
184+
* @param predivS: Synchronous prescaler value.
185+
* @note Reset value: (PREDIVS_MAX + 1), not used for STM32F1xx series.
168186
* @retval None
169187
*/
170-
void STM32RTC::setPrediv(uint32_t predivA, int16_t dummy)
188+
void STM32RTC::setPrediv(uint32_t predivA, uint32_t predivS)
171189
{
172-
UNUSED(dummy);
173-
RTC_setPrediv(predivA);
190+
setClockSource(_clockSource, predivA, predivS);
174191
}
175-
#else
176-
/**
177-
* @brief set user (a)synchronous prescalers value.
178-
* @note This method must be called before begin().
179-
* @param predivA: Asynchronous prescaler value. Reset value: -1
180-
* @param predivS: Synchronous prescaler value. Reset value: -1
181-
* @retval None
182-
*/
183-
void STM32RTC::setPrediv(int8_t predivA, int16_t predivS)
184-
{
185-
RTC_setPrediv(predivA, predivS);
186-
}
187-
#endif /* STM32F1xx */
188192

189193
/**
190194
* @brief enable the RTC alarm.
@@ -827,7 +831,7 @@ void STM32RTC::setAlarmSubSeconds(uint32_t subSeconds, Alarm name)
827831
#ifdef RTC_ALARM_B
828832
if (name == ALARM_B) {
829833
_alarmBSubSeconds = subSeconds;
830-
}
834+
} else
831835
#else
832836
UNUSED(name);
833837
#endif
@@ -850,7 +854,7 @@ void STM32RTC::setAlarmSeconds(uint8_t seconds, Alarm name)
850854
#ifdef RTC_ALARM_B
851855
if (name == ALARM_B) {
852856
_alarmBSeconds = seconds;
853-
}
857+
} else
854858
#else
855859
UNUSED(name);
856860
#endif
@@ -873,7 +877,7 @@ void STM32RTC::setAlarmMinutes(uint8_t minutes, Alarm name)
873877
#ifdef RTC_ALARM_B
874878
if (name == ALARM_B) {
875879
_alarmBMinutes = minutes;
876-
}
880+
} else
877881
#else
878882
UNUSED(name);
879883
#endif

src/STM32RTC.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ class STM32RTC {
8585
PM = HOUR_PM
8686
};
8787

88+
enum Binary_Mode : uint8_t {
89+
MODE_BCD = MODE_BINARY_NONE, /* not used */
90+
MODE_BIN = MODE_BINARY_ONLY,
91+
MODE_MIX = MODE_BINARY_MIX
92+
};
93+
8894
enum Alarm_Match : uint8_t {
8995
MATCH_OFF = OFF_MSK, // Never
9096
MATCH_SS = SS_MSK, // Every Minute
@@ -126,7 +132,12 @@ class STM32RTC {
126132
void end(void);
127133

128134
Source_Clock getClockSource(void);
129-
void setClockSource(Source_Clock source);
135+
void setClockSource(Source_Clock source, uint32_t predivA = (PREDIVA_MAX + 1), uint32_t predivS = (PREDIVS_MAX + 1));
136+
void getPrediv(uint32_t *predivA, uint32_t *predivS);
137+
void setPrediv(uint32_t predivA, uint32_t predivS);
138+
139+
Binary_Mode getBinaryMode(void);
140+
void setBinaryMode(Binary_Mode mode);
130141

131142
void enableAlarm(Alarm_Match match, Alarm name = ALARM_A);
132143
void disableAlarm(Alarm name = ALARM_A);
@@ -212,13 +223,6 @@ class STM32RTC {
212223
void setAlarmEpoch(time_t ts, Alarm_Match match, Alarm name);
213224
void setAlarmEpoch(time_t ts, Alarm_Match match = MATCH_DHHMMSS, uint32_t subSeconds = 0, Alarm name = ALARM_A);
214225

215-
#if defined(STM32F1xx)
216-
void getPrediv(uint32_t *predivA, int16_t *dummy = nullptr);
217-
void setPrediv(uint32_t predivA, int16_t dummy = 0);
218-
#else
219-
void getPrediv(int8_t *predivA, int16_t *predivS);
220-
void setPrediv(int8_t predivA, int16_t predivS);
221-
#endif /* STM32F1xx */
222226
bool isConfigured(void)
223227
{
224228
return RTC_IsConfigured();
@@ -232,11 +236,15 @@ class STM32RTC {
232236
friend class STM32LowPower;
233237

234238
private:
235-
STM32RTC(void): _clockSource(LSI_CLOCK) {}
239+
STM32RTC(void): _mode(MODE_BCD), _clockSource(LSI_CLOCK)
240+
{
241+
setClockSource(_clockSource);
242+
}
236243

237244
static bool _timeSet;
238245

239246
Hour_Format _format;
247+
Binary_Mode _mode;
240248
AM_PM _hoursPeriod;
241249
uint8_t _hours;
242250
uint8_t _minutes;

0 commit comments

Comments
 (0)