Skip to content

Commit f6769ee

Browse files
Merge pull request #148 from martinayotte/master
make PeriodicWakeup and AlarmA/AlarmB working
2 parents 68c76de + 1268e34 commit f6769ee

2 files changed

Lines changed: 188 additions & 81 deletions

File tree

STM32F4/libraries/RTClock/src/RTClock.cpp

Lines changed: 150 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ static rtc_dev rtc = {
3838

3939
rtc_dev *RTC = &rtc;
4040

41+
voidFuncPtr handlerAlarmA = NULL;
42+
voidFuncPtr handlerAlarmB = NULL;
43+
voidFuncPtr handlerPeriodicWakeup = NULL;
44+
4145

4246
RTClock::RTClock() {
4347
RTClock(RTCSEL_HSE, 7999, 124);
@@ -50,54 +54,54 @@ RTClock::RTClock(rtc_clk_src src) {
5054
RTClock::RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler) {
5155
uint32 t = 0;
5256
RCC_BASE->APB1ENR |= RCC_APB1RSTR_PWRRST;
53-
dbg_printf("RCC_BASE->APB1ENR = %08X\r\n", RCC_BASE->APB1ENR);
54-
dbg_printf("before bkp_init\r\n");
57+
rtc_debug_printf("RCC_BASE->APB1ENR = %08X\r\n", RCC_BASE->APB1ENR);
58+
rtc_debug_printf("before bkp_init\r\n");
5559
bkp_init(); // turn on peripheral clocks to PWR and BKP and reset the backup domain via RCC registers.
5660
// (we reset the backup domain here because we must in order to change the rtc clock source).
57-
dbg_printf("before bkp_disable_writes\r\n");
61+
rtc_debug_printf("before bkp_disable_writes\r\n");
5862
bkp_disable_writes();
59-
dbg_printf("before bkp_enable_writes\r\n");
63+
rtc_debug_printf("before bkp_enable_writes\r\n");
6064
bkp_enable_writes(); // enable writes to the backup registers and the RTC registers via the DBP bit in the PWR control register
61-
dbg_printf("RCC_BASE->CFGR = %08X\r\n", RCC_BASE->CFGR);
65+
rtc_debug_printf("RCC_BASE->CFGR = %08X\r\n", RCC_BASE->CFGR);
6266
RCC_BASE->CFGR |= (0x08 << 16); // Set the RTCPRE to HSE / 8.
63-
dbg_printf("RCC_BASE->CFGR = %08X\r\n", RCC_BASE->CFGR);
67+
rtc_debug_printf("RCC_BASE->CFGR = %08X\r\n", RCC_BASE->CFGR);
6468

6569
switch (src) {
6670
case RTCSEL_LSE :
67-
dbg_printf("Preparing RTC for LSE mode\r\n");
71+
rtc_debug_printf("Preparing RTC for LSE mode\r\n");
6872
if ((RCC_BASE->BDCR & 0x00000300) != 0x0100)
6973
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
7074
RCC_BASE->BDCR = 0x00008101;
71-
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
75+
rtc_debug_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
7276
while (!(RCC_BASE->BDCR & 0x00000002)) {
7377
if (++t > 1000000) {
74-
dbg_printf("RCC_BASE->BDCR.LSERDY Timeout !\r\n");
75-
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
78+
rtc_debug_printf("RCC_BASE->BDCR.LSERDY Timeout !\r\n");
79+
rtc_debug_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
7680
return;
7781
}
7882
}
79-
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
83+
rtc_debug_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
8084
rtc_enter_config_mode();
8185
if (sync_prescaler == 0 && async_prescaler == 0)
8286
RTC_BASE->PRER = 255 | (127 << 16);
8387
else
8488
RTC_BASE->PRER = sync_prescaler | (async_prescaler << 16);
8589
break;
8690
case RTCSEL_LSI :
87-
dbg_printf("Preparing RTC for LSI mode\r\n");
91+
rtc_debug_printf("Preparing RTC for LSI mode\r\n");
8892
if ((RCC_BASE->BDCR & 0x00000300) != 0x0200)
8993
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
9094
RCC_BASE->BDCR = 0x00008204;
9195
RCC_BASE->CSR |= 0x00000001;
92-
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
96+
rtc_debug_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
9397
while (!(RCC_BASE->CSR & 0x00000002)) {
9498
if (++t > 1000000) {
95-
dbg_printf("RCC_BASE->CSR.LSIRDY Timeout !\r\n");
96-
dbg_printf("RCC_BASE->CSR = %08X\r\n", RCC_BASE->CSR);
99+
rtc_debug_printf("RCC_BASE->CSR.LSIRDY Timeout !\r\n");
100+
rtc_debug_printf("RCC_BASE->CSR = %08X\r\n", RCC_BASE->CSR);
97101
return;
98102
}
99103
}
100-
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
104+
rtc_debug_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
101105
rtc_enter_config_mode();
102106
if (sync_prescaler == 0 && async_prescaler == 0)
103107
RTC_BASE->PRER = 249 | (127 << 16);
@@ -106,32 +110,32 @@ RTClock::RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler)
106110
break;
107111
case RTCSEL_DEFAULT:
108112
case RTCSEL_HSE :
109-
dbg_printf("Preparing RTC for HSE mode\r\n");
113+
rtc_debug_printf("Preparing RTC for HSE mode\r\n");
110114
if ((RCC_BASE->BDCR & 0x00000300) != 0x0300)
111115
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
112116
RCC_BASE->BDCR = 0x00008304;
113-
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
117+
rtc_debug_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
114118
rtc_enter_config_mode();
115119
if (sync_prescaler == 0 && async_prescaler == 0)
116120
RTC_BASE->PRER = 7999 | (124 << 16);
117121
else
118122
RTC_BASE->PRER = sync_prescaler | (async_prescaler << 16);
119123
break;
120124
case RTCSEL_NONE:
121-
dbg_printf("Preparing RTC for NONE mode\r\n");
125+
rtc_debug_printf("Preparing RTC for NONE mode\r\n");
122126
if ((RCC_BASE->BDCR & 0x00000300) != 0x0000)
123127
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
124128
RCC_BASE->BDCR = RCC_BDCR_RTCSEL_NONE;
125129
//do nothing. Have a look at the clocks to see the diff between NONE and DEFAULT
126130
break;
127131
}
128132
RCC_BASE->CR |= 0x00000040; // Turn to 24hrs mode
129-
// dbg_printf("before rtc_clear_sync\r\n");
133+
// rtc_debug_printf("before rtc_clear_sync\r\n");
130134
// rtc_clear_sync();
131-
// dbg_printf("before rtc_wait_sync\r\n");
135+
// rtc_debug_printf("before rtc_wait_sync\r\n");
132136
// rtc_wait_sync();
133137
rtc_exit_config_mode();
134-
dbg_printf("end of rtc_init\r\n");
138+
rtc_debug_printf("end of rtc_init\r\n");
135139
}
136140

137141
/*
@@ -192,6 +196,9 @@ void RTClock::setTime (time_t time_stamp) {
192196

193197
void RTClock::setTime (struct tm* tm_ptr) {
194198
rtc_enter_config_mode();
199+
if (tm_ptr->tm_year > 99)
200+
tm_ptr->tm_year = tm_ptr->tm_year % 100;
201+
tm_ptr->tm_wday = tm_ptr->tm_wday & 0x7;
195202
RTC_BASE->TR = ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) |
196203
((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) |
197204
((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10);
@@ -202,12 +209,14 @@ void RTClock::setTime (struct tm* tm_ptr) {
202209
}
203210

204211
time_t RTClock::getTime() {
205-
int years = 10 * ((RTC_BASE->DR & 0x00F00000) >> 20) + ((RTC_BASE->DR & 0x000F0000) >> 16);
206-
int months = 10 * ((RTC_BASE->DR & 0x00001000) >> 12) + ((RTC_BASE->DR & 0x00000F00) >> 8);
207-
int days = 10 * ((RTC_BASE->DR & 0x00000030) >> 4) + (RTC_BASE->DR & 0x000000F);
208-
int hours = 10 * ((RTC_BASE->TR & 0x00300000) >> 20) + ((RTC_BASE->TR & 0x000F0000) >> 16);
209-
int mins = 10 * ((RTC_BASE->TR & 0x00007000) >> 12) + ((RTC_BASE->TR & 0x0000F00) >> 8);
210-
int secs = 10 * ((RTC_BASE->TR & 0x00000070) >> 4) + (RTC_BASE->TR & 0x0000000F);
212+
uint32 dr_reg = RTC_BASE->DR;
213+
uint32 tr_reg = RTC_BASE->TR;
214+
int years = 10 * ((dr_reg & 0x00F00000) >> 20) + ((dr_reg & 0x000F0000) >> 16);
215+
int months = 10 * ((dr_reg & 0x00001000) >> 12) + ((dr_reg & 0x00000F00) >> 8);
216+
int days = 10 * ((dr_reg & 0x00000030) >> 4) + (dr_reg & 0x000000F);
217+
int hours = 10 * ((tr_reg & 0x00300000) >> 20) + ((tr_reg & 0x000F0000) >> 16);
218+
int mins = 10 * ((tr_reg & 0x00007000) >> 12) + ((tr_reg & 0x0000F00) >> 8);
219+
int secs = 10 * ((tr_reg & 0x00000070) >> 4) + (tr_reg & 0x0000000F);
211220
// seconds from 1970 till 1 jan 00:00:00 of the given year
212221
time_t t = (years + 30) * SECS_PER_DAY * 365;
213222
for (int i = 0; i < years; i++) {
@@ -228,34 +237,19 @@ time_t RTClock::getTime() {
228237
}
229238

230239
struct tm* RTClock::getTime(struct tm* tm_ptr) {
231-
tm_ptr->tm_year = 10 * ((RTC_BASE->DR & 0x00F00000) >> 20) + ((RTC_BASE->DR & 0x000F0000) >> 16);
232-
tm_ptr->tm_mon = 10 * ((RTC_BASE->DR & 0x00001000) >> 12) + ((RTC_BASE->DR & 0x00000F00) >> 8);
233-
tm_ptr->tm_mday = 10 * ((RTC_BASE->DR & 0x00000030) >> 4) + (RTC_BASE->DR & 0x000000F);
234-
tm_ptr->tm_hour = 10 * ((RTC_BASE->TR & 0x00300000) >> 20) + ((RTC_BASE->TR & 0x000F0000) >> 16);
235-
tm_ptr->tm_min = 10 * ((RTC_BASE->TR & 0x00007000) >> 12) + ((RTC_BASE->TR & 0x0000F00) >> 8);
236-
tm_ptr->tm_sec = 10 * ((RTC_BASE->TR & 0x00000070) >> 4) + (RTC_BASE->TR & 0x0000000F);
240+
uint32 dr_reg = RTC_BASE->DR;
241+
uint32 tr_reg = RTC_BASE->TR;
242+
tm_ptr->tm_year = 10 * ((dr_reg & 0x00F00000) >> 20) + ((dr_reg & 0x000F0000) >> 16);
243+
tm_ptr->tm_mon = 10 * ((dr_reg & 0x00001000) >> 12) + ((dr_reg & 0x00000F00) >> 8);
244+
tm_ptr->tm_mday = 10 * ((dr_reg & 0x00000030) >> 4) + (dr_reg & 0x000000F);
245+
tm_ptr->tm_hour = 10 * ((tr_reg & 0x00300000) >> 20) + ((tr_reg & 0x000F0000) >> 16);
246+
tm_ptr->tm_min = 10 * ((tr_reg & 0x00007000) >> 12) + ((tr_reg & 0x0000F00) >> 8);
247+
tm_ptr->tm_sec = 10 * ((tr_reg & 0x00000070) >> 4) + (tr_reg & 0x0000000F);
237248
return tm_ptr;
238249
}
239250

240-
void RTClock::createAlarm(voidFuncPtr function, time_t alarm_time_t) {
241-
// rtc_set_alarm(alarm_time_t); //must be int... for standardization sake.
242-
// rtc_attach_interrupt(RTC_ALARM_SPECIFIC_INTERRUPT, function);
243-
}
244-
245-
void RTClock::createAlarm(voidFuncPtr function, tm* alarm_tm) {
246-
// time_t alarm = mktime(alarm_tm);//convert to time_t
247-
// createAlarm(function, alarm);
248-
}
249-
250-
void RTClock::attachSecondsInterrupt(voidFuncPtr function) {
251-
// rtc_attach_interrupt(RTC_SECONDS_INTERRUPT, function);
252-
}
253-
254-
void RTClock::detachSecondsInterrupt() {
255-
// rtc_detach_interrupt(RTC_SECONDS_INTERRUPT);
256-
}
257-
258251
void RTClock::setAlarmATime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) {
252+
uint32 t = 0;
259253
rtc_enter_config_mode();
260254
unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) |
261255
((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) |
@@ -265,9 +259,21 @@ void RTClock::setAlarmATime (tm * tm_ptr, bool hours_match, bool mins_match, boo
265259
if (!hours_match) bits |= (1 << 23);
266260
if (!mins_match) bits |= (1 << 15);
267261
if (!secs_match) bits |= (1 << 7);
262+
RTC_BASE->CR &= ~(1 << RTC_CR_ALRAE_BIT);
263+
while (!(RTC_BASE->ISR & (1 << RTC_ISR_ALRAWF_BIT))) {
264+
if (++t > 1000000) {
265+
rtc_debug_printf("RTC_BASE->ISR.ALRAWF Timeout !\r\n");
266+
rtc_debug_printf("RTC_BASE->ISR = %08X\r\n", RTC_BASE->ISR);
267+
return;
268+
}
269+
}
268270
RTC_BASE->ALRMAR = bits;
271+
RTC_BASE->CR |= (1 << RTC_CR_ALRAE_BIT);
269272
RTC_BASE->CR |= (1 << RTC_CR_ALRAIE_BIT); // turn on ALRAIE
270273
rtc_exit_config_mode();
274+
nvic_irq_enable(NVIC_RTCALARM);
275+
nvic_irq_enable(NVIC_RTC);
276+
rtc_enable_alarm_event();
271277
}
272278

273279

@@ -285,6 +291,7 @@ void RTClock::turnOffAlarmA() {
285291

286292

287293
void RTClock::setAlarmBTime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) {
294+
uint32 t = 0;
288295
rtc_enter_config_mode();
289296
unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) |
290297
((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) |
@@ -294,9 +301,21 @@ void RTClock::setAlarmBTime (tm * tm_ptr, bool hours_match, bool mins_match, boo
294301
if (!hours_match) bits |= (1 << 23);
295302
if (!mins_match) bits |= (1 << 15);
296303
if (!secs_match) bits |= (1 << 7);
304+
RTC_BASE->CR &= ~(1 << RTC_CR_ALRBE_BIT);
305+
while (!(RTC_BASE->ISR & (1 << RTC_ISR_ALRBWF_BIT))) {
306+
if (++t > 1000000) {
307+
rtc_debug_printf("RTC_BASE->ISR.ALRBWF Timeout !\r\n");
308+
rtc_debug_printf("RTC_BASE->ISR = %08X\r\n", RTC_BASE->ISR);
309+
return;
310+
}
311+
}
297312
RTC_BASE->ALRMBR = bits;
313+
RTC_BASE->CR |= (1 << RTC_CR_ALRBE_BIT);
298314
RTC_BASE->CR |= (1 << RTC_CR_ALRBIE_BIT); // turn on ALRBIE
299315
rtc_exit_config_mode();
316+
nvic_irq_enable(NVIC_RTCALARM);
317+
nvic_irq_enable(NVIC_RTC);
318+
rtc_enable_alarm_event();
300319
}
301320

302321

@@ -314,32 +333,98 @@ void RTClock::turnOffAlarmB() {
314333

315334

316335
void RTClock::setPeriodicWakeup(uint16 period) {
336+
uint32 t = 0;
317337
rtc_enter_config_mode();
318-
dbg_printf("before setting RTC_BASE->WUTR\r\n");
338+
RTC_BASE->CR &= ~(1 << RTC_CR_WUTE_BIT);
339+
while (!(RTC_BASE->ISR & (1 << RTC_ISR_WUTWF_BIT))) {
340+
if (++t > 1000000) {
341+
rtc_debug_printf("RTC_BASE->ISR.WUTWF Timeout !\r\n");
342+
rtc_debug_printf("RTC_BASE->ISR = %08X\r\n", RTC_BASE->ISR);
343+
return;
344+
}
345+
}
346+
rtc_debug_printf("before setting RTC_BASE->WUTR\r\n");
319347
RTC_BASE->WUTR = period; // set the period
320-
dbg_printf("before setting RTC_BASE->CR.WUCKSEL\r\n");
348+
rtc_debug_printf("RTC_BASE->WUTR = %08X\r\n", RTC_BASE->WUTR);
349+
rtc_debug_printf("before setting RTC_BASE->CR.WUCKSEL\r\n");
321350
RTC_BASE->CR &= ~(3); RTC_BASE->CR |= 4; // Set the WUCKSEL to 1Hz (0x00000004)
351+
RTC_BASE->ISR &= ~(1 << RTC_ISR_WUTF_BIT);
352+
RTC_BASE->CR |= (1 << RTC_CR_WUTE_BIT);
322353
if (period == 0)
323354
RTC_BASE->CR &= ~(1 << RTC_CR_WUTIE_BIT); // if period is 0, turn off periodic wakeup interrupt.
324355
else {
325-
dbg_printf("before turn ON RTC_BASE->CR.WUTIE\r\n");
356+
rtc_debug_printf("before turn ON RTC_BASE->CR.WUTIE\r\n");
326357
RTC_BASE->CR |= (1 << RTC_CR_WUTIE_BIT); // turn on WUTIE
327358
}
328-
dbg_printf("RCC_BASE->CR = %08X\r\n", RCC_BASE->CR);
359+
rtc_debug_printf("RCC_BASE->CR = %08X\r\n", RCC_BASE->CR);
329360
rtc_exit_config_mode();
330361
rtc_enable_wakeup_event();
331362
nvic_irq_enable(NVIC_RTC);
332-
nvic_irq_enable(NVIC_RTCALARM);
333-
dbg_printf("setPeriodicWakeup() done !\r\n");
363+
rtc_debug_printf("setPeriodicWakeup() done !\r\n");
334364
}
335365

336-
extern "C" {
337-
void __irq_rtc(void) {
338-
dbg_printf("__irq_rtc() called !\r\n");
339-
*bb_perip(&EXTI_BASE->PR, EXTI_RTC_WAKEUP_BIT) = 1;
366+
367+
void RTClock::attachAlarmAInterrupt(voidFuncPtr function) {
368+
handlerAlarmA = function;
340369
}
341-
void __irq_rtcalarm(void) {
342-
dbg_printf("__irq_rtcalarm() called !\r\n");
343-
*bb_perip(&EXTI_BASE->PR, EXTI_RTC_ALARM_BIT) = 1;
370+
371+
void RTClock::detachAlarmAInterrupt() {
372+
handlerAlarmA = NULL;
373+
}
374+
375+
void RTClock::attachAlarmBInterrupt(voidFuncPtr function) {
376+
handlerAlarmB = function;
344377
}
378+
379+
void RTClock::detachAlarmBInterrupt() {
380+
handlerAlarmB = NULL;
381+
}
382+
383+
void RTClock::attachPeriodicWakeupInterrupt(voidFuncPtr function) {
384+
handlerPeriodicWakeup = function;
385+
}
386+
387+
void RTClock::detachPeriodicWakeupInterrupt() {
388+
handlerPeriodicWakeup = NULL;
389+
}
390+
391+
392+
393+
extern "C" {
394+
void __irq_rtc(void) {
395+
rtc_debug_printf("__irq_rtc() called !\r\n");
396+
rtc_enter_config_mode();
397+
RTC_BASE->ISR &= ~(1 << RTC_ISR_WUTF_BIT);
398+
rtc_exit_config_mode();
399+
*bb_perip(&EXTI_BASE->PR, EXTI_RTC_WAKEUP_BIT) = 1;
400+
if (handlerPeriodicWakeup != NULL) {
401+
handlerPeriodicWakeup();
402+
}
403+
}
404+
405+
void __irq_rtcalarm(void) {
406+
bool isAlarmA = false;
407+
bool isAlarmB = false;
408+
rtc_debug_printf("__irq_rtcalarm() called !\r\n");
409+
rtc_enter_config_mode();
410+
if (RTC_BASE->ISR & (1 << RTC_ISR_ALRAF_BIT)) {
411+
isAlarmA = true;
412+
rtc_debug_printf("AlarmA !\r\n");
413+
RTC_BASE->ISR &= ~(1 << RTC_ISR_ALRAF_BIT);
414+
}
415+
if (RTC_BASE->ISR & (1 << RTC_ISR_ALRBF_BIT)) {
416+
isAlarmB = true;
417+
rtc_debug_printf("AlarmB !\r\n");
418+
RTC_BASE->ISR &= ~(1 << RTC_ISR_ALRBF_BIT);
419+
}
420+
rtc_exit_config_mode();
421+
*bb_perip(&EXTI_BASE->PR, EXTI_RTC_ALARM_BIT) = 1;
422+
if (isAlarmA && handlerAlarmA != NULL) {
423+
handlerAlarmA();
424+
}
425+
if (isAlarmB && handlerAlarmB != NULL) {
426+
handlerAlarmB();
427+
}
428+
}
345429
}
430+

0 commit comments

Comments
 (0)