Jelajahi Sumber

Merge branch 'feature/support_EXT1_WAKEUP_MODE_PER_PIN_for_esp32c6_and_esp32h2' into 'master'

Feature: support ext1 wakeup mode per pin for esp32c6 and esp32h2

See merge request espressif/esp-idf!24875
Lou Tian Hao 2 tahun lalu
induk
melakukan
0878b9bdcd

+ 57 - 17
components/esp_hw_support/include/esp_sleep.h

@@ -251,7 +251,7 @@ esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);
  * 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 any of the selected pins goes into the state given by mode argument,
+ * 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
@@ -267,28 +267,68 @@ 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.
  *
- * @param 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 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
+ * @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 any of the selected GPIOs is not an RTC GPIO,
  *        or mode is invalid
  */
-esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);
+esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode);
 
+#if SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+/**
+ * @brief Enable wakeup using multiple pins, allows different trigger mode per pin
+ *
+ * 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:
+ *                    - ESP32-C6: 0-7.
+ *                    - ESP32-H2: 7-14.
+ * @param level_mask Select logic function used to determine wakeup condition per pin.
+ *                   Each bit of the level_mask corresponds to the respective GPIO. Each bit's corresponding
+ *                   position is set to 0, the wakeup level will be low, on the contrary,
+ *                   each bit's corresponding position is set to 1, the wakeup level will be high.
+ * @return
+ *      - 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_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
 
 #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP

+ 40 - 7
components/esp_hw_support/sleep_modes.c

@@ -189,8 +189,8 @@ typedef struct {
     uint64_t sleep_duration;
     uint32_t wakeup_triggers : 15;
 #if SOC_PM_SUPPORT_EXT1_WAKEUP
-    uint32_t ext1_trigger_mode : 1;
-    uint32_t ext1_rtc_gpio_mask : 22; // 22 is the maximum RTCIO number in all chips
+    uint32_t ext1_trigger_mode : 22;  // 22 is the maximum RTCIO number in all chips
+    uint32_t ext1_rtc_gpio_mask : 22;
 #endif
 #if SOC_PM_SUPPORT_EXT0_WAKEUP
     uint32_t ext0_trigger_level : 1;
@@ -1395,15 +1395,15 @@ static void ext0_wakeup_prepare(void)
 #endif // SOC_PM_SUPPORT_EXT0_WAKEUP
 
 #if SOC_PM_SUPPORT_EXT1_WAKEUP
-esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode)
+esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode)
 {
-    if (mode > ESP_EXT1_WAKEUP_ANY_HIGH) {
+    if (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
     uint32_t rtc_gpio_mask = 0;
-    for (int gpio = 0; mask; ++gpio, mask >>= 1) {
-        if ((mask & 1) == 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)) {
@@ -1413,11 +1413,44 @@ esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode
         rtc_gpio_mask |= BIT(rtc_io_number_get(gpio));
     }
     s_config.ext1_rtc_gpio_mask = rtc_gpio_mask;
-    s_config.ext1_trigger_mode = mode;
+    if (level_mode) {
+        s_config.ext1_trigger_mode = io_mask;
+    } else {
+        s_config.ext1_trigger_mode = 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)
+{
+    if ((level_mask & io_mask) != level_mask) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    // Translate bit map of GPIO numbers into the bit map of RTC IO numbers
+    // Translate bit map of GPIO wakeup mode into the bit map of RTC IO wakeup mode
+    uint32_t rtc_gpio_mask = 0, rtc_gpio_wakeup_mode_mask = 0;
+    for (int gpio = 0; io_mask; ++gpio, io_mask >>= 1, level_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));
+        if ((level_mask & 1) == 1) {
+            rtc_gpio_wakeup_mode_mask |= BIT(rtc_io_number_get(gpio));
+        }
+    }
+    s_config.ext1_rtc_gpio_mask = rtc_gpio_mask;
+    s_config.ext1_trigger_mode = rtc_gpio_wakeup_mode_mask;
+    s_config.wakeup_triggers |= RTC_EXT1_TRIG_EN;
+    return ESP_OK;
+}
+#endif
+
 static void ext1_wakeup_prepare(void)
 {
     // Configure all RTC IOs selected as ext1 wakeup inputs

+ 13 - 5
components/hal/esp32/include/hal/rtc_cntl_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -11,6 +11,7 @@
 #include "esp_attr.h"
 #include "clk_tree_ll.h"
 #include "esp_rom_sys.h"
+#include "hal/assert.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -32,11 +33,18 @@ FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void)
     return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
 }
 
-FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode)
+FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t io_mask, uint32_t mode_mask)
 {
-    REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask);
-    SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
-            mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    // The target only supports a unified trigger mode among all EXT1 wakeup IOs
+    HAL_ASSERT((io_mask & mode_mask) == io_mask || (io_mask & mode_mask) == 0);
+    REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, io_mask);
+    if ((io_mask & mode_mask) == io_mask) {
+        SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
+                1, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    } else {
+        SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
+                0, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    }
 }
 
 FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_pins(void)

