diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index 169a3b2fbf..1adfe8b458 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/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 diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 01b118ff93..d2c8d69069 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -195,8 +195,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; @@ -1393,15 +1393,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)) { @@ -1411,11 +1411,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 diff --git a/components/hal/esp32/include/hal/rtc_cntl_ll.h b/components/hal/esp32/include/hal/rtc_cntl_ll.h index 7e87d1d2ab..3c495752d3 100644 --- a/components/hal/esp32/include/hal/rtc_cntl_ll.h +++ b/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) diff --git a/components/hal/esp32c6/include/hal/lp_aon_hal.h b/components/hal/esp32c6/include/hal/lp_aon_hal.h index f3cd9e6b85..c38f6da831 100644 --- a/components/hal/esp32c6/include/hal/lp_aon_hal.h +++ b/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) diff --git a/components/hal/esp32c6/include/hal/lp_aon_ll.h b/components/hal/esp32c6/include/hal/lp_aon_ll.h index 22ae12dbf6..ef77b7561d 100644 --- a/components/hal/esp32c6/include/hal/lp_aon_ll.h +++ b/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); } diff --git a/components/hal/esp32h2/include/hal/lp_aon_hal.h b/components/hal/esp32h2/include/hal/lp_aon_hal.h index f3cd9e6b85..c38f6da831 100644 --- a/components/hal/esp32h2/include/hal/lp_aon_hal.h +++ b/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) diff --git a/components/hal/esp32h2/include/hal/lp_aon_ll.h b/components/hal/esp32h2/include/hal/lp_aon_ll.h index f556def282..38492a1728 100644 --- a/components/hal/esp32h2/include/hal/lp_aon_ll.h +++ b/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); } diff --git a/components/hal/esp32s2/include/hal/rtc_cntl_ll.h b/components/hal/esp32s2/include/hal/rtc_cntl_ll.h index 0ccdedc879..754e9bcf11 100644 --- a/components/hal/esp32s2/include/hal/rtc_cntl_ll.h +++ b/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) diff --git a/components/hal/esp32s3/include/hal/rtc_cntl_ll.h b/components/hal/esp32s3/include/hal/rtc_cntl_ll.h index 464aa99cd6..34d4cb8e34 100644 --- a/components/hal/esp32s3/include/hal/rtc_cntl_ll.h +++ b/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/apb_ctrl_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) diff --git a/components/hal/include/hal/rtc_hal.h b/components/hal/include/hal/rtc_hal.h index 6848d559d8..c889a2ad07 100644 --- a/components/hal/include/hal/rtc_hal.h +++ b/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 */ @@ -41,15 +41,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 diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 3f0300f07c..d18ec6b892 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -353,4 +353,12 @@ menu "OpenThread" Select this option to enable time synchronization feature, the devices in the same Thread network could sync to the same network time. + config OPENTHREAD_RADIO_STATS_ENABLE + bool "Enable Radio Statistics feature" + depends on OPENTHREAD_FTD || OPENTHREAD_MTD + default n + help + Select this option to enable the radio statistics feature, you can use radio command to print some radio + Statistics informations. + endmenu diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index 0da476f5e1..b27bc53963 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -579,4 +579,15 @@ #define OPENTHREAD_CONFIG_TIME_SYNC_ENABLE 1 #endif +/** + * @def OPENTHREAD_CONFIG_RADIO_STATS_ENABLE + * + * Set to 1 to enable support for Radio Statistics. Note that this option only works for OPENTHREAD_FTD and + * OPENTHREAD_MTD. + * + */ +#if CONFIG_OPENTHREAD_RADIO_STATS_ENABLE +#define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 1 +#endif + #define OPENTHREAD_FTD 1 diff --git a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h index e5980244b7..f706d364e2 100644 --- a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h @@ -263,4 +263,15 @@ #define OPENTHREAD_CONFIG_TIME_SYNC_ENABLE 1 #endif +/** + * @def OPENTHREAD_CONFIG_RADIO_STATS_ENABLE + * + * Set to 1 to enable support for Radio Statistics. Note that this option only works for OPENTHREAD_FTD and + * OPENTHREAD_MTD. + * + */ +#if CONFIG_OPENTHREAD_RADIO_STATS_ENABLE +#define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 1 +#endif + #define OPENTHREAD_MTD 1 diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 356eb7ac3c..bc2c2e6ed6 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1123,6 +1123,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 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 283f07ff09..060fd88245 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -472,6 +472,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) /*! Openthread ---> Thread Operation Dataset`, ensuring that the openthread sleepy device's dataset matches the dataset of the Leader device. + +### Build and Flash + +Build the project and flash it to the board. Use the following command: `idf.py -p erase-flash flash monitor`. + +### Example Output + +As the example runs, you will see the log output indicating the initialization and operation of OpenThread, including the device joining the OpenThread network as a Sleepy End Device (SED). + +``` +I(281) OPENTHREAD:[I] Settings------: Read NetworkInfo {rloc:0x4001, extaddr:623954c9725869e6, role:child, mode:0x04, version:4, keyseq:0x0, ... +I(291) OPENTHREAD:[I] Settings------: ... pid:0x3b33d767, mlecntr:0x3ba17, maccntr:0x3baa8, mliid:868f19ce8c3f6207} +I(301) OPENTHREAD:[I] Settings------: Read ParentInfo {extaddr:3afe8db4802dc1aa, version:4} +I (311) ot_esp_power_save: Wake up from timer. Time spent in deep sleep and boot: 20321ms +I (331) ot_esp_power_save: Enabling timer wakeup, 20s +I (331) OPENTHREAD: OpenThread attached to netif +I(341) OPENTHREAD:[N] Mle-----------: Role disabled -> detached +I (291) main_task: Returned from app_main() +I (371) OT_STATE: netif up +I(511) OPENTHREAD:[N] Mle-----------: Role detached -> child +I (531) ot_esp_power_save: Start one-shot timer for 5s to enter the deep sleep +I (5531) ot_esp_power_save: Enter deep sleep +``` + +When the device enter deep sleep, GPIO9 also can wake up the device, you can push down the BOOT button then you can see the device wakes up: + +``` +I(281) OPENTHREAD:[I] Settings------: Read NetworkInfo {rloc:0x4001, extaddr:623954c9725869e6, role:child, mode:0x04, version:4, keyseq:0x0, ... +I(291) OPENTHREAD:[I] Settings------: ... pid:0x3b33d767, mlecntr:0x3d576, maccntr:0x3d609, mliid:868f19ce8c3f6207} +I(301) OPENTHREAD:[I] Settings------: Read ParentInfo {extaddr:3afe8db4802dc1aa, version:4} +I (321) ot_esp_power_save: Wake up from GPIO. Time spent in deep sleep and boot: 8470ms +I (331) ot_esp_power_save: Enabling timer wakeup, 20s +I (331) OPENTHREAD: OpenThread attached to netif +I(341) OPENTHREAD:[N] Mle-----------: Role disabled -> detached +I (291) main_task: Returned from app_main() +I (371) OT_STATE: netif up +I(511) OPENTHREAD:[N] Mle-----------: Role detached -> child +I (531) ot_esp_power_save: Start one-shot timer for 5s to enter the deep sleep +I (5531) ot_esp_power_save: Enter deep sleep +``` + +During the deep sleep, a typical power consumption is shown below: +![H2-deep-sleep-power-consumption](image/H2-deep-sleep-power-consumption.png) \ No newline at end of file diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/image/H2-deep-sleep-power-consumption.png b/examples/openthread/ot_sleepy_device/deep_sleep/image/H2-deep-sleep-power-consumption.png new file mode 100644 index 0000000000..26df545015 Binary files /dev/null and b/examples/openthread/ot_sleepy_device/deep_sleep/image/H2-deep-sleep-power-consumption.png differ diff --git a/examples/openthread/ot_sleepy_device/main/CMakeLists.txt b/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt similarity index 100% rename from examples/openthread/ot_sleepy_device/main/CMakeLists.txt rename to examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c new file mode 100644 index 0000000000..4c2e592485 --- /dev/null +++ b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c @@ -0,0 +1,220 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + * + * OpenThread Command Line Example + * + * This example code is in the Public Domain (or CC0 licensed, at your option.) + * + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "esp_err.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_sleep.h" +#include "esp_timer.h" +#include "esp_openthread.h" +#include "esp_openthread_netif_glue.h" +#include "esp_ot_sleepy_device_config.h" +#include "esp_vfs_eventfd.h" +#include "nvs_flash.h" +#include "driver/rtc_io.h" +#include "driver/uart.h" +#include "openthread/logging.h" +#include "openthread/thread.h" + +#if !SOC_IEEE802154_SUPPORTED +#error "Openthread sleepy device is only supported for the SoCs which have IEEE 802.15.4 module" +#endif + +#define TAG "ot_esp_power_save" + +static RTC_DATA_ATTR struct timeval s_sleep_enter_time; +static esp_timer_handle_t s_oneshot_timer; + +static void create_config_network(otInstance *instance) +{ + otLinkModeConfig linkMode = { 0 }; + + linkMode.mRxOnWhenIdle = false; + linkMode.mDeviceType = false; + linkMode.mNetworkData = false; + + if (otLinkSetPollPeriod(instance, CONFIG_OPENTHREAD_NETWORK_POLLPERIOD_TIME) != OT_ERROR_NONE) { + ESP_LOGE(TAG, "Failed to set OpenThread pollperiod."); + abort(); + } + + if (otThreadSetLinkMode(instance, linkMode) != OT_ERROR_NONE) { + ESP_LOGE(TAG, "Failed to set OpenThread linkmode."); + abort(); + } + ESP_ERROR_CHECK(esp_openthread_auto_start(NULL)); +} + +static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config) +{ + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD(); + esp_netif_t *netif = esp_netif_new(&cfg); + assert(netif != NULL); + ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init(config))); + + return netif; +} + +static void ot_state_change_callback(otChangedFlags changed_flags, void* ctx) +{ + OT_UNUSED_VARIABLE(ctx); + static otDeviceRole s_previous_role = OT_DEVICE_ROLE_DISABLED; + otInstance* instance = esp_openthread_get_instance(); + if (!instance) { + return; + } + otDeviceRole role = otThreadGetDeviceRole(instance); + if (role == OT_DEVICE_ROLE_CHILD && s_previous_role != OT_DEVICE_ROLE_CHILD) { + // Start the one-shot timer + const int before_deep_sleep_time_sec = 5; + ESP_LOGI(TAG, "Start one-shot timer for %ds to enter the deep sleep", before_deep_sleep_time_sec); + ESP_ERROR_CHECK(esp_timer_start_once(s_oneshot_timer, before_deep_sleep_time_sec * 1000000)); + } + s_previous_role = role; +} + +static void s_oneshot_timer_callback(void* arg) +{ + // Enter deep sleep + ESP_LOGI(TAG, "Enter deep sleep"); + gettimeofday(&s_sleep_enter_time, NULL); + esp_deep_sleep_start(); +} + +static void ot_deep_sleep_init(void) +{ + // Within this function, we print the reason for the wake-up and configure the method of waking up from deep sleep. + // This example provides support for two wake-up sources from deep sleep: RTC timer and GPIO. + + // The one-shot timer will start when the device transitions to the CHILD state for the first time. + // After a 5-second delay, the device will enter deep sleep. + + const esp_timer_create_args_t s_oneshot_timer_args = { + .callback = &s_oneshot_timer_callback, + .name = "one-shot" + }; + + ESP_ERROR_CHECK(esp_timer_create(&s_oneshot_timer_args, &s_oneshot_timer)); + + // Print the wake-up reason: + struct timeval now; + gettimeofday(&now, NULL); + int sleep_time_ms = (now.tv_sec - s_sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - s_sleep_enter_time.tv_usec) / 1000; + esp_sleep_wakeup_cause_t wake_up_cause = esp_sleep_get_wakeup_cause(); + switch (wake_up_cause) { + case ESP_SLEEP_WAKEUP_TIMER: { + ESP_LOGI(TAG, "Wake up from timer. Time spent in deep sleep and boot: %dms", sleep_time_ms); + break; + } + case ESP_SLEEP_WAKEUP_EXT1: { + ESP_LOGI(TAG, "Wake up from GPIO. Time spent in deep sleep and boot: %dms", sleep_time_ms); + break; + } + case ESP_SLEEP_WAKEUP_UNDEFINED: + default: + ESP_LOGI(TAG, "Not a deep sleep reset"); + break; + } + + // Set the methods of how to wake up: + // 1. RTC timer waking-up + const int wakeup_time_sec = 20; + ESP_LOGI(TAG, "Enabling timer wakeup, %ds\n", wakeup_time_sec); + ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000)); + + // 2. GPIO waking-up +#if CONFIG_IDF_TARGET_ESP32C6 + // For ESP32C6 boards, RTCIO only supports GPIO0~GPIO7 + // GPIO7 pull down to wake up + const int gpio_wakeup_pin = 7; +#elif CONFIG_IDF_TARGET_ESP32H2 + // You can wake up by pulling down GPIO9. On ESP32H2 development boards, the BOOT button is connected to GPIO9. + // You can use the BOOT button to wake up the boards directly. + const int gpio_wakeup_pin = 9; +#endif + const uint64_t gpio_wakeup_pin_mask = 1ULL << gpio_wakeup_pin; + // The configuration mode depends on your hardware design. + // Since the BOOT button is connected to a pull-up resistor, the wake-up mode is configured as LOW. + const uint64_t ext_wakeup_mode = 0 << gpio_wakeup_pin; + ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup_with_level_mask(gpio_wakeup_pin_mask, ext_wakeup_mode)); + + // Also these two GPIO configurations are also depended on the hardware design. + // The BOOT button is connected to the pull-up resistor, so enable the pull-up mode and disable the pull-down mode. + + // Notice: if these GPIO configurations do not match the hardware design, the deep sleep module will enable the GPIO hold + // feature to hold the GPIO voltage when enter the sleep, which will ensure the board be waked up by GPIO. But it will cause + // 3~4 times power consumption increasing during sleep. + ESP_ERROR_CHECK(gpio_pullup_en(gpio_wakeup_pin)); + ESP_ERROR_CHECK(gpio_pulldown_dis(gpio_wakeup_pin)); +} + + +static void ot_task_worker(void *aContext) +{ + esp_openthread_platform_config_t config = { + .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(), + .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(), + .port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(), + }; + + // Initialize the OpenThread stack + ESP_ERROR_CHECK(esp_openthread_init(&config)); + + ot_deep_sleep_init(); + +#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC + // The OpenThread log level directly matches ESP log level + (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL); +#endif + esp_netif_t *openthread_netif; + // Initialize the esp_netif bindings + openthread_netif = init_openthread_netif(&config); + esp_netif_set_default_netif(openthread_netif); + otSetStateChangedCallback(esp_openthread_get_instance(), ot_state_change_callback, NULL); + + create_config_network(esp_openthread_get_instance()); + + // Run the main loop + esp_openthread_launch_mainloop(); + + // Clean up + esp_netif_destroy(openthread_netif); + esp_openthread_netif_glue_deinit(); + + esp_vfs_eventfd_unregister(); + vTaskDelete(NULL); +} + + +void app_main(void) +{ + // Used eventfds: + // * netif + // * ot task queue + // * radio driver + esp_vfs_eventfd_config_t eventfd_config = { + .max_fds = 3, + }; + + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); + + xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL); +} diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device_config.h b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device_config.h new file mode 100644 index 0000000000..145bb245cc --- /dev/null +++ b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device_config.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + * + * OpenThread Command Line Example + * + * This example code is in the Public Domain (or CC0 licensed, at your option.) + * + * Unless required by applicable law or agreed to in writing, this + * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. + */ + +#pragma once + +#include "esp_openthread_types.h" + +# define CONFIG_OPENTHREAD_NETWORK_POLLPERIOD_TIME 30000 + +#if SOC_IEEE802154_SUPPORTED +#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \ + { \ + .radio_mode = RADIO_MODE_NATIVE, \ + } +#endif + +#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ + { \ + .host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \ + .host_uart_config = { \ + .port = 0, \ + .uart_config = \ + { \ + .baud_rate = 115200, \ + .data_bits = UART_DATA_8_BITS, \ + .parity = UART_PARITY_DISABLE, \ + .stop_bits = UART_STOP_BITS_1, \ + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \ + .rx_flow_ctrl_thresh = 0, \ + .source_clk = UART_SCLK_DEFAULT, \ + }, \ + .rx_pin = UART_PIN_NO_CHANGE, \ + .tx_pin = UART_PIN_NO_CHANGE, \ + }, \ + } + +#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ + { \ + .storage_partition_name = "nvs", \ + .netif_queue_size = 10, \ + .task_queue_size = 10, \ + } diff --git a/examples/openthread/ot_sleepy_device/partitions.csv b/examples/openthread/ot_sleepy_device/deep_sleep/partitions.csv similarity index 100% rename from examples/openthread/ot_sleepy_device/partitions.csv rename to examples/openthread/ot_sleepy_device/deep_sleep/partitions.csv diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults b/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults new file mode 100644 index 0000000000..00774aa81d --- /dev/null +++ b/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults @@ -0,0 +1,54 @@ +# +# Partition Table +# +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +# end of Partition Table + +# +# mbedTLS +# +# TODO: Re-enable HW acceleration when HW AES support pm_lock (IDF-7704) +CONFIG_MBEDTLS_HARDWARE_AES=n +CONFIG_MBEDTLS_HARDWARE_MPI=n +CONFIG_MBEDTLS_HARDWARE_SHA=n +CONFIG_MBEDTLS_CMAC_C=y +CONFIG_MBEDTLS_SSL_PROTO_DTLS=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y +CONFIG_MBEDTLS_ECJPAKE_C=y +# end of mbedTLS + +# +# OpenThread +# +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_OPENTHREAD_BORDER_ROUTER=n +CONFIG_OPENTHREAD_DNS64_CLIENT=y +# end of OpenThread + +# +# lwIP +# +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096 +CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 +CONFIG_LWIP_IPV4=n +CONFIG_LWIP_ND6=n +# end of lwIP + +# +# IEEE 802.15.4 +# +CONFIG_IEEE802154_ENABLED=y +# end of IEEE 802.15.4 + +# +# deep sleep +# +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=80 +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_RESERVE_MEM=512 +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +CONFIG_RTC_CLK_SRC_INT_RC=y +CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y diff --git a/examples/openthread/ot_sleepy_device/light_sleep/CMakeLists.txt b/examples/openthread/ot_sleepy_device/light_sleep/CMakeLists.txt new file mode 100644 index 0000000000..876f5798c5 --- /dev/null +++ b/examples/openthread/ot_sleepy_device/light_sleep/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ot_sleepy_device) diff --git a/examples/openthread/ot_sleepy_device/README.md b/examples/openthread/ot_sleepy_device/light_sleep/README.md similarity index 89% rename from examples/openthread/ot_sleepy_device/README.md rename to examples/openthread/ot_sleepy_device/light_sleep/README.md index 5c832db28d..ebcf8eae27 100644 --- a/examples/openthread/ot_sleepy_device/README.md +++ b/examples/openthread/ot_sleepy_device/light_sleep/README.md @@ -3,7 +3,7 @@ # OpenThread Sleepy Device Example -The example demonstrates the Thread Sleepy End Device (SED), the device will enter [Light Sleep mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/system/sleep_modes.html#sleep-modes) during idle state. +The example demonstrates the Thread Sleepy End Device (SED), the device will enter [Light Sleep mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/api-reference/system/sleep_modes.html#sleep-modes) during idle state. ## How to use example ### Hardware Required @@ -14,7 +14,7 @@ The example demonstrates the Thread Sleepy End Device (SED), the device will ent ## Configure the Openthread Dataset -* Run [ot_cli](../ot_cli/) on another 802.15.4 SoC device to create openthread dataset configuration and start an openthread network as the leader. +* Run [ot_cli](../../ot_cli/) on another 802.15.4 SoC device to create openthread dataset configuration and start an openthread network as the leader. * Configure the Openthread dataset using `idf.py menuconfig` in `Component config ---> Openthread ---> Thread Operation Dataset`, ensuring that the openthread sleepy device's dataset matches the dataset of the leader. ### Build and Flash diff --git a/examples/openthread/ot_sleepy_device/light_sleep/main/CMakeLists.txt b/examples/openthread/ot_sleepy_device/light_sleep/main/CMakeLists.txt new file mode 100644 index 0000000000..a7cde9d16a --- /dev/null +++ b/examples/openthread/ot_sleepy_device/light_sleep/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "esp_ot_sleepy_device.c" + INCLUDE_DIRS ".") diff --git a/examples/openthread/ot_sleepy_device/main/esp_ot_sleepy_device.c b/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c similarity index 100% rename from examples/openthread/ot_sleepy_device/main/esp_ot_sleepy_device.c rename to examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c diff --git a/examples/openthread/ot_sleepy_device/main/esp_ot_sleepy_device_config.h b/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device_config.h similarity index 100% rename from examples/openthread/ot_sleepy_device/main/esp_ot_sleepy_device_config.h rename to examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device_config.h diff --git a/examples/openthread/ot_sleepy_device/light_sleep/partitions.csv b/examples/openthread/ot_sleepy_device/light_sleep/partitions.csv new file mode 100644 index 0000000000..6c0e048dba --- /dev/null +++ b/examples/openthread/ot_sleepy_device/light_sleep/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 0x120000, diff --git a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_c6 b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_c6 new file mode 100644 index 0000000000..80eea90801 --- /dev/null +++ b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_c6 @@ -0,0 +1,6 @@ +CONFIG_IDF_TARGET="esp32c6" +CONFIG_IDF_TARGET_ESP32C6=y +CONFIG_OPENTHREAD_NETWORK_CHANNEL=12 +CONFIG_OPENTHREAD_NETWORK_MASTERKEY="aabbccddeeff00112233445566778899" +CONFIG_ESP_SLEEP_DEBUG=y +CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y diff --git a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_h2 b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_h2 new file mode 100644 index 0000000000..4afe327821 --- /dev/null +++ b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_h2 @@ -0,0 +1,6 @@ +CONFIG_IDF_TARGET="esp32h2" +CONFIG_IDF_TARGET_ESP32H2=y +CONFIG_OPENTHREAD_NETWORK_CHANNEL=12 +CONFIG_OPENTHREAD_NETWORK_MASTERKEY="aabbccddeeff00112233445566778899" +CONFIG_ESP_SLEEP_DEBUG=y +CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y diff --git a/examples/openthread/ot_sleepy_device/sdkconfig.defaults b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults similarity index 100% rename from examples/openthread/ot_sleepy_device/sdkconfig.defaults rename to examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults diff --git a/examples/system/deep_sleep/main/Kconfig.projbuild b/examples/system/deep_sleep/main/Kconfig.projbuild index 281703bcd9..51dffc1f8c 100644 --- a/examples/system/deep_sleep/main/Kconfig.projbuild +++ b/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 diff --git a/examples/system/deep_sleep/main/ext_wakeup.c b/examples/system/deep_sleep/main/ext_wakeup.c index e6cc7ac10a..de329b6973 100644 --- a/examples/system/deep_sleep/main/ext_wakeup.c +++ b/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