Переглянути джерело

Merge branch 'feature/esp32c6_light_sleep_support_ieee802154' into 'master'

ieee802154: esp32c6 light sleep support

See merge request espressif/esp-idf!23629
Shu Chen 2 роки тому
батько
коміт
f64a6bcb6a
27 змінених файлів з 537 додано та 23 видалено
  1. 1 0
      components/esp_hw_support/include/esp_private/esp_regdma.h
  2. 1 2
      components/esp_hw_support/include/esp_private/sleep_retention.h
  3. 3 3
      components/esp_hw_support/sleep_clock.c
  4. 2 2
      components/esp_hw_support/sleep_modem.c
  5. 0 1
      components/esp_hw_support/sleep_retention.c
  6. 2 2
      components/esp_phy/src/btbb_init.c
  7. 8 0
      components/ieee802154/Kconfig
  8. 56 3
      components/ieee802154/driver/esp_ieee802154_dev.c
  9. 13 1
      components/ieee802154/esp_ieee802154.c
  10. 10 0
      components/ieee802154/include/esp_ieee802154.h
  11. 1 0
      components/ieee802154/include/esp_ieee802154_types.h
  12. 13 0
      components/ieee802154/private_include/esp_ieee802154_dev.h
  13. 7 7
      components/ieee802154/test_apps/test_ieee802154/pytest_test_ieee802154.py
  14. 5 0
      components/openthread/CMakeLists.txt
  15. 42 0
      components/openthread/private_include/esp_openthread_sleep.h
  16. 12 1
      components/openthread/src/esp_openthread.cpp
  17. 1 1
      components/openthread/src/port/esp_openthread_radio.c
  18. 52 0
      components/openthread/src/port/esp_openthread_sleep.c
  19. 9 0
      examples/openthread/.build-test-rules.yml
  20. 2 0
      examples/openthread/README.md
  21. 6 0
      examples/openthread/ot_sleepy_device/CMakeLists.txt
  22. 40 0
      examples/openthread/ot_sleepy_device/README.md
  23. 2 0
      examples/openthread/ot_sleepy_device/main/CMakeLists.txt
  24. 140 0
      examples/openthread/ot_sleepy_device/main/esp_ot_sleepy_device.c
  25. 53 0
      examples/openthread/ot_sleepy_device/main/esp_ot_sleepy_device_config.h
  26. 5 0
      examples/openthread/ot_sleepy_device/partitions.csv
  27. 51 0
      examples/openthread/ot_sleepy_device/sdkconfig.defaults

+ 1 - 0
components/esp_hw_support/include/esp_private/esp_regdma.h