+ 6 - 6
components/hal/esp32c6/include/hal/lp_aon_hal.h

@@ -8,10 +8,10 @@
 
 #include "hal/lp_aon_ll.h"
 
-#define rtc_hal_ext1_get_wakeup_status()                    lp_aon_ll_ext1_get_wakeup_status()
-#define rtc_hal_ext1_clear_wakeup_status()                  lp_aon_ll_ext1_clear_wakeup_status()
-#define rtc_hal_ext1_set_wakeup_pins(mask, mode)            lp_aon_ll_ext1_set_wakeup_pins(mask, mode)
-#define rtc_hal_ext1_clear_wakeup_pins()                    lp_aon_ll_ext1_clear_wakeup_pins()
-#define rtc_hal_ext1_get_wakeup_pins()                      lp_aon_ll_ext1_get_wakeup_pins()
+#define rtc_hal_ext1_get_wakeup_status()                        lp_aon_ll_ext1_get_wakeup_status()
+#define rtc_hal_ext1_clear_wakeup_status()                      lp_aon_ll_ext1_clear_wakeup_status()
+#define rtc_hal_ext1_set_wakeup_pins(io_mask, mode_mask)        lp_aon_ll_ext1_set_wakeup_pins(io_mask, mode_mask)
+#define rtc_hal_ext1_clear_wakeup_pins()                        lp_aon_ll_ext1_clear_wakeup_pins()
+#define rtc_hal_ext1_get_wakeup_pins()                          lp_aon_ll_ext1_get_wakeup_pins()
 
-#define lp_aon_hal_inform_wakeup_type(dslp)                 lp_aon_ll_inform_wakeup_type(dslp)
+#define lp_aon_hal_inform_wakeup_type(dslp)                     lp_aon_ll_inform_wakeup_type(dslp)

+ 10 - 10
components/hal/esp32c6/include/hal/lp_aon_ll.h

@@ -39,22 +39,22 @@ static inline void lp_aon_ll_ext1_clear_wakeup_status(void)
 
 /**
  * @brief Set the wake-up LP_IO of the ext1 wake-up source
- * @param mask wakeup LP_IO bitmap, bit 0~7 corresponds to LP_IO 0~7
- * @param mode 0: Wake the chip when any of the selected GPIOs go low
- *             1: Wake the chip when any of the selected GPIOs go high
+ * @param io_mask     wakeup LP_IO bitmap, bit 0~7 corresponds to LP_IO 0~7
+ * @param level_mask  LP_IO wakeup level bitmap, bit 0~7 corresponds to LP_IO 0~7 wakeup level
+ *                    each bit's corresponding position is set to 0, the wakeup level will be low
+ *                    on the contrary, each bit's corresponding position is set to 1, the wakeup
+ *                    level will be high
  */
-static inline  void lp_aon_ll_ext1_set_wakeup_pins(uint32_t mask, int mode)
+static inline void lp_aon_ll_ext1_set_wakeup_pins(uint32_t io_mask, uint32_t level_mask)
 {
     uint32_t wakeup_sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel);
-    wakeup_sel_mask |= mask;
+    wakeup_sel_mask |= io_mask;
     HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel, wakeup_sel_mask);
 
     uint32_t wakeup_level_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_lv);
