From 9100cd558e2f0159659beeceab56d5539bb1978a 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/esp32/sleep_modes.c | 6 +- components/soc/CMakeLists.txt | 8 ++- .../soc/esp32/include/hal/touch_sensor_ll.h | 1 + components/soc/esp32/rtc_clk.c | 71 ++++++++++++++----- .../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, 99 insertions(+), 33 deletions(-) diff --git a/components/driver/esp32/touch_sensor.c b/components/driver/esp32/touch_sensor.c index ccee01bf80..c754767ede 100644 --- a/components/driver/esp32/touch_sensor.c +++ b/components/driver/esp32/touch_sensor.c @@ -276,6 +276,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 7294ffccbd..dd7eb2002e 100644 --- a/components/driver/include/driver/touch_sensor_common.h +++ b/components/driver/include/driver/touch_sensor_common.h @@ -30,6 +30,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 b1edfd366b..7a4e4f594b 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -590,18 +590,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/esp32/sleep_modes.c b/components/esp32/sleep_modes.c index fc3f96fd15..3c708ed3ba 100644 --- a/components/esp32/sleep_modes.c +++ b/components/esp32/sleep_modes.c @@ -407,7 +407,8 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source) esp_err_t esp_sleep_enable_ulp_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 #ifdef CONFIG_ESP32_ULP_COPROC_ENABLED @@ -443,7 +444,8 @@ static void timer_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/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 4f5bb2e3f8..0c9349890c 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -53,7 +53,13 @@ if(IDF_TARGET STREQUAL "esp32s2beta") list(APPEND srcs "src/hal/spi_flash_hal_gpspi.c") endif() +set(priv_requires ${soc_name}) +if(${soc_name} STREQUAL "esp32") + # For rtc_clk.c + list(APPEND priv_requires efuse) +endif() + idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" - PRIV_REQUIRES ${soc_name} + PRIV_REQUIRES ${priv_requires} LDFRAGMENTS linker.lf) diff --git a/components/soc/esp32/include/hal/touch_sensor_ll.h b/components/soc/esp32/include/hal/touch_sensor_ll.h index e6c302f661..2c322b4a6e 100644 --- a/components/soc/esp32/include/hal/touch_sensor_ll.h +++ b/components/soc/esp32/include/hal/touch_sensor_ll.h @@ -228,6 +228,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/components/soc/esp32/rtc_clk.c b/components/soc/esp32/rtc_clk.c index 6e8c6653ab..a42d6a816a 100644 --- a/components/soc/esp32/rtc_clk.c +++ b/components/soc/esp32/rtc_clk.c @@ -20,6 +20,7 @@ #include "esp32/rom/rtc.h" #include "esp32/rom/uart.h" #include "esp32/rom/gpio.h" +#include "esp_efuse.h" #include "soc/rtc.h" #include "soc/rtc_periph.h" #include "soc/sens_periph.h" @@ -57,7 +58,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 @@ -126,20 +127,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); } @@ -154,9 +177,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/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 6a7a64a6f2..aaa71407a6 100644 --- a/examples/system/deep_sleep/main/deep_sleep_example_main.c +++ b/examples/system/deep_sleep/main/deep_sleep_example_main.c @@ -155,7 +155,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