diff --git a/drv/rcc.c b/drv/rcc.c index c229c45..502769f 100644 --- a/drv/rcc.c +++ b/drv/rcc.c @@ -72,7 +72,7 @@ void rcc_configure_lsi(bool enable) void rcc_configure_rtc(bool enable, enum RccRtcClockSrc clock_src) { - regs->BDCR.RTCSEL = clock_src; + regs->BDCR.RTCSEL = 0x2; regs->BDCR.RTCEN = enable; } diff --git a/drv/rtc.c b/drv/rtc.c new file mode 100644 index 0000000..fe5ddd1 --- /dev/null +++ b/drv/rtc.c @@ -0,0 +1,139 @@ +//--includes-------------------------------------------------------------------- + +#include "rtc.h" +#include "rtc_regs.h" +#include "rcc.h" +#include "pwr.h" +#include "nvic.h" + + +//--local definitions----------------------------------------------------------- + +//--local variables------------------------------------------------------------- + +static volatile struct RTC* regs = (struct RTC*)RTC_BASE_ADDRESS; +static RtcCallback rtc_callback; + + +//--public functions------------------------------------------------------------ + +void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src, + enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback) +{ + pwr_configure_bkp_write(true); + //start RTC + rcc_configure_rtc(true, clock_src + 1); + + //rtc_reset(); + rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); + //rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE); + + //compute prescaler + uint32_t prescaler = 0; + switch (clock_src) { + case RTC_CLOCK_SRC_LSE: + prescaler = 32768000; //32.768kHz + break; + case RTC_CLOCK_SRC_LSI: + prescaler = 40000000; //40khz + break; + case RTC_CLOCK_SRC_HSE: + prescaler = 62500000; //8Mhz / 128 + break; + default: + return; + } + prescaler /= period_ms; + + //wait for registers to synchronize + regs->CRL.RSF = 0; + while (regs->CRL.RSF != 1) {} + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + //enable core configuration + regs->CRL.CNF = 1; + + //configure core registers + regs->PRLH.PRL = prescaler >> 16; + regs->PRLL.PRL = prescaler; + regs->ALRH.RTC_ALR = alarm_tick >> 16; + regs->ALRL.RTC_ALR = alarm_tick; + + //apply irq config + regs->CRH.word |= irq_mask & 0x7; + + //disable/apply core configuration + regs->CRL.CNF = 0; + + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + pwr_configure_bkp_write(false); + + if (callback) { + rtc_callback = callback; + nvic_enable(NVIC_IRQ_RTC); + } +} + +void rtc_reset(void) +{ + nvic_disable(NVIC_IRQ_RTC); + pwr_configure_bkp_write(true); + rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); + + //wait for registers to synchronize + regs->CRL.RSF = 0; + //while (regs->CRL.RSF != 1) {} + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + //clear config registers + regs->CRH.word &= ~0x7; + regs->CRL.word &= ~0xf; + + //enable core configuration + regs->CRL.CNF = 1; + + //reset core registers. DIV register can be ignore since it is reset on any + //changes of the other 2 + regs->PRLH.PRL = 0x0; + regs->PRLL.PRL = 0x8000; + regs->CNTH.RTC_CNT = 0x0; + regs->CNTL.RTC_CNT = 0x0; + + //disable/apply core configuration + regs->CRL.CNF = 0; + + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE); + rcc_disable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); + pwr_configure_bkp_write(false); +} + +uint32_t stk_read_s(void) +{ + //wait for core registers to be synchronized, immediate most of the time + while (regs->CRL.RSF != 1) {} + + uint32_t time = regs->CNTH.RTC_CNT << 16; + time |= regs->CNTL.RTC_CNT << 0; + + return time; +} + + +//--local functions------------------------------------------------------------- + +void hdr_rtc(void) +{ + nvic_clear_pending(NVIC_IRQ_RTC); + + //copy and clear and pass along src flags + enum RtcIrq src = regs->CRL.word & 0x7; + regs->CRL.word &= ~(0x7); + rtc_callback(src); +} diff --git a/drv/rtc.h b/drv/rtc.h new file mode 100644 index 0000000..ff161f4 --- /dev/null +++ b/drv/rtc.h @@ -0,0 +1,43 @@ +/** @file rtc.h + * Module handling the Real-Time Clock (RTC). + * + */ + +#ifndef _RTC_H_ +#define _RTC_H_ + +//--includes-------------------------------------------------------------------- + +#include "stdint.h" + + +//--type definitions------------------------------------------------------------ + +enum RtcClockSrc { + RTC_CLOCK_SRC_LSE = 0x0, + RTC_CLOCK_SRC_LSI = 0x1, + RTC_CLOCK_SRC_HSE = 0x2, +}; + +enum RtcIrq { + RTC_IRQ_NONE = 0, + RTC_IRQ_SECOND = 0x1 << 0, + RTC_IRQ_ALARM = 0x1 << 1, + RTC_IRQ_OVERFLOW = 0x1 << 2, +}; + +typedef void (*RtcCallback)(enum RtcIrq src); + + +//--functions------------------------------------------------------------------- + +void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src, + enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback); + +void rtc_reset(void); + +uint32_t stk_read_s(void); + + +#endif //_RTC_H_ +