-    if (mode) {
-        wakeup_level_mask |= mask;
-    } else {
-        wakeup_level_mask &= ~mask;
-    }
+    wakeup_level_mask |= io_mask & level_mask;
+    wakeup_level_mask &= ~(io_mask & ~level_mask);
+
     HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_lv, wakeup_level_mask);
 }
 

+ 6 - 6
components/hal/esp32h2/include/hal/lp_aon_hal.h

@@ -8,10 +8,10 @@
 
 #include "hal/lp_aon_ll.h"
 
-#define rtc_hal_ext1_get_wakeup_status()                    lp_aon_ll_ext1_get_wakeup_status()
-#define rtc_hal_ext1_clear_wakeup_status()                  lp_aon_ll_ext1_clear_wakeup_status()
-#define rtc_hal_ext1_set_wakeup_pins(mask, mode)            lp_aon_ll_ext1_set_wakeup_pins(mask, mode)
-#define rtc_hal_ext1_clear_wakeup_pins()                    lp_aon_ll_ext1_clear_wakeup_pins()
-#define rtc_hal_ext1_get_wakeup_pins()                      lp_aon_ll_ext1_get_wakeup_pins()
+#define rtc_hal_ext1_get_wakeup_status()                        lp_aon_ll_ext1_get_wakeup_status()
+#define rtc_hal_ext1_clear_wakeup_status()                      lp_aon_ll_ext1_clear_wakeup_status()
+#define rtc_hal_ext1_set_wakeup_pins(io_mask, mode_mask)        lp_aon_ll_ext1_set_wakeup_pins(io_mask, mode_mask)
+#define rtc_hal_ext1_clear_wakeup_pins()                        lp_aon_ll_ext1_clear_wakeup_pins()
+#define rtc_hal_ext1_get_wakeup_pins()                          lp_aon_ll_ext1_get_wakeup_pins()
 
-#define lp_aon_hal_inform_wakeup_type(dslp)                 lp_aon_ll_inform_wakeup_type(dslp)
+#define lp_aon_hal_inform_wakeup_type(dslp)                     lp_aon_ll_inform_wakeup_type(dslp)

+ 10 - 10
components/hal/esp32h2/include/hal/lp_aon_ll.h

@@ -39,22 +39,22 @@ static inline void lp_aon_ll_ext1_clear_wakeup_status(void)
 
 /**
  * @brief Set the wake-up LP_IO of the ext1 wake-up source
- * @param mask wakeup LP_IO bitmap, bit 0~7 corresponds to LP_IO 0~7
- * @param mode 0: Wake the chip when any of the selected GPIOs go low
- *             1: Wake the chip when any of the selected GPIOs go high
+ * @param io_mask     wakeup LP_IO bitmap, bit 0~7 corresponds to LP_IO 0~7
+ * @param level_mask  LP_IO wakeup level bitmap, bit 0~7 corresponds to LP_IO 0~7 wakeup level
+ *                    each bit's corresponding position is set to 0, the wakeup level will be low
+ *                    on the contrary, each bit's corresponding position is set to 1, the wakeup
+ *                    level will be high
  */
-static inline  void lp_aon_ll_ext1_set_wakeup_pins(uint32_t mask, int mode)
+static inline void lp_aon_ll_ext1_set_wakeup_pins(uint32_t io_mask, uint32_t level_mask)
 {
     uint32_t wakeup_sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel);
-    wakeup_sel_mask |= mask;
+    wakeup_sel_mask |= io_mask;
     HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_sel, wakeup_sel_mask);
 
     uint32_t wakeup_level_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_lv);
-    if (mode) {
-        wakeup_level_mask |= mask;
-    } else {
-        wakeup_level_mask &= ~mask;
-    }
+    wakeup_level_mask |= io_mask & level_mask;
+    wakeup_level_mask &= ~(io_mask & ~level_mask);
+
     HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, ext_wakeup_lv, wakeup_level_mask);
 }
 

+ 13 - 5
components/hal/esp32s2/include/hal/rtc_cntl_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -10,6 +10,7 @@
 #include "soc/rtc.h"
 #include "soc/rtc_cntl_reg.h"
 #include "esp_attr.h"
