Merge branch 'feature/xtal_freq_autodetect' into 'master'

XTAL frequency detection, support for selecting XTAL frequency

This MR adds more robust XTAL frequency detection code (which gets run in the bootloader) and an option to set XTAL frequency in Kconfig. By default we still use autodetection, since it is more reliable than the one used in ROM code.

This will help with issues about XTAL frequency detection in high ambient temperature conditions.

Ref TW12008

See merge request !694
This commit is contained in:
Ivan Grokhotkov 2017-04-25 16:30:36 +08:00
commit 8131c77860
7 changed files with 86 additions and 36 deletions

View file

@ -240,6 +240,7 @@ void bootloader_main()
/* Set CPU to 80MHz. Keep other clocks unmodified. */
uart_tx_wait_idle(0);
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
clk_cfg.cpu_freq = RTC_CPU_FREQ_80M;
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
clk_cfg.fast_freq = rtc_clk_fast_freq_get();

View file

@ -560,6 +560,34 @@ config ESP32_DEEP_SLEEP_WAKEUP_DELAY
If you are seeing "flash read err, 1000" message printed to the
console after deep sleep reset, try increasing this value.
choice ESP32_XTAL_FREQ_SEL
prompt "Main XTAL frequency"
default ESP32_XTAL_FREQ_AUTO
help
ESP32 currently supports the following XTAL frequencies:
- 26 MHz
- 40 MHz
Startup code can automatically estimate XTAL frequency. This feature
uses the internal 8MHz oscillator as a reference. Because the internal
oscillator frequency is temperature dependent, it is not recommended
to use automatic XTAL frequency detection in applications which need
to work at high ambient temperatures and use high-temperature
qualified chips and modules.
config ESP32_XTAL_FREQ_40
bool "40 MHz"
config ESP32_XTAL_FREQ_26
bool "26 MHz"
config ESP32_XTAL_FREQ_AUTO
bool "Autodetect"
endchoice
# Keep these values in sync with rtc_xtal_freq_t enum in soc/rtc.h
config ESP32_XTAL_FREQ
int
default 0 if ESP32_XTAL_FREQ_AUTO
default 40 if ESP32_XTAL_FREQ_40
default 26 if ESP32_XTAL_FREQ_26
endmenu
menuconfig WIFI_ENABLED

View file

@ -92,6 +92,9 @@ typedef enum {
RTC_FAST_FREQ_8M = 1, //!< Internal 8 MHz RC oscillator
} rtc_fast_freq_t;
/* With the default value of CK8M_DFREQ, 8M clock frequency is 8.5 MHz +/- 7% */
#define RTC_FAST_CLK_FREQ_APPROX 8500000
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*/
@ -307,6 +310,15 @@ uint32_t rtc_clk_apb_freq_get();
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
/**
* @brief Measure ratio between XTAL frequency and RTC slow clock frequency
* @param cal_clk slow clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average ratio between XTAL frequency and slow clock frequency,
* Q13.19 fixed point format, or 0 if calibration has timed out.
*/
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
* @param time_in_us Time interval in microseconds

View file

@ -511,6 +511,7 @@
#define RTC_IO_DEBUG_SEL0_M ((RTC_IO_DEBUG_SEL0_V)<<(RTC_IO_DEBUG_SEL0_S))
#define RTC_IO_DEBUG_SEL0_V 0x1F
#define RTC_IO_DEBUG_SEL0_S 0
#define RTC_IO_DEBUG_SEL0_8M 1
#define RTC_IO_DEBUG_SEL0_32K_XTAL 4
#define RTC_IO_DEBUG_SEL0_150K_OSC 5

View file

@ -67,6 +67,11 @@ static const char* TAG = "rtc_clk";
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
* 10 cycles will take approximately 300 microseconds.
*/
#define XTAL_FREQ_EST_CYCLES 10
void rtc_clk_32k_enable(bool enable)
{
@ -422,19 +427,12 @@ void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate()
{
/* ROM startup code estimates XTAL frequency using an 8MD256 clock and stores
* the value into RTC_APB_FREQ_REG. The value is in Hz, right shifted by 12.
* Use this value to guess the real XTAL frequency.
*
* TODO: make this more robust by calibrating again after setting
* RTC_CNTL_CK8M_DFREQ.
uint64_t cal_val = rtc_clk_cal_ratio(RTC_CAL_8MD256, XTAL_FREQ_EST_CYCLES);
/* cal_val contains period of 8M/256 clock in XTAL clock cycles
* (shifted by RTC_CLK_CAL_FRACT bits).
* Xtal frequency will be (cal_val * 8M / 256) / 2^19
*/
uint32_t apb_freq_reg = READ_PERI_REG(RTC_APB_FREQ_REG);
if (!clk_val_is_valid(apb_freq_reg)) {
SOC_LOGW(TAG, "invalid RTC_APB_FREQ_REG value: 0x%08x", apb_freq_reg);
return RTC_XTAL_FREQ_AUTO;
}
uint32_t freq_mhz = (reg_val_to_clk_val(apb_freq_reg) << 12) / MHZ;
uint32_t freq_mhz = (cal_val * (RTC_FAST_CLK_FREQ_APPROX / MHZ) / 256 ) >> RTC_CLK_CAL_FRACT;
/* Guess the XTAL type. For now, only 40 and 26MHz are supported.
*/
switch (freq_mhz) {
@ -467,6 +465,19 @@ uint32_t rtc_clk_apb_freq_get()
void rtc_clk_init(rtc_clk_config_t cfg)
{
/* If we get a TG WDT system reset while running at 240MHz,
* DPORT_CPUPERIOD_SEL register will be reset to 0 resulting in 120MHz
* APB and CPU frequencies after reset. This will cause issues with XTAL
* frequency estimation, so we switch to XTAL frequency first.
*
* Ideally we would only do this if RTC_CNTL_SOC_CLK_SEL == PLL and
* PLL is configured for 480M, but it takes less time to switch to 40M and
* run the following code than querying the PLL does.
*/
if (REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL) == RTC_CNTL_SOC_CLK_SEL_PLL) {
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
}
/* Set tuning parameters for 8M and 150k clocks.
* Note: this doesn't attempt to set the clocks to precise frequencies.
* Instead, we calibrate these clocks against XTAL frequency later, when necessary.
@ -521,20 +532,3 @@ void rtc_clk_init(rtc_clk_config_t cfg)
* TODO: update the library to use rtc_clk_xtal_freq_get
*/
rtc_xtal_freq_t rtc_get_xtal() __attribute__((alias("rtc_clk_xtal_freq_get")));
/* Referenced in librtc.a:rtc.o.
* TODO: remove
*/
void rtc_uart_div_modify(int latch)
{
}
/* Referenced in librtc.a:rtc.o.
* TODO: remove
*/
void rtc_uart_tx_wait_idle(int uart)
{
}

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

View file

@ -82,3 +82,10 @@ TEST_CASE("Output 32k XTAL clock to GPIO25", "[rtc_clk][ignore]")
rtc_clk_32k_enable(true);
pull_out_clk(RTC_IO_DEBUG_SEL0_32K_XTAL);
}
TEST_CASE("Output 8M XTAL clock to GPIO25", "[rtc_clk][ignore]")
{
rtc_clk_8m_enable(true, true);
SET_PERI_REG_MASK(RTC_IO_RTC_DEBUG_SEL_REG, RTC_IO_DEBUG_12M_NO_GATING);
pull_out_clk(RTC_IO_DEBUG_SEL0_8M);
}