Skip to content

Commit ad158d3

Browse files
authored
Merge pull request #86 from fpistm/AlarmAB
feat: add second alarm (B) support
2 parents e5afbbf + 5fcb571 commit ad158d3

File tree

9 files changed

+853
-140
lines changed

9 files changed

+853
-140
lines changed

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ _SubSeconds alarm management_
7272
* **`void setAlarmTime(uint8_t hours, uint8_t minutes, uint8_t seconds, uint32_t subSeconds = 0, AM_PM period = AM)`**
7373
* **`uint32_t getEpoch(uint32_t *subSeconds = nullptr)`**
7474
* **`void setEpoch(uint32_t ts, uint32_t subSeconds = 0)`**
75-
* **`void setAlarmEpoch(uint32_t ts, Alarm_Match match = MATCH_DHHMMSS, uint32_t subSeconds = 0)`**
75+
* **`void setAlarmEpoch(uint32_t ts, Alarm_Match match = MATCH_DHHMMSS, uint32_t subSeconds = 0)`**
7676

7777
_Library version management_
7878

@@ -105,7 +105,7 @@ _Library version management_
105105
_One-Second interrupt_
106106

107107
STM32 RTC includes a one-second interrupt for generating a periodic interrupt signal.
108-
- This feature is native on the stm32F1xx and mapped on the existing WakeUp interrupt on other stm32 mcus.
108+
- This feature is native on the stm32F1xx and mapped on the existing WakeUp interrupt on other stm32 mcus.
109109
- It is not available on some stm32F0 devices.
110110