+#include "hal/assert.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -34,11 +35,18 @@ FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void)
     return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
 }
 
-FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode)
+FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t io_mask, uint32_t mode_mask)
 {
-    REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask);
-    SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
-            mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    // The target only supports a unified trigger mode among all EXT1 wakeup IOs
+    HAL_ASSERT((io_mask & mode_mask) == io_mask || (io_mask & mode_mask) == 0);
+    REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, io_mask);
+    if ((io_mask & mode_mask) == io_mask) {
+        SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
+                1, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    } else {
+        SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
+                0, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    }
 }
 
 FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_pins(void)

+ 13 - 5
components/hal/esp32s3/include/hal/rtc_cntl_ll.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -11,6 +11,7 @@
 #include "soc/rtc_cntl_reg.h"
 #include "soc/syscon_reg.h"
 #include "esp_attr.h"
+#include "hal/assert.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -38,11 +39,18 @@ FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void)
     return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
 }
 
-FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode)
+FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t io_mask, uint32_t mode_mask)
 {
-    REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask);
-    SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
-            mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    // The target only supports a unified trigger mode among all EXT1 wakeup IOs
+    HAL_ASSERT((io_mask & mode_mask) == io_mask || (io_mask & mode_mask) == 0);
+    REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, io_mask);
+    if ((io_mask & mode_mask) == io_mask) {
+        SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
+                1, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    } else {
+        SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
+                0, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    }
 }
 
 FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_pins(void)

