Arduino_STM32/STM32F1XX/libraries/RTClock/utility/rtc_util.h

261 lines
7.3 KiB
C

/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 Visible Assets Inc.
*
* 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.
*****************************************************************************/
/**
* @file rtc.h
* @author Rod Gilchrist <rod@visibleassets.com>
* @brief Real Time Clock interface.
*
*/
#ifndef _RTC_UTIL_H
#define _RTC_UTIL_H
#include <libmaple\libmaple.h>
#include <libmaple\rcc.h>
#include <libmaple\nvic.h>
#include <libmaple\bitband.h>
#include <libmaple\pwr.h>
#include <libmaple\bkp.h>
#include <libmaple\exti.h>
#define EXTI_RTC_ALARM_BIT 17 // the extra exti interrupts (16,17,18,19) should be defined in exti.h (BUG)
//#define RCC_BDCR_RTCSEL_LSI (0x2 << 8)
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rtc_reg_map {
__io uint32 CRH; /**< Control register high */
__io uint32 CRL; /**< Control register high */
__io uint32 PRLH; /**< Prescaler load register high */
__io uint32 PRLL; /**< Prescaler load register low */
__io uint32 DIVH; /**< Prescaler divider register high */
__io uint32 DIVL; /**< Prescaler divider register low */
__io uint32 CNTH; /**< Counter register high */
__io uint32 CNTL; /**< Counter register low */
__io uint32 ALRH; /**< Alarm register high */
__io uint32 ALRL; /**< Alarm register low */
} 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;
/*
* Register bit definitions
*/
/* Control register high (CRH) */
#define RTC_CRH_OWIE_BIT 2
#define RTC_CRH_ALRIE_BIT 1
#define RTC_CRH_SECIE_BIT 0
#define RTC_CRH_OWIE BIT(RTC_CRH_OWIE_BIT)
#define RTC_CRH_ALRIE BIT(RTC_CRH_ALRIE_BIT)
#define RTC_CRH_SECIE BIT(RTC_CRH_SECIE_BIT)
/* Control register low (CRL) */
#define RTC_CRL_RTOFF_BIT 5
#define RTC_CRL_CNF_BIT 4
#define RTC_CRL_RSF_BIT 3
#define RTC_CRL_OWF_BIT 2
#define RTC_CRL_ALRF_BIT 1
#define RTC_CRL_SECF_BIT 0
#define RTC_CRL_RTOFF BIT(RTC_CRL_RTOFF_BIT)
#define RTC_CRL_CNF BIT(RTC_CRL_CNF_BIT)
#define RTC_CRL_RSF BIT(RTC_CRL_RSF_BIT)
#define RTC_CRL_OWF BIT(RTC_CRL_OWF_BIT)
#define RTC_CRL_ALRF BIT(RTC_CRL_ALRF_BIT)
#define RTC_CRL_SECF BIT(RTC_CRL_SECF_BIT)
/**
* @brief RTC interrupt number.
*
*/
typedef enum rtc_interrupt_id {
RTC_SECONDS_INTERRUPT = 0, /**< Counter seconds interrupt */
RTC_ALARM_GLOBAL_INTERRUPT = 1, /**< RTC alarm global interrupt (i.e. __irq_rtc()) */
RTC_OVERFLOW_INTERRUPT = 2, /**< Counter overflow interrupt */
RTC_ALARM_SPECIFIC_INTERRUPT = 3 /**< RTC alarm specific interrupt (i.e. __irq_rtcalarm(), wake up from halt/sleep) */
} rtc_interrupt_id;
void rtc_attach_interrupt( uint8 interrupt,
voidFuncPtr handler);
void rtc_detach_interrupt( uint8 interrupt);
/**
* @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;
void rtc_init(rtc_clk_src src);
void rtc_attach_interrupt(uint8 interrupt, voidFuncPtr handler);
void rtc_detach_interrupt(uint8 interrupt);
uint32 rtc_get_count();
void rtc_set_count(uint32 value);
void rtc_set_prescaler_load(uint32 value);
uint32 rtc_get_divider();
void rtc_set_alarm(uint32 value);
/**
* @brief Check (wait if necessary) to see the previous write operation has completed.
*/
static inline void rtc_wait_finished() {
while (*bb_perip(&(RTC->regs)->CRL, RTC_CRL_RTOFF_BIT) == 0);
}
/**
* @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() {
rtc_wait_finished();
*bb_perip(&(RTC->regs)->CRL, RTC_CRL_RSF_BIT) = 0;
}
/**
* @brief Check (wait if necessary) to see RTC registers are synchronized.
*/
static inline void rtc_wait_sync() {
while (*bb_perip(&(RTC->regs)->CRL, RTC_CRL_RSF_BIT) == 0);
}
/**
* @brief Enter configuration mode.
*/
static inline void rtc_enter_config_mode() {
rtc_wait_finished();
*bb_perip(&(RTC->regs)->CRL, RTC_CRL_CNF_BIT) = 1;
}
/**
* @brief Exit configuration mode.
*/
static inline void rtc_exit_config_mode() {
rtc_wait_finished();
*bb_perip(&(RTC->regs)->CRL, RTC_CRL_CNF_BIT) = 0;
}
/**
* @brief Enable an RTC interrupt.
* @param interrupt Interrupt number to enable; this may be any rtc_interrupt_id.
* @see rtc_interrupt_id
*/
static inline void rtc_enable_irq(uint8 interrupt) {
rtc_wait_finished();
if (interrupt == RTC_ALARM_SPECIFIC_INTERRUPT) { // Enabling this interrupt allows waking up from deep sleep via WFI.
*bb_perip(&EXTI_BASE->IMR, EXTI_RTC_ALARM_BIT) = 1;
*bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_ALARM_BIT) = 1;
}
else *bb_perip(&(RTC->regs)->CRH, interrupt) = 1;
}
/**
* @brief Disable an RTC interrupt.
* @param interrupt Interrupt number to disable; this may be any rtc_interrupt_id value.
* @see rtc_interrupt_id
*/
static inline void rtc_disable_irq(uint8 interrupt) {
rtc_wait_finished();
if (interrupt == RTC_ALARM_SPECIFIC_INTERRUPT) {
*bb_perip(&EXTI_BASE->IMR, EXTI_RTC_ALARM_BIT) = 0;
*bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_ALARM_BIT) = 0;
}
else *bb_perip(&(RTC->regs)->CRH, interrupt) = 0;
}
/**
* @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->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 Test for global interrupt second type.
* @see rtc_interrupt_id
*/
static inline int rtc_is_second() {
return *bb_perip(&(RTC->regs)->CRL, RTC_CRL_SECF_BIT);
}
/**
* @brief Test for global interrupt alarm type.
* @see rtc_interrupt_id
*/
static inline int rtc_is_alarm() {
return *bb_perip(&(RTC->regs)->CRL, RTC_CRL_ALRF_BIT);
}
/**
* @brief Test for global interrupt overflow type.
* @see rtc_interrupt_id
*/
static inline int rtc_is_overflow() {
return *bb_perip(&(RTC->regs)->CRL, RTC_CRL_OWF_BIT);
}
#ifdef __cplusplus
}
#endif
#endif /* _RTC_H */