stm32f1xx_HBL/drv/rtc.c
Steins7 004b0b9a76 Implement RTC module's basic functionnalities
FUnctions need a cleanup and some details need be ironned, like the
clock management since the whole backup domain must be reset to
configure them
2024-07-27 16:39:49 +02:00

140 lines
3.2 KiB
C

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