+ 6 - 6
components/hal/include/hal/rtc_hal.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -51,15 +51,15 @@ typedef struct rtc_cntl_sleep_retent {
 
 #if SOC_PM_SUPPORT_EXT1_WAKEUP
 
-#define rtc_hal_ext1_get_wakeup_status()                  rtc_cntl_ll_ext1_get_wakeup_status()
+#define rtc_hal_ext1_get_wakeup_status()                    rtc_cntl_ll_ext1_get_wakeup_status()
 
-#define rtc_hal_ext1_clear_wakeup_status()                rtc_cntl_ll_ext1_clear_wakeup_status()
+#define rtc_hal_ext1_clear_wakeup_status()                  rtc_cntl_ll_ext1_clear_wakeup_status()
 
-#define rtc_hal_ext1_set_wakeup_pins(mask, mode)          rtc_cntl_ll_ext1_set_wakeup_pins(mask, mode)
+#define rtc_hal_ext1_set_wakeup_pins(io_mask, mode_mask)    rtc_cntl_ll_ext1_set_wakeup_pins(io_mask, mode_mask)
 
-#define rtc_hal_ext1_clear_wakeup_pins()                  rtc_cntl_ll_ext1_clear_wakeup_pins()
+#define rtc_hal_ext1_clear_wakeup_pins()                    rtc_cntl_ll_ext1_clear_wakeup_pins()
 
-#define rtc_hal_ext1_get_wakeup_pins()                    rtc_cntl_ll_ext1_get_wakeup_pins()
+#define rtc_hal_ext1_get_wakeup_pins()                      rtc_cntl_ll_ext1_get_wakeup_pins()
 
 #endif // SOC_PM_SUPPORT_EXT1_WAKEUP
 

+ 4 - 0
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -1159,6 +1159,10 @@ config SOC_PM_SUPPORT_EXT1_WAKEUP
     bool
     default y
 
+config SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+    bool
+    default y
+
 config SOC_PM_SUPPORT_CPU_PD
     bool
     default y

+ 1 - 0
components/soc/esp32c6/include/soc/soc_caps.h

@@ -481,6 +481,7 @@
 #define SOC_PM_SUPPORT_BEACON_WAKEUP    (1)
 #define SOC_PM_SUPPORT_BT_WAKEUP        (1)
 #define SOC_PM_SUPPORT_EXT1_WAKEUP      (1)
+#define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN   (1) /*!<Supports one bit per pin to configue the EXT1 trigger level */
 #define SOC_PM_SUPPORT_CPU_PD           (1)
 #define SOC_PM_SUPPORT_MODEM_PD         (1)
 #define SOC_PM_SUPPORT_XTAL32K_PD       (1)

+ 4 - 0
components/soc/esp32h2/include/soc/Kconfig.soc_caps.in

@@ -1111,6 +1111,10 @@ config SOC_PM_SUPPORT_EXT1_WAKEUP
     bool
     default y
 
+config SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+    bool
+    default y
+
 config SOC_PM_SUPPORT_CPU_PD
     bool
     default y

+ 1 - 0
components/soc/esp32h2/include/soc/soc_caps.h

@@ -465,6 +465,7 @@
 /*-------------------------- Power Management CAPS ----------------------------*/
 #define SOC_PM_SUPPORT_BT_WAKEUP        (1)
 #define SOC_PM_SUPPORT_EXT1_WAKEUP      (1)
+#define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN   (1) /*!<Supports one bit per pin to configue the EXT1 trigger level */
 #define SOC_PM_SUPPORT_CPU_PD           (1)
 #define SOC_PM_SUPPORT_MODEM_PD         (1) /*!<modem includes BLE and 15.4 */
 #define SOC_PM_SUPPORT_XTAL32K_PD       (1)

+ 34 - 0
examples/system/deep_sleep/main/Kconfig.projbuild

@@ -186,6 +186,7 @@ menu "Example Configuration"
         choice EXAMPLE_EXT1_WAKEUP_MODE_SEL
             prompt "Select wakeup mode from EXT1"
             default ESP_EXT1_WAKEUP_ANY_HIGH
+            depends on !SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
             config ESP_EXT1_WAKEUP_ANY_LOW
                 bool "GPIO any low level"
                 depends on !IDF_TARGET_ESP32
@@ -198,10 +199,43 @@ menu "Example Configuration"
 
         config EXAMPLE_EXT1_WAKEUP_MODE
             int
+            depends on !SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
             default 0 if ESP_EXT1_WAKEUP_ANY_LOW
             default 0 if ESP_EXT1_WAKEUP_ALL_LOW
             default 1 if ESP_EXT1_WAKEUP_ANY_HIGH
 
+        choice EXAMPLE_EXT1_WAKEUP_PIN_1_MODE_SEL
+            prompt "Select pin_1 wakeup mode from EXT1"
+            default ESP_EXT1_WAKEUP_PIN_1_HIGH
+            depends on SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+            config ESP_EXT1_WAKEUP_PIN_1_LOW
+                bool "GPIO low level"
+            config ESP_EXT1_WAKEUP_PIN_1_HIGH
+                bool "GPIO high level"
+        endchoice
+
+        config EXAMPLE_EXT1_WAKEUP_MODE_PIN_1
+            int
+            depends on SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+            default 0 if ESP_EXT1_WAKEUP_PIN_1_LOW
+            default 1 if ESP_EXT1_WAKEUP_PIN_1_HIGH
+
+        choice EXAMPLE_EXT1_WAKEUP_PIN_2_MODE_SEL
+            prompt "Select pin_2 wakeup mode from EXT1"
+            default ESP_EXT1_WAKEUP_PIN_2_HIGH
+            depends on SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+            config ESP_EXT1_WAKEUP_PIN_2_LOW
+                bool "GPIO low level"
+            config ESP_EXT1_WAKEUP_PIN_2_HIGH
+                bool "GPIO high level"
+        endchoice
+
+        config EXAMPLE_EXT1_WAKEUP_MODE_PIN_2
+            int
+            depends on SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+            default 0 if ESP_EXT1_WAKEUP_PIN_2_LOW
+            default 1 if ESP_EXT1_WAKEUP_PIN_2_HIGH
+
         config EXAMPLE_EXT1_USE_INTERNAL_PULLUPS
             bool "Use internal pull-up/downs for EXT1 wakeup source"
             default n

+ 45 - 6
examples/system/deep_sleep/main/ext_wakeup.c

@@ -12,9 +12,9 @@
 
 #if CONFIG_EXAMPLE_EXT0_WAKEUP
 #if CONFIG_IDF_TARGET_ESP32
-    const int ext_wakeup_pin_0 = 25;
+const int ext_wakeup_pin_0 = 25;
 #else
-    const int ext_wakeup_pin_0 = 3;
+const int ext_wakeup_pin_0 = 3;
 #endif
 
 void example_deep_sleep_register_ext0_wakeup(void)
@@ -38,9 +38,15 @@ void example_deep_sleep_register_ext1_wakeup(void)
     const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
     const uint64_t ext_wakeup_pin_2_mask = 1ULL << ext_wakeup_pin_2;
     printf("Enabling EXT1 wakeup on pins GPIO%d, GPIO%d\n", ext_wakeup_pin_1, ext_wakeup_pin_2);
-    const esp_sleep_ext1_wakeup_mode_t ext_wakeup_mode = CONFIG_EXAMPLE_EXT1_WAKEUP_MODE;
 
+#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));
+#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));
+#endif
 
     /* If there are no external pull-up/downs, tie wakeup pins to inactive level with internal pull-up/downs via RTC IO
      * during deepsleep. However, RTC IO relies on the RTC_PERIPH power domain. Keeping this power domain on will
@@ -48,7 +54,23 @@ void example_deep_sleep_register_ext1_wakeup(void)
      * domain, we will use the HOLD feature to maintain the pull-up and pull-down on the pins during sleep.*/
 #if CONFIG_EXAMPLE_EXT1_USE_INTERNAL_PULLUPS
 #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
-    if (ext_wakeup_mode) {
+#if SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+    if (CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_1) {
+        ESP_ERROR_CHECK(rtc_gpio_pullup_dis(ext_wakeup_pin_1));
+        ESP_ERROR_CHECK(rtc_gpio_pulldown_en(ext_wakeup_pin_1));
+    } else {
+        ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_1));
+        ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_1));
+    }
+    if (CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_2) {
+        ESP_ERROR_CHECK(rtc_gpio_pullup_dis(ext_wakeup_pin_2));
+        ESP_ERROR_CHECK(rtc_gpio_pulldown_en(ext_wakeup_pin_2));
+    } else {
+        ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_2));
+        ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_2));
+    }
+#else // !SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+    if (CONFIG_EXAMPLE_EXT1_WAKEUP_MODE) {
         ESP_ERROR_CHECK(rtc_gpio_pullup_dis(ext_wakeup_pin_1));
         ESP_ERROR_CHECK(rtc_gpio_pulldown_en(ext_wakeup_pin_1));
         ESP_ERROR_CHECK(rtc_gpio_pullup_dis(ext_wakeup_pin_2));
