Implement rtc's LSI calibration
This commit is contained in:
parent
ae9cdc3582
commit
05e3397d95
64
drv/bkp.c
64
drv/bkp.c
@ -18,12 +18,14 @@
|
||||
|
||||
//--local definitions-----------------------------------------------------------
|
||||
|
||||
uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src);
|
||||
static uint32_t compute_prescaler(uint32_t period_ms,
|
||||
enum BkpRtcClockSrc clock_src);
|
||||
static void lsi_calib_callback(enum TimIRQSource src);
|
||||
|
||||
|
||||
//--local variables-------------------------------------------------------------
|
||||
|
||||
//static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS;
|
||||
static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS;
|
||||
static volatile struct RCC* rcc_regs = (struct RCC*)RCC_BASE_ADDRESS;
|
||||
static volatile struct RTC* rtc_regs = (struct RTC*)RTC_BASE_ADDRESS;
|
||||
|
||||
@ -103,6 +105,17 @@ uint32_t bkp_read_rtc(void)
|
||||
return time;
|
||||
}
|
||||
|
||||
uint32_t bkp_read_rtc_div(void)
|
||||
{
|
||||
//wait for core registers to be synchronized, immediate most of the time
|
||||
while (rtc_regs->CRL.RSF != 1) {}
|
||||
|
||||
uint32_t div = rtc_regs->DIVH.RTC_DIV << 16;
|
||||
div |= rtc_regs->DIVL.RTC_DIV << 0;
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
void bkp_reset(void)
|
||||
{
|
||||
rcc_regs->BDCR.BDRST = 1;
|
||||
@ -119,13 +132,44 @@ uint16_t bkp_read_data(enum BkpData data_index)
|
||||
return bkp_regs->DR[data_index].D;
|
||||
}
|
||||
|
||||
void bkp_calibrate_lsi(enum TimPeriph timer)
|
||||
{
|
||||
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
|
||||
|
||||
//do not calibrate if already calibrated
|
||||
if (bkp_read_data(BKP_DATA_LSI_CALIB) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//configure timer to count 1s exactly
|
||||
struct RccClocks clocks;
|
||||
rcc_get_clocks(&clocks);
|
||||
|
||||
tim_set_prescaler(timer, (clocks.tim_freq / 10000)); //10000 to avoid
|
||||
//prescaler overflow
|
||||
tim_set_auto_reload(timer, 10000);
|
||||
tim_configure_master(timer, TIM_CONFIG_ONE_SHOT
|
||||
| TIM_CONFIG_DIR_UP, TIM_MASTER_CONFIG_MODE_RESET,
|
||||
lsi_calib_callback);
|
||||
|
||||
//configure rtc to tick every 2s so the div value isn't reset during the
|
||||
//timer's delay if the clock is too fast
|
||||
bkp_configure_rtc(2000, BKP_RTC_CLOCK_SRC_LSI, BKP_RTC_IRQ_NONE, nullptr);
|
||||
tim_start(timer);
|
||||
|
||||
while (bkp_read_data(BKP_DATA_LSI_CALIB) == 0) {}
|
||||
|
||||
//TODO reset timer
|
||||
}
|
||||
|
||||
//--local functions-------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Computes the prescaler value based on the clock source and the required
|
||||
* period
|
||||
*/
|
||||
uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src)
|
||||
static uint32_t compute_prescaler(uint32_t period_ms,
|
||||
enum BkpRtcClockSrc clock_src)
|
||||
{
|
||||
uint32_t prescaler;
|
||||
|
||||
@ -134,7 +178,10 @@ uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src)
|
||||
prescaler = 32768; //32.768kHz
|
||||
break;
|
||||
case BKP_RTC_CLOCK_SRC_LSI:
|
||||
prescaler = 40000; //40khz
|
||||
prescaler = bkp_read_data(BKP_DATA_LSI_CALIB);
|
||||
if (prescaler == 0) {
|
||||
prescaler = 40000; //40khz
|
||||
}
|
||||
break;
|
||||
case BKP_RTC_CLOCK_SRC_HSE:
|
||||
prescaler = 62500; //8Mhz / 128
|
||||
@ -146,6 +193,15 @@ uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src)
|
||||
return (period_ms * prescaler) / 1000;
|
||||
}
|
||||
|
||||
static void lsi_calib_callback(enum TimIRQSource src)
|
||||
{
|
||||
if (src == TIM_IRQ_SOURCE_UPDATE) {
|
||||
//div is decremented from 40kHz * programmed delay (in s)
|
||||
uint32_t lsi_freq = (40000 * 2) - bkp_read_rtc_div();
|
||||
bkp_write_data(BKP_DATA_LSI_CALIB, lsi_freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--ISRs------------------------------------------------------------------------
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
//--includes--------------------------------------------------------------------
|
||||
|
||||
#include "stdint.h"
|
||||
#include "tim.h"
|
||||
|
||||
|
||||
//--type definitions------------------------------------------------------------
|
||||
@ -98,6 +99,7 @@ void bkp_set_rtc_alam(uint32_t offset);
|
||||
* Returns the current counter value of the RTC
|
||||
*/
|
||||
uint32_t bkp_read_rtc(void);
|
||||
uint32_t bkp_read_rtc_div(void);
|
||||
|
||||
/**
|
||||
* Resets the entire backup domain, composed of everything configured through
|
||||
@ -108,9 +110,10 @@ void bkp_reset(void);
|
||||
void bkp_write_data(enum BkpData data_index, uint16_t data);
|
||||
uint16_t bkp_read_data(enum BkpData data_index);
|
||||
|
||||
void bkp_calibrate_lsi(enum TimPeriph timer);
|
||||
|
||||
//unimplemented functions
|
||||
void bkp_configure_tamper();
|
||||
void bkp_calibrate_lsi(void);
|
||||
void bkp_configure_lse(bool enable);
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user