diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index bb5db22e7d..079f41c33a 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -267,6 +267,59 @@ esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level); * the pins during sleep. HOLD feature will be acted on the pin internally * before the system entering sleep, and this can further reduce power consumption. * + * @note Call this func will reset the previous ext1 configuration. + * + * @note This function will be deprecated in release/v6.0. Please switch to use `esp_sleep_enable_ext1_wakeup_io` and `esp_sleep_disable_ext1_wakeup_io` + * + * @param io_mask Bit mask of GPIO numbers which will cause wakeup. Only GPIOs + * which have RTC functionality can be used in this bit map. + * For different SoCs, the related GPIOs are: + * - ESP32: 0, 2, 4, 12-15, 25-27, 32-39 + * - ESP32-S2: 0-21 + * - ESP32-S3: 0-21 + * - ESP32-C6: 0-7 + * - ESP32-H2: 7-14 + * @param level_mode Select logic function used to determine wakeup condition: + * When target chip is ESP32: + * - ESP_EXT1_WAKEUP_ALL_LOW: wake up when all selected GPIOs are low + * - ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high + * When target chip is ESP32-S2, ESP32-S3, ESP32-C6 or ESP32-H2: + * - ESP_EXT1_WAKEUP_ANY_LOW: wake up when any of the selected GPIOs is low + * - ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if io_mask is zero, + * or mode is invalid + */ +esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode); + +/** + * @brief Enable ext1 wakeup pins with IO masks. + * + * This will append selected IOs to the wakeup IOs, it will not reset previously enabled IOs. + * To reset specific previously enabled IOs, call esp_sleep_disable_ext1_wakeup_io with the io_mask. + * To reset all the enabled IOs, call esp_sleep_disable_ext1_wakeup_io(0). + * + * This function uses external wakeup feature of RTC controller. + * It will work even if RTC peripherals are shut down during sleep. + * + * This feature can monitor any number of pins which are in RTC IOs. + * Once selected pins go into the state given by level_mode argument, + * the chip will be woken up. + * + * @note This function does not modify pin configuration. The pins are + * configured in esp_deep_sleep_start/esp_light_sleep_start, + * immediately before entering sleep mode. + * + * @note Internal pullups and pulldowns don't work when RTC peripherals are + * shut down. In this case, external resistors need to be added. + * Alternatively, RTC peripherals (and pullups/pulldowns) may be + * kept enabled using esp_sleep_pd_config function. If we turn off the + * ``RTC_PERIPH`` domain or certain chips lack the ``RTC_PERIPH`` domain, + * we will use the HOLD feature to maintain the pull-up and pull-down on + * the pins during sleep. HOLD feature will be acted on the pin internally + * before the system entering sleep, and this can further reduce power consumption. + * * @param io_mask Bit mask of GPIO numbers which will cause wakeup. Only GPIOs * which have RTC functionality can be used in this bit map. * For different SoCs, the related GPIOs are: @@ -286,8 +339,28 @@ esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level); * - ESP_OK on success * - ESP_ERR_INVALID_ARG if any of the selected GPIOs is not an RTC GPIO, * or mode is invalid + * - ESP_ERR_NOT_SUPPORTED when wakeup level will become different between + * ext1 IOs if !SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN */ -esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode); +esp_err_t esp_sleep_enable_ext1_wakeup_io(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode); + +/** + * @brief Disable ext1 wakeup pins with IO masks. This will remove selected IOs from the wakeup IOs. + * @param io_mask Bit mask of GPIO numbers which will cause wakeup. Only GPIOs + * which have RTC functionality can be used in this bit map. + * If value is zero, this func will remove all previous ext1 configuration. + * For different SoCs, the related GPIOs are: + * - ESP32: 0, 2, 4, 12-15, 25-27, 32-39 + * - ESP32-S2: 0-21 + * - ESP32-S3: 0-21 + * - ESP32-C6: 0-7 + * - ESP32-H2: 7-14 + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if any of the selected GPIOs is not an RTC GPIO. + */ +esp_err_t esp_sleep_disable_ext1_wakeup_io(uint64_t io_mask); #if SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN /** @@ -328,6 +401,7 @@ esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_m * or mode is invalid */ esp_err_t esp_sleep_enable_ext1_wakeup_with_level_mask(uint64_t io_mask, uint64_t level_mask); + #endif // SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN #endif // SOC_PM_SUPPORT_EXT1_WAKEUP diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index c1640e840c..bdea40d337 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1541,7 +1541,19 @@ static void ext0_wakeup_prepare(void) #if SOC_PM_SUPPORT_EXT1_WAKEUP esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode) { - if (level_mode > ESP_EXT1_WAKEUP_ANY_HIGH) { + if (io_mask == 0 && level_mode > ESP_EXT1_WAKEUP_ANY_HIGH) { + return ESP_ERR_INVALID_ARG; + } + // Reset all EXT1 configs + esp_sleep_disable_ext1_wakeup_io(0); + + return esp_sleep_enable_ext1_wakeup_io(io_mask, level_mode); +} + + +esp_err_t esp_sleep_enable_ext1_wakeup_io(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode) +{ + if (io_mask == 0 && level_mode > ESP_EXT1_WAKEUP_ANY_HIGH) { return ESP_ERR_INVALID_ARG; } // Translate bit map of GPIO numbers into the bit map of RTC IO numbers @@ -1556,16 +1568,61 @@ esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_m } rtc_gpio_mask |= BIT(rtc_io_number_get(gpio)); } - s_config.ext1_rtc_gpio_mask = rtc_gpio_mask; + +#if !SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN + uint32_t ext1_rtc_gpio_mask = 0; + uint32_t ext1_trigger_mode = 0; + + ext1_rtc_gpio_mask = s_config.ext1_rtc_gpio_mask | rtc_gpio_mask; if (level_mode) { - s_config.ext1_trigger_mode = rtc_gpio_mask; + ext1_trigger_mode = s_config.ext1_trigger_mode | rtc_gpio_mask; } else { - s_config.ext1_trigger_mode = 0; + ext1_trigger_mode = s_config.ext1_trigger_mode & (~rtc_gpio_mask); + } + if (((ext1_rtc_gpio_mask & ext1_trigger_mode) != ext1_rtc_gpio_mask) && + ((ext1_rtc_gpio_mask & ext1_trigger_mode) != 0)) { + return ESP_ERR_NOT_SUPPORTED; + } +#endif + + s_config.ext1_rtc_gpio_mask |= rtc_gpio_mask; + if (level_mode) { + s_config.ext1_trigger_mode |= rtc_gpio_mask; + } else { + s_config.ext1_trigger_mode &= (~rtc_gpio_mask); } s_config.wakeup_triggers |= RTC_EXT1_TRIG_EN; return ESP_OK; } +esp_err_t esp_sleep_disable_ext1_wakeup_io(uint64_t io_mask) +{ + if (io_mask == 0) { + s_config.ext1_rtc_gpio_mask = 0; + s_config.ext1_trigger_mode = 0; + } else { + // Translate bit map of GPIO numbers into the bit map of RTC IO numbers + uint32_t rtc_gpio_mask = 0; + for (int gpio = 0; io_mask; ++gpio, io_mask >>= 1) { + if ((io_mask & 1) == 0) { + continue; + } + if (!esp_sleep_is_valid_wakeup_gpio(gpio)) { + ESP_LOGE(TAG, "Not an RTC IO Considering io_mask: GPIO%d", gpio); + return ESP_ERR_INVALID_ARG; + } + rtc_gpio_mask |= BIT(rtc_io_number_get(gpio)); + } + s_config.ext1_rtc_gpio_mask &= (~rtc_gpio_mask); + s_config.ext1_trigger_mode &= (~rtc_gpio_mask); + } + + if (s_config.ext1_rtc_gpio_mask == 0) { + s_config.wakeup_triggers &= (~RTC_EXT1_TRIG_EN); + } + return ESP_OK; +} + #if SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN esp_err_t esp_sleep_enable_ext1_wakeup_with_level_mask(uint64_t io_mask, uint64_t level_mask) { diff --git a/components/esp_pm/test_apps/esp_pm/main/test_pm.c b/components/esp_pm/test_apps/esp_pm/main/test_pm.c index a2151cc8a4..8ce499058e 100644 --- a/components/esp_pm/test_apps/esp_pm/main/test_pm.c +++ b/components/esp_pm/test_apps/esp_pm/main/test_pm.c @@ -178,7 +178,7 @@ TEST_CASE("Can wake up from automatic light sleep by GPIO", "[pm][ignore]") rtc_gpio_set_level(ext1_wakeup_gpio, 0); /* Enable wakeup */ - TEST_ESP_OK(esp_sleep_enable_ext1_wakeup(1ULL << ext1_wakeup_gpio, ESP_EXT1_WAKEUP_ANY_HIGH)); + TEST_ESP_OK(esp_sleep_enable_ext1_wakeup_io(1ULL << ext1_wakeup_gpio, ESP_EXT1_WAKEUP_ANY_HIGH)); /* To simplify test environment, we'll use a ULP program to set GPIO high */ ulp_insn_t ulp_code[] = { diff --git a/examples/system/deep_sleep/main/ext_wakeup.c b/examples/system/deep_sleep/main/ext_wakeup.c index de329b6973..9768faab21 100644 --- a/examples/system/deep_sleep/main/ext_wakeup.c +++ b/examples/system/deep_sleep/main/ext_wakeup.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -40,12 +40,10 @@ void example_deep_sleep_register_ext1_wakeup(void) printf("Enabling EXT1 wakeup on pins GPIO%d, GPIO%d\n", ext_wakeup_pin_1, ext_wakeup_pin_2); #if SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN - const uint64_t ext_wakeup_mode = CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_1 << ext_wakeup_pin_1 | \ - CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_2 << ext_wakeup_pin_2; - ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_with_level_mask(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, ext_wakeup_mode)); + ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(ext_wakeup_pin_1_mask, CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_1)); + ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(ext_wakeup_pin_2_mask, CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_2)); #else - const esp_sleep_ext1_wakeup_mode_t ext_wakeup_mode = CONFIG_EXAMPLE_EXT1_WAKEUP_MODE; - ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, ext_wakeup_mode)); + ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, CONFIG_EXAMPLE_EXT1_WAKEUP_MODE)); #endif /* If there are no external pull-up/downs, tie wakeup pins to inactive level with internal pull-up/downs via RTC IO