Merge remote-tracking branch 'refs/remotes/rogerclarkmelbourne/master'
This commit is contained in:
commit
6f1aab1f2e
|
@ -0,0 +1,8 @@
|
|||
name=RTClock
|
||||
version=1.0
|
||||
author=Various
|
||||
email=
|
||||
sentence=Real Time Clock
|
||||
paragraph=Real Time Clock for STM32F4
|
||||
url=
|
||||
architectures=STM32F4
|
|
@ -0,0 +1,345 @@
|
|||
/******************************************************************************
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 LeafLabs LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
Inspired of the F1xx version adapted for the F4xx, not much F1xx left.
|
||||
author : Martin Ayotte, 2015.
|
||||
*/
|
||||
|
||||
#include "RTClock.h"
|
||||
|
||||
static rtc_dev rtc = {
|
||||
.regs = RTC_BASE,
|
||||
// .handlers = { [NR_RTC_HANDLERS - 1] = 0 },
|
||||
};
|
||||
|
||||
rtc_dev *RTC = &rtc;
|
||||
|
||||
|
||||
RTClock::RTClock() {
|
||||
RTClock(RTCSEL_HSE, 7999, 124);
|
||||
}
|
||||
|
||||
RTClock::RTClock(rtc_clk_src src) {
|
||||
RTClock(src, 0, 0);
|
||||
}
|
||||
|
||||
RTClock::RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler) {
|
||||
uint32 t = 0;
|
||||
RCC_BASE->APB1ENR |= RCC_APB1RSTR_PWRRST;
|
||||
dbg_printf("RCC_BASE->APB1ENR = %08X\r\n", RCC_BASE->APB1ENR);
|
||||
dbg_printf("before bkp_init\r\n");
|
||||
bkp_init(); // turn on peripheral clocks to PWR and BKP and reset the backup domain via RCC registers.
|
||||
// (we reset the backup domain here because we must in order to change the rtc clock source).
|
||||
dbg_printf("before bkp_disable_writes\r\n");
|
||||
bkp_disable_writes();
|
||||
dbg_printf("before bkp_enable_writes\r\n");
|
||||
bkp_enable_writes(); // enable writes to the backup registers and the RTC registers via the DBP bit in the PWR control register
|
||||
dbg_printf("RCC_BASE->CFGR = %08X\r\n", RCC_BASE->CFGR);
|
||||
RCC_BASE->CFGR |= (0x08 << 16); // Set the RTCPRE to HSE / 8.
|
||||
dbg_printf("RCC_BASE->CFGR = %08X\r\n", RCC_BASE->CFGR);
|
||||
|
||||
switch (src) {
|
||||
case RTCSEL_LSE :
|
||||
dbg_printf("Preparing RTC for LSE mode\r\n");
|
||||
if ((RCC_BASE->BDCR & 0x00000300) != 0x0100)
|
||||
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
|
||||
RCC_BASE->BDCR = 0x00008101;
|
||||
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
|
||||
while (!(RCC_BASE->BDCR & 0x00000002)) {
|
||||
if (++t > 1000000) {
|
||||
dbg_printf("RCC_BASE->BDCR.LSERDY Timeout !\r\n");
|
||||
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
|
||||
rtc_enter_config_mode();
|
||||
if (sync_prescaler == 0 && async_prescaler == 0)
|
||||
RTC_BASE->PRER = 255 | (127 << 16);
|
||||
else
|
||||
RTC_BASE->PRER = sync_prescaler | (async_prescaler << 16);
|
||||
break;
|
||||
case RTCSEL_LSI :
|
||||
dbg_printf("Preparing RTC for LSI mode\r\n");
|
||||
if ((RCC_BASE->BDCR & 0x00000300) != 0x0200)
|
||||
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
|
||||
RCC_BASE->BDCR = 0x00008204;
|
||||
RCC_BASE->CSR |= 0x00000001;
|
||||
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
|
||||
while (!(RCC_BASE->CSR & 0x00000002)) {
|
||||
if (++t > 1000000) {
|
||||
dbg_printf("RCC_BASE->CSR.LSIRDY Timeout !\r\n");
|
||||
dbg_printf("RCC_BASE->CSR = %08X\r\n", RCC_BASE->CSR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
|
||||
rtc_enter_config_mode();
|
||||
if (sync_prescaler == 0 && async_prescaler == 0)
|
||||
RTC_BASE->PRER = 249 | (127 << 16);
|
||||
else
|
||||
RTC_BASE->PRER = sync_prescaler | (async_prescaler << 16);
|
||||
break;
|
||||
case RTCSEL_DEFAULT:
|
||||
case RTCSEL_HSE :
|
||||
dbg_printf("Preparing RTC for HSE mode\r\n");
|
||||
if ((RCC_BASE->BDCR & 0x00000300) != 0x0300)
|
||||
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
|
||||
RCC_BASE->BDCR = 0x00008304;
|
||||
dbg_printf("RCC_BASE->BDCR = %08X\r\n", RCC_BASE->BDCR);
|
||||
rtc_enter_config_mode();
|
||||
if (sync_prescaler == 0 && async_prescaler == 0)
|
||||
RTC_BASE->PRER = 7999 | (124 << 16);
|
||||
else
|
||||
RTC_BASE->PRER = sync_prescaler | (async_prescaler << 16);
|
||||
break;
|
||||
case RTCSEL_NONE:
|
||||
dbg_printf("Preparing RTC for NONE mode\r\n");
|
||||
if ((RCC_BASE->BDCR & 0x00000300) != 0x0000)
|
||||
RCC_BASE->BDCR = 0x00010000; // Reset the entire Backup domain
|
||||
RCC_BASE->BDCR = RCC_BDCR_RTCSEL_NONE;
|
||||
//do nothing. Have a look at the clocks to see the diff between NONE and DEFAULT
|
||||
break;
|
||||
}
|
||||
RCC_BASE->CR |= 0x00000040; // Turn to 24hrs mode
|
||||
// dbg_printf("before rtc_clear_sync\r\n");
|
||||
// rtc_clear_sync();
|
||||
// dbg_printf("before rtc_wait_sync\r\n");
|
||||
// rtc_wait_sync();
|
||||
rtc_exit_config_mode();
|
||||
dbg_printf("end of rtc_init\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
RTClock::~RTClock() {
|
||||
//to implement
|
||||
}
|
||||
*/
|
||||
|
||||
void RTClock::setTime (time_t time_stamp) {
|
||||
unsigned char years = 0;
|
||||
unsigned char months = 0;
|
||||
unsigned char monthLength = 0;
|
||||
unsigned char wdays = 0;
|
||||
unsigned char hours = 0;
|
||||
unsigned char mins = 0;
|
||||
unsigned char secs = 0;
|
||||
unsigned long days;
|
||||
|
||||
secs = time_stamp % 60;
|
||||
time_stamp /= 60; // now it is minutes
|
||||
mins = time_stamp % 60;
|
||||
time_stamp /= 60; // now it is hours
|
||||
hours = time_stamp % 24;
|
||||
time_stamp /= 24; // now it is days
|
||||
wdays = ((time_stamp + 4) % 7) + 1; // Sunday is day 1
|
||||
|
||||
while((unsigned)(days += (LEAP_YEAR(years) ? 366 : 365)) <= time_stamp) {
|
||||
years++;
|
||||
}
|
||||
|
||||
days -= LEAP_YEAR(years) ? 366 : 365;
|
||||
time_stamp -= days; // now it is days in this year, starting at 0
|
||||
|
||||
for (months = 0; months < 12; months++) {
|
||||
if (months == 1) { // february
|
||||
if (LEAP_YEAR(years)) {
|
||||
monthLength = 29;
|
||||
} else {
|
||||
monthLength = 28;
|
||||
}
|
||||
} else {
|
||||
monthLength = monthDays[months];
|
||||
}
|
||||
|
||||
if (time_stamp >= monthLength) {
|
||||
time_stamp -= monthLength;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
months++; // jan is month 1
|
||||
days = time_stamp + 1; // day of month
|
||||
rtc_enter_config_mode();
|
||||
RTC_BASE->TR = ((hours / 10) << 20) | ((hours % 10) << 16) | ((mins / 10) << 12) | ((mins % 10) << 8) | ((secs / 10) << 4) | (secs % 10);
|
||||
RTC_BASE->DR = ((years / 10) << 20) | ((years % 10) << 16) | (wdays << 13) | ((months / 10) << 12) | ((months % 10) << 8) | ((days / 10) << 4) | (days % 10);
|
||||
rtc_exit_config_mode();
|
||||
}
|
||||
|
||||
void RTClock::setTime (struct tm* tm_ptr) {
|
||||
rtc_enter_config_mode();
|
||||
RTC_BASE->TR = ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) |
|
||||
((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) |
|
||||
((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10);
|
||||
RTC_BASE->DR = ((tm_ptr->tm_year / 10) << 20) | ((tm_ptr->tm_year % 10) << 16) | (tm_ptr->tm_wday << 13) |
|
||||
((tm_ptr->tm_mon / 10) << 12) | ((tm_ptr->tm_mon % 10) << 8) |
|
||||
((tm_ptr->tm_mday / 10) << 4) | (tm_ptr->tm_mday % 10);
|
||||
rtc_exit_config_mode();
|
||||
}
|
||||
|
||||
time_t RTClock::getTime() {
|
||||
int years = 10 * ((RTC_BASE->DR & 0x00F00000) >> 20) + ((RTC_BASE->DR & 0x000F0000) >> 16);
|
||||
int months = 10 * ((RTC_BASE->DR & 0x00001000) >> 12) + ((RTC_BASE->DR & 0x00000F00) >> 8);
|
||||
int days = 10 * ((RTC_BASE->DR & 0x00000030) >> 4) + (RTC_BASE->DR & 0x000000F);
|
||||
int hours = 10 * ((RTC_BASE->TR & 0x00300000) >> 20) + ((RTC_BASE->TR & 0x000F0000) >> 16);
|
||||
int mins = 10 * ((RTC_BASE->TR & 0x00007000) >> 12) + ((RTC_BASE->TR & 0x0000F00) >> 8);
|
||||
int secs = 10 * ((RTC_BASE->TR & 0x00000070) >> 4) + (RTC_BASE->TR & 0x0000000F);
|
||||
// seconds from 1970 till 1 jan 00:00:00 of the given year
|
||||
time_t t = (years + 30) * SECS_PER_DAY * 365;
|
||||
for (int i = 0; i < years; i++) {
|
||||
if (LEAP_YEAR(i)) {
|
||||
t += SECS_PER_DAY; // add extra days for leap years
|
||||
}
|
||||
}
|
||||
// add days for this year, months start from 1
|
||||
for (int i = 1; i < months; i++) {
|
||||
if ( (i == 2) && LEAP_YEAR(years)) {
|
||||
t += SECS_PER_DAY * 29;
|
||||
} else {
|
||||
t += SECS_PER_DAY * monthDays[i - 1]; //monthDays array starts from 0
|
||||
}
|
||||
}
|
||||
t += (days - 1) * SECS_PER_DAY + hours * SECS_PER_HOUR + mins * SECS_PER_MIN + secs;
|
||||
return t;
|
||||
}
|
||||
|
||||
struct tm* RTClock::getTime(struct tm* tm_ptr) {
|
||||
tm_ptr->tm_year = 10 * ((RTC_BASE->DR & 0x00F00000) >> 20) + ((RTC_BASE->DR & 0x000F0000) >> 16);
|
||||
tm_ptr->tm_mon = 10 * ((RTC_BASE->DR & 0x00001000) >> 12) + ((RTC_BASE->DR & 0x00000F00) >> 8);
|
||||
tm_ptr->tm_mday = 10 * ((RTC_BASE->DR & 0x00000030) >> 4) + (RTC_BASE->DR & 0x000000F);
|
||||
tm_ptr->tm_hour = 10 * ((RTC_BASE->TR & 0x00300000) >> 20) + ((RTC_BASE->TR & 0x000F0000) >> 16);
|
||||
tm_ptr->tm_min = 10 * ((RTC_BASE->TR & 0x00007000) >> 12) + ((RTC_BASE->TR & 0x0000F00) >> 8);
|
||||
tm_ptr->tm_sec = 10 * ((RTC_BASE->TR & 0x00000070) >> 4) + (RTC_BASE->TR & 0x0000000F);
|
||||
return tm_ptr;
|
||||
}
|
||||
|
||||
void RTClock::createAlarm(voidFuncPtr function, time_t alarm_time_t) {
|
||||
// rtc_set_alarm(alarm_time_t); //must be int... for standardization sake.
|
||||
// rtc_attach_interrupt(RTC_ALARM_SPECIFIC_INTERRUPT, function);
|
||||
}
|
||||
|
||||
void RTClock::createAlarm(voidFuncPtr function, tm* alarm_tm) {
|
||||
// time_t alarm = mktime(alarm_tm);//convert to time_t
|
||||
// createAlarm(function, alarm);
|
||||
}
|
||||
|
||||
void RTClock::attachSecondsInterrupt(voidFuncPtr function) {
|
||||
// rtc_attach_interrupt(RTC_SECONDS_INTERRUPT, function);
|
||||
}
|
||||
|
||||
void RTClock::detachSecondsInterrupt() {
|
||||
// rtc_detach_interrupt(RTC_SECONDS_INTERRUPT);
|
||||
}
|
||||
|
||||
void RTClock::setAlarmATime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) {
|
||||
rtc_enter_config_mode();
|
||||
unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) |
|
||||
((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) |
|
||||
((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) |
|
||||
((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10);
|
||||
if (!date_match) bits |= (1 << 31);
|
||||
if (!hours_match) bits |= (1 << 23);
|
||||
if (!mins_match) bits |= (1 << 15);
|
||||
if (!secs_match) bits |= (1 << 7);
|
||||
RTC_BASE->ALRMAR = bits;
|
||||
RTC_BASE->CR |= (1 << RTC_CR_ALRAIE_BIT); // turn on ALRAIE
|
||||
rtc_exit_config_mode();
|
||||
}
|
||||
|
||||
|
||||
void RTClock::setAlarmATime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) {
|
||||
struct tm* tm_ptr = gmtime(&alarm_time);
|
||||
setAlarmATime(tm_ptr, hours_match, mins_match, secs_match, date_match);
|
||||
}
|
||||
|
||||
|
||||
void RTClock::turnOffAlarmA() {
|
||||
rtc_enter_config_mode();
|
||||
RTC_BASE->CR &= ~(1 << RTC_CR_ALRAIE_BIT); // turn off ALRAIE
|
||||
rtc_exit_config_mode();
|
||||
}
|
||||
|
||||
|
||||
void RTClock::setAlarmBTime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) {
|
||||
rtc_enter_config_mode();
|
||||
unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) |
|
||||
((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) |
|
||||
((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) |
|
||||
((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10);
|
||||
if (!date_match) bits |= (1 << 31);
|
||||
if (!hours_match) bits |= (1 << 23);
|
||||
if (!mins_match) bits |= (1 << 15);
|
||||
if (!secs_match) bits |= (1 << 7);
|
||||
RTC_BASE->ALRMBR = bits;
|
||||
RTC_BASE->CR |= (1 << RTC_CR_ALRBIE_BIT); // turn on ALRBIE
|
||||
rtc_exit_config_mode();
|
||||
}
|
||||
|
||||
|
||||
void RTClock::setAlarmBTime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) {
|
||||
struct tm* tm_ptr = gmtime(&alarm_time);
|
||||
setAlarmBTime(tm_ptr, hours_match, mins_match, secs_match, date_match);
|
||||
}
|
||||
|
||||
|
||||
void RTClock::turnOffAlarmB() {
|
||||
rtc_enter_config_mode();
|
||||
RTC_BASE->CR &= ~(1 << RTC_CR_ALRBIE_BIT); // turn off ALRBIE
|
||||
rtc_exit_config_mode();
|
||||
}
|
||||
|
||||
|
||||
void RTClock::setPeriodicWakeup(uint16 period) {
|
||||
rtc_enter_config_mode();
|
||||
dbg_printf("before setting RTC_BASE->WUTR\r\n");
|
||||
RTC_BASE->WUTR = period; // set the period
|
||||
dbg_printf("before setting RTC_BASE->CR.WUCKSEL\r\n");
|
||||
RTC_BASE->CR &= ~(3); RTC_BASE->CR |= 4; // Set the WUCKSEL to 1Hz (0x00000004)
|
||||
if (period == 0)
|
||||
RTC_BASE->CR &= ~(1 << RTC_CR_WUTIE_BIT); // if period is 0, turn off periodic wakeup interrupt.
|
||||
else {
|
||||
dbg_printf("before turn ON RTC_BASE->CR.WUTIE\r\n");
|
||||
RTC_BASE->CR |= (1 << RTC_CR_WUTIE_BIT); // turn on WUTIE
|
||||
}
|
||||
dbg_printf("RCC_BASE->CR = %08X\r\n", RCC_BASE->CR);
|
||||
rtc_exit_config_mode();
|
||||
rtc_enable_wakeup_event();
|
||||
nvic_irq_enable(NVIC_RTC);
|
||||
nvic_irq_enable(NVIC_RTCALARM);
|
||||
dbg_printf("setPeriodicWakeup() done !\r\n");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void __irq_rtc(void) {
|
||||
dbg_printf("__irq_rtc() called !\r\n");
|
||||
*bb_perip(&EXTI_BASE->PR, EXTI_RTC_WAKEUP_BIT) = 1;
|
||||
}
|
||||
void __irq_rtcalarm(void) {
|
||||
dbg_printf("__irq_rtcalarm() called !\r\n");
|
||||
*bb_perip(&EXTI_BASE->PR, EXTI_RTC_ALARM_BIT) = 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
#include <libmaple/rcc.h>
|
||||
#include <libmaple/bitband.h>
|
||||
#include <libmaple/pwr.h>
|
||||
#include <libmaple/bkp.h>
|
||||
#include <libmaple/nvic.h>
|
||||
#include <libmaple/exti.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#ifndef _RTCLOCK_H_
|
||||
#define _RTCLOCK_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern void dbg_printf(const char *fmt, ... );
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define SECS_PER_MIN (60UL)
|
||||
#define SECS_PER_HOUR (3600UL)
|
||||
#define SECS_PER_DAY (SECS_PER_HOUR * 24UL)
|
||||
#define DAYS_PER_WEEK (7UL)
|
||||
#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK)
|
||||
#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL)
|
||||
#define SECS_YR_2000 (946684800UL) // the time at the start of y2k
|
||||
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
|
||||
|
||||
static const unsigned char monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0
|
||||
|
||||
|
||||
typedef struct rtc_reg_map {
|
||||
__io uint32 TR; /**< Time register */
|
||||
__io uint32 DR; /**< Date register */
|
||||
__io uint32 CR; /**< Control register */
|
||||
__io uint32 ISR; /**< Init Status register */
|
||||
__io uint32 PRER; /**< Prescaler register */
|
||||
__io uint32 WUTR; /**< Wakeup Timer register */
|
||||
__io uint32 CALIBR; /**< Calibration register */
|
||||
__io uint32 ALRMAR; /**< Alarm A register */
|
||||
__io uint32 ALRMBR; /**< Alarm B register */
|
||||
__io uint32 WPR; /**< Write Protect register */
|
||||
__io uint32 SSR; /**< SubSecond register */
|
||||
__io uint32 SHIFTR; /**< Shift Control register */
|
||||
__io uint32 TSTR; /**< TimeStamp Time register */
|
||||
__io uint32 TSDR; /**< TimeStamp Date register */
|
||||
__io uint32 TSSSR; /**< TimeStamp SubSecond register */
|
||||
__io uint32 CALR; /**< Calibration register */
|
||||
__io uint32 TAFCR; /**< Tamper and Alternate Function Config register */
|
||||
__io uint32 ALRMASSR; /**< Alarm A subSecond register */
|
||||
__io uint32 ALRMBSSR; /**< Alarm B subSecond register */
|
||||
__io uint32 BKPxR; /**< Backup registers */
|
||||
} rtc_reg_map;
|
||||
|
||||
/** RTC register map base pointer */
|
||||
#define RTC_BASE ((struct rtc_reg_map*)0x40002800)
|
||||
|
||||
/** rtc device type */
|
||||
typedef struct rtc_dev {
|
||||
rtc_reg_map *regs; /**< Register map */
|
||||
voidFuncPtr handlers[]; /**< User IRQ handlers */
|
||||
} rtc_dev;
|
||||
|
||||
extern rtc_dev *RTC;
|
||||
|
||||
#define NR_RTC_HANDLERS 4
|
||||
|
||||
#define EXTI_RTC_ALARM_BIT 17
|
||||
#define EXTI_RTC_WAKEUP_BIT 22
|
||||
#define EXTI_RTC_TAMPSTAMP_BIT 21
|
||||
|
||||
|
||||
/**
|
||||
* @brief RTC clock source.
|
||||
*
|
||||
*/
|
||||
typedef enum rtc_clk_src {
|
||||
RTCSEL_DEFAULT = 0,
|
||||
RTCSEL_NONE = 0x10,
|
||||
RTCSEL_LSE = 0x11,
|
||||
RTCSEL_LSI = 0x12,
|
||||
RTCSEL_HSE = 0x13,
|
||||
} rtc_clk_src;
|
||||
|
||||
|
||||
/* Control Register */
|
||||
#define RTC_CR_TSIE_BIT 15
|
||||
#define RTC_CR_WUTIE_BIT 14
|
||||
#define RTC_CR_ALRBIE_BIT 13
|
||||
#define RTC_CR_ALRAIE_BIT 12
|
||||
|
||||
/* Initialization and Status Register */
|
||||
#define RTC_ISR_INIT_BIT 7
|
||||
#define RTC_ISR_INITF_BIT 6
|
||||
#define RTC_ISR_RSF_BIT 5
|
||||
#define RTC_ISR_INITS_BIT 4
|
||||
|
||||
|
||||
|
||||
class RTClock {
|
||||
public:
|
||||
RTClock();
|
||||
RTClock(rtc_clk_src src );
|
||||
RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler);
|
||||
//~RTClock(); //to implement
|
||||
|
||||
void setTime (time_t time_stamp);
|
||||
void setTime (struct tm * tm_ptr);
|
||||
|
||||
struct tm* getTime(struct tm* tm_ptr);
|
||||
time_t getTime();
|
||||
|
||||
void createAlarm(voidFuncPtr function, time_t alarm_time_t);
|
||||
void createAlarm(voidFuncPtr function, struct tm* alarm_tm);
|
||||
|
||||
void attachSecondsInterrupt(voidFuncPtr function);
|
||||
void detachSecondsInterrupt();
|
||||
|
||||
void setAlarmATime (tm * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false);
|
||||
void setAlarmATime (time_t alarm_time, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false);
|
||||
void turnOffAlarmA();
|
||||
void setAlarmBTime (tm * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false);
|
||||
void setAlarmBTime (time_t alarm_time, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false);
|
||||
void turnOffAlarmB();
|
||||
|
||||
void setPeriodicWakeup(uint16 period);
|
||||
//private:
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clear the register synchronized flag. The flag is then set by hardware after a write to PRL/DIV or CNT.
|
||||
*/
|
||||
static inline void rtc_clear_sync() {
|
||||
*bb_perip(&(RTC->regs)->ISR, RTC_ISR_RSF_BIT) = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check (wait if necessary) to see RTC registers are synchronized.
|
||||
*/
|
||||
static inline void rtc_wait_sync() {
|
||||
uint32 t = 0;
|
||||
dbg_printf("entering rtc_wait_sync\r\n");
|
||||
while (*bb_perip(&(RTC->regs)->ISR, RTC_ISR_RSF_BIT) == 0) {
|
||||
if (++t > 1000000) {
|
||||
dbg_printf("RTC_BASE->ISR.RSF Timeout !\r\n");
|
||||
dbg_printf("RTC_BASE->ISR = %08X\r\n", RTC_BASE->ISR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dbg_printf("finished rtc_wait_sync\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enter configuration mode.
|
||||
*/
|
||||
static inline void rtc_enter_config_mode() {
|
||||
uint32 t = 0;
|
||||
// Unlock Write Protect
|
||||
RTC_BASE->WPR = 0xCA;
|
||||
RTC_BASE->WPR = 0x53;
|
||||
*bb_perip(&(RTC->regs)->ISR, RTC_ISR_INIT_BIT) = 1;
|
||||
dbg_printf("RTC_BASE->ISR = %08X\r\n", RTC_BASE->ISR);
|
||||
while (!(RTC_BASE->ISR & 0x00000040)) {
|
||||
if (++t > 1000000) {
|
||||
dbg_printf("RTC_BASE->ISR.INITF Timeout !\r\n");
|
||||
dbg_printf("RTC_BASE->ISR = %08X\r\n", RTC_BASE->ISR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dbg_printf("rtc_enter_config_mode done !\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exit configuration mode.
|
||||
*/
|
||||
static inline void rtc_exit_config_mode() {
|
||||
*bb_perip(&(RTC->regs)->ISR, RTC_ISR_INIT_BIT) = 0;
|
||||
dbg_printf("rtc_exit_config_mode done !\r\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable an RTC alarm event. Enabling this event allows waking up from deep sleep via WFE.
|
||||
* @see rtc_interrupt_id
|
||||
*/
|
||||
static inline void rtc_enable_alarm_event() {
|
||||
*bb_perip(&EXTI_BASE->IMR, EXTI_RTC_ALARM_BIT) = 1;
|
||||
*bb_perip(&EXTI_BASE->EMR, EXTI_RTC_ALARM_BIT) = 1;
|
||||
*bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_ALARM_BIT) = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the RTC alarm event.
|
||||
* @see rtc_interrupt_id
|
||||
*/
|
||||
static inline void rtc_disable_alarm_event() {
|
||||
*bb_perip(&EXTI_BASE->EMR, EXTI_RTC_ALARM_BIT) = 0;
|
||||
*bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_ALARM_BIT) = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable an RTC Wakeup event.
|
||||
* @see rtc_interrupt_id
|
||||
*/
|
||||
static inline void rtc_enable_wakeup_event() {
|
||||
*bb_perip(&EXTI_BASE->IMR, EXTI_RTC_WAKEUP_BIT) = 1;
|
||||
*bb_perip(&EXTI_BASE->EMR, EXTI_RTC_WAKEUP_BIT) = 1;
|
||||
*bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_WAKEUP_BIT) = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the RTC alarm event.
|
||||
* @see rtc_interrupt_id
|
||||
*/
|
||||
static inline void rtc_disable_wakeup_event() {
|
||||
*bb_perip(&EXTI_BASE->EMR, EXTI_RTC_WAKEUP_BIT) = 0;
|
||||
*bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_WAKEUP_BIT) = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // _RTCLOCK_H_
|
||||
|
Loading…
Reference in New Issue