Merge branch 'feature/esp32c6_light_sleep_support_ieee802154' into 'master'

ieee802154: esp32c6 light sleep support

See merge request espressif/esp-idf!23629
This commit is contained in:
Shu Chen
2023-07-04 10:13:28 +08:00
27 changed files with 537 additions and 23 deletions

View File

@ -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 {

View File

@ -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.. */

View File

@ -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;

View File

@ -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));

View File

@ -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";
/** /**

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)
{ {

View File

@ -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.
* *

View File

@ -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 */

View File

@ -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.

View File

@ -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('tx sfd done, Radio state: 4', timeout=10)
transmit.expect('rx sfd done, Radio state: 3', 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)

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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
```

View File

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

View File

@ -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);
}

View File

@ -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, \
}

View File

@ -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,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 0x120000,

View File

@ -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