From 9efc06be0fb8cd3e0f290f6e01f8caacb35a70bc Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 13 Aug 2018 01:09:06 +0300 Subject: [PATCH 1/4] esp32/clk: remove unused code When 32k XTAL was selected as clock source, if the first calibration attempt failed, the code would fall back to 150kHz internal clock. Calibration with the internal clock will always succeed. Therefore `wait` would always be either 0 or 1. Based on this, some code in this routine can be eliminated. --- components/esp32/clk.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/components/esp32/clk.c b/components/esp32/clk.c index bb348fd672..5e7fd33714 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -120,11 +120,7 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) { uint32_t cal_val = 0; - uint32_t wait = 0; uint32_t freq_hz = ((slow_clk == RTC_SLOW_FREQ_32K_XTAL) ? 32768 : 150000); - uint32_t warning_timeout = 3 /* sec */ * freq_hz /* Hz */ / (SLOW_CLK_CAL_CYCLES + 1); - warning_timeout = ((warning_timeout == 0) ? 3 /* sec */ : warning_timeout); - bool changing_clock_to_150k = false; do { if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) { /* 32k XTAL oscillator needs to be enabled and running before it can @@ -140,20 +136,12 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) if (SLOW_CLK_CAL_CYCLES > 0) { cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); if (cal_val == 0 || cal_val < 15000000L) { - ESP_EARLY_LOGE(TAG, "RTC: Not found External 32 kHz XTAL. Switching to Internal 150 kHz RC chain"); slow_clk = RTC_SLOW_FREQ_RTC; - changing_clock_to_150k = true; + ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator"); } } } rtc_clk_slow_freq_set(slow_clk); - if (changing_clock_to_150k == true && wait > 1){ - // This helps when there are errors when switching the clock from External 32 kHz XTAL to Internal 150 kHz RC chain. - rtc_clk_32k_enable(false); - uint32_t min_bootstrap = 5; // Min bootstrapping for continue switching the clock. - rtc_clk_32k_bootstrap(min_bootstrap); - rtc_clk_32k_enable(true); - } if (SLOW_CLK_CAL_CYCLES > 0) { /* TODO: 32k XTAL oscillator has some frequency drift at startup. @@ -164,9 +152,6 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); } - if (++wait % warning_timeout == 0) { - ESP_EARLY_LOGW(TAG, "still waiting for source selection RTC"); - } } while (cal_val == 0); ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); esp_clk_slowclk_cal_set(cal_val); From 8365f0f5d2d82413d3fa40bfded3942499243fd1 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 13 Aug 2018 01:10:29 +0300 Subject: [PATCH 2/4] soc/rtc: add support for external 32k oscillator Compared to external 32k XTAL, when active oscillator is used as input, some parameters need to be set differently. --- components/soc/esp32/include/soc/rtc.h | 5 +++++ components/soc/esp32/rtc_clk.c | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index b02d31eac3..a528bdd15d 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -193,6 +193,11 @@ void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq); */ void rtc_clk_32k_enable(bool en); +/** + * @brief Configure 32 kHz XTAL oscillator to accept external clock signal + */ +void rtc_clk_32k_enable_external(); + /** * @brief Get the state of 32k XTAL oscillator * @return true if 32k XTAL oscillator has been enabled diff --git a/components/soc/esp32/rtc_clk.c b/components/soc/esp32/rtc_clk.c index 38737fbaa2..30f20e0eb0 100644 --- a/components/soc/esp32/rtc_clk.c +++ b/components/soc/esp32/rtc_clk.c @@ -62,6 +62,10 @@ #define XTAL_32K_BOOTSTRAP_DBIAS_VAL 0 #define XTAL_32K_BOOTSTRAP_TIME_US 7 +#define XTAL_32K_EXT_DAC_VAL 2 +#define XTAL_32K_EXT_DRES_VAL 3 +#define XTAL_32K_EXT_DBIAS_VAL 1 + /* Delays for various clock sources to be enabled/switched. * All values are in microseconds. * TODO: some of these are excessive, and should be reduced. @@ -98,7 +102,7 @@ static bool rtc_clk_cpu_freq_from_mhz_internal(int mhz, rtc_cpu_freq_t* out_val) // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled. static int s_cur_pll_freq; -static void rtc_clk_32k_enable_internal(int dac, int dres, int dbias) +static void rtc_clk_32k_enable_common(int dac, int dres, int dbias) { SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL); CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, @@ -113,12 +117,17 @@ static void rtc_clk_32k_enable_internal(int dac, int dres, int dbias) void rtc_clk_32k_enable(bool enable) { if (enable) { - rtc_clk_32k_enable_internal(XTAL_32K_DAC_VAL, XTAL_32K_DRES_VAL, XTAL_32K_DBIAS_VAL); + rtc_clk_32k_enable_common(XTAL_32K_DAC_VAL, XTAL_32K_DRES_VAL, XTAL_32K_DBIAS_VAL); } else { CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K); } } +void rtc_clk_32k_enable_external() +{ + rtc_clk_32k_enable_common(XTAL_32K_EXT_DAC_VAL, XTAL_32K_EXT_DRES_VAL, XTAL_32K_EXT_DBIAS_VAL); +} + /* Helping external 32kHz crystal to start up. * External crystal connected to outputs GPIO32 GPIO33. * Forms N pulses with a frequency of about 32KHz on the outputs of the crystal. @@ -150,7 +159,7 @@ void rtc_clk_32k_bootstrap(uint32_t cycle) SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE | RTC_IO_X32N_RDE); ets_delay_us(XTAL_32K_BOOTSTRAP_TIME_US); - rtc_clk_32k_enable_internal(XTAL_32K_BOOTSTRAP_DAC_VAL, + rtc_clk_32k_enable_common(XTAL_32K_BOOTSTRAP_DAC_VAL, XTAL_32K_BOOTSTRAP_DRES_VAL, XTAL_32K_BOOTSTRAP_DBIAS_VAL); } From 5bf36546379b55ba80313699a551104c7e29a8c9 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 13 Aug 2018 01:11:32 +0300 Subject: [PATCH 3/4] soc/rtc: Force power on 8M clock if it is used to derive RTC slow clock --- components/soc/esp32/rtc_sleep.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/soc/esp32/rtc_sleep.c b/components/soc/esp32/rtc_sleep.c index 041c2d1b6b..6b16aa2889 100644 --- a/components/soc/esp32/rtc_sleep.c +++ b/components/soc/esp32/rtc_sleep.c @@ -197,6 +197,12 @@ void rtc_sleep_init(rtc_sleep_config_t cfg) REG_SET_FIELD(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU, cfg.xtal_fpu); + if (REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL) == RTC_SLOW_FREQ_8MD256) { + REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU); + } else { + REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU); + } + /* enable VDDSDIO control by state machine */ REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE); REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en); From 96971e3e9fb5e1569e5d28549c86b6dc7ab0644d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 13 Aug 2018 01:12:01 +0300 Subject: [PATCH 4/4] esp32: add support for 8MD256 and external 32k as slow clock options --- components/esp32/Kconfig | 23 ++++++++++++++++++++- components/esp32/clk.c | 44 ++++++++++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 7824823a44..b04a7eb2f6 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -683,18 +683,39 @@ choice ESP32_RTC_CLOCK_SOURCE default ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC help Choose which clock is used as RTC clock source. + + - "Internal 150kHz oscillator" option provides lowest deep sleep current + consumption, and does not require extra external components. However + frequency stability with respect to temperature is poor, so time may + drift in deep/light sleep modes. + - "External 32kHz crystal" provides better frequency stability, at the + expense of slightly higher (1uA) deep sleep current consumption. + - "External 32kHz oscillator" allows using 32kHz clock generated by an + external circuit. In this case, external clock signal must be connected + to 32K_XP pin. Amplitude should be <1.2V in case of sine wave signal, + and <1V in case of square wave signal. Common mode voltage should be + 0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude. + Additionally, 1nF capacitor must be connected between 32K_XN pin and + ground. 32K_XN pin can not be used as a GPIO in this case. + - "Internal 8.5MHz oscillator divided by 256" option results in higher + deep sleep current (by 5uA) but has better frequency stability than + the internal 150kHz oscillator. It does not require external components. config ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC bool "Internal 150kHz RC oscillator" config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL bool "External 32kHz crystal" +config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC + bool "External 32kHz oscillator at 32K_XP pin" +config ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 + bool "Internal 8.5MHz oscillator, divided by 256 (~33kHz)" endchoice config ESP32_RTC_CLK_CAL_CYCLES int "Number of cycles for RTC_SLOW_CLK calibration" default 3000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL default 1024 if ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC - range 0 27000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL + range 0 27000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL || ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC || ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 range 0 32766 if ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC help When the startup code initializes RTC_SLOW_CLK, it can perform diff --git a/components/esp32/clk.c b/components/esp32/clk.c index 5e7fd33714..17afaa1b34 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -40,7 +40,23 @@ #define MHZ (1000000) -static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk); +/* Indicates that this 32k oscillator gets input from external oscillator, rather + * than a crystal. + */ +#define EXT_OSC_FLAG BIT(3) + +/* This is almost the same as rtc_slow_freq_t, except that we define + * an extra enum member for the external 32k oscillator. + * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. + */ +typedef enum { + SLOW_CLK_150K = RTC_SLOW_FREQ_RTC, //!< Internal 150 kHz RC oscillator + SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL + SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 + SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin +} slow_clk_sel_t; + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); // g_ticks_us defined in ROMs for PRO and APP CPU extern uint32_t g_ticks_per_us_pro; @@ -71,8 +87,12 @@ void esp_clk_init(void) rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); -#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL - select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); +#if defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL) + select_rtc_slow_clk(SLOW_CLK_32K_XTAL); +#elif defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC) + select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); +#elif defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256) + select_rtc_slow_clk(SLOW_CLK_8MD256); #else select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); #endif @@ -117,12 +137,12 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) g_ticks_per_us_app = ticks_per_us; } -static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) { + rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; uint32_t cal_val = 0; - uint32_t freq_hz = ((slow_clk == RTC_SLOW_FREQ_32K_XTAL) ? 32768 : 150000); do { - if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) { + if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { /* 32k XTAL oscillator needs to be enabled and running before it can * be used. Hardware doesn't have a direct way of checking if the * oscillator is running. Here we use rtc_clk_cal function to count @@ -131,17 +151,23 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) * will time out, returning 0. */ ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); - rtc_clk_32k_enable(true); + if (slow_clk == SLOW_CLK_32K_XTAL) { + rtc_clk_32k_enable(true); + } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { + rtc_clk_32k_enable_external(); + } // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. if (SLOW_CLK_CAL_CYCLES > 0) { cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); if (cal_val == 0 || cal_val < 15000000L) { - slow_clk = RTC_SLOW_FREQ_RTC; ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator"); + rtc_slow_freq = RTC_SLOW_FREQ_RTC; } } + } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { + rtc_clk_8m_enable(true, true); } - rtc_clk_slow_freq_set(slow_clk); + rtc_clk_slow_freq_set(rtc_slow_freq); if (SLOW_CLK_CAL_CYCLES > 0) { /* TODO: 32k XTAL oscillator has some frequency drift at startup.