From 4b71ebbe49823abc16a096457a6b73cb04a3660d Mon Sep 17 00:00:00 2001 From: jingli Date: Fri, 16 Sep 2022 20:25:44 +0800 Subject: [PATCH 1/4] esp_hw_support/sleep: fix current leakage when hold digital io during deep sleep --- components/driver/include/driver/gpio.h | 4 +- .../include/esp_private/esp_sleep_internal.h | 10 +++ components/esp_hw_support/sleep_gpio.c | 43 ++++++++++++ components/esp_hw_support/sleep_modes.c | 5 ++ components/hal/esp32/include/hal/gpio_ll.h | 70 ++++++++++++++++++- components/hal/esp32c3/include/hal/gpio_ll.h | 62 ++++++++++++++-- components/hal/esp32s2/include/hal/gpio_ll.h | 56 ++++++++++++++- components/hal/esp32s3/include/hal/gpio_ll.h | 59 +++++++++++++++- components/hal/include/hal/gpio_hal.h | 40 ++++++++++- components/soc/esp32/gpio_periph.c | 44 ++++++++++++ components/soc/esp32/include/soc/soc_caps.h | 3 + components/soc/esp32c3/include/soc/soc_caps.h | 3 + components/soc/esp32h2/include/soc/soc_caps.h | 2 + components/soc/esp32s2/include/soc/soc_caps.h | 3 + components/soc/esp32s3/include/soc/soc_caps.h | 2 + 15 files changed, 390 insertions(+), 16 deletions(-) diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index b904def347..b6184329b3 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -50,7 +50,9 @@ extern "C" { #define GPIO_IS_VALID_GPIO(gpio_num) (((1ULL << (gpio_num)) & SOC_GPIO_VALID_GPIO_MASK) != 0) /// Check whether it can be a valid GPIO number of output mode #define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) (((1ULL << (gpio_num)) & SOC_GPIO_VALID_OUTPUT_GPIO_MASK) != 0) - +/// Check whether it can be a valid digital I/O pad +#define GPIO_IS_VALID_DIGITAL_IO_PAD(gpio_num) ((gpio_num >= 0) && \ + (((1ULL << (gpio_num)) & SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK) != 0)) typedef intr_handle_t gpio_isr_handle_t; diff --git a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h index ee0b72953f..5eb5081b56 100644 --- a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h +++ b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h @@ -6,6 +6,7 @@ #pragma once #include +#include "sdkconfig.h" #ifdef __cplusplus extern "C" { @@ -20,6 +21,15 @@ extern "C" { */ void esp_sleep_enable_adc_tsens_monitor(bool enable); +// IDF does not officially support esp32h2 in v4.4 +#if !CONFIG_IDF_TARGET_ESP32H2 +/** + * @brief Isolate all digital IOs except those that are held during deep sleep + * + * Reduce digital IOs current leakage during deep sleep. + */ +void esp_sleep_isolate_digital_gpio(void); +#endif #ifdef __cplusplus } diff --git a/components/esp_hw_support/sleep_gpio.c b/components/esp_hw_support/sleep_gpio.c index ae4cede0f0..9a092b19fe 100644 --- a/components/esp_hw_support/sleep_gpio.c +++ b/components/esp_hw_support/sleep_gpio.c @@ -12,11 +12,13 @@ #include "esp_attr.h" #include "esp_sleep.h" #include "esp_log.h" +#include "soc/soc_memory_types.h" #include "soc/soc_caps.h" #include "sdkconfig.h" #include "driver/gpio.h" +#include "hal/gpio_hal.h" #include "esp_private/gpio.h" #include "esp_private/sleep_gpio.h" #include "esp_private/spi_flash_os.h" @@ -94,3 +96,44 @@ void esp_sleep_enable_gpio_switch(bool enable) } #endif // SOC_GPIO_SUPPORT_SLP_SWITCH + +// IDF does not officially support esp32h2 in v4.4 +#if !CONFIG_IDF_TARGET_ESP32H2 +IRAM_ATTR void esp_sleep_isolate_digital_gpio(void) +{ + gpio_hal_context_t gpio_hal = { + .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) + }; + + /* no need to do isolate if digital IOs are not being held in deep sleep */ + if (!gpio_hal_deep_sleep_hold_is_en(&gpio_hal)) { + return; + } + + /** + * there is a situation where we cannot isolate digital IO before deep sleep: + * - task stack is located in external ram(mspi ram), since we will isolate mspi io + * + * assert here instead of returning directly, because if digital IO is not isolated, + * the bottom current of deep sleep will be higher than light sleep, and there is no + * reason to use deep sleep at this time. + */ + assert(esp_ptr_internal(&gpio_hal) && "If hold digital IO, the stack of the task calling esp_deep_sleep_start must be in internal ram!"); + + /* isolate digital IO that is not held(keep the configuration of digital IOs held by users) */ + for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) { + if (GPIO_IS_VALID_DIGITAL_IO_PAD(gpio_num) && !gpio_hal_is_digital_io_hold(&gpio_hal, gpio_num)) { + /* disable I/O */ + gpio_hal_input_disable(&gpio_hal, gpio_num); + gpio_hal_output_disable(&gpio_hal, gpio_num); + + /* disable pull up/down */ + gpio_hal_pullup_dis(&gpio_hal, gpio_num); + gpio_hal_pulldown_dis(&gpio_hal, gpio_num); + + /* make pad work as gpio(otherwise, deep sleep bottom current will rise) */ + gpio_hal_func_sel(&gpio_hal, gpio_num, PIN_FUNC_GPIO); + } + } +} +#endif diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 3fced84a8d..f58e51546a 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -13,6 +13,7 @@ #include "esp_sleep.h" #include "esp_private/esp_timer_private.h" #include "esp_private/system_internal.h" +#include "esp_private/esp_sleep_internal.h" #include "esp_log.h" #include "esp_newlib.h" #include "esp_timer.h" @@ -500,6 +501,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) */ portENTER_CRITICAL(&spinlock_rtc_deep_sleep); +#if !CONFIG_IDF_TARGET_ESP32H2 // IDF does not officially support esp32h2 in v4.4 + esp_sleep_isolate_digital_gpio(); +#endif + #if SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY extern char _rtc_text_start[]; #if CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM diff --git a/components/hal/esp32/include/hal/gpio_ll.h b/components/hal/esp32/include/hal/gpio_ll.h index fcff6a22bd..c245da1ef8 100644 --- a/components/hal/esp32/include/hal/gpio_ll.h +++ b/components/hal/esp32/include/hal/gpio_ll.h @@ -27,6 +27,9 @@ extern "C" { #endif +// the address of esp32's IO_MUX_GPIOx_REGs are not incremented as the gpio number increments(address are out of order) +extern const uint8_t GPIO_PIN_MUX_REG_OFFSET[SOC_GPIO_PIN_COUNT]; + // Get GPIO hardware instance with giving gpio num #define GPIO_LL_GET_HW(num) (((num) == 0) ? (&GPIO) : NULL) @@ -53,9 +56,10 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU); + REG_CLR_BIT(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num], FUN_PU); } /** @@ -87,9 +91,10 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD); + REG_CLR_BIT(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num], FUN_PD); } /** @@ -297,9 +302,10 @@ static inline void gpio_ll_intr_disable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_DISABLE(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num]); } /** @@ -319,6 +325,7 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { if (gpio_num < 32) { @@ -413,6 +420,18 @@ static inline void gpio_ll_od_enable(gpio_dev_t *hw, gpio_num_t gpio_num) hw->pin[gpio_num].pad_driver = 1; } +/** + * @brief Select a function for the pin in the IOMUX + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + * @param func Function to assign to the pin + */ +static inline __attribute__((always_inline)) void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t func) +{ + PIN_FUNC_SELECT(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num], func); +} + /** * @brief GPIO set output level * @@ -526,6 +545,21 @@ static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); } +/** + * @brief Get deep sleep hold status + * + * @param hw Peripheral GPIO hardware instance address. + * + * @return + * - true deep sleep hold is enabled + * - false deep sleep hold is disabled + */ +__attribute__((always_inline)) +static inline bool gpio_ll_deep_sleep_hold_is_en(gpio_dev_t *hw) +{ + return !GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD) && GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); +} + /** * @brief Enable gpio pad hold function. * @@ -548,6 +582,36 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num) CLEAR_PERI_REG_MASK(RTC_IO_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]); } +/** + * @brief Get digital gpio pad hold status. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + * + * @note caller must ensure that gpio_num is a digital io pad + * + * @return + * - true digital gpio pad is held + * - false digital gpio pad is unheld + */ +__attribute__((always_inline)) +static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num) +{ + uint32_t mask = 0; + + switch (gpio_num) { + case 1: mask = BIT(1); break; + case 3: mask = BIT(0); break; + case 5: mask = BIT(8); break; + case 6 ... 11 : mask = BIT(gpio_num - 4); break; + case 16 ... 19: + case 21 ... 23: mask = BIT(gpio_num - 7); break; + default: break; + } + + return GET_PERI_REG_MASK(RTC_IO_DIG_PAD_HOLD_REG, mask); +} + /** * @brief Set pad input to a peripheral signal through the IOMUX. * diff --git a/components/hal/esp32c3/include/hal/gpio_ll.h b/components/hal/esp32c3/include/hal/gpio_ll.h index 0b57785955..f1f4b61349 100644 --- a/components/hal/esp32c3/include/hal/gpio_ll.h +++ b/components/hal/esp32c3/include/hal/gpio_ll.h @@ -14,13 +14,14 @@ #pragma once +#include +#include #include "soc/soc.h" #include "soc/gpio_periph.h" #include "soc/gpio_struct.h" #include "soc/rtc_cntl_reg.h" #include "soc/usb_serial_jtag_reg.h" #include "hal/gpio_types.h" -#include "stdlib.h" #ifdef __cplusplus extern "C" { @@ -48,6 +49,7 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value @@ -56,7 +58,7 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); } - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU); + REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU); } /** @@ -76,9 +78,10 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD); + REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD); } /** @@ -172,9 +175,10 @@ static inline void gpio_ll_intr_disable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); } /** @@ -194,6 +198,7 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { hw->enable_w1tc.enable_w1tc = (0x1 << gpio_num); @@ -235,6 +240,22 @@ static inline void gpio_ll_od_enable(gpio_dev_t *hw, gpio_num_t gpio_num) hw->pin[gpio_num].pad_driver = 1; } +/** + * @brief Select a function for the pin in the IOMUX + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + * @param func Function to assign to the pin + */ +static inline __attribute__((always_inline)) void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t func) +{ + // Disable USB Serial JTAG if pins 18 or pins 19 needs to select an IOMUX function + if (gpio_num == 18 || gpio_num == 19) { + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); + } + PIN_FUNC_SELECT(IO_MUX_GPIO0_REG + (gpio_num * 4), func); +} + /** * @brief GPIO set output level * @@ -337,6 +358,21 @@ static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD); } +/** + * @brief Get deep sleep hold status + * + * @param hw Peripheral GPIO hardware instance address. + * + * @return + * - true deep sleep hold is enabled + * - false deep sleep hold is disabled + */ +__attribute__((always_inline)) +static inline bool gpio_ll_deep_sleep_hold_is_en(gpio_dev_t *hw) +{ + return !GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD) && GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); +} + /** * @brief Enable gpio pad hold function. * @@ -367,6 +403,24 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num) } } +/** + * @brief Get digital gpio pad hold status. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + * + * @note caller must ensure that gpio_num is a digital io pad + * + * @return + * - true digital gpio pad is held + * - false digital gpio pad is unheld + */ +__attribute__((always_inline)) +static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num) +{ + return GET_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, BIT(gpio_num)); +} + /** * @brief Set pad input to a peripheral signal through the IOMUX. * diff --git a/components/hal/esp32s2/include/hal/gpio_ll.h b/components/hal/esp32s2/include/hal/gpio_ll.h index 1056230604..f4c9c81620 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -14,6 +14,7 @@ #pragma once +#include #include "soc/soc.h" #include "soc/gpio_periph.h" #include "soc/rtc_cntl_reg.h" @@ -48,9 +49,10 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU); + REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU); } /** @@ -70,9 +72,10 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD); + REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD); } /** @@ -164,9 +167,10 @@ static inline void gpio_ll_intr_disable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); } /** @@ -186,6 +190,7 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { if (gpio_num < 32) { @@ -236,6 +241,18 @@ static inline void gpio_ll_od_enable(gpio_dev_t *hw, gpio_num_t gpio_num) hw->pin[gpio_num].pad_driver = 1; } +/** + * @brief Select a function for the pin in the IOMUX + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + * @param func Function to assign to the pin + */ +static inline __attribute__((always_inline)) void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t func) +{ + PIN_FUNC_SELECT(IO_MUX_GPIO0_REG + (gpio_num * 4), func); +} + /** * @brief GPIO set output level * @@ -349,6 +366,21 @@ static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD); } +/** + * @brief Get deep sleep hold status + * + * @param hw Peripheral GPIO hardware instance address. + * + * @return + * - true deep sleep hold is enabled + * - false deep sleep hold is disabled + */ +__attribute__((always_inline)) +static inline bool gpio_ll_deep_sleep_hold_is_en(gpio_dev_t *hw) +{ + return !GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD) && GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); +} + /** * @brief Enable gpio pad hold function. * @@ -371,6 +403,24 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num) CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]); } +/** + * @brief Get digital gpio pad hold status. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + * + * @note caller must ensure that gpio_num is a digital io pad + * + * @return + * - true digital gpio pad is held + * - false digital gpio pad is unheld + */ +__attribute__((always_inline)) +static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num) +{ + return GET_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, BIT(gpio_num - 21)); +} + /** * @brief Set pad input to a peripheral signal through the IOMUX. * diff --git a/components/hal/esp32s3/include/hal/gpio_ll.h b/components/hal/esp32s3/include/hal/gpio_ll.h index a68ff6729c..a4a2bd265b 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -14,6 +14,7 @@ #pragma once +#include #include "soc/soc.h" #include "soc/gpio_periph.h" #include "soc/rtc_cntl_reg.h" @@ -50,6 +51,7 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value @@ -60,7 +62,7 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); } - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU); + REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU); } /** @@ -80,9 +82,10 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { - REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD); + REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD); } /** @@ -177,9 +180,10 @@ static inline void gpio_ll_intr_disable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); } /** @@ -199,6 +203,7 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number */ +__attribute__((always_inline)) static inline void gpio_ll_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num) { if (gpio_num < 32) { @@ -249,6 +254,21 @@ static inline void gpio_ll_od_enable(gpio_dev_t *hw, gpio_num_t gpio_num) hw->pin[gpio_num].pad_driver = 1; } +/** + * @brief Select a function for the pin in the IOMUX + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + * @param func Function to assign to the pin + */ +static inline __attribute__((always_inline)) void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t func) +{ + if (gpio_num == 19 || gpio_num == 20) { + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); + } + PIN_FUNC_SELECT(IO_MUX_GPIO0_REG + (gpio_num * 4), func); +} + /** * @brief GPIO set output level * @@ -362,6 +382,21 @@ static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD); } +/** + * @brief Get deep sleep hold status + * + * @param hw Peripheral GPIO hardware instance address. + * + * @return + * - true deep sleep hold is enabled + * - false deep sleep hold is disabled + */ +__attribute__((always_inline)) +static inline bool gpio_ll_deep_sleep_hold_is_en(gpio_dev_t *hw) +{ + return !GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD) && GET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); +} + /** * @brief Enable gpio pad hold function. * @@ -384,6 +419,24 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num) CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]); } +/** + * @brief Get gpio pad hold status. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + * + * @note caller must ensure that gpio_num is a digital io pad + * + * @return + * - true digital gpio pad is held + * - false digital gpio pad is unheld + */ +__attribute__((always_inline)) +static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num) +{ + return GET_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, BIT(gpio_num - 21)); +} + /** * @brief Set pad input to a peripheral signal through the IOMUX. * diff --git a/components/hal/include/hal/gpio_hal.h b/components/hal/include/hal/gpio_hal.h index 018b4be128..258c6c1f08 100644 --- a/components/hal/include/hal/gpio_hal.h +++ b/components/hal/include/hal/gpio_hal.h @@ -187,6 +187,15 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, gpio_num_t gpio_num); */ #define gpio_hal_od_enable(hal, gpio_num) gpio_ll_od_enable((hal)->dev, gpio_num) +/** + * @brief Select a function for the pin in the IOMUX + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + * @param func Function to assign to the pin + */ +#define gpio_hal_func_sel(hal, gpio_num, func) gpio_ll_func_sel((hal)->dev, gpio_num, func) + /** * @brief GPIO set output level * @@ -280,6 +289,22 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, gpio_num_t gpio_num); */ #define gpio_hal_hold_dis(hal, gpio_num) gpio_ll_hold_dis((hal)->dev, gpio_num) +/** + * @brief Get wether digital gpio pad is held + * + * @param hal Context of the HAL layer + * @param gpio_num GPIO number, only support output GPIOs + * + * @note digital io means io pad powered by VDD3P3_CPU or VDD_SPI + * rtc io means io pad powered by VDD3P3_RTC + * caller must ensure that gpio_num is a digital io pad + * + * @return + * - true digital gpio pad is held + * - false digital gpio pad is unheld + */ +#define gpio_hal_is_digital_io_hold(hal, gpio_num) gpio_ll_is_digital_io_hold((hal)->dev, gpio_num) + /** * @brief Enable all digital gpio pad hold function during Deep-sleep. * @@ -300,6 +325,17 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, gpio_num_t gpio_num); */ #define gpio_hal_deep_sleep_hold_dis(hal) gpio_ll_deep_sleep_hold_dis((hal)->dev) +/** + * @brief Get whether all digital gpio pad hold function during Deep-sleep is enabled. + * + * @param hal Context of the HAL layer + * + * @return + * - true deep sleep hold is enabled + * - false deep sleep hold is disabled + */ +#define gpio_hal_deep_sleep_hold_is_en(hal) gpio_ll_deep_sleep_hold_is_en((hal)->dev) + /** * @brief Set pad input to a peripheral signal through the IOMUX. * @@ -322,7 +358,7 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, gpio_num_t gpio_num); #if SOC_GPIO_SUPPORT_FORCE_HOLD /** - * @brief Force hold digital and rtc gpio pad. + * @brief Force hold digital gpio pad. * @note GPIO force hold, whether the chip in sleep mode or wakeup mode. * * @param hal Context of the HAL layer @@ -330,7 +366,7 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, gpio_num_t gpio_num); #define gpio_hal_force_hold_all(hal) gpio_ll_force_hold_all((hal)->dev) /** - * @brief Force unhold digital and rtc gpio pad. + * @brief Force unhold digital gpio pad. * @note GPIO force unhold, whether the chip in sleep mode or wakeup mode. * * @param hal Context of the HAL layer diff --git a/components/soc/esp32/gpio_periph.c b/components/soc/esp32/gpio_periph.c index d993cb42ac..a6e130f0d0 100644 --- a/components/soc/esp32/gpio_periph.c +++ b/components/soc/esp32/gpio_periph.c @@ -13,6 +13,7 @@ // limitations under the License. #include "soc/gpio_periph.h" +#include "esp_attr.h" const uint32_t GPIO_PIN_MUX_REG[SOC_GPIO_PIN_COUNT] = { IO_MUX_GPIO0_REG, @@ -99,3 +100,46 @@ const uint32_t GPIO_HOLD_MASK[SOC_GPIO_PIN_COUNT] = { 0, 0, }; + +DRAM_ATTR const uint8_t GPIO_PIN_MUX_REG_OFFSET[] = { + 0x44, + 0x88, + 0x40, + 0x84, + 0x48, + 0x6c, + 0x60, + 0x64, + 0x68, + 0x54, + 0x58, + 0x5c, + 0x34, + 0x38, + 0x30, + 0x3c, + 0x4c, + 0x50, + 0x70, + 0x74, + 0x78, + 0x7c, + 0x80, + 0x8c, + 0xFF, // 24 + 0x24, + 0x28, + 0x2c, + 0xFF, // 28 + 0xFF, // 29 + 0xFF, // 30 + 0xFF, // 31 + 0x1c, + 0x20, + 0x14, + 0x18, + 0x04, + 0x08, + 0x0c, + 0x10, +}; diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 67007c4d70..e9b88916ac 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -131,6 +131,9 @@ // GPIO >= 34 are input only #define SOC_GPIO_VALID_OUTPUT_GPIO_MASK (SOC_GPIO_VALID_GPIO_MASK & ~(0ULL | BIT34 | BIT35 | BIT36 | BIT37 | BIT38 | BIT39)) +// digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM: 1, 3, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 21, 22, 23) +#define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0xEF0FEAULL + // Support to configure slept status #define SOC_GPIO_SUPPORT_SLP_SWITCH (1) diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 91aee64f27..520a6be6ef 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -116,6 +116,9 @@ #define SOC_GPIO_VALID_OUTPUT_GPIO_MASK SOC_GPIO_VALID_GPIO_MASK #define SOC_GPIO_DEEP_SLEEP_WAKEUP_VALID_GPIO_MASK (0ULL | BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5) +// digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_6~GPIO_NUM_21) +#define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x00000000003FFFC0ULL + // Support to configure sleep status #define SOC_GPIO_SUPPORT_SLP_SWITCH (1) diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index dfc0f64115..964f18cd27 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -102,6 +102,8 @@ #define SOC_GPIO_VALID_GPIO_MASK ((1U< Date: Mon, 26 Sep 2022 14:22:17 +0800 Subject: [PATCH 2/4] hal/gpio_ll: fix digital gpio can not disable hold during deep sleep --- components/hal/esp32c3/include/hal/gpio_ll.h | 2 +- components/hal/esp32s2/include/hal/gpio_ll.h | 2 +- components/hal/esp32s3/include/hal/gpio_ll.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/hal/esp32c3/include/hal/gpio_ll.h b/components/hal/esp32c3/include/hal/gpio_ll.h index f1f4b61349..20e65ce4fc 100644 --- a/components/hal/esp32c3/include/hal/gpio_ll.h +++ b/components/hal/esp32c3/include/hal/gpio_ll.h @@ -355,7 +355,7 @@ static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) */ static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) { - SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); } /** diff --git a/components/hal/esp32s2/include/hal/gpio_ll.h b/components/hal/esp32s2/include/hal/gpio_ll.h index f4c9c81620..29fbfb2d4e 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -363,7 +363,7 @@ static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) */ static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) { - SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); } /** diff --git a/components/hal/esp32s3/include/hal/gpio_ll.h b/components/hal/esp32s3/include/hal/gpio_ll.h index a4a2bd265b..87f746c868 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -379,7 +379,7 @@ static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) */ static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) { - SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); } /** From 6e7c8f18b9d2a81a4451704648517c641fdbca97 Mon Sep 17 00:00:00 2001 From: jingli Date: Mon, 26 Sep 2022 14:35:34 +0800 Subject: [PATCH 3/4] hal/gpio_ll: fix digital gpio can not enable hold during deep sleep when force_unhold set(32/s2/s3) --- components/hal/esp32/include/hal/gpio_ll.h | 1 + components/hal/esp32s2/include/hal/gpio_ll.h | 1 + components/hal/esp32s3/include/hal/gpio_ll.h | 1 + 3 files changed, 3 insertions(+) diff --git a/components/hal/esp32/include/hal/gpio_ll.h b/components/hal/esp32/include/hal/gpio_ll.h index c245da1ef8..7ffa3ffda7 100644 --- a/components/hal/esp32/include/hal/gpio_ll.h +++ b/components/hal/esp32/include/hal/gpio_ll.h @@ -532,6 +532,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_ */ static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) { + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD); SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); } diff --git a/components/hal/esp32s2/include/hal/gpio_ll.h b/components/hal/esp32s2/include/hal/gpio_ll.h index 29fbfb2d4e..abea490045 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -353,6 +353,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_ */ static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) { + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD); SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); } diff --git a/components/hal/esp32s3/include/hal/gpio_ll.h b/components/hal/esp32s3/include/hal/gpio_ll.h index 87f746c868..7ed456103d 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -369,6 +369,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_ */ static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) { + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD); SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M); } From ced9c9eeb679ab3edf1ecbbecce6ed137ce91a4a Mon Sep 17 00:00:00 2001 From: jingli Date: Sat, 5 Nov 2022 17:09:58 +0800 Subject: [PATCH 4/4] esp_hw_support/sleep: remove redundant spinlock protection for deep sleep --- components/esp_hw_support/sleep_modes.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index f58e51546a..791909b203 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -493,14 +493,6 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) uint32_t result; if (deep_sleep) { - /* Disable interrupts in case another task writes to RTC memory while we - * calculate RTC memory CRC - * - * Note: for ESP32-S3 running in dual core mode this is currently not enough, - * see the assert at top of this function. - */ - portENTER_CRITICAL(&spinlock_rtc_deep_sleep); - #if !CONFIG_IDF_TARGET_ESP32H2 // IDF does not officially support esp32h2 in v4.4 esp_sleep_isolate_digital_gpio(); #endif @@ -526,8 +518,6 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); #endif #endif // SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY - - portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); } else { result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu); }