mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
feat(esp_driver_gpio): support rtc_io edge wakeup deepsleep
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -335,6 +335,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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user