diff --git a/components/esp_driver_gpio/include/driver/gpio.h b/components/esp_driver_gpio/include/driver/gpio.h index 13fbe124079..ff5d452e7c0 100644 --- a/components/esp_driver_gpio/include/driver/gpio.h +++ b/components/esp_driver_gpio/include/driver/gpio.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -575,7 +575,10 @@ esp_err_t gpio_sleep_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); * * @param gpio_num GPIO number. * - * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used. + * @param intr_type GPIO wake-up type. + * - Always supported: GPIO_INTR_LOW_LEVEL, GPIO_INTR_HIGH_LEVEL + * - If SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED: + * GPIO_INTR_POSEDGE, GPIO_INTR_NEGEDGE, GPIO_INTR_ANYEDGE * * @note Called by the SDK. User shouldn't call this directly in the APP. * diff --git a/components/esp_driver_gpio/include/driver/rtc_io.h b/components/esp_driver_gpio/include/driver/rtc_io.h index 42294a8c053..5b7622100e9 100644 --- a/components/esp_driver_gpio/include/driver/rtc_io.h +++ b/components/esp_driver_gpio/include/driver/rtc_io.h @@ -309,12 +309,13 @@ esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num); /** * @brief Enable wakeup from sleep mode using specific GPIO * @param gpio_num GPIO number - * @param intr_type Wakeup on high level (GPIO_INTR_HIGH_LEVEL) or low level - * (GPIO_INTR_LOW_LEVEL) + * @param intr_type Wakeup trigger type: + * - Always supported: GPIO_INTR_HIGH_LEVEL, GPIO_INTR_LOW_LEVEL + * - If SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED: + * GPIO_INTR_POSEDGE, GPIO_INTR_NEGEDGE, GPIO_INTR_ANYEDGE * @return * - ESP_OK Success - * - ESP_ERR_INVALID_ARG The IO is not an RTC IO, or intr_type is not - * one of GPIO_INTR_HIGH_LEVEL, GPIO_INTR_LOW_LEVEL. + * - ESP_ERR_INVALID_ARG The IO is not an RTC IO, or intr_type is not supported by the target. */ esp_err_t rtc_gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type); diff --git a/components/esp_driver_gpio/src/gpio.c b/components/esp_driver_gpio/src/gpio.c index 0c0a6723ab1..9118f41f451 100644 --- a/components/esp_driver_gpio/src/gpio.c +++ b/components/esp_driver_gpio/src/gpio.c @@ -1067,10 +1067,17 @@ esp_err_t gpio_wakeup_enable_on_hp_periph_powerdown_sleep(gpio_num_t gpio_num, g ESP_LOGE(GPIO_TAG, "GPIO %d does not support wakeup on peripheral powerdown sleep", gpio_num); return ESP_ERR_INVALID_ARG; } +#if SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + if (intr_type == GPIO_INTR_DISABLE || intr_type > GPIO_INTR_HIGH_LEVEL) { + ESP_LOGE(GPIO_TAG, "invalid intr_type for wakeup, gpio_num:%u", gpio_num); + return ESP_ERR_INVALID_ARG; + } +#else if ((intr_type != GPIO_INTR_LOW_LEVEL) && (intr_type != GPIO_INTR_HIGH_LEVEL)) { ESP_LOGE(GPIO_TAG, "GPIO wakeup only supports level mode, but edge mode set. gpio_num:%u", gpio_num); return ESP_ERR_INVALID_ARG; } +#endif portENTER_CRITICAL(&gpio_context.gpio_spinlock); #if SOC_LP_IO_CLOCK_IS_INDEPENDENT io_mux_enable_lp_io_clock(gpio_num, true); diff --git a/components/esp_driver_gpio/src/rtc_io.c b/components/esp_driver_gpio/src/rtc_io.c index b312de316ad..ec5c9d4c697 100644 --- a/components/esp_driver_gpio/src/rtc_io.c +++ b/components/esp_driver_gpio/src/rtc_io.c @@ -16,9 +16,6 @@ #include "hal/rtc_io_hal.h" #include "hal/rtc_io_periph.h" #include "soc/soc_caps.h" -#if SOC_RTCIO_PIN_COUNT > 0 -#include "hal/rtc_gpio_caps.h" -#endif #if SOC_LP_GPIO_MATRIX_SUPPORTED #include "soc/lp_gpio_pins.h" #endif @@ -320,11 +317,11 @@ esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num) esp_err_t rtc_gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type) { ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "RTCIO number error"); -#if !RTC_GPIO_CAPS_GET(EDGE_WAKEUP_SUPPORTED) +#if !SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED if (intr_type == GPIO_INTR_POSEDGE || intr_type == GPIO_INTR_NEGEDGE || intr_type == GPIO_INTR_ANYEDGE) { return ESP_ERR_INVALID_ARG; // Dont support this mode. } -#endif //!RTC_GPIO_CAPS_GET(EDGE_WAKEUP_SUPPORTED) +#endif //!SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED RTCIO_ENTER_CRITICAL(); rtcio_hal_wakeup_enable(rtc_io_number_get(gpio_num), intr_type); RTCIO_EXIT_CRITICAL(); diff --git a/components/esp_hal_gpio/esp32c5/include/hal/rtc_gpio_caps.h b/components/esp_hal_gpio/esp32c5/include/hal/rtc_gpio_caps.h index 0aebcd28f56..340f7a22c7c 100644 --- a/components/esp_hal_gpio/esp32c5/include/hal/rtc_gpio_caps.h +++ b/components/esp_hal_gpio/esp32c5/include/hal/rtc_gpio_caps.h @@ -7,5 +7,3 @@ #pragma once #define RTC_GPIO_CAPS_GET(_attr) _RTC_GPIO_ ## _attr - -#define _RTC_GPIO_EDGE_WAKEUP_SUPPORTED 1 diff --git a/components/esp_hal_gpio/esp32c5/include/hal/rtc_io_ll.h b/components/esp_hal_gpio/esp32c5/include/hal/rtc_io_ll.h index 0248e415bd4..22c0461ff31 100644 --- a/components/esp_hal_gpio/esp32c5/include/hal/rtc_io_ll.h +++ b/components/esp_hal_gpio/esp32c5/include/hal/rtc_io_ll.h @@ -344,6 +344,16 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_GPIO.pinn[rtcio_num].pinn_int_type = 0; } +/** + * Clear edge-wakeup latch. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_clear_edge_wakeup_latch(int rtcio_num) +{ + LP_GPIO.pinn[rtcio_num].pinn_edge_wakeup_clr = 1; +} + /** * Enable interrupt function and set interrupt type * diff --git a/components/esp_hal_gpio/esp32c6/include/hal/rtc_gpio_caps.h b/components/esp_hal_gpio/esp32c6/include/hal/rtc_gpio_caps.h index 0aebcd28f56..340f7a22c7c 100644 --- a/components/esp_hal_gpio/esp32c6/include/hal/rtc_gpio_caps.h +++ b/components/esp_hal_gpio/esp32c6/include/hal/rtc_gpio_caps.h @@ -7,5 +7,3 @@ #pragma once #define RTC_GPIO_CAPS_GET(_attr) _RTC_GPIO_ ## _attr - -#define _RTC_GPIO_EDGE_WAKEUP_SUPPORTED 1 diff --git a/components/esp_hal_gpio/esp32c6/include/hal/rtc_io_ll.h b/components/esp_hal_gpio/esp32c6/include/hal/rtc_io_ll.h index a1551cd865f..956eaa26a3e 100644 --- a/components/esp_hal_gpio/esp32c6/include/hal/rtc_io_ll.h +++ b/components/esp_hal_gpio/esp32c6/include/hal/rtc_io_ll.h @@ -341,6 +341,16 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_IO.pin[rtcio_num].int_type = 0; } +/** + * Clear edge-wakeup latch. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_clear_edge_wakeup_latch(int rtcio_num) +{ + LP_IO.pin[rtcio_num].edge_wakeup_clr = 1; +} + /** * Enable interrupt function and set interrupt type * diff --git a/components/esp_hal_gpio/esp32c61/include/hal/rtc_gpio_caps.h b/components/esp_hal_gpio/esp32c61/include/hal/rtc_gpio_caps.h index 0aebcd28f56..340f7a22c7c 100644 --- a/components/esp_hal_gpio/esp32c61/include/hal/rtc_gpio_caps.h +++ b/components/esp_hal_gpio/esp32c61/include/hal/rtc_gpio_caps.h @@ -7,5 +7,3 @@ #pragma once #define RTC_GPIO_CAPS_GET(_attr) _RTC_GPIO_ ## _attr - -#define _RTC_GPIO_EDGE_WAKEUP_SUPPORTED 1 diff --git a/components/esp_hal_gpio/esp32c61/include/hal/rtc_io_ll.h b/components/esp_hal_gpio/esp32c61/include/hal/rtc_io_ll.h index db0ced69ea9..a1a1f79b971 100644 --- a/components/esp_hal_gpio/esp32c61/include/hal/rtc_io_ll.h +++ b/components/esp_hal_gpio/esp32c61/include/hal/rtc_io_ll.h @@ -334,6 +334,16 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_GPIO.pinn[rtcio_num].pinn_int_type = 0; } +/** + * Clear edge-wakeup latch. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_clear_edge_wakeup_latch(int rtcio_num) +{ + LP_GPIO.pinn[rtcio_num].pinn_edge_wakeup_clr = 1; +} + /** * @brief Enable interrupt function and set interrupt type * diff --git a/components/esp_hal_gpio/esp32h4/include/hal/rtc_gpio_caps.h b/components/esp_hal_gpio/esp32h4/include/hal/rtc_gpio_caps.h index 0aebcd28f56..340f7a22c7c 100644 --- a/components/esp_hal_gpio/esp32h4/include/hal/rtc_gpio_caps.h +++ b/components/esp_hal_gpio/esp32h4/include/hal/rtc_gpio_caps.h @@ -7,5 +7,3 @@ #pragma once #define RTC_GPIO_CAPS_GET(_attr) _RTC_GPIO_ ## _attr - -#define _RTC_GPIO_EDGE_WAKEUP_SUPPORTED 1 diff --git a/components/esp_hal_gpio/esp32h4/include/hal/rtc_io_ll.h b/components/esp_hal_gpio/esp32h4/include/hal/rtc_io_ll.h index 1e18cc7f8a4..bacde507910 100644 --- a/components/esp_hal_gpio/esp32h4/include/hal/rtc_io_ll.h +++ b/components/esp_hal_gpio/esp32h4/include/hal/rtc_io_ll.h @@ -334,6 +334,16 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_GPIO.pinn[rtcio_num].pinn_int_type = 0; } +/** + * Clear edge-wakeup latch. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_clear_edge_wakeup_latch(int rtcio_num) +{ + LP_GPIO.pinn[rtcio_num].pinn_edge_wakeup_clr = 1; +} + /** * @brief Enable interrupt function and set interrupt type * diff --git a/components/esp_hal_gpio/esp32p4/include/hal/rtc_gpio_caps.h b/components/esp_hal_gpio/esp32p4/include/hal/rtc_gpio_caps.h index 0aebcd28f56..340f7a22c7c 100644 --- a/components/esp_hal_gpio/esp32p4/include/hal/rtc_gpio_caps.h +++ b/components/esp_hal_gpio/esp32p4/include/hal/rtc_gpio_caps.h @@ -7,5 +7,3 @@ #pragma once #define RTC_GPIO_CAPS_GET(_attr) _RTC_GPIO_ ## _attr - -#define _RTC_GPIO_EDGE_WAKEUP_SUPPORTED 1 diff --git a/components/esp_hal_gpio/esp32p4/include/hal/rtc_io_ll.h b/components/esp_hal_gpio/esp32p4/include/hal/rtc_io_ll.h index d61d6116d73..596fa274bb9 100644 --- a/components/esp_hal_gpio/esp32p4/include/hal/rtc_io_ll.h +++ b/components/esp_hal_gpio/esp32p4/include/hal/rtc_io_ll.h @@ -404,6 +404,16 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_GPIO.pin[rtcio_num].int_type = 0; } +/** + * Clear edge-wakeup latch. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_clear_edge_wakeup_latch(int rtcio_num) +{ + LP_GPIO.pin[rtcio_num].edge_wakeup_clr = 1; +} + /** * Enable interrupt function and set interrupt type * diff --git a/components/esp_hal_gpio/esp32s31/include/hal/rtc_gpio_caps.h b/components/esp_hal_gpio/esp32s31/include/hal/rtc_gpio_caps.h index 8fcac029b16..8d990695c15 100644 --- a/components/esp_hal_gpio/esp32s31/include/hal/rtc_gpio_caps.h +++ b/components/esp_hal_gpio/esp32s31/include/hal/rtc_gpio_caps.h @@ -7,5 +7,3 @@ #pragma once #define RTC_GPIO_CAPS_GET(_attr) _RTC_GPIO_ ## _attr - -#define _RTC_GPIO_EDGE_WAKEUP_SUPPORTED 1 diff --git a/components/esp_hal_gpio/esp32s31/include/hal/rtc_io_ll.h b/components/esp_hal_gpio/esp32s31/include/hal/rtc_io_ll.h index 407ee0e3a45..5d0937f6846 100644 --- a/components/esp_hal_gpio/esp32s31/include/hal/rtc_io_ll.h +++ b/components/esp_hal_gpio/esp32s31/include/hal/rtc_io_ll.h @@ -333,6 +333,16 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_GPIO.pinn[rtcio_num].pinn_int_type = 0; } +/** + * Clear edge-wakeup latch. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_clear_edge_wakeup_latch(int rtcio_num) +{ + LP_GPIO.pinn[rtcio_num].pinn_edge_wakeup_clr = 1; +} + /** * @brief Enable interrupt function and set interrupt type * diff --git a/components/esp_hal_gpio/include/hal/rtc_io_hal.h b/components/esp_hal_gpio/include/hal/rtc_io_hal.h index b86dfa9c13f..e27792c8c28 100644 --- a/components/esp_hal_gpio/include/hal/rtc_io_hal.h +++ b/components/esp_hal_gpio/include/hal/rtc_io_hal.h @@ -320,6 +320,20 @@ void rtcio_hal_isolate(int rtcio_num); #define rtc_hal_gpio_get_wakeup_status() rtcio_hal_get_interrupt_status() #define rtc_hal_gpio_clear_wakeup_status() rtcio_hal_clear_interrupt_status() +#if SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED +/** + * @brief Clear the latched edge-wakeup state for a GPIO that is enabled for + * peripheral-powerdown-sleep wakeup in edge mode. + * + * Must be called before entering sleep on every pin configured for posedge/negedge/anyedge + * wakeup, otherwise a stale latched edge would immediately wake the chip. + * + * @param hal Context of the HAL layer (unused, kept for API symmetry). + * @param gpio_num GPIO number. + */ +#define gpio_hal_clear_hp_periph_pd_sleep_edge_wakeup_latch(hal, gpio_num) rtcio_ll_clear_edge_wakeup_latch(rtc_io_num_map[gpio_num]) +#endif //SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + /** * @brief Get the status of whether an IO is used for sleep wake-up. * diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index cc331c851dc..8d0941435d7 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -44,8 +44,15 @@ typedef enum { #if SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP typedef enum { ESP_GPIO_WAKEUP_GPIO_LOW = 0, - ESP_GPIO_WAKEUP_GPIO_HIGH = 1 + ESP_GPIO_WAKEUP_GPIO_HIGH = 1, +#if SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + ESP_GPIO_WAKEUP_GPIO_POSEDGE = 2, + ESP_GPIO_WAKEUP_GPIO_NEGEDGE = 3, + ESP_GPIO_WAKEUP_GPIO_ANYEDGE = 4, +#endif } esp_sleep_gpio_wake_up_mode_t; + +#define WAKEUP_MODE_2_INT_TYPE(mode) ((gpio_int_type_t)((0x32154 >> ((mode) * 4)) & 0xF)) #endif /** @@ -482,11 +489,14 @@ __attribute__((deprecated("please use 'esp_sleep_enable_ext1_wakeup_io' and 'esp * and external resistors may cause interference. BTW, when you use low level to wake up the * chip, we strongly recommend you to add external resistors (pull-up). * + * @note The wakeup signal must be held (level mode) or have a pulse width (edge mode) + * of at least 3 RTC slow-clock cycles to be reliably sampled by the wakeup logic. + * The duration of one slow-clock cycle depends on `CONFIG_RTC_CLK_SRC` (e.g. + * RC_SLOW @ ~136 kHz ~= 7.4 us/cycle, XTAL32K @ 32.768 kHz ~= 30.5 us/cycle). + * * @param gpio_pin_mask Bit mask of GPIO numbers which will cause wakeup. Only GPIOs * which have RTC functionality (pads that powered by VDD3P3_RTC) can be used in this bit map. - * @param mode Select logic function used to determine wakeup condition: - * - ESP_GPIO_WAKEUP_GPIO_LOW: wake up when the gpio turn to low. - * - ESP_GPIO_WAKEUP_GPIO_HIGH: wake up when the gpio turn to high. + * @param mode Wakeup condition, see esp_sleep_gpio_wake_up_mode_t. * @return * - ESP_OK on success * - ESP_ERR_INVALID_ARG if the mask contains any invalid wakeup pin or wakeup mode is invalid diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 5781683bfeb..91c349b6f38 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -301,7 +301,7 @@ typedef struct { #endif #if SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP uint64_t gpio_wakeup_mask; - uint64_t gpio_trigger_mode; + uint8_t gpio_trigger_mode[SOC_GPIO_PIN_COUNT]; #endif uint32_t sleep_time_adjustment; uint32_t ccount_ticks_record; @@ -315,7 +315,6 @@ typedef struct { bool overhead_out_need_remeasure; } sleep_config_t; - #if CONFIG_ESP_SLEEP_DEBUG static esp_sleep_context_t *s_sleep_ctx = NULL; @@ -1782,7 +1781,7 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source) } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_GPIO, RTC_GPIO_TRIG_EN)) { #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP s_config.gpio_wakeup_mask = 0; - s_config.gpio_trigger_mode = 0; + memset(s_config.gpio_trigger_mode, 0, sizeof(s_config.gpio_trigger_mode)); #endif s_config.wakeup_triggers &= ~RTC_GPIO_TRIG_EN; } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_UART0, RTC_UART0_TRIG_EN)) { @@ -2260,18 +2259,28 @@ static void esp_sleep_gpio_wakeup_prepare_on_hp_periph_powerdown(void) int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); rtcio_ll_enable_io_clock(true); #endif + __attribute__ ((unused)) gpio_int_type_t intr_type = (gpio_int_type_t)s_config.gpio_trigger_mode[gpio_idx]; #if CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS if (GPIO_IS_VALID_OUTPUT_GPIO(gpio_idx)) { - if (s_config.gpio_trigger_mode & BIT(gpio_idx)) { + if (intr_type == GPIO_INTR_LOW_LEVEL || intr_type == GPIO_INTR_NEGEDGE) { + gpio_pullup_en(gpio_idx); + gpio_pulldown_dis(gpio_idx); + } else if (intr_type == GPIO_INTR_HIGH_LEVEL || intr_type == GPIO_INTR_POSEDGE) { gpio_pullup_dis(gpio_idx); gpio_pulldown_en(gpio_idx); } else { - gpio_pullup_en(gpio_idx); + gpio_pullup_dis(gpio_idx); gpio_pulldown_dis(gpio_idx); } } else { ESP_EARLY_LOGE(TAG, "GPIO%d not support internal PU/PD", gpio_idx); } +#endif +#if SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + /* Clear any pending edge-wakeup latch so a stale event does not immediately re-wake the chip. */ + if (intr_type == GPIO_INTR_POSEDGE || intr_type == GPIO_INTR_NEGEDGE || intr_type == GPIO_INTR_ANYEDGE) { + gpio_hal_clear_hp_periph_pd_sleep_edge_wakeup_latch(NULL, gpio_idx); + } #endif ESP_ERROR_CHECK(gpio_hold_en(gpio_idx)); valid_wake_io_mask &= valid_wake_io_mask - 1; @@ -2282,14 +2291,20 @@ static void esp_sleep_gpio_wakeup_prepare_on_hp_periph_powerdown(void) esp_err_t esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(uint64_t gpio_pin_mask, esp_sleep_gpio_wake_up_mode_t mode) { - if (mode > ESP_GPIO_WAKEUP_GPIO_HIGH) { - ESP_LOGE(TAG, "invalid mode"); - return ESP_ERR_INVALID_ARG; - } if (gpio_pin_mask == 0) { return ESP_ERR_INVALID_ARG; } - gpio_int_type_t intr_type = ((mode == ESP_GPIO_WAKEUP_GPIO_LOW) ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL); + const gpio_int_type_t intr_type = WAKEUP_MODE_2_INT_TYPE(mode); + if (intr_type == GPIO_INTR_DISABLE || intr_type > GPIO_INTR_HIGH_LEVEL) { + ESP_LOGE(TAG, "invalid mode"); + return ESP_ERR_INVALID_ARG; + } +#if !SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + if (intr_type != GPIO_INTR_LOW_LEVEL && intr_type != GPIO_INTR_HIGH_LEVEL) { + ESP_LOGE(TAG, "invalid mode"); + return ESP_ERR_INVALID_ARG; + } +#endif esp_err_t err = ESP_OK; uint64_t invalid_io_mask = gpio_pin_mask & ~SOC_GPIO_HP_PERIPH_PD_SLEEP_WAKEABLE_MASK; @@ -2306,11 +2321,7 @@ esp_err_t esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(uint64_t gpio_pin_ err = gpio_wakeup_enable_on_hp_periph_powerdown_sleep(gpio_idx, intr_type); if (err != ESP_OK) return err; s_config.gpio_wakeup_mask |= BIT64(gpio_idx); - if (mode == ESP_GPIO_WAKEUP_GPIO_HIGH) { - s_config.gpio_trigger_mode |= BIT64(gpio_idx); - } else { - s_config.gpio_trigger_mode &= ~BIT64(gpio_idx); - } + s_config.gpio_trigger_mode[gpio_idx] = (uint8_t)intr_type; gpio_pin_mask &= gpio_pin_mask - 1; } s_config.wakeup_triggers |= RTC_GPIO_TRIG_EN; diff --git a/components/esp_hw_support/test_apps/.build-test-rules.yml b/components/esp_hw_support/test_apps/.build-test-rules.yml index d5055d19b78..d7b2f899479 100644 --- a/components/esp_hw_support/test_apps/.build-test-rules.yml +++ b/components/esp_hw_support/test_apps/.build-test-rules.yml @@ -114,6 +114,6 @@ components/esp_hw_support/test_apps/wakeup_tests: - esp_hw_support - soc disable_test: - - if: IDF_TARGET in ["esp32h21", "esp32h4"] + - if: IDF_TARGET in ["esp32h21"] temporary: true reason: lack of runners diff --git a/components/esp_hw_support/test_apps/wakeup_tests/main/src/io_wakeup_cmd.c b/components/esp_hw_support/test_apps/wakeup_tests/main/src/io_wakeup_cmd.c index e516c4d49b1..095cf13a24a 100644 --- a/components/esp_hw_support/test_apps/wakeup_tests/main/src/io_wakeup_cmd.c +++ b/components/esp_hw_support/test_apps/wakeup_tests/main/src/io_wakeup_cmd.c @@ -8,6 +8,7 @@ #include "unity_test_utils.h" #include "test_utils.h" #include "esp_sleep.h" +#include "soc/soc_caps.h" #include "driver/gpio.h" #include "hal/gpio_ll.h" #include "esp_console.h" @@ -84,7 +85,7 @@ static struct { static int process_ext1_wakeup(int argc, char **argv) { int nerrors = arg_parse(argc, argv, (void **) &ext1_wakeup_args); - int io_wakeup_num = 0, io_wakeup_level = 0; + int io_wakeup_num = 0, io_wakeup_type = 0; if (nerrors != 0) { arg_print_errors(stderr, ext1_wakeup_args.end, argv[0]); return 1; @@ -100,21 +101,21 @@ static int process_ext1_wakeup(int argc, char **argv) if (ext1_wakeup_args.mode->count) { if (ext1_wakeup_args.mode->count == 1) { - io_wakeup_level = ext1_wakeup_args.mode->ival[0]; + io_wakeup_type = ext1_wakeup_args.mode->ival[0]; } else { ESP_LOGE(TAG, "no valid arguments"); return 1; } } - ESP_LOGI(TAG, "io_wakeup_level = %d\n", io_wakeup_level); + ESP_LOGI(TAG, "io_wakeup_type = %d\n", io_wakeup_type); if (ext1_wakeup_args.disable->count) { ESP_ERROR_CHECK(esp_sleep_disable_ext1_wakeup_io(1ULL << io_wakeup_num)); } else { #if CONFIG_IDF_TARGET_ESP32 - ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(1ULL << io_wakeup_num, io_wakeup_level == 0 ? ESP_EXT1_WAKEUP_ALL_LOW : ESP_EXT1_WAKEUP_ANY_HIGH)); + ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(1ULL << io_wakeup_num, io_wakeup_type == 0 ? ESP_EXT1_WAKEUP_ALL_LOW : ESP_EXT1_WAKEUP_ANY_HIGH)); #else - ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(1ULL << io_wakeup_num, io_wakeup_level == 0 ? ESP_EXT1_WAKEUP_ANY_LOW : ESP_EXT1_WAKEUP_ANY_HIGH)); + ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_io(1ULL << io_wakeup_num, io_wakeup_type == 0 ? ESP_EXT1_WAKEUP_ANY_LOW : ESP_EXT1_WAKEUP_ANY_HIGH)); #endif } return 0; @@ -151,7 +152,7 @@ static struct { static int process_rtcio_wakeup(int argc, char **argv) { int nerrors = arg_parse(argc, argv, (void **) &rtcio_wakeup_args); - int io_wakeup_num = 0, io_wakeup_level = 0; + int io_wakeup_num = 0, io_wakeup_type = 0; if (nerrors != 0) { arg_print_errors(stderr, rtcio_wakeup_args.end, argv[0]); return 1; @@ -167,13 +168,13 @@ static int process_rtcio_wakeup(int argc, char **argv) if (rtcio_wakeup_args.level->count) { if (rtcio_wakeup_args.level->count == 1) { - io_wakeup_level = rtcio_wakeup_args.level->ival[0]; + io_wakeup_type = rtcio_wakeup_args.level->ival[0]; } else { ESP_LOGE(TAG, "no valid arguments"); return 1; } } - ESP_LOGI(TAG, "io_wakeup_level = %d\n", io_wakeup_level); + ESP_LOGI(TAG, "io_wakeup_type = %d\n", io_wakeup_type); if (rtcio_wakeup_args.disable->count) { ESP_ERROR_CHECK(gpio_wakeup_disable_on_hp_periph_powerdown_sleep(io_wakeup_num)); @@ -187,8 +188,8 @@ static int process_rtcio_wakeup(int argc, char **argv) }; ESP_ERROR_CHECK(gpio_config(&config)); - /* Enable wake up from GPIO */ - ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(BIT64(io_wakeup_num), io_wakeup_level)); + esp_sleep_gpio_wake_up_mode_t mode = (esp_sleep_gpio_wake_up_mode_t)io_wakeup_type; + ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(BIT64(io_wakeup_num), mode)); } return 0; @@ -199,7 +200,12 @@ static void register_rtcio_wakeup(void) rtcio_wakeup_args.pin = arg_int0("p", "pin", "", "configure the rtcio wakeup pin num"); rtcio_wakeup_args.level = - arg_int0("l", "level", "", "configure the rtcio wakeup level"); + arg_int0("l", "level", "", + "esp_sleep_gpio_wake_up_mode_t: 0=LOW, 1=HIGH" +#if SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + ", 2=POSEDGE, 3=NEGEDGE, 4=ANYEDGE" +#endif + ); rtcio_wakeup_args.disable = arg_lit0("d", "disable", "disable the rtcio wakeup on certain pin"); rtcio_wakeup_args.end = arg_end(4); @@ -225,7 +231,7 @@ static struct { static int process_gpio_wakeup(int argc, char **argv) { int nerrors = arg_parse(argc, argv, (void **) &gpio_wakeup_args); - int io_wakeup_num = 0, io_wakeup_level = 0; + int io_wakeup_num = 0, io_wakeup_type = 0; if (nerrors != 0) { arg_print_errors(stderr, gpio_wakeup_args.end, argv[0]); return 1; @@ -241,13 +247,13 @@ static int process_gpio_wakeup(int argc, char **argv) if (gpio_wakeup_args.level->count) { if (gpio_wakeup_args.level->count == 1) { - io_wakeup_level = gpio_wakeup_args.level->ival[0]; + io_wakeup_type = gpio_wakeup_args.level->ival[0]; } else { ESP_LOGE(TAG, "no valid arguments"); return 1; } } - ESP_LOGI(TAG, "io_wakeup_level = %d\n", io_wakeup_level); + ESP_LOGI(TAG, "io_wakeup_type = %d\n", io_wakeup_type); if (gpio_wakeup_args.disable->count) { ESP_ERROR_CHECK(gpio_wakeup_disable(io_wakeup_num)); @@ -258,12 +264,12 @@ static int process_gpio_wakeup(int argc, char **argv) .mode = GPIO_MODE_INPUT, .pull_down_en = GPIO_PULLDOWN_DISABLE, .pull_up_en = GPIO_PULLUP_DISABLE, - .intr_type = (io_wakeup_level == 0) ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL + .intr_type = (io_wakeup_type == 0) ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL }; ESP_ERROR_CHECK(gpio_config(&config)); /* Enable wake up from GPIO */ - ESP_ERROR_CHECK(gpio_wakeup_enable(io_wakeup_num, io_wakeup_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL)); + ESP_ERROR_CHECK(gpio_wakeup_enable(io_wakeup_num, io_wakeup_type == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL)); ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup()); } diff --git a/components/esp_hw_support/test_apps/wakeup_tests/pytest_wakeup_tests.py b/components/esp_hw_support/test_apps/wakeup_tests/pytest_wakeup_tests.py index aa15087842a..33c0f0e73d0 100644 --- a/components/esp_hw_support/test_apps/wakeup_tests/pytest_wakeup_tests.py +++ b/components/esp_hw_support/test_apps/wakeup_tests/pytest_wakeup_tests.py @@ -24,8 +24,14 @@ available_gpio_nums = { + [28, 29, 30, 31, 32, 33, 36, 49, 50, 51, 52, 53, 54], 'esp32c5': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 23, 24, 25, 26], 'esp32c61': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 22, 23, 24, 25, 26, 27, 28, 29], + 'esp32h4': [0, 1, 2, 3, 4, 5, 15, 16, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39], + 'esp32s31': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] + + [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57], } +# Matches SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED in soc_caps.h (HP-periph PD GPIO wakeup edge) +RTC_GPIO_EDGE_HP_PD_TARGETS = frozenset({'esp32c5', 'esp32c6', 'esp32c61', 'esp32p4', 'esp32h4'}) + available_rtcio_nums = { 'esp32': [36, 37, 38, 39, 34, 35, 25, 26, 33, 32, 4, 0, 2, 15, 13, 12, 14, 27], 'esp32s2': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], @@ -37,6 +43,8 @@ available_rtcio_nums = { 'esp32p4': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 'esp32c5': [0, 1, 2, 3, 4, 5, 6], 'esp32c61': [0, 1, 2, 3, 4, 5, 6], + 'esp32h4': [0, 1, 2, 3, 4, 5], + 'esp32s31': [0, 1, 2, 3, 4, 5, 6, 7], } @@ -48,7 +56,6 @@ available_rtcio_nums = { soc_filtered_targets('SOC_PM_SUPPORT_EXT1_WAKEUP == 1 and SOC_DEEP_SLEEP_SUPPORTED == 1'), indirect=['target'], ) -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='lack of multi-device runners') # TODO: IDFCI-10702 def test_ext1_deepsleep(dut: tuple[IdfDut, IdfDut]) -> None: wakee = dut[0] waker = dut[1] @@ -67,7 +74,7 @@ def test_ext1_deepsleep(dut: tuple[IdfDut, IdfDut]) -> None: wakee.expect('io_wakeup_test>', timeout=10) wakee.write(f'ext1 -p {gpio_num} -m {wakeup_level}') wakee.expect(f'io_wakeup_num = {gpio_num}', timeout=10) - wakee.expect(f'io_wakeup_level = {wakeup_level}', timeout=10) + wakee.expect(f'io_wakeup_type = {wakeup_level}', timeout=10) waker.expect('io_wakeup_test>', timeout=10) sleep_level = 1 - wakeup_level @@ -100,7 +107,6 @@ def test_ext1_deepsleep(dut: tuple[IdfDut, IdfDut]) -> None: @pytest.mark.parametrize('count', [2], indirect=True) @pytest.mark.parametrize('config', TEST_CONFIGS, indirect=True) @idf_parametrize('target', soc_filtered_targets('SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP == 1'), indirect=['target']) -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='lack of multi-device runners') # TODO: IDFCI-10702 def test_rtcio_deepsleep(dut: tuple[IdfDut, IdfDut]) -> None: wakee = dut[0] waker = dut[1] @@ -109,7 +115,21 @@ def test_rtcio_deepsleep(dut: tuple[IdfDut, IdfDut]) -> None: gpio_nums = available_gpio_nums.get(chip_type, []) rtcio_nums = available_rtcio_nums.get(chip_type, []) - for wakeup_level in [0, 1]: + # Modes: 0=LOW, 1=HIGH, 2=POSEDGE, 3=NEGEDGE, 4=ANYEDGE + # Tuple: (esp_sleep_gpio_wake_up_mode_t as int, waker_level_before_sleep, waker_level_to_wake) + dslp_io_wakeup_cases = [ + (0, 1, 0), # low level: hold high, then pull low + (1, 0, 1), # high level: hold low, then drive high + ] + if chip_type in RTC_GPIO_EDGE_HP_PD_TARGETS: + dslp_io_wakeup_cases += [ + (2, 0, 1), # posedge: low then rising edge + (3, 1, 0), # negedge: high then falling edge + (4, 0, 1), # anyedge: rising edge from low + (4, 1, 0), # anyedge: falling edge from high + ] + + for wakeup_mode, prep_level, wake_level in dslp_io_wakeup_cases: for gpio_num in rtcio_nums: if gpio_num not in gpio_nums: continue @@ -117,23 +137,22 @@ def test_rtcio_deepsleep(dut: tuple[IdfDut, IdfDut]) -> None: wakee.write('\r\n') sleep(0.1) wakee.expect('io_wakeup_test>', timeout=10) - wakee.write(f'rtcio -p {gpio_num} -l {wakeup_level}') + wakee.write(f'rtcio -p {gpio_num} -l {wakeup_mode}') wakee.expect(f'io_wakeup_num = {gpio_num}', timeout=10) - wakee.expect(f'io_wakeup_level = {wakeup_level}', timeout=10) + wakee.expect(f'io_wakeup_type = {wakeup_mode}', timeout=10) waker.expect('io_wakeup_test>', timeout=10) - sleep_level = 1 - wakeup_level - waker.write(f'gpio_control -p {gpio_num} -l {sleep_level}') + waker.write(f'gpio_control -p {gpio_num} -l {prep_level}') waker.expect(f'io_num = {gpio_num}', timeout=10) - waker.expect(f'io_level = {sleep_level}', timeout=10) + waker.expect(f'io_level = {prep_level}', timeout=10) wakee.write('sleep -m 1') wakee.expect('enter deep sleep', timeout=10) sleep(2) - waker.write(f'gpio_control -p {gpio_num} -l {wakeup_level}') + waker.write(f'gpio_control -p {gpio_num} -l {wake_level}') waker.expect(f'io_num = {gpio_num}', timeout=10) - waker.expect(f'io_level = {wakeup_level}', timeout=10) + waker.expect(f'io_level = {wake_level}', timeout=10) wakee.expect('io_wakeup_test>', timeout=10) wakee.write('cause') @@ -146,8 +165,6 @@ def test_rtcio_deepsleep(dut: tuple[IdfDut, IdfDut]) -> None: @pytest.mark.parametrize('count', [2], indirect=True) @pytest.mark.parametrize('config', TEST_CONFIGS, indirect=True) @idf_parametrize('target', ['supported_targets'], indirect=['target']) -@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='bringup on this module is not done') -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='lack of multi-device runners') # TODO: IDFCI-10702 def test_gpio_wakeup_enable_lightsleep(dut: tuple[IdfDut, IdfDut]) -> None: wakee = dut[0] waker = dut[1] @@ -161,7 +178,7 @@ def test_gpio_wakeup_enable_lightsleep(dut: tuple[IdfDut, IdfDut]) -> None: wakee.expect('io_wakeup_test>', timeout=10) wakee.write(f'gpio -p {gpio_num} -l {wakeup_level}') wakee.expect(f'io_wakeup_num = {gpio_num}', timeout=10) - wakee.expect(f'io_wakeup_level = {wakeup_level}', timeout=10) + wakee.expect(f'io_wakeup_type = {wakeup_level}', timeout=10) waker.expect('io_wakeup_test>', timeout=10) sleep_level = 1 - wakeup_level diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 88abeed5316..afbcf6fb0e7 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -579,6 +579,10 @@ config SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP bool default y +config SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + bool + default y + config SOC_LP_IO_CLOCK_IS_INDEPENDENT bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 43814f52316..70e68f00dbf 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -227,6 +227,7 @@ // GPIO0~7 on ESP32C5 can support chip HP peripheral powerdown-ed sleep wakeup #define SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP (1) #define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP +#define SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED (1) // LP IO peripherals have independent clock gating to manage #define SOC_LP_IO_CLOCK_IS_INDEPENDENT (1) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index b2863279a67..3a14ce33a43 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -499,6 +499,10 @@ config SOC_LP_IO_CLOCK_IS_INDEPENDENT bool default y +config SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + bool + default y + config SOC_GPIO_IN_RANGE_MAX int default 30 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 2f84c538d40..ae3cb874159 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -202,6 +202,7 @@ #define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP // LP IO peripherals have independent clock gating to manage #define SOC_LP_IO_CLOCK_IS_INDEPENDENT (1) +#define SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED (1) #define SOC_GPIO_VALID_GPIO_MASK ((1U<`__ > Section IO Pins. + .. note:: + Any GPIO/IO wakeup signal -- whether level or edge -- must be held (or have a pulse width) of at least 3 RTC slow-clock cycles to be reliably sampled by the wakeup logic. The duration of one slow-clock cycle depends on :ref:`CONFIG_RTC_CLK_SRC` (e.g. RC_SLOW @ ~136 kHz ~= 7.4 us/cycle, XTAL32K @ 32.768 kHz ~= 30.5 us/cycle). This applies to both :cpp:func:`esp_sleep_enable_gpio_wakeup` and :cpp:func:`esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown`. + .. only:: esp32h2 GPIO Wakeup ^^^^^^^^^^^ - Any IO can be used as the external input to wake up the chip from Light-sleep. Each pin can be individually configured to trigger wakeup on high or low level using the :cpp:func:`gpio_wakeup_enable` function. Then the :cpp:func:`esp_sleep_enable_gpio_wakeup` function should be called to enable this wakeup source. + Any IO can be used as the external input to wake up the chip from Light-sleep. Each pin can be individually configured using :cpp:func:`gpio_wakeup_enable` (low/high level only). Then the :cpp:func:`esp_sleep_enable_gpio_wakeup` function should be called to enable this wakeup source. .. _uart_wakeup_light_sleep: diff --git a/docs/zh_CN/api-reference/system/sleep_modes.rst b/docs/zh_CN/api-reference/system/sleep_modes.rst index fb451f1eb01..fb0bc941944 100644 --- a/docs/zh_CN/api-reference/system/sleep_modes.rst +++ b/docs/zh_CN/api-reference/system/sleep_modes.rst @@ -381,15 +381,22 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒 - Deep-sleep 模式(始终可用) - 启用 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP` 时的 Light-sleep 模式 + .. only:: SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + + 在 {IDF_TARGET_NAME} 上,该 API 还支持边沿触发的唤醒模式:``ESP_GPIO_WAKEUP_GPIO_POSEDGE``(上升沿)、``ESP_GPIO_WAKEUP_GPIO_NEGEDGE``(下降沿)和 ``ESP_GPIO_WAKEUP_GPIO_ANYEDGE``(任意沿)。对于 ``ESP_GPIO_WAKEUP_GPIO_ANYEDGE``,当启用 :ref:`CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS` 时,由于空闲电平不确定,驱动会关闭内部上拉/下拉,建议使用外部上/下拉电阻或保证进入睡眠前线路电平稳定。 + .. note:: 只有由 VDD3P3_RTC 电源域供电的 GPIO(RTC IO)可以与此 API 一起使用。具体支持的管脚请参考 `datasheet <{IDF_TARGET_DATASHEET_CN_URL}>`__ > IO 管脚。 + .. note:: + 使用 IO 唤醒源(无论是电平模式还是边沿模式)将芯片从睡眠中唤醒时,唤醒信号必须保持(电平模式)或脉冲宽度(边沿模式)至少 3 个 RTC 慢时钟周期,唤醒逻辑才能可靠采样。一个慢时钟周期的时长取决于 :ref:`CONFIG_RTC_CLK_SRC` 的配置(例如 RC_SLOW @ ~136 kHz ≈ 7.4 µs/周期,XTAL32K @ 32.768 kHz ≈ 30.5 µs/周期)。该约束同样适用于 :cpp:func:`esp_sleep_enable_gpio_wakeup` 和 :cpp:func:`esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown`。 + .. only:: esp32h2 GPIO 唤醒 ^^^^^^^^^^^ - 任何一个 IO 都可以用作外部输入管脚,将芯片从 Light-sleep 状态唤醒。调用 :cpp:func:`gpio_wakeup_enable` 函数可以将任意管脚单独配置为在高电平或低电平触发唤醒。此后,应调用 :cpp:func:`esp_sleep_enable_gpio_wakeup` 函数来启用此唤醒源。 + 任何一个 IO 都可以用作外部输入管脚,将芯片从 Light-sleep 状态唤醒。可调用 :cpp:func:`gpio_wakeup_enable` 为每个管脚单独配置唤醒条件(仅高/低电平)。此后,应调用 :cpp:func:`esp_sleep_enable_gpio_wakeup` 函数来启用此唤醒源。 .. _uart_wakeup_light_sleep: diff --git a/examples/system/deep_sleep/README.md b/examples/system/deep_sleep/README.md index 296cf07c926..6d347bc4873 100644 --- a/examples/system/deep_sleep/README.md +++ b/examples/system/deep_sleep/README.md @@ -40,7 +40,7 @@ This example should be able to run on any commonly available ESP32 series develo - **EXT1:** GPIO2 and GPIO4 should be connected to LOW to avoid floating pins. When triggering a wake up, connect one or both of the pins to HIGH. Note that floating pins may trigger a wake up. -- **GPIO:** If `EXAMPLE_GPIO_WAKEUP_HIGH_LEVEL` is selected in menuconfig, then connect `EXAMPLE_GPIO_WAKEUP_PIN` to HIGH to trigger a wake up; Otherwise, connect `EXAMPLE_GPIO_WAKEUP_PIN` to LOW to trigger a wake up. +- **GPIO:** In `Example configuration > GPIO wakeup configuration`, set **GPIO wakeup trigger type** to match how you drive `EXAMPLE_GPIO_WAKEUP_PIN`: for **High level**, hold the pin low before sleep then drive high to wake; for **Low level**, hold high then pull low; for **Rising/Falling/Any edge** (targets with `SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED`), use an edge after a stable idle level as required by the selected mode. ### Configure the project @@ -51,8 +51,8 @@ idf.py menuconfig * **EXT0 wake up** can be enabled/disabled via `Example configuration > Enable wakeup from GPIO (ext0)` * **EXT1 wake up** can be enabled/disabled via `Example configuration > Enable wakeup from GPIO (ext1)` * **GPIO wake up** can be enabled/disabled via `Example configuration > Enable wakeup from GPIO` - Trigger pin can be chosen via `Example configuration > GPIO wakeup configuration > Enable wakeup from GPIO` - Trigger level can be selected via `Example configuration > GPIO wakeup configuration > Enable GPIO high-level wakeup` + The pin is set under `Example configuration > GPIO wakeup configuration > Enable wakeup from GPIO`. + The trigger is set under `Example configuration > GPIO wakeup configuration > GPIO wakeup trigger type` (level or edge where supported). Wake up sources that are unused or unconnected should be disabled in configuration to prevent inadvertent triggering of wake up as a result of floating pins. diff --git a/examples/system/deep_sleep/main/Kconfig.projbuild b/examples/system/deep_sleep/main/Kconfig.projbuild index 2657efb2b88..5a843a76e16 100644 --- a/examples/system/deep_sleep/main/Kconfig.projbuild +++ b/examples/system/deep_sleep/main/Kconfig.projbuild @@ -275,12 +275,38 @@ menu "Example Configuration" You need to ensure that the set IO can be configured as a GPIO wake-up source, refer SOC_GPIO_HP_PERIPH_PD_SLEEP_WAKEABLE_MASK in soc_caps.h. - config EXAMPLE_GPIO_WAKEUP_HIGH_LEVEL - bool "Enable GPIO high-level wakeup" - default y + choice EXAMPLE_GPIO_WAKEUP_TRIGGER + prompt "GPIO wakeup trigger type" + default EXAMPLE_GPIO_WAKEUP_TRIGGER_HIGH help - This option set the gpio wake-up trigger signal, In deep sleep, only high or low level wake-up is - supported. If this option is enabled, it is a high level wake up, otherwise it is a low level wake up. + Selects esp_sleep_gpio_wake_up_mode_t for + esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown. + Edge choices require SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED on the target. + + config EXAMPLE_GPIO_WAKEUP_TRIGGER_LOW + bool "Low level" + config EXAMPLE_GPIO_WAKEUP_TRIGGER_HIGH + bool "High level" + config EXAMPLE_GPIO_WAKEUP_TRIGGER_POSEDGE + bool "Rising edge (posedge)" + depends on SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + config EXAMPLE_GPIO_WAKEUP_TRIGGER_NEGEDGE + bool "Falling edge (negedge)" + depends on SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + config EXAMPLE_GPIO_WAKEUP_TRIGGER_ANYEDGE + bool "Any edge" + depends on SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + endchoice + + config EXAMPLE_GPIO_WAKEUP_MODE + int + default 0 if EXAMPLE_GPIO_WAKEUP_TRIGGER_LOW + default 1 if EXAMPLE_GPIO_WAKEUP_TRIGGER_HIGH + default 2 if EXAMPLE_GPIO_WAKEUP_TRIGGER_POSEDGE + default 3 if EXAMPLE_GPIO_WAKEUP_TRIGGER_NEGEDGE + default 4 if EXAMPLE_GPIO_WAKEUP_TRIGGER_ANYEDGE + help + esp_sleep_gpio_wake_up_mode_t index (0=LOW, 1=HIGH, 2=POSEDGE, 3=NEGEDGE, 4=ANYEDGE); endmenu endmenu diff --git a/examples/system/deep_sleep/main/gpio_wakeup.c b/examples/system/deep_sleep/main/gpio_wakeup.c index 31ddeead431..aec0e08ebda 100644 --- a/examples/system/deep_sleep/main/gpio_wakeup.c +++ b/examples/system/deep_sleep/main/gpio_wakeup.c @@ -1,34 +1,54 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include #include "driver/gpio.h" +#include "hal/gpio_types.h" #include "esp_sleep.h" +#include "soc/soc_caps.h" #include "sdkconfig.h" #if CONFIG_EXAMPLE_GPIO_WAKEUP -#define DEFAULT_WAKEUP_PIN CONFIG_EXAMPLE_GPIO_WAKEUP_PIN -#ifdef CONFIG_EXAMPLE_GPIO_WAKEUP_HIGH_LEVEL -#define DEFAULT_WAKEUP_LEVEL ESP_GPIO_WAKEUP_GPIO_HIGH -#else -#define DEFAULT_WAKEUP_LEVEL ESP_GPIO_WAKEUP_GPIO_LOW +#define WAKEUP_PIN CONFIG_EXAMPLE_GPIO_WAKEUP_PIN +#define WAKEUP_MODE CONFIG_EXAMPLE_GPIO_WAKEUP_MODE + +/* Index by esp_sleep_gpio_wake_up_mode_t */ +static const char *const s_wakeup_mode_str[] = { + "LOW_LEVEL", + "HIGH_LEVEL", +#if SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + "POSEDGE", + "NEGEDGE", + "ANYEDGE", #endif +}; void example_deep_sleep_register_gpio_wakeup(void) { + const esp_sleep_gpio_wake_up_mode_t wakeup_mode = WAKEUP_MODE; +#if SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED + const gpio_pullup_t pull_up_en = + ((wakeup_mode == ESP_GPIO_WAKEUP_GPIO_LOW) || (wakeup_mode == ESP_GPIO_WAKEUP_GPIO_NEGEDGE)) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; + const gpio_pulldown_t pull_down_en = + ((wakeup_mode == ESP_GPIO_WAKEUP_GPIO_HIGH) || (wakeup_mode == ESP_GPIO_WAKEUP_GPIO_POSEDGE)) ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; +#else + const gpio_pullup_t pull_up_en = (wakeup_mode == ESP_GPIO_WAKEUP_GPIO_LOW) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; + const gpio_pulldown_t pull_down_en = (wakeup_mode == ESP_GPIO_WAKEUP_GPIO_HIGH) ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; +#endif const gpio_config_t config = { - .pin_bit_mask = BIT64(DEFAULT_WAKEUP_PIN), + .pin_bit_mask = BIT64(WAKEUP_PIN), .mode = GPIO_MODE_INPUT, - .pull_up_en = !DEFAULT_WAKEUP_LEVEL, - .pull_down_en = DEFAULT_WAKEUP_LEVEL + .pull_up_en = pull_up_en, + .pull_down_en = pull_down_en, + .intr_type = GPIO_INTR_DISABLE, }; ESP_ERROR_CHECK(gpio_config(&config)); - ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(BIT(DEFAULT_WAKEUP_PIN), DEFAULT_WAKEUP_LEVEL)); + ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(BIT64(WAKEUP_PIN), wakeup_mode)); - printf("Enabling GPIO wakeup on pins GPIO%d\n", DEFAULT_WAKEUP_PIN); + printf("Enabling GPIO wakeup on GPIO%d, trigger=%s\n", WAKEUP_PIN, s_wakeup_mode_str[wakeup_mode]); } #endif diff --git a/tools/ci/dynamic_pipelines/templates/known_generate_test_child_pipeline_warnings.yml b/tools/ci/dynamic_pipelines/templates/known_generate_test_child_pipeline_warnings.yml index d60e668ef53..f2ad651ce26 100644 --- a/tools/ci/dynamic_pipelines/templates/known_generate_test_child_pipeline_warnings.yml +++ b/tools/ci/dynamic_pipelines/templates/known_generate_test_child_pipeline_warnings.yml @@ -28,4 +28,3 @@ no_runner_tags: - esp32p4,jtag - esp32s2,usb_host_flash_disk - esp32s31,usb_host_flash_disk - - esp32s31_2,generic_multi_device,rev_default