//--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); }