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-----------------------------------------------------------
|
//--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------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user