Implement rtc's LSI calibration

This commit is contained in:
Steins7 2024-10-21 17:05:26 +02:00
parent ae9cdc3582
commit 05e3397d95
2 changed files with 64 additions and 5 deletions

View File

@ -18,12 +18,14 @@
//--local definitions----------------------------------------------------------- //--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------------------------------------------------------------- //--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 RCC* rcc_regs = (struct RCC*)RCC_BASE_ADDRESS;
static volatile struct RTC* rtc_regs = (struct RTC*)RTC_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; 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) void bkp_reset(void)
{ {
rcc_regs->BDCR.BDRST = 1; 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; 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------------------------------------------------------------- //--local functions-------------------------------------------------------------
/** /**
* Computes the prescaler value based on the clock source and the required * Computes the prescaler value based on the clock source and the required
* period * 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; uint32_t prescaler;
@ -134,7 +178,10 @@ uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src)
prescaler = 32768; //32.768kHz prescaler = 32768; //32.768kHz
break; break;
case BKP_RTC_CLOCK_SRC_LSI: case BKP_RTC_CLOCK_SRC_LSI:
prescaler = 40000; //40khz prescaler = bkp_read_data(BKP_DATA_LSI_CALIB);
if (prescaler == 0) {
prescaler = 40000; //40khz
}
break; break;
case BKP_RTC_CLOCK_SRC_HSE: case BKP_RTC_CLOCK_SRC_HSE:
prescaler = 62500; //8Mhz / 128 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; 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------------------------------------------------------------------------ //--ISRs------------------------------------------------------------------------

View File

@ -14,6 +14,7 @@
//--includes-------------------------------------------------------------------- //--includes--------------------------------------------------------------------
#include "stdint.h" #include "stdint.h"
#include "tim.h"
//--type definitions------------------------------------------------------------ //--type definitions------------------------------------------------------------
@ -98,6 +99,7 @@ void bkp_set_rtc_alam(uint32_t offset);
* Returns the current counter value of the RTC * Returns the current counter value of the RTC
*/ */
uint32_t bkp_read_rtc(void); uint32_t bkp_read_rtc(void);
uint32_t bkp_read_rtc_div(void);
/** /**
* Resets the entire backup domain, composed of everything configured through * 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); void bkp_write_data(enum BkpData data_index, uint16_t data);
uint16_t bkp_read_data(enum BkpData data_index); uint16_t bkp_read_data(enum BkpData data_index);
void bkp_calibrate_lsi(enum TimPeriph timer);
//unimplemented functions //unimplemented functions
void bkp_configure_tamper(); void bkp_configure_tamper();
void bkp_calibrate_lsi(void);
void bkp_configure_lse(bool enable); void bkp_configure_lse(bool enable);