111111
* **new API:**
@@ -138,6 +138,21 @@ To know if a time has already been set use:
138138
}
139139
```
140140
141+
### Since STM32RTC version higher than 1.3.4
142+
_Second alarm (Alarm B)_
143+
144+
Some STM32 RTC have a second alarm named `RTC_ALARM_B`.
145+
It is possible to use it thanks all alarm API with an extra argument:
146+
- `STM32RTC::ALARM_A`
147+
- `STM32RTC::ALARM_B`
148+
149+
```C++
150+
rtc.attachInterrupt(myCallback, &myCallbackdata, STM32RTC::ALARM_B);
151+
rtc.setAlarmDay(day, STM32RTC::ALARM_B);
152+
rtc.setAlarmTime(hours, minutes, seconds + 5, 567, STM32RTC::ALARM_B);
153+
rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B);
154+
```
155+
141156
Refer to the Arduino RTC documentation for the other functions
142157
http://arduino.cc/en/Reference/RTC
143158

examples/Epoch/Epoch.ino

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
*/
1515

1616
#include <STM32RTC.h>
17-
#include <time.h>
1817

1918
/* Get the rtc object */
2019
STM32RTC& rtc = STM32RTC::getInstance();
@@ -63,4 +62,4 @@ void print2digits(uint32_t number) {
6362
Serial.print("0");
6463
}
6564
Serial.print(number);
66-
}
65+
}

examples/RTCReset/RTCReset.ino

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
RTCReset
3+
4+
This sketch allows to test STM32RTC after a software reset or power off
5+
with VBat. Including Alarm A and B management.
6+
7+
Creation 17 jan 2023
8+
by Frederic Pillon for STMicroelectronics
9+
10+
This example code is in the public domain.
11+
12+
https://github.com/stm32duino/STM32RTC
13+
14+
*/
15+
#include <STM32RTC.h>
16+
17+
/* Get the rtc object */
18+
STM32RTC& rtc = STM32RTC::getInstance();
19+
20+
/* Change these values to set the current initial time
21+
22+
format: date: "Dec 31 2022" and time: "23:59:56"
23+
by default use built date and time
24+
*/
25+
static const char* mydate = __DATE__;
26+
static const char* mytime = __TIME__;
27+
//static const char* mydate = "Dec 31 2022";
28+
//static const char* mytime = "23:59:56";
29+
30+
/* Declare it volatile since it's incremented inside an interrupt */
31+
volatile int alarmMatch_counter = 0;
32+
volatile int alarmMatchB_counter = 0;
33+
34+
typedef struct {
35+
uint32_t next;
36+
bool alarm_a;
37+
} cb_data_t;
38+
39+
static cb_data_t atime = { 2222, true};
40+
#ifdef RTC_ALARM_B
41+
static cb_data_t btime = { 3333, false};
42+
#endif
43+
static byte seconds = 0;
44+
static byte minutes = 0;
45+
static byte hours = 0;
46+
static uint32_t subSeconds = 0;
47+
48+
static byte weekDay = 1;
49+
static byte day = 0;
50+
static byte month = 0;
51+
static byte year = 0;
52+
static STM32RTC::Hour_Format hourFormat = STM32RTC::HOUR_24;
53+
static STM32RTC::AM_PM period = STM32RTC::AM;
54+
55+
#ifndef USER_BTN
56+
#define USER_BTN PA0
57+
#endif
58+
59+
static uint8_t conv2d(const char* p) {
60+
uint8_t v = 0;
61+
if ('0' <= *p && *p <= '9')
62+
v = *p - '0';
63+
return 10 * v + *++p - '0';
64+
}
65+
66+
// sample input: date = "Dec 26 2009", time = "12:34:56"
67+
void initDateTime (void) {
68+
Serial.printf("Build date & time %s, %s\n", mydate, mytime);
69+
70+
year = conv2d(mydate + 9);
71+
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
72+
switch (mydate[0]) {
73+
case 'J': month = (mydate[1] == 'a') ? 1 : ((mydate[2] == 'n') ? 6 : 7); break;
74+
case 'F': month = 2; break;
75+
case 'A': month = mydate[2] == 'r' ? 4 : 8; break;
76+
case 'M': month = mydate[2] == 'r' ? 3 : 5; break;
77+
case 'S': month = 9; break;
78+
case 'O': month = 10; break;
79+
case 'N': month = 11; break;
80+
case 'D': month = 12; break;
81+
}
82+
day = conv2d(mydate + 4);
83+
hours = conv2d(mytime);
84+
if (hourFormat == rtc.HOUR_12) {
85+
period = hours >= 12 ? rtc.PM : rtc.AM;
86+
hours = hours >= 13 ? hours - 12 : (hours < 1 ? hours + 12 : hours);
87+
}
88+
minutes = conv2d(mytime + 3);
89+
seconds = conv2d(mytime + 6);
90+
}
91+
92+
void setup()
93+
{
94+
pinMode(USER_BTN, INPUT_PULLUP);
95+
int32_t default_state = digitalRead(USER_BTN);
96+
97+
Serial.begin(9600);
98+
while (!Serial);
99+
// Wait user input to start
100+
while (digitalRead(USER_BTN) == default_state);
101+
// Convenient function to init date and time variables
102+
initDateTime();
103+
104+
// Select RTC clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK.
105+
// By default the LSI is selected as source.
106+
// rtc.setClockSource(STM32RTC::LSE_CLOCK);
107+
108+
// In any case attach a callback to the RTC alarm interrupt.
109+
rtc.attachInterrupt(alarmMatch, &atime);
110+
#ifdef RTC_ALARM_B
111+
rtc.attachInterrupt(alarmMatch, &btime, STM32RTC::ALARM_B);
112+
#endif
113+
rtc.begin(); // Initialize RTC 24H format
114+
if (!rtc.isTimeSet()) {
115+
Serial.printf("RTC time not set\n Set it.\n");
116+
// Set the time
117+
rtc.setTime(hours, minutes, seconds);
118+
rtc.setDate(weekDay, day, month, year);
119+
// ALARM_A (default argument)
120+
rtc.setAlarmDay(day);
121+
rtc.setAlarmTime(hours, minutes, seconds + 5, 567);
122+
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
123+
#ifdef RTC_ALARM_B
124+
// ALARM_B
125+
rtc.setAlarmDay(day, STM32RTC::ALARM_B);
126+
rtc.setAlarmTime(hours, minutes, seconds + 5, 567, STM32RTC::ALARM_B);
127+
rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B);
128+
#endif
129+
} else {
130+
// RTC already initialized
131+
time_t epoc, alarm_epoc;
132+
if (rtc.isAlarmEnabled()) {
133+
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
134+
alarm_epoc = rtc.getAlarmEpoch();
135+
epoc = rtc.getEpoch();
136+
if (difftime(alarm_epoc, epoc) <= 0) {
137+
Serial.printf("Alarm A was enabled and expired, force callback call\n");
138+
alarmMatch(&atime);
139+
} else {
140+
Serial.printf("Alarm A was enabled and restored\n");
141+
}
142+
}
143+
#ifdef RTC_ALARM_B
144+
// ALARM_B
145+
if (rtc.isAlarmEnabled(STM32RTC::ALARM_B)) {
146+
rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B);
147+
alarm_epoc = rtc.getAlarmEpoch(STM32RTC::ALARM_B);
148+
epoc = rtc.getEpoch();
149+
if (difftime(alarm_epoc, epoc) <= 0) {
150+
Serial.printf("Alarm B was enabled and expired, force callback call\n");
151+
alarmMatch(&btime);
152+
} else {
153+
Serial.printf("Alarm B was enabled and restored\n");
154+
}
155+
}
156+
#endif
157+
Serial.printf("RTC time already set\n");
158+
}
159+
Serial.printf("Alarm A enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_A)) ? "True" : "False");
160+
#ifdef RTC_ALARM_B
161+
Serial.printf("Alarm B enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_B)) ? "True" : "False");
162+
#else
163+
Serial.println("Alarm B not available.");
164+
#endif
165+
}
166+
167+
void loop()
168+
{
169+
rtc.getTime(&hours, &minutes, &seconds, &subSeconds, &period);
170+
// Print current date & time
171+
Serial.printf("\n%02d/%02d/%02d %02d:%02d:%02d.%03d\n", rtc.getDay(), rtc.getMonth(), rtc.getYear(), hours, minutes, seconds, subSeconds);
172+
// Print current alarm configuration
173+
Serial.printf("Alarm A: %02d %02d:%02d:%02d.%03d\n", rtc.getAlarmDay(), rtc.getAlarmHours(), rtc.getAlarmMinutes(), rtc.getAlarmSeconds(), rtc.getAlarmSubSeconds());
174+
#ifdef RTC_ALARM_B
175+
Serial.printf("Alarm B: %02d %02d:%02d:%02d.%03d\n", rtc.getAlarmDay(STM32RTC::ALARM_B), rtc.getAlarmHours(STM32RTC::ALARM_B), rtc.getAlarmMinutes(STM32RTC::ALARM_B), rtc.getAlarmSeconds(STM32RTC::ALARM_B), rtc.getAlarmSubSeconds(STM32RTC::ALARM_B));
176+
#endif
177+
delay(1000);
178+
}
179+
180+
void alarmMatch(void *data)
181+
{
182+
time_t epoc;
183+
uint32_t epoc_ms;
184+
uint32_t sec = 0;
185+
uint32_t _millis = 1000;
186+
cb_data_t cbdata = {.next = 1000, .alarm_a = true};
187+
if (data != NULL) {
188+
cbdata.next = ((cb_data_t*)data)->next;
189+
cbdata.alarm_a = ((cb_data_t*)data)->alarm_a;
190+
_millis = cbdata.next;
191+
}
192+
193+
sec = _millis / 1000;
194+
#if !defined(RTC_SSR_SS)
195+
// Minimum is 1 second
196+
if (sec == 0) {
197+
sec = 1;
198+
}
199+
epoc = rtc.getEpoch(&epoc_ms);
200+
#else
201+
_millis = _millis % 1000;
202+
epoc = rtc.getEpoch(&epoc_ms);
203+
204+
// Update epoch_ms - might need to add a second to epoch
205+
epoc_ms += _millis;
206+
if (epoc_ms >= 1000) {
207+
sec ++;
208+
epoc_ms -= 1000;
209+
}
210+
#endif
211+
if (cbdata.alarm_a) {
212+
Serial.printf("\t\t\tAlarm A Match %i\n", ++alarmMatch_counter);
213+
rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_SS, epoc_ms);
214+
}
215+
#ifdef RTC_ALARM_B
216+
else {
217+
Serial.printf("\t\t\tAlarm B Match %i\n", ++alarmMatchB_counter);
218+
rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_SS, epoc_ms, STM32RTC::ALARM_B);
219+
}
220+
#endif
221+
}

examples/advancedRTCAlarm/advancedRTCAlarm.ino

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
It uses the optional 'data' alarm callback parameters to
66
reload alarm with 'atime' offset indefinitely.
77
8+
If a second alarm (B) is available, it is configured
9+
to trigger each second.
10+
811
Creation 25 May 2018
912
by Frederic Pillon for STMicroelectronics
1013
Modified 03 Jul 2020
@@ -22,11 +25,17 @@ STM32RTC& rtc = STM32RTC::getInstance();
2225

2326
/* Declare it volatile since it's incremented inside an interrupt */
2427
volatile int alarmMatch_counter = 0;
28+
#ifdef RTC_ALARM_B
29+
volatile int alarmBMatch_counter = 0;
30+
#endif
2531

2632
/* Change this value to set alarm match offset in millisecond */
27-
/* Note that STM32F1xx does not manage subsecond only second */
33+
/* Note that only mcu with RTC_SSR_SS defined managed subsecond else only second */
34+
#if defined(RTC_SSR_SS)
2835
static uint32_t atime = 678;
29-
36+
#else
37+
static uint32_t atime = 1000;
38+
#endif
3039
/* Change these values to set the current initial time */
3140
const byte seconds = 0;
3241
const byte minutes = 0;
@@ -54,6 +63,13 @@ void setup()
5463
rtc.setAlarmDay(day);
5564
rtc.setAlarmTime(16, 0, 10, 567);
5665
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
66+
67+
#ifdef RTC_ALARM_B
68+
rtc.attachInterrupt(alarmBMatch, STM32RTC::ALARM_B);
69+
rtc.setAlarmDay(day, STM32RTC::ALARM_B);
70+
rtc.setAlarmTime(16, 0, 11, 567, STM32RTC::ALARM_B);
71+
rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B);
72+
#endif
5773
}
5874

5975
void loop()
@@ -70,14 +86,10 @@ void alarmMatch(void *data)
7086

7187
if (data != NULL) {
7288
_millis = *(uint32_t*)data;
73-
// Minimum is 1 second
74-
if (sec == 0) {
75-
sec = 1;
76-
}
7789
}
7890

7991
sec = _millis / 1000;
80-
#ifdef STM32F1xx
92+
#if !defined(RTC_SSR_SS)
8193
// Minimum is 1 second
8294
if (sec == 0) {
8395
sec = 1;
@@ -97,3 +109,12 @@ void alarmMatch(void *data)
97109
Serial.printf("Alarm Match %i\n", ++alarmMatch_counter);
98110
rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_SS, epoc_ms);
99111
}
112+
113+
#ifdef RTC_ALARM_B
114+
void alarmBMatch(void *data)
115+
{
116+
(void)data;
117+
Serial.printf("Alarm B Match %i\n", ++alarmBMatch_counter);
118+
rtc.setAlarmEpoch(rtc.getEpoch() + 2, STM32RTC::MATCH_SS, STM32RTC::ALARM_B);
119+
}
120+
#endif

keywords.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ setTime KEYWORD2
3838

3939
getEpoch KEYWORD2
4040
getY2kEpoch KEYWORD2
41+
getAlarmEpoch KEYWORD2
4142
setEpoch KEYWORD2
4243
setY2kEpoch KEYWORD2
4344
setAlarmEpoch KEYWORD2
@@ -70,6 +71,7 @@ detachSecondsInterrupt KEYWORD2
7071

7172
getClockSource KEYWORD2
7273
setClockSource KEYWORD2
74+
isAlarmEnabled KEYWORD2
7375
isConfigured KEYWORD2
7476
isTimeSet KEYWORD2
7577

@@ -96,3 +98,5 @@ PM LITERAL1
9698
LSE_CLOCK LITERAL1
9799
LSI_CLOCK LITERAL1
98100
HSE_CLOCK LITERAL1
101+
ALARM_A LITERAL1
102+
ALARM_B LITERAL1

0 commit comments

Comments
 (0)