soc: implement XTAL frequency detection

ROM code already implements XTAL frequency detection, but it uses the 8M
clock before the clock tuning parameters are initialized. With the
zero clock tuning parameter, 8M clock has significant frequency deviation
at high temperatures, which can lead to erroneous detection of 40 MHz
crystal as a 26 MHz one.

This change adds XTAL frequency detection code to rtc_clk_init routine,
and detection is performed after the 8M clock tuning parameter as been
initialized.
This commit is contained in:
Ivan Grokhotkov
2017-04-24 15:29:30 +08:00
parent 36ed7f507e
commit 3323f31cfb
5 changed files with 57 additions and 36 deletions
+14 -7
View File
@@ -31,9 +31,8 @@
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
* enabled using TIMG_RTC_CALI_START bit.
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
/* Enable requested clock (150k clock is always on) */
if (cal_clk == RTC_CAL_32K_XTAL) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
@@ -53,7 +52,7 @@ uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
expected_freq = 32768; /* standard 32k XTAL */
} else if (cal_clk == RTC_CAL_8MD256 ||
(cal_clk == RTC_CAL_RTC_MUX && slow_freq == RTC_SLOW_FREQ_8MD256)) {
expected_freq = 8 * MHZ / 256;
expected_freq = RTC_FAST_CLK_FREQ_APPROX / 256;
} else {
expected_freq = 150000; /* 150k internal oscillator */
}
@@ -69,7 +68,8 @@ uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
/* Wait for calibration to finish up to another us_time_estimate */
int timeout_us = us_time_estimate;
while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY) &&
timeout_us-- > 0) {
timeout_us > 0) {
timeout_us--;
ets_delay_us(1);
}
if (cal_clk == RTC_CAL_32K_XTAL) {
@@ -84,9 +84,16 @@ uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
uint64_t xtal_cycles = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles;
uint64_t period_64 = (xtal_cycles << RTC_CLK_CAL_FRACT) / divider;
uint32_t period = (uint32_t)(period_64 & UINT32_MAX);
uint64_t ratio_64 = (xtal_cycles << RTC_CLK_CAL_FRACT) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint32_t ratio = rtc_clk_cal_ratio(cal_clk, slowclk_cycles);
uint32_t period = ratio / xtal_freq;
return period;
}