From 24eea75f9c13cb484ed729d557e5e9618ab06ef9 Mon Sep 17 00:00:00 2001 From: jingli Date: Fri, 16 Sep 2022 20:25:44 +0800 Subject: [PATCH 1/3] esp_hw_support/sleep: fix current leakage when hold digital io during deep sleep --- components/driver/include/driver/gpio.h | 4 +- components/esp_system/sleep_modes.c | 42 +++++++++++ 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 | 56 ++++++++++++++- 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/esp32s2/include/soc/soc_caps.h | 3 + .../soc/esp32s3/include/soc/gpio_caps.h | 2 + 12 files changed, 369 insertions(+), 16 deletions(-) diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 84b60b2a8b..1aceee29ea 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -48,7 +48,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_system/sleep_modes.c b/components/esp_system/sleep_modes.c index 4c67c5e6bf..9b538b4d50 100644 --- a/components/esp_system/sleep_modes.c +++ b/components/esp_system/sleep_modes.c @@ -27,6 +27,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "soc/soc_caps.h" +#include "soc/soc_memory_layout.h" #include "regi2c_ctrl.h" #include "driver/rtc_io.h" #include "hal/rtc_io_hal.h" @@ -40,6 +41,7 @@ #include "hal/wdt_hal.h" #include "hal/rtc_hal.h" #include "hal/uart_hal.h" +#include "hal/gpio_hal.h" #if SOC_TOUCH_SENSOR_NUM > 0 #include "hal/touch_sensor_hal.h" #include "driver/touch_sensor.h" @@ -461,6 +463,44 @@ void esp_sleep_enable_gpio_switch(bool enable) } #endif // SOC_GPIO_SUPPORT_SLP_SWITCH +static 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); + } + } +} + inline static void IRAM_ATTR misc_modules_sleep_prepare(void) { #if CONFIG_MAC_BB_PD @@ -621,6 +661,8 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) */ portENTER_CRITICAL(&spinlock_rtc_deep_sleep); + esp_sleep_isolate_digital_gpio(); + #if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP /* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */ set_rtc_memory_crc(); diff --git a/components/hal/esp32/include/hal/gpio_ll.h b/components/hal/esp32/include/hal/gpio_ll.h index 10f35353d6..c519020f86 100644 --- a/components/hal/esp32/include/hal/gpio_ll.h +++ b/components/hal/esp32/include/hal/gpio_ll.h @@ -35,6 +35,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) @@ -61,9 +64,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); } /** @@ -95,9 +99,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); } /** @@ -305,9 +310,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]); } /** @@ -327,6 +333,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) { @@ -421,6 +428,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 * @@ -534,6 +553,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. * @@ -556,6 +590,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 2baaf77e70..f89a35695c 100644 --- a/components/hal/esp32c3/include/hal/gpio_ll.h +++ b/components/hal/esp32c3/include/hal/gpio_ll.h @@ -22,13 +22,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" { @@ -56,9 +57,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); } /** @@ -78,9 +80,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); } /** @@ -174,9 +177,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)); } /** @@ -196,6 +200,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); @@ -237,6 +242,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 * @@ -339,6 +360,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. * @@ -369,6 +405,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 4d27786c3e..8f3f867db7 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -22,6 +22,7 @@ #pragma once +#include #include "soc/soc.h" #include "soc/gpio_periph.h" #include "soc/gpio_struct.h" @@ -57,9 +58,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); } /** @@ -79,9 +81,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); } /** @@ -173,9 +176,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)); } /** @@ -195,6 +199,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) { @@ -245,6 +250,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 * @@ -358,6 +375,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. * @@ -380,6 +412,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 fccbb5764e..bb9735830f 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -22,6 +22,7 @@ #pragma once +#include #include "soc/soc.h" #include "soc/gpio_periph.h" #include "soc/rtc_cntl_reg.h" @@ -56,9 +57,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); } /** @@ -78,9 +80,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); } /** @@ -175,9 +178,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)); } /** @@ -197,6 +201,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) { @@ -247,6 +252,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 * @@ -360,6 +377,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. * @@ -382,6 +414,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 b5ecd9dca2..8620e6b2cb 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -121,6 +121,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 002c506765..00547cf8b1 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -86,6 +86,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/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 0967f42e75..e970445171 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -108,6 +108,9 @@ // GPIO 46 is input only #define SOC_GPIO_VALID_OUTPUT_GPIO_MASK (SOC_GPIO_VALID_GPIO_MASK & ~(0ULL | BIT46)) +// digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_26~GPIO_NUM_46) +#define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x00007FFFFC000000ULL + // Support to configure slept status #define SOC_GPIO_SUPPORT_SLP_SWITCH (1) diff --git a/components/soc/esp32s3/include/soc/gpio_caps.h b/components/soc/esp32s3/include/soc/gpio_caps.h index e4cfb898c7..deda2e4889 100644 --- a/components/soc/esp32s3/include/soc/gpio_caps.h +++ b/components/soc/esp32s3/include/soc/gpio_caps.h @@ -32,6 +32,8 @@ extern "C" { // GPIO 46 is input only #define SOC_GPIO_VALID_OUTPUT_GPIO_MASK (SOC_GPIO_VALID_GPIO_MASK & ~(0ULL | BIT46)) +// digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_26~GPIO_NUM_48) +#define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x0001FFFFFC000000ULL #ifdef __cplusplus } From 58e9ce6fe3406f5c505f22eb16d690f0cbe25af6 Mon Sep 17 00:00:00 2001 From: jingli Date: Mon, 26 Sep 2022 14:22:17 +0800 Subject: [PATCH 2/3] 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 f89a35695c..376cfc3f0d 100644 --- a/components/hal/esp32c3/include/hal/gpio_ll.h +++ b/components/hal/esp32c3/include/hal/gpio_ll.h @@ -357,7 +357,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 8f3f867db7..fcbcdc59ed 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -372,7 +372,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 bb9735830f..7abd1b0a05 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -374,7 +374,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 b6896055a29d03168dab724d2e67010ba480308c Mon Sep 17 00:00:00 2001 From: jingli Date: Mon, 26 Sep 2022 14:35:34 +0800 Subject: [PATCH 3/3] 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 c519020f86..1a6525a3f0 100644 --- a/components/hal/esp32/include/hal/gpio_ll.h +++ b/components/hal/esp32/include/hal/gpio_ll.h @@ -540,6 +540,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 fcbcdc59ed..626b324896 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -362,6 +362,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 7abd1b0a05..4fe9c60b2b 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -364,6 +364,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); }