@@ -59,8 +81,25 @@ void example_deep_sleep_register_ext1_wakeup(void)
         ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_2));
         ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_2));
     }
+#endif
+#else // ! SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
+#if SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN
+    if (CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_1) {
+        gpio_pullup_dis(ext_wakeup_pin_1);
+        gpio_pulldown_en(ext_wakeup_pin_1);
+    } else {
+        gpio_pulldown_dis(ext_wakeup_pin_1);
+        gpio_pullup_en(ext_wakeup_pin_1);
+    }
+    if (CONFIG_EXAMPLE_EXT1_WAKEUP_MODE_PIN_2) {
+        gpio_pullup_dis(ext_wakeup_pin_2);
+        gpio_pulldown_en(ext_wakeup_pin_2);
+    } else {
+        gpio_pulldown_dis(ext_wakeup_pin_2);
+        gpio_pullup_en(ext_wakeup_pin_2);
+    }
 #else
-    if (ext_wakeup_mode) {
+    if (CONFIG_EXAMPLE_EXT1_WAKEUP_MODE) {
         ESP_ERROR_CHECK(gpio_pullup_dis(ext_wakeup_pin_1));
         ESP_ERROR_CHECK(gpio_pulldown_en(ext_wakeup_pin_1));
         ESP_ERROR_CHECK(gpio_pullup_dis(ext_wakeup_pin_2));
@@ -72,7 +111,7 @@ void example_deep_sleep_register_ext1_wakeup(void)
         ESP_ERROR_CHECK(gpio_pullup_en(ext_wakeup_pin_2));
     }
 #endif
+#endif
 #endif // CONFIG_EXAMPLE_EXT1_USE_INTERNAL_PULLUPS
 }
-
 #endif // CONFIG_EXAMPLE_EXT1_WAKEUP