From a48b5246ccd1c54f0abbc05e0759fcd5363700de Mon Sep 17 00:00:00 2001 From: chaijie Date: Fri, 18 Sep 2020 17:23:28 +0800 Subject: [PATCH] ESP32: Fix xtal 32k not oscillate or oscillate too slowly issue ESP32 in revision0 and revision1 uses touchpad to provide current to oscillate xtal 32k. But revision2 and revision3 do not need to do that. Note: touchpad can not work and toupad/ULP wakeup sources are not available when toupad provides current to xtal 32k --- components/driver/esp32/touch_sensor.c | 4 ++ .../include/driver/touch_sensor_common.h | 1 + components/esp32/Kconfig | 35 ++++++--- components/esp_hw_support/CMakeLists.txt | 9 ++- .../esp_hw_support/port/esp32/rtc_clk.c | 71 ++++++++++++++----- components/esp_system/sleep_modes.c | 8 ++- .../hal/esp32/include/hal/touch_sensor_ll.h | 1 + .../main/esp32/tp_interrupt_main.c | 2 +- .../touch_pad_read/main/esp32/tp_read_main.c | 2 +- .../deep_sleep/main/deep_sleep_example_main.c | 2 +- 10 files changed, 101 insertions(+), 34 deletions(-) diff --git a/components/driver/esp32/touch_sensor.c b/components/driver/esp32/touch_sensor.c index 9f61299944..5e8215e73c 100644 --- a/components/driver/esp32/touch_sensor.c +++ b/components/driver/esp32/touch_sensor.c @@ -287,6 +287,10 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold) esp_err_t touch_pad_init(void) { +#ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2 + ESP_LOGE(TOUCH_TAG, "Touch Pad can't work because it provides current to external XTAL"); + return ESP_ERR_NOT_SUPPORTED; +#endif // CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2 if (rtc_touch_mux == NULL) { rtc_touch_mux = xSemaphoreCreateMutex(); } diff --git a/components/driver/include/driver/touch_sensor_common.h b/components/driver/include/driver/touch_sensor_common.h index 46ed3d7130..f9855bc9dc 100644 --- a/components/driver/include/driver/touch_sensor_common.h +++ b/components/driver/include/driver/touch_sensor_common.h @@ -28,6 +28,7 @@ extern "C" { * @return * - ESP_OK Success * - ESP_ERR_NO_MEM Touch pad init error + * - ESP_ERR_NOT_SUPPORTED Touch pad is providing current to external XTAL */ esp_err_t touch_pad_init(void); diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 4c815dddab..10c72be32d 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -570,18 +570,35 @@ menu "ESP32-specific" bool "Internal 8.5MHz oscillator, divided by 256 (~33kHz)" endchoice - config ESP32_RTC_EXT_CRYST_ADDIT_CURRENT - bool "Additional current for external 32kHz crystal" + choice ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_METHOD + prompt "Additional current for external 32kHz crystal" depends on ESP32_RTC_CLK_SRC_EXT_CRYS - default "n" + depends on ESP32_REV_MIN <= 1 + default ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_NONE help - Choose which additional current is used for rtc external crystal. + With some 32kHz crystal configurations, the X32N and X32P pins may not have enough + drive strength to keep the crystal oscillating. Choose the method to provide + additional current from touchpad 9 to the external 32kHz crystal. Note that + the deep sleep current is slightly high (4-5uA) and the touchpad and the + wakeup sources of both touchpad and ULP are not available in method 1 and method 2. - - With some 32kHz crystal configurations, the X32N and X32P pins may not - have enough drive strength to keep the crystal oscillating during deep sleep. - If this option is enabled, additional current from touchpad 9 is provided - internally to drive the 32kHz crystal. If this option is enabled, deep sleep current - is slightly higher (4-5uA) and the touchpad and ULP wakeup sources are not available. + This problem is fixed in ESP32 ECO 3, so this workaround is not needed. Setting the + project configuration to minimum revision ECO3 will disable this option, , allow + all wakeup sources, and save some code size. + + - "None" option will not provide additional current to external crystal + - "Method 1" option can't ensure 100% to solve the external 32k crystal start failed + issue, but the touchpad can work in this method. + - "Method 2" option can solve the external 32k issue, but the touchpad can't work + in this method. + + config ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_NONE + bool "None" + config ESP32_RTC_EXT_CRYST_ADDIT_CURRENT + bool "Method 1" + config ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2 + bool "Method 2" + endchoice config ESP32_RTC_CLK_CAL_CYCLES int "Number of cycles for RTC_SLOW_CLK calibration" diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index ab097c4f69..987abe80ee 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -1,7 +1,14 @@ +idf_build_get_property(target IDF_TARGET) + +set(requires soc) +if(${target} STREQUAL "esp32") + list(APPEND requires efuse) +endif() + idf_component_register(SRCS "compare_set.c" "cpu_util.c" INCLUDE_DIRS include - REQUIRES soc + REQUIRES ${requires} LDFRAGMENTS linker.lf) idf_build_get_property(target IDF_TARGET) diff --git a/components/esp_hw_support/port/esp32/rtc_clk.c b/components/esp_hw_support/port/esp32/rtc_clk.c index bd65f5ae5c..2dac3a9c93 100644 --- a/components/esp_hw_support/port/esp32/rtc_clk.c +++ b/components/esp_hw_support/port/esp32/rtc_clk.c @@ -19,6 +19,7 @@ #include "esp32/rom/ets_sys.h" // for ets_update_cpu_frequency #include "esp32/rom/rtc.h" #include "esp_rom_gpio.h" +#include "esp_efuse.h" #include "soc/rtc.h" #include "soc/rtc_periph.h" #include "soc/sens_periph.h" @@ -58,7 +59,7 @@ #define APLL_CAL_DELAY_2 0x3f #define APLL_CAL_DELAY_3 0x1f -#define XTAL_32K_DAC_VAL 3 +#define XTAL_32K_DAC_VAL 1 #define XTAL_32K_DRES_VAL 3 #define XTAL_32K_DBIAS_VAL 0 @@ -127,20 +128,42 @@ static void rtc_clk_32k_enable_common(int dac, int dres, int dbias) REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, dbias); #ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT - /* TOUCH sensor can provide additional current to external XTAL. - In some case, X32N and X32P PAD don't have enough drive capability to start XTAL */ - SET_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M); - /* Tie PAD Touch8 to VDD - NOTE: TOUCH8 and TOUCH9 register settings are reversed except for DAC, so we set RTC_IO_TOUCH_PAD9_REG here instead - */ - SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_TIE_OPT_M); - /* Set the current used to compensate TOUCH PAD8 */ - SET_PERI_REG_BITS(RTC_IO_TOUCH_PAD8_REG, RTC_IO_TOUCH_PAD8_DAC, 4, RTC_IO_TOUCH_PAD8_DAC_S); - /* Power up TOUCH8 - So the Touch DAC start to drive some current from VDD to TOUCH8(which is also XTAL-N) - */ - SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M); -#endif // CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT + uint8_t chip_ver = esp_efuse_get_chip_ver(); + // version0 and version1 need provide additional current to external XTAL. + if(chip_ver == 0 || chip_ver == 1) { + /* TOUCH sensor can provide additional current to external XTAL. + In some case, X32N and X32P PAD don't have enough drive capability to start XTAL */ + SET_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M); + /* Tie PAD Touch8 to VDD + NOTE: TOUCH8 and TOUCH9 register settings are reversed except for DAC, so we set RTC_IO_TOUCH_PAD9_REG here instead*/ + SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_TIE_OPT_M); + /* Set the current used to compensate TOUCH PAD8 */ + SET_PERI_REG_BITS(RTC_IO_TOUCH_PAD8_REG, RTC_IO_TOUCH_PAD8_DAC, 4, RTC_IO_TOUCH_PAD8_DAC_S); + /* Power up TOUCH8 + So the Touch DAC start to drive some current from VDD to TOUCH8(which is also XTAL-N)*/ + SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M); + } +#elif defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2 + uint8_t chip_ver = esp_efuse_get_chip_ver(); + if(chip_ver == 0 || chip_ver == 1) { + /* TOUCH sensor can provide additional current to external XTAL. + In some case, X32N and X32P PAD don't have enough drive capability to start XTAL */ + SET_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M); + SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_DCUR, 3, RTC_IO_TOUCH_DCUR_S); + CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FSM_EN_M); + /* Tie PAD Touch8 to VDD + NOTE: TOUCH8 and TOUCH9 register settings are reversed except for DAC, so we set RTC_IO_TOUCH_PAD9_REG here instead + */ + SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_TIE_OPT_M); + /* Set the current used to compensate TOUCH PAD8 */ + SET_PERI_REG_BITS(RTC_IO_TOUCH_PAD8_REG, RTC_IO_TOUCH_PAD8_DAC, 1, RTC_IO_TOUCH_PAD8_DAC_S); + /* Power up TOUCH8 + So the Touch DAC start to drive some current from VDD to TOUCH8(which is also XTAL-N) + */ + SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M); + CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_START_M); + } +#endif /* Power up external xtal */ SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M); } @@ -155,9 +178,21 @@ void rtc_clk_32k_enable(bool enable) CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL); #ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT - /* Power down TOUCH */ - CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M); -#endif // CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT + uint8_t chip_ver = esp_efuse_get_chip_ver(); + if(chip_ver == 0 || chip_ver == 1) { + /* Power down TOUCH */ + CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M); + } +#elif defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2 + uint8_t chip_ver = esp_efuse_get_chip_ver(); + if(chip_ver == 0 || chip_ver == 1) { + /* Power down TOUCH */ + CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M); + SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_DCUR, 0, RTC_IO_TOUCH_DCUR_S); + CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M); + SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FSM_EN_M); + } +#endif } } diff --git a/components/esp_system/sleep_modes.c b/components/esp_system/sleep_modes.c index 9882bdcbbc..e23149d511 100644 --- a/components/esp_system/sleep_modes.c +++ b/components/esp_system/sleep_modes.c @@ -542,9 +542,10 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source) esp_err_t esp_sleep_enable_ulp_wakeup(void) { #if CONFIG_IDF_TARGET_ESP32 -#ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT +#if ((defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT) || (defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2)) + ESP_LOGE(TAG, "Failed to enable wakeup when provide current to external 32kHz crystal"); return ESP_ERR_NOT_SUPPORTED; -#endif // CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT +#endif #ifdef CONFIG_ESP32_ULP_COPROC_ENABLED if(s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) { ESP_LOGE(TAG, "Conflicting wake-up trigger: ext0"); @@ -596,7 +597,8 @@ static void touch_wakeup_prepare(void) esp_err_t esp_sleep_enable_touchpad_wakeup(void) { -#ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT +#if ((defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT) || (defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2)) + ESP_LOGE(TAG, "Failed to enable wakeup when provide current to external 32kHz crystal"); return ESP_ERR_NOT_SUPPORTED; #endif if (s_config.wakeup_triggers & (RTC_EXT0_TRIG_EN)) { diff --git a/components/hal/esp32/include/hal/touch_sensor_ll.h b/components/hal/esp32/include/hal/touch_sensor_ll.h index b65120b684..0b876039b0 100644 --- a/components/hal/esp32/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32/include/hal/touch_sensor_ll.h @@ -233,6 +233,7 @@ static inline void touch_ll_get_tie_option(touch_pad_t touch_num, touch_tie_opt_ */ static inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode) { + SENS.sar_touch_ctrl2.touch_start_fsm_en = 1; SENS.sar_touch_ctrl2.touch_start_en = 0; SENS.sar_touch_ctrl2.touch_start_force = mode; } diff --git a/examples/peripherals/touch_pad_interrupt/main/esp32/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/esp32/tp_interrupt_main.c index 76552239d9..0c0187c498 100644 --- a/examples/peripherals/touch_pad_interrupt/main/esp32/tp_interrupt_main.c +++ b/examples/peripherals/touch_pad_interrupt/main/esp32/tp_interrupt_main.c @@ -151,7 +151,7 @@ void app_main(void) { // Initialize touch pad peripheral, it will start a timer to run a filter ESP_LOGI(TAG, "Initializing touch pad"); - touch_pad_init(); + ESP_ERROR_CHECK(touch_pad_init()); // If use interrupt trigger mode, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'. touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // Set reference voltage for charging/discharging diff --git a/examples/peripherals/touch_pad_read/main/esp32/tp_read_main.c b/examples/peripherals/touch_pad_read/main/esp32/tp_read_main.c index a3093b3982..4ab44003c8 100644 --- a/examples/peripherals/touch_pad_read/main/esp32/tp_read_main.c +++ b/examples/peripherals/touch_pad_read/main/esp32/tp_read_main.c @@ -57,7 +57,7 @@ void app_main(void) { // Initialize touch pad peripheral. // The default fsm mode is software trigger mode. - touch_pad_init(); + ESP_ERROR_CHECK(touch_pad_init()); // Set reference voltage for charging/discharging // In this case, the high reference valtage will be 2.7V - 1V = 1.7V // The low reference voltage will be 0.5 diff --git a/examples/system/deep_sleep/main/deep_sleep_example_main.c b/examples/system/deep_sleep/main/deep_sleep_example_main.c index a56f3613b4..f406b6e7de 100644 --- a/examples/system/deep_sleep/main/deep_sleep_example_main.c +++ b/examples/system/deep_sleep/main/deep_sleep_example_main.c @@ -159,7 +159,7 @@ void app_main(void) #if CONFIG_IDF_TARGET_ESP32 // Initialize touch pad peripheral. // The default fsm mode is software trigger mode. - touch_pad_init(); + ESP_ERROR_CHECK(touch_pad_init()); // If use touch pad wake up, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'. touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // Set reference voltage for charging/discharging