@@ -41,6 +41,7 @@ extern "C" {
 #define REGDMA_SYSTIMER_LINK(_pri)          ((0x14 << 8) | _pri)
 #define REGDMA_SYSTIMER_LINK(_pri)          ((0x14 << 8) | _pri)
 #define REGDMA_BLE_MAC_LINK(_pri)           ((0x15 << 8) | _pri)
 #define REGDMA_BLE_MAC_LINK(_pri)           ((0x15 << 8) | _pri)
 #define REGDMA_MODEM_BT_BB_LINK(_pri)       ((0x16 << 8) | _pri)
 #define REGDMA_MODEM_BT_BB_LINK(_pri)       ((0x16 << 8) | _pri)
+#define REGDMA_MODEM_IEEE802154_LINK(_pri)  ((0x17 << 8) | _pri)
 #define REGDMA_MODEM_FE_LINK(_pri)          ((0xFF << 8) | _pri)
 #define REGDMA_MODEM_FE_LINK(_pri)          ((0xFF << 8) | _pri)
 
 
 typedef enum {
 typedef enum {

+ 1 - 2
components/esp_hw_support/include/esp_private/sleep_retention.h

@@ -32,9 +32,8 @@ typedef enum sleep_retention_module_bitmap {
     SLEEP_RETENTION_MODULE_WIFI_MAC     = BIT(10),
     SLEEP_RETENTION_MODULE_WIFI_MAC     = BIT(10),
     SLEEP_RETENTION_MODULE_WIFI_BB      = BIT(11),
     SLEEP_RETENTION_MODULE_WIFI_BB      = BIT(11),
     SLEEP_RETENTION_MODULE_BLE_MAC      = BIT(12),
     SLEEP_RETENTION_MODULE_BLE_MAC      = BIT(12),
-    SLEEP_RETENTION_MODULE_BLE_BB       = BIT(13),
+    SLEEP_RETENTION_MODULE_BT_BB        = BIT(13),
     SLEEP_RETENTION_MODULE_802154_MAC   = BIT(14),
     SLEEP_RETENTION_MODULE_802154_MAC   = BIT(14),
-    SLEEP_RETENTION_MODULE_802154_BB    = BIT(15),
 
 
     /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM,
     /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM,
      * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */
      * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */

+ 3 - 3
components/esp_hw_support/sleep_clock.c

@@ -71,21 +71,21 @@ bool IRAM_ATTR clock_domain_pd_allowed(void)
     const uint32_t modules = sleep_retention_get_modules();
     const uint32_t modules = sleep_retention_get_modules();
     const uint32_t mask = (const uint32_t) (
     const uint32_t mask = (const uint32_t) (
             SLEEP_RETENTION_MODULE_CLOCK_SYSTEM
             SLEEP_RETENTION_MODULE_CLOCK_SYSTEM
-#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE
+#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE
           | SLEEP_RETENTION_MODULE_CLOCK_MODEM
           | SLEEP_RETENTION_MODULE_CLOCK_MODEM
 #endif
 #endif
           );
           );
     return ((modules & mask) == mask);
     return ((modules & mask) == mask);
 }
 }
 
 
-#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP || CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE
+#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP || CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE
 ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, BIT(0), 106)
 ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, BIT(0), 106)
 {
 {
 #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
 #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
     sleep_clock_system_retention_init();
     sleep_clock_system_retention_init();
 #endif
 #endif
 
 
-#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE
+#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE
     sleep_clock_modem_retention_init();
     sleep_clock_modem_retention_init();
 #endif
 #endif
     return ESP_OK;
     return ESP_OK;

+ 2 - 2
components/esp_hw_support/sleep_modem.c

@@ -279,9 +279,9 @@ bool IRAM_ATTR modem_domain_pd_allowed(void)
     const uint32_t mask_wifi = (const uint32_t) (SLEEP_RETENTION_MODULE_WIFI_MAC |
     const uint32_t mask_wifi = (const uint32_t) (SLEEP_RETENTION_MODULE_WIFI_MAC |
                                                  SLEEP_RETENTION_MODULE_WIFI_BB);
                                                  SLEEP_RETENTION_MODULE_WIFI_BB);
     const uint32_t mask_ble = (const uint32_t) (SLEEP_RETENTION_MODULE_BLE_MAC |
     const uint32_t mask_ble = (const uint32_t) (SLEEP_RETENTION_MODULE_BLE_MAC |
-                                                SLEEP_RETENTION_MODULE_BLE_BB);
+                                                SLEEP_RETENTION_MODULE_BT_BB);
     const uint32_t mask_154 = (const uint32_t) (SLEEP_RETENTION_MODULE_802154_MAC |
     const uint32_t mask_154 = (const uint32_t) (SLEEP_RETENTION_MODULE_802154_MAC |
-                                                SLEEP_RETENTION_MODULE_802154_BB);
+                                                SLEEP_RETENTION_MODULE_BT_BB);
     return (((modules & mask_wifi) == mask_wifi) ||
     return (((modules & mask_wifi) == mask_wifi) ||
             ((modules & mask_ble)  == mask_ble) ||
             ((modules & mask_ble)  == mask_ble) ||
             ((modules & mask_154)  == mask_154));
             ((modules & mask_154)  == mask_154));

+ 0 - 1
components/esp_hw_support/sleep_retention.c

@@ -21,7 +21,6 @@
 #include "sdkconfig.h"
 #include "sdkconfig.h"
 #include "esp_pmu.h"
 #include "esp_pmu.h"
 
 
-
 static __attribute__((unused)) const char *TAG = "sleep";
 static __attribute__((unused)) const char *TAG = "sleep";
 
 
 /**
 /**

+ 2 - 2
components/esp_phy/src/btbb_init.c

@@ -35,7 +35,7 @@ static esp_err_t btbb_sleep_retention_init(void)
         [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_BT_BB_LINK(0x01), BB_PART_1_ADDR, BB_PART_1_ADDR, BB_PART_1_SIZE, 0, 0), .owner = BTBB_LINK_OWNER },
         [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_BT_BB_LINK(0x01), BB_PART_1_ADDR, BB_PART_1_ADDR, BB_PART_1_SIZE, 0, 0), .owner = BTBB_LINK_OWNER },
         [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_BT_BB_LINK(0x02), BB_PART_2_ADDR, BB_PART_2_ADDR, BB_PART_2_SIZE, 0, 0), .owner = BTBB_LINK_OWNER }
         [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_BT_BB_LINK(0x02), BB_PART_2_ADDR, BB_PART_2_ADDR, BB_PART_2_SIZE, 0, 0), .owner = BTBB_LINK_OWNER }
     };
     };
-    esp_err_t err = sleep_retention_entries_create(btbb_regs_retention, ARRAY_SIZE(btbb_regs_retention), REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_BLE_BB);
+    esp_err_t err = sleep_retention_entries_create(btbb_regs_retention, ARRAY_SIZE(btbb_regs_retention), REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_BT_BB);
     ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for btbb retention");
     ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for btbb retention");
     ESP_LOGI(TAG, "btbb sleep retention initialization");
     ESP_LOGI(TAG, "btbb sleep retention initialization");
     return ESP_OK;
     return ESP_OK;
@@ -43,7 +43,7 @@ static esp_err_t btbb_sleep_retention_init(void)
 
 
 static void btbb_sleep_retention_deinit(void)
 static void btbb_sleep_retention_deinit(void)
 {
 {
-    sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_BLE_BB);
+    sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_BT_BB);
 }
 }
 #endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE && !CONFIG_IDF_TARGET_ESP32H2
 #endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE && !CONFIG_IDF_TARGET_ESP32H2
 
 

+ 8 - 0
components/ieee802154/Kconfig

@@ -74,4 +74,12 @@ menu "IEEE 802.15.4"
             Enabling this option increases throughput by ~5% at the expense of ~2.1k
             Enabling this option increases throughput by ~5% at the expense of ~2.1k
             IRAM code size increase.
             IRAM code size increase.
 
 
+    config IEEE802154_SLEEP_ENABLE
+        # Todo: Remove when support safe power-down of the power domain (IDF-7317)
+        bool "Enable IEEE802154 light sleep"
+        depends on PM_ENABLE && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
+        default n
+        help
+            Enabling this option allows the IEEE802.15.4 module to be powered down during automatic light sleep,
+            which reduces current consumption.
 endmenu  # IEEE 802.15.4
 endmenu  # IEEE 802.15.4

+ 56 - 3
components/ieee802154/driver/esp_ieee802154_dev.c

@@ -24,6 +24,13 @@
 #include "esp_ieee802154_timer.h"
 #include "esp_ieee802154_timer.h"
 #include "hal/ieee802154_ll.h"
 #include "hal/ieee802154_ll.h"
 #include "esp_attr.h"
 #include "esp_attr.h"
+#include "esp_phy_init.h"
+
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+#include "esp_pm.h"
+#include "esp_private/esp_clk.h"
+#include "esp_private/sleep_retention.h"
+#endif
 
 
 #define CCA_DETECTION_TIME 8
 #define CCA_DETECTION_TIME 8
 
 
@@ -38,6 +45,8 @@ static uint8_t s_enh_ack_frame[128];
 static uint8_t s_recent_rx_frame_info_index;
 static uint8_t s_recent_rx_frame_info_index;
 static portMUX_TYPE s_ieee802154_spinlock = portMUX_INITIALIZER_UNLOCKED;
 static portMUX_TYPE s_ieee802154_spinlock = portMUX_INITIALIZER_UNLOCKED;
 
 
+static esp_err_t ieee802154_sleep_init(void);
+
 static IRAM_ATTR void event_end_process(void)
 static IRAM_ATTR void event_end_process(void)
 {
 {
     ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL0);
     ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL0);
@@ -193,7 +202,11 @@ static bool stop_current_operation(void)
         break;
         break;
 
 
     case IEEE802154_STATE_IDLE:
     case IEEE802154_STATE_IDLE:
-        // do nothing
+        ieee802154_ll_set_cmd(IEEE802154_CMD_STOP);
+        break;
+
+    case IEEE802154_STATE_SLEEP:
+        // Do nothing
         break;
         break;
 
 
     case IEEE802154_STATE_RX:
     case IEEE802154_STATE_RX:
@@ -555,10 +568,12 @@ static IRAM_ATTR void ieee802154_exit_critical(void)
 void ieee802154_enable(void)
 void ieee802154_enable(void)
 {
 {
     modem_clock_module_enable(ieee802154_periph.module);
     modem_clock_module_enable(ieee802154_periph.module);
+    s_ieee802154_state = IEEE802154_STATE_IDLE;
 }
 }
 
 
 void ieee802154_disable(void)
 void ieee802154_disable(void)
 {
 {
+    modem_clock_module_disable(ieee802154_periph.module);
     s_ieee802154_state = IEEE802154_STATE_DISABLE;
     s_ieee802154_state = IEEE802154_STATE_DISABLE;
 }
 }
 
 
@@ -589,12 +604,13 @@ esp_err_t ieee802154_mac_init(void)
 #endif
 #endif
 
 
     memset(s_rx_frame, 0, sizeof(s_rx_frame));
     memset(s_rx_frame, 0, sizeof(s_rx_frame));
-    s_ieee802154_state = IEEE802154_STATE_IDLE;
 
 
     // TODO: Add flags for IEEE802154 ISR allocating. TZ-102
     // TODO: Add flags for IEEE802154 ISR allocating. TZ-102
     ret = esp_intr_alloc(ieee802154_periph.irq_id, 0, ieee802154_isr, NULL, NULL);
     ret = esp_intr_alloc(ieee802154_periph.irq_id, 0, ieee802154_isr, NULL, NULL);
     ESP_RETURN_ON_FALSE(ret == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC init failed");
     ESP_RETURN_ON_FALSE(ret == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC init failed");
 
 
+    ESP_RETURN_ON_FALSE(ieee802154_sleep_init() == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC sleep init failed");
+
     return ret;
     return ret;
 }
 }
 
 
@@ -716,12 +732,49 @@ esp_err_t ieee802154_receive_at(uint32_t time)
     return ESP_OK;
     return ESP_OK;
 }
 }
 
 
+static esp_err_t ieee802154_sleep_init(void)
+{
+    esp_err_t err = ESP_OK;
+#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE
+    #define N_REGS_IEEE802154() (((IEEE802154_MAC_DATE_REG - IEEE802154_REG_BASE) / 4) + 1)
+    const static sleep_retention_entries_config_t ieee802154_mac_regs_retention[] = {
+        [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_IEEE802154_LINK(0x00), IEEE802154_REG_BASE, IEEE802154_REG_BASE, N_REGS_IEEE802154(), 0, 0), .owner = ENTRY(3) },
+    };
+    err = sleep_retention_entries_create(ieee802154_mac_regs_retention, ARRAY_SIZE(ieee802154_mac_regs_retention), REGDMA_LINK_PRI_7, SLEEP_RETENTION_MODULE_802154_MAC);
+    ESP_RETURN_ON_ERROR(err, IEEE802154_TAG, "failed to allocate memory for ieee802154 mac retention");
+    ESP_LOGI(IEEE802154_TAG, "ieee802154 mac sleep retention initialization");
+#endif
+    return err;
+}
+
+IRAM_ATTR void ieee802154_enter_sleep(void)
+{
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+    esp_phy_disable();
+#if SOC_PM_RETENTION_HAS_CLOCK_BUG
+    sleep_retention_do_extra_retention(true);// backup
+#endif
+    ieee802154_disable(); // IEEE802154 CLOCK Disable
+#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
+}
+
+IRAM_ATTR void ieee802154_wakeup(void)
+{
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+    ieee802154_enable(); // IEEE802154 CLOCK Enable
+#if SOC_PM_RETENTION_HAS_CLOCK_BUG
+    sleep_retention_do_extra_retention(false);// restore
+#endif
+    esp_phy_enable();
+#endif //CONFIG_FREERTOS_USE_TICKLESS_IDLE
+}
+
 esp_err_t ieee802154_sleep(void)
 esp_err_t ieee802154_sleep(void)
 {
 {
     ieee802154_enter_critical();
     ieee802154_enter_critical();
 
 
     stop_current_operation();
     stop_current_operation();
-    s_ieee802154_state = IEEE802154_STATE_IDLE;
+    s_ieee802154_state = IEEE802154_STATE_SLEEP;
 
 
     ieee802154_exit_critical();
     ieee802154_exit_critical();
     return ESP_OK;
     return ESP_OK;

+ 13 - 1
components/ieee802154/esp_ieee802154.c

@@ -21,7 +21,6 @@
 
 
 esp_err_t esp_ieee802154_enable(void)
 esp_err_t esp_ieee802154_enable(void)
 {
 {
-
     ieee802154_enable();
     ieee802154_enable();
     esp_phy_enable();
     esp_phy_enable();
     esp_btbb_enable();
     esp_btbb_enable();
@@ -281,6 +280,9 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void)
         return ESP_IEEE802154_RADIO_DISABLE;
         return ESP_IEEE802154_RADIO_DISABLE;
 
 
     case IEEE802154_STATE_IDLE:
     case IEEE802154_STATE_IDLE:
+        return ESP_IEEE802154_RADIO_IDLE;
+
+    case IEEE802154_STATE_SLEEP:
         return ESP_IEEE802154_RADIO_SLEEP;
         return ESP_IEEE802154_RADIO_SLEEP;
 
 
     case IEEE802154_STATE_RX:
     case IEEE802154_STATE_RX:
@@ -332,6 +334,16 @@ uint8_t esp_ieee802154_get_recent_lqi(void)
     return ieee802154_get_recent_lqi();
     return ieee802154_get_recent_lqi();
 }
 }
 
 
+void esp_ieee802154_enter_sleep(void)
+{
+    ieee802154_enter_sleep();
+}
+
+void esp_ieee802154_wakeup(void)
+{
+    ieee802154_wakeup();
+}
+
 __attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info)
 __attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info)
 {
 {
 
 

+ 10 - 0
components/ieee802154/include/esp_ieee802154.h

@@ -111,6 +111,16 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void);
  */
  */
 esp_err_t esp_ieee802154_sleep(void);
 esp_err_t esp_ieee802154_sleep(void);
 
 
+/**
+ * @brief  The IEEE 802.15.4 enter sleep.
+ */
+void esp_ieee802154_enter_sleep(void);
+
+/**
+ * @brief  The IEEE 802.15.4 wakeup.
+ */
+void esp_ieee802154_wakeup(void);
+
 /**
 /**
  * @brief  Set the IEEE 802.15.4 Radio to receive state.
  * @brief  Set the IEEE 802.15.4 Radio to receive state.
  *
  *

+ 1 - 0
components/ieee802154/include/esp_ieee802154_types.h

@@ -18,6 +18,7 @@ extern "C" {
  */
  */
 typedef enum {
 typedef enum {
     ESP_IEEE802154_RADIO_DISABLE,   /*!< Radio not up */
     ESP_IEEE802154_RADIO_DISABLE,   /*!< Radio not up */
+    ESP_IEEE802154_RADIO_IDLE,      /*!< Radio in the idle state */
     ESP_IEEE802154_RADIO_SLEEP,     /*!< Radio in the sleep state */
     ESP_IEEE802154_RADIO_SLEEP,     /*!< Radio in the sleep state */
     ESP_IEEE802154_RADIO_RECEIVE,   /*!< Radio in the receive state */
     ESP_IEEE802154_RADIO_RECEIVE,   /*!< Radio in the receive state */
     ESP_IEEE802154_RADIO_TRANSMIT,  /*!< Radio in the transmit state */
     ESP_IEEE802154_RADIO_TRANSMIT,  /*!< Radio in the transmit state */

+ 13 - 0
components/ieee802154/private_include/esp_ieee802154_dev.h

@@ -31,6 +31,7 @@ extern "C" {
 typedef enum {
 typedef enum {
     IEEE802154_STATE_DISABLE,               /*!< IEEE802154 radio state disable */
     IEEE802154_STATE_DISABLE,               /*!< IEEE802154 radio state disable */
     IEEE802154_STATE_IDLE,                  /*!< IEEE802154 radio state idle */
     IEEE802154_STATE_IDLE,                  /*!< IEEE802154 radio state idle */
+    IEEE802154_STATE_SLEEP,                 /*!< IEEE802154 radio state sleep */
     IEEE802154_STATE_RX,                    /*!< IEEE802154 radio state rx */
     IEEE802154_STATE_RX,                    /*!< IEEE802154 radio state rx */
     IEEE802154_STATE_TX_ACK,                /*!< IEEE802154 radio state tx ack */
     IEEE802154_STATE_TX_ACK,                /*!< IEEE802154 radio state tx ack */
     IEEE802154_STATE_TX_ENH_ACK,            /*!< IEEE802154 radio state tx enh-ack */
     IEEE802154_STATE_TX_ENH_ACK,            /*!< IEEE802154 radio state tx enh-ack */
@@ -177,6 +178,18 @@ uint8_t ieee802154_get_recent_lqi(void);
  */
  */
 ieee802154_state_t ieee802154_get_state(void);
 ieee802154_state_t ieee802154_get_state(void);
 
 
+/**
+ * @brief  The IEEE 802.15.4 enter sleep.
+ *
+ */
+void ieee802154_enter_sleep(void);
+
+/**
+ * @brief  The IEEE 802.15.4 wakeup.
+ *
+ */
+void ieee802154_wakeup(void);
+
 /** The following three functions are only used for internal test. **/
 /** The following three functions are only used for internal test. **/
 /**
 /**
  * @brief  The clear channel assessment done.
  * @brief  The clear channel assessment done.

+ 7 - 7
components/ieee802154/test_apps/test_ieee802154/pytest_test_ieee802154.py

@@ -129,17 +129,17 @@ def test_based_txrx(dut: Tuple[IdfDut, IdfDut]) -> None:
     receive.expect('RX Start', timeout=10)
     receive.expect('RX Start', timeout=10)
     transmit.expect('ieee802154>', timeout=10)
     transmit.expect('ieee802154>', timeout=10)
     transmit.write('tx -l 10')
     transmit.write('tx -l 10')
-    transmit.expect('tx sfd done, Radio state: 3', timeout=10)
+    transmit.expect('tx sfd done, Radio state: 4', timeout=10)
     transmit.expect('Tx Done 10 bytes', timeout=10)
     transmit.expect('Tx Done 10 bytes', timeout=10)
     transmit.expect('00 01 02 03 04 05 06 07', timeout=10)
     transmit.expect('00 01 02 03 04 05 06 07', timeout=10)
     transmit.expect('08 09 00 00 00 00 00 00', timeout=10)
     transmit.expect('08 09 00 00 00 00 00 00', timeout=10)
-    receive.expect('rx sfd done, Radio state: 2', timeout=10)
+    receive.expect('rx sfd done, Radio state: 3', timeout=10)
     receive.expect('Rx Done 10 bytes', timeout=10)
     receive.expect('Rx Done 10 bytes', timeout=10)
     receive.expect('00 01 02 03 04 05 06 07', timeout=10)
     receive.expect('00 01 02 03 04 05 06 07', timeout=10)
     receive.write('rx -r 0')
     receive.write('rx -r 0')
     receive.expect('radio exit receive mode', timeout=10)
     receive.expect('radio exit receive mode', timeout=10)
     transmit.write('tx -l 10')
     transmit.write('tx -l 10')
-    transmit.expect('tx sfd done, Radio state: 3', timeout=10)
+    transmit.expect('tx sfd done, Radio state: 4', timeout=10)
     transmit.expect('Tx Done 10 bytes', timeout=10)
     transmit.expect('Tx Done 10 bytes', timeout=10)
     transmit.expect('00 01 02 03 04 05 06 07', timeout=10)
     transmit.expect('00 01 02 03 04 05 06 07', timeout=10)
     transmit.expect('08 09 00 00 00 00 00 00', timeout=10)
     transmit.expect('08 09 00 00 00 00 00 00', timeout=10)
@@ -344,13 +344,13 @@ def test_based_autoack(dut: Tuple[IdfDut, IdfDut]) -> None:
     receive.expect('RX Start', timeout=10)
     receive.expect('RX Start', timeout=10)
 
 
     transmit.write('tx 0x20 0x88 0x00 0x0A 0x28 0xDB 0x6F 0xBC 0x94 0x5A 0x43 0x68 0x02 0xaa 0x15 0x30 0x01 0x02')
     transmit.write('tx 0x20 0x88 0x00 0x0A 0x28 0xDB 0x6F 0xBC 0x94 0x5A 0x43 0x68 0x02 0xaa 0x15 0x30 0x01 0x02')
-    transmit.expect('tx sfd done, Radio state: 3', timeout=10)
-    transmit.expect('rx sfd done, Radio state: 3', timeout=10)
+    transmit.expect('tx sfd done, Radio state: 4', timeout=10)
+    transmit.expect('rx sfd done, Radio state: 4', timeout=10)
     transmit.expect('Tx Done 18 bytes', timeout=10)
     transmit.expect('Tx Done 18 bytes', timeout=10)
     transmit.expect('20 88 00 0a 28 db 6f bc', timeout=10)
     transmit.expect('20 88 00 0a 28 db 6f bc', timeout=10)
     transmit.expect('94 5a 43 68 02 aa 15 30', timeout=10)
     transmit.expect('94 5a 43 68 02 aa 15 30', timeout=10)
 
 
-    receive.expect('rx sfd done, Radio state: 2', timeout=10)
+    receive.expect('rx sfd done, Radio state: 3', timeout=10)
     receive.expect('Rx Done 18 bytes', timeout=10)
     receive.expect('Rx Done 18 bytes', timeout=10)
     receive.expect('20 88 00 0a 28 db 6f bc', timeout=10)
     receive.expect('20 88 00 0a 28 db 6f bc', timeout=10)
     receive.expect('94 5a 43 68 02 aa 15 30', timeout=10)
     receive.expect('94 5a 43 68 02 aa 15 30', timeout=10)
@@ -573,7 +573,7 @@ def test_based_transmit_failed(dut: IdfDut) -> None:
     transmit.write('tx -l 10 -C')
     transmit.write('tx -l 10 -C')
     transmit.expect('the Frame Transmission failed, Failure reason: 1', timeout=10)
     transmit.expect('the Frame Transmission failed, Failure reason: 1', timeout=10)
     transmit.write('tx -l 10')
     transmit.write('tx -l 10')
-    transmit.expect('tx sfd done, Radio state: 3', timeout=10)
+    transmit.expect('tx sfd done, Radio state: 4', timeout=10)
     transmit.expect('Tx Done 10 bytes', timeout=10)
     transmit.expect('Tx Done 10 bytes', timeout=10)
     transmit.expect('00 01 02 03 04 05 06 07', timeout=10)
     transmit.expect('00 01 02 03 04 05 06 07', timeout=10)
     transmit.expect('08 09 00 00 00 00 00 00', timeout=10)
     transmit.expect('08 09 00 00 00 00 00 00', timeout=10)

+ 5 - 0
components/openthread/CMakeLists.txt

@@ -139,6 +139,11 @@ if(CONFIG_OPENTHREAD_ENABLED)
             "src/esp_openthread_dns64.c")
             "src/esp_openthread_dns64.c")
     endif()
     endif()
 
 
+    if(NOT CONFIG_FREERTOS_USE_TICKLESS_IDLE)
+        list(APPEND exclude_srcs
+            "src/port/esp_openthread_sleep.c")
+    endif()
+
     if(CONFIG_OPENTHREAD_FTD)
     if(CONFIG_OPENTHREAD_FTD)
         set(device_type "OPENTHREAD_FTD=1")
         set(device_type "OPENTHREAD_FTD=1")
     elseif(CONFIG_OPENTHREAD_MTD)
     elseif(CONFIG_OPENTHREAD_MTD)

+ 42 - 0
components/openthread/private_include/esp_openthread_sleep.h

@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include "esp_err.h"
+#include "sdkconfig.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef CONFIG_FREERTOS_USE_TICKLESS_IDLE
+/**
+ * @brief This function initializes the OpenThread sleep.
+ *
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_FAIL on failure
+ *
+ */
+esp_err_t esp_openthread_sleep_init(void);
+
+/**
+ * @brief This function performs the OpenThread sleep process.
+ *
+ */
+void esp_openthread_sleep_process(void);
+
+/**
+ * @brief This function performs the OpenThread wakeup process.
+ *
+ */
+void esp_openthread_wakeup_process(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif

+ 12 - 1
components/openthread/src/esp_openthread.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
  *
  *
  * SPDX-License-Identifier: Apache-2.0
  * SPDX-License-Identifier: Apache-2.0
  */
  */
@@ -11,6 +11,7 @@
 #include "esp_openthread_dns64.h"
 #include "esp_openthread_dns64.h"
 #include "esp_openthread_lock.h"
 #include "esp_openthread_lock.h"
 #include "esp_openthread_platform.h"
 #include "esp_openthread_platform.h"
+#include "esp_openthread_sleep.h"
 #include "esp_openthread_task_queue.h"
 #include "esp_openthread_task_queue.h"
 #include "esp_openthread_types.h"
 #include "esp_openthread_types.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/FreeRTOS.h"
@@ -58,6 +59,10 @@ esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *config)
 {
 {
     ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG,
     ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG,
                         "Failed to initialize OpenThread platform driver");
                         "Failed to initialize OpenThread platform driver");
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+    ESP_RETURN_ON_ERROR(esp_openthread_sleep_init(), OT_PLAT_LOG_TAG,
+                        "Failed to initialize OpenThread esp pm_lock");
+#endif
     esp_openthread_lock_acquire(portMAX_DELAY);
     esp_openthread_lock_acquire(portMAX_DELAY);
     ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG,
     ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG,
                         "Failed to initialize OpenThread instance");
                         "Failed to initialize OpenThread instance");
@@ -154,11 +159,17 @@ esp_err_t esp_openthread_launch_mainloop(void)
             mainloop.timeout.tv_sec = 0;
             mainloop.timeout.tv_sec = 0;
             mainloop.timeout.tv_usec = 0;
             mainloop.timeout.tv_usec = 0;
         }
         }
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+        esp_openthread_sleep_process();
+#endif
         esp_openthread_lock_release();
         esp_openthread_lock_release();
 
 
         if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds,
         if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds,
                    &mainloop.timeout) >= 0) {
                    &mainloop.timeout) >= 0) {
             esp_openthread_lock_acquire(portMAX_DELAY);
             esp_openthread_lock_acquire(portMAX_DELAY);
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+            esp_openthread_wakeup_process();
+#endif
             error = esp_openthread_platform_process(instance, &mainloop);
             error = esp_openthread_platform_process(instance, &mainloop);
             while (otTaskletsArePending(instance)) {
             while (otTaskletsArePending(instance)) {
                 otTaskletsProcess(instance);
                 otTaskletsProcess(instance);

+ 1 - 1
components/openthread/src/port/esp_openthread_radio.c

@@ -273,7 +273,7 @@ otError otPlatRadioEnable(otInstance *aInstance)
 
 
 otError otPlatRadioDisable(otInstance *aInstance)
 otError otPlatRadioDisable(otInstance *aInstance)
 {
 {
-    esp_ieee802154_disable();
+    // radio will be disabled in esp_openthread_radio_deinit()
 
 
     return OT_ERROR_NONE;
     return OT_ERROR_NONE;
 }
 }

+ 52 - 0
components/openthread/src/port/esp_openthread_sleep.c

@@ -0,0 +1,52 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "sdkconfig.h"
+
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+#include "esp_log.h"
+#include "esp_check.h"
+#include "esp_ieee802154.h"
+#include "esp_pm.h"
+static esp_pm_lock_handle_t s_pm_lock = NULL;
+static const char* TAG = "esp openthread sleep";
+static bool s_ot_sleep = false;
+
+esp_err_t esp_openthread_sleep_init(void)
+{
+    esp_err_t err = ESP_OK;
+
+    err = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ieee802154", &s_pm_lock);
+    if (err == ESP_OK) {
+        esp_pm_lock_acquire(s_pm_lock);
+        ESP_LOGI(TAG, "Enable ieee802154 light sleep, the wake up source is ESP timer");
+    } else {
+        if (s_pm_lock != NULL) {
+            esp_pm_lock_delete(s_pm_lock);
+            s_pm_lock = NULL;
+        }
+    }
+    return err;
+}
+
+void esp_openthread_sleep_process(void)
+{
+    if (esp_ieee802154_get_state() == ESP_IEEE802154_RADIO_SLEEP) {
+        esp_ieee802154_enter_sleep();
+        esp_pm_lock_release(s_pm_lock);
+        s_ot_sleep = true;
+    }
+}
+
+void esp_openthread_wakeup_process(void)
+{
+    if (s_ot_sleep) {
+        esp_pm_lock_acquire(s_pm_lock);
+        esp_ieee802154_wakeup();
+        s_ot_sleep = false;
+    }
+}
+#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE

+ 9 - 0
examples/openthread/.build-test-rules.yml

@@ -49,3 +49,12 @@ examples/openthread/ot_rcp:
       temporary: true
       temporary: true
       reason: only test on esp32c6
       reason: only test on esp32c6
   <<: *openthread_dependencies
   <<: *openthread_dependencies
+
+examples/openthread/ot_sleepy_device:
+  enable:
+    - if: IDF_TARGET  == "esp32c6"
+  disable_test:
+    - if: IDF_TARGET in ["esp32h2", "esp32c6"]
+      temporary: true
+      reason: No support # TO-DO: TZ-134
+  <<: *openthread_dependencies

+ 2 - 0
examples/openthread/README.md

@@ -11,3 +11,5 @@ In this folder, it contains following OpenThread examples:
 * [ot_rcp](ot_rcp) is an [OpenThread RCP](https://openthread.io/platforms/co-processor) example. It runs on an 802.15.4 SoC like ESP32-H2, to extend 802.15.4 radio.
 * [ot_rcp](ot_rcp) is an [OpenThread RCP](https://openthread.io/platforms/co-processor) example. It runs on an 802.15.4 SoC like ESP32-H2, to extend 802.15.4 radio.
 
 
 * [ot_br](ot_br) is an [OpenThread Border Router](https://openthread.io/guides/border-router) example. It runs on a Wi-Fi SoC such as ESP32, ESP32-C3 and ESP32-S3. It needs an 802.15.4 SoC like ESP32-H2 running [ot_rcp](ot_rcp) example to provide 802.15.4 radio.
 * [ot_br](ot_br) is an [OpenThread Border Router](https://openthread.io/guides/border-router) example. It runs on a Wi-Fi SoC such as ESP32, ESP32-C3 and ESP32-S3. It needs an 802.15.4 SoC like ESP32-H2 running [ot_rcp](ot_rcp) example to provide 802.15.4 radio.
+
+* [ot_sleepy_device](ot_sleepy_device) is an OpenThread sleepy device example, it supports 802.15.4 radio light sleep. It runs on an 802.15.4 SoC.

+ 6 - 0
examples/openthread/ot_sleepy_device/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)

+ 40 - 0
examples/openthread/ot_sleepy_device/README.md

@@ -0,0 +1,40 @@
+| Supported Targets | ESP32-C6 |
+| ----------------- | -------- |
+
+# 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.
+## How to use example
+
+### Hardware Required
+
+* Prepare an 802.15.4 SoC development board as an OpenThread Sleepy End Device (SED).
+* Connect the board using a USB cable for power supply and programming.
+* Choose another 802.15.4 SoC as the OpenThread Leader.
+
+## 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.
+* 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
+
+Build the project and flash it to the board. Use the following command: `idf.py -p <PORT> 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) and periodic polling of the leader.
+
+```
+I (769) btbb_init: btbb sleep retention initialization
+I (769) ieee802154: ieee802154 mac sleep retention initialization
+I(769) OPENTHREAD:[I] ChildSupervsn-: Timeout: 0 -> 190
+I (699) main_task: Returned from app_main()
+I (799) OPENTHREAD: OpenThread attached to netif
+I(799) OPENTHREAD:[N] Mle-----------: Mode 0x0f -> 0x04 [rx-on:no ftd:no full-net:no]
+I(809) OPENTHREAD:[N] Mle-----------: Role disabled -> detached
+I (819) OPENTHREAD: netif up
+I(1519) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset
+I(2479) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 5023
+I(2529) OPENTHREAD:[N] Mle-----------: Role detached -> child
+```  

+ 2 - 0
examples/openthread/ot_sleepy_device/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "esp_ot_sleepy_device.c"
+                       INCLUDE_DIRS ".")

+ 140 - 0
examples/openthread/ot_sleepy_device/main/esp_ot_sleepy_device.c

@@ -0,0 +1,140 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "esp_err.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "esp_openthread.h"
+#include "esp_openthread_netif_glue.h"
+#include "esp_ot_sleepy_device_config.h"
+#include "esp_vfs_eventfd.h"
+#include "driver/uart.h"
+#include "nvs_flash.h"
+#include "openthread/logging.h"
+#include "openthread/thread.h"
+
+#ifdef CONFIG_PM_ENABLE
+#include "esp_pm.h"
+#endif
+
+#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 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_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));
+
+#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);
+
+    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);
+}
+
+static esp_err_t ot_power_save_init(void)
+{
+    esp_err_t rc = ESP_OK;
+#ifdef CONFIG_PM_ENABLE
+    int cur_cpu_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
+
+    esp_pm_config_t pm_config = {
+        .max_freq_mhz = cur_cpu_freq_mhz,
+        .min_freq_mhz = cur_cpu_freq_mhz,
+#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
+        .light_sleep_enable = true
+#endif
+    };
+
+    rc = esp_pm_configure(&pm_config);
+#endif
+    return rc;
+}
+
+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));
+    ESP_ERROR_CHECK(ot_power_save_init());
+
+    xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL);
+}

+ 53 - 0
examples/openthread/ot_sleepy_device/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 3000
+
+#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,                  \
+    }

+ 5 - 0
examples/openthread/ot_sleepy_device/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,

+ 51 - 0
examples/openthread/ot_sleepy_device/sdkconfig.defaults

@@ -0,0 +1,51 @@
+#
+# 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_MULTICAST_PING=y
+# end of lwIP
+
+#
+# IEEE 802.15.4
+#
+CONFIG_IEEE802154_ENABLED=y
+# end of IEEE 802.15.4
+
+#
+# light sleep
+#
+CONFIG_PM_ENABLE=y
+CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
+CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
+CONFIG_IEEE802154_SLEEP_ENABLE=y
+# end of light sleep