diff --git a/components/driver/include/driver/rtc_io.h b/components/driver/include/driver/rtc_io.h index c7219d3eb..522a9f9b6 100644 --- a/components/driver/include/driver/rtc_io.h +++ b/components/driver/include/driver/rtc_io.h @@ -224,6 +224,24 @@ esp_err_t rtc_gpio_hold_en(gpio_num_t gpio_num); */ esp_err_t rtc_gpio_hold_dis(gpio_num_t gpio_num); +/** + * @brief Helper function to disconnect internal circuits from an RTC IO + * This function disables input, output, pullup, pulldown, and enables + * hold feature for an RTC IO. + * Use this function if an RTC IO needs to be disconnected from internal + * circuits in deep sleep, to minimize leakage current. + * + * In particular, for ESP32-WROVER module, call + * rtc_gpio_isolate(GPIO_NUM_12) before entering deep sleep, to reduce + * deep sleep current. + * + * @param gpio_num GPIO number (e.g. GPIO_NUM_12). + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if GPIO is not an RTC IO + */ +esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num); + /** * @brief Disable force hold signal for all RTC IOs * diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index 9a6b6faf1..0d3974c5c 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -381,6 +381,19 @@ esp_err_t rtc_gpio_hold_dis(gpio_num_t gpio_num) return ESP_OK; } +esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num) +{ + if (rtc_gpio_desc[gpio_num].reg == 0) { + return ESP_ERR_INVALID_ARG; + } + + rtc_gpio_pullup_dis(gpio_num); + rtc_gpio_pulldown_dis(gpio_num); + rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED); + rtc_gpio_hold_en(gpio_num); + + return ESP_OK; +} void rtc_gpio_force_hold_dis_all() { diff --git a/docs/api-reference/system/sleep_modes.rst b/docs/api-reference/system/sleep_modes.rst index 8a46c91d1..3e6d8344b 100644 --- a/docs/api-reference/system/sleep_modes.rst +++ b/docs/api-reference/system/sleep_modes.rst @@ -122,6 +122,20 @@ The following function can be used to enter deep sleep once wakeup sources are c .. doxygenfunction:: esp_deep_sleep_start +Configuring IOs +--------------- + +Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default. If an external circuit drives this pin in deep sleep mode, current consumption may increase due to current flowing through these pullups and pulldowns. + +To isolate a pin, preventing extra current draw, call :cpp:func:`rtc_gpio_isolate` function. + +For example, on ESP32-WROVER module, GPIO12 is pulled up externally. GPIO12 also has an internal pulldown in the ESP32 chip. This means that in deep sleep, some current will flow through these external and internal resistors, increasing deep sleep current above the minimal possible value. +Add the following code before :cpp:func:`esp_deep_sleep_start` to remove this extra current: + +```c++ +rtc_gpio_isolate(GPIO_NUM_12); +``` + Checking sleep wakeup cause --------------------------- diff --git a/examples/system/console/main/cmd_system.c b/examples/system/console/main/cmd_system.c index ceb5a4ac9..b65645829 100644 --- a/examples/system/console/main/cmd_system.c +++ b/examples/system/console/main/cmd_system.c @@ -155,6 +155,7 @@ static int deep_sleep(int argc, char** argv) ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup(1ULL << io_num, level) ); } + rtc_gpio_isolate(GPIO_NUM_12); esp_deep_sleep_start(); } 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 5a4f33f7b..32e4fc3fa 100644 --- a/examples/system/deep_sleep/main/deep_sleep_example_main.c +++ b/examples/system/deep_sleep/main/deep_sleep_example_main.c @@ -157,6 +157,11 @@ void app_main() esp_sleep_enable_ulp_wakeup(); #endif + // Isolate GPIO12 pin from external circuits. This is needed for modules + // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER) + // to minimize current consumption. + rtc_gpio_isolate(GPIO_NUM_12); + printf("Entering deep sleep\n"); gettimeofday(&sleep_enter_time, NULL); diff --git a/examples/system/ulp/main/ulp_example_main.c b/examples/system/ulp/main/ulp_example_main.c index 650744e88..873a17620 100644 --- a/examples/system/ulp/main/ulp_example_main.c +++ b/examples/system/ulp/main/ulp_example_main.c @@ -68,11 +68,13 @@ static void init_ulp_program() rtc_gpio_pullup_dis(gpio_num); rtc_gpio_hold_en(gpio_num); - /* Disable pullup on GPIO15, in case it is connected to ground to suppress - * boot messages. + /* Disconnect GPIO12 and GPIO15 to remove current drain through + * pullup/pulldown resistors. + * GPIO15 may be connected to ground to suppress boot messages. + * GPIO12 may be pulled high to select flash voltage. */ - rtc_gpio_pullup_dis(GPIO_NUM_15); - rtc_gpio_hold_en(GPIO_NUM_15); + rtc_gpio_isolate(GPIO_NUM_12); + rtc_gpio_isolate(GPIO_NUM_15); /* Set ULP wake up period to T = 20ms (3095 cycles of RTC_SLOW_CLK clock). * Minimum pulse width has to be T * (ulp_debounce_counter + 1) = 80ms. diff --git a/examples/system/ulp_adc/main/ulp_adc_example_main.c b/examples/system/ulp_adc/main/ulp_adc_example_main.c index 5e43ca22d..29d8eac9a 100644 --- a/examples/system/ulp_adc/main/ulp_adc_example_main.c +++ b/examples/system/ulp_adc/main/ulp_adc_example_main.c @@ -74,11 +74,13 @@ static void init_ulp_program() /* Set ULP wake up period to 20ms */ ulp_set_wakeup_period(0, 20000); - /* Disable pullup on GPIO15, in case it is connected to ground to suppress - * boot messages. + /* Disconnect GPIO12 and GPIO15 to remove current drain through + * pullup/pulldown resistors. + * GPIO15 may be connected to ground to suppress boot messages. + * GPIO12 may be pulled high to select flash voltage. */ - rtc_gpio_pullup_dis(GPIO_NUM_15); - rtc_gpio_hold_en(GPIO_NUM_15); + rtc_gpio_isolate(GPIO_NUM_12); + rtc_gpio_isolate(GPIO_NUM_15); } static void start_ulp_program()