ieee802154: support light sleep

This commit is contained in:
xiaqilin
2023-05-25 18:18:03 +08:00
committed by BOT
parent f30a420a74
commit dc4b3f24bc
22 changed files with 699 additions and 12 deletions
@@ -39,8 +39,8 @@ extern "C" {
#define REGDMA_IOMUX_LINK(_pri) ((0x12 << 8) | _pri)
#define REGDMA_SPIMEM_LINK(_pri) ((0x13 << 8) | _pri)
#define REGDMA_SYSTIMER_LINK(_pri) ((0x14 << 8) | _pri)
#define REGDMA_BLE_MAC_LINK(_pri) ((0x15 << 8) | _pri)
#define REGDMA_MODEM_BT_BB_LINK(_pri) ((0x16 << 8) | _pri)
#define REGDMA_MODEM_BTBB_LINK(_pri) ((0x15 << 8) | _pri)
#define REGDMA_MODEM_IEEE802154_LINK(_pri) ((0x16 << 8) | _pri)
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
typedef enum {
@@ -32,9 +32,8 @@ typedef enum sleep_retention_module_bitmap {
SLEEP_RETENTION_MODULE_WIFI_MAC = BIT(10),
SLEEP_RETENTION_MODULE_WIFI_BB = BIT(11),
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_BB = BIT(15),
/* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM,
* TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */
+3 -3
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 mask = (const uint32_t) (
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
#endif
);
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)
{
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
sleep_clock_system_retention_init();
#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();
#endif
return ESP_OK;
@@ -21,7 +21,6 @@
#include "sdkconfig.h"
#include "esp_pmu.h"
static __attribute__((unused)) const char *TAG = "sleep";
/**
+8
View File
@@ -74,4 +74,12 @@ menu "IEEE 802.15.4"
Enabling this option increases throughput by ~5% at the expense of ~2.1k
IRAM code size increase.
config IEEE802154_SLEEP_ENABLE
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
@@ -24,6 +24,13 @@
#include "esp_ieee802154_timer.h"
#include "hal/ieee802154_ll.h"
#include "esp_attr.h"
#include "esp_phy_init.h"
#if CONFIG_IEEE802154_SLEEP_ENABLE
#include "esp_pm.h"
#include "esp_private/esp_clk.h"
#include "esp_private/sleep_retention.h"
#endif
#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 portMUX_TYPE s_ieee802154_spinlock = portMUX_INITIALIZER_UNLOCKED;
static esp_err_t ieee802154_sleep_init(void);
static IRAM_ATTR void event_end_process(void)
{
ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL0);
@@ -193,7 +202,7 @@ static bool stop_current_operation(void)
break;
case IEEE802154_STATE_IDLE:
// do nothing
ieee802154_ll_set_cmd(IEEE802154_CMD_STOP);
break;
case IEEE802154_STATE_RX:
@@ -555,10 +564,12 @@ static IRAM_ATTR void ieee802154_exit_critical(void)
void ieee802154_enable(void)
{
modem_clock_module_enable(ieee802154_periph.module);
s_ieee802154_state = IEEE802154_STATE_IDLE;
}
void ieee802154_disable(void)
{
modem_clock_module_disable(ieee802154_periph.module);
s_ieee802154_state = IEEE802154_STATE_DISABLE;
}
@@ -589,12 +600,13 @@ esp_err_t ieee802154_mac_init(void)
#endif
memset(s_rx_frame, 0, sizeof(s_rx_frame));
s_ieee802154_state = IEEE802154_STATE_IDLE;
// TODO: Add flags for IEEE802154 ISR allocating. TZ-102
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");
ret = ieee802154_sleep_init();
return ret;
}
@@ -716,6 +728,44 @@ esp_err_t ieee802154_receive_at(uint32_t time)
return ESP_OK;
}
static esp_err_t ieee802154_sleep_init(void)
{
esp_err_t err = ESP_OK;
#if CONFIG_IEEE802154_SLEEP_ENABLE
#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_sleep_cb(void)
{
#if CONFIG_IEEE802154_SLEEP_ENABLE
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_IEEE802154_SLEEP_ENABLE
}
IRAM_ATTR void ieee802154_wakeup_cb(void)
{
#if CONFIG_IEEE802154_SLEEP_ENABLE
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_IEEE802154_SLEEP_ENABLE
}
esp_err_t ieee802154_sleep(void)
{
ieee802154_enter_critical();
+10 -1
View File
@@ -21,7 +21,6 @@
esp_err_t esp_ieee802154_enable(void)
{
ieee802154_enable();
esp_phy_enable();
esp_btbb_enable();
@@ -332,6 +331,16 @@ uint8_t esp_ieee802154_get_recent_lqi(void)
return ieee802154_get_recent_lqi();
}
void esp_ieee802154_sleep_cb(void)
{
ieee802154_sleep_cb();
}
void esp_ieee802154_wakeup_cb(void)
{
ieee802154_wakeup_cb();
}
__attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info)
{
@@ -111,6 +111,17 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void);
*/
esp_err_t esp_ieee802154_sleep(void);
/**
* @brief The IEEE 802.15.4 sleep callback.
*/
void esp_ieee802154_sleep_cb(void);
/**
* @brief The IEEE 802.15.4 wakeup callback.
*/
void esp_ieee802154_wakeup_cb(void);
/**
* @brief Set the IEEE 802.15.4 Radio to receive state.
*
@@ -177,6 +177,18 @@ uint8_t ieee802154_get_recent_lqi(void);
*/
ieee802154_state_t ieee802154_get_state(void);
/**
* @brief The callback of IEEE 802.15.4 sleep.
*
*/
void ieee802154_sleep_cb(void);
/**
* @brief The callback of IEEE 802.15.4 wakeup.
*
*/
void ieee802154_wakeup_cb(void);
/** The following three functions are only used for internal test. **/
/**
* @brief The clear channel assessment done.
@@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_openthread.h"
#include "esp_check.h"
#include "esp_openthread_border_router.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_dns64.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_platform.h"
#include "esp_openthread_task_queue.h"
#include "esp_openthread_types.h"
#include "freertos/FreeRTOS.h"
#include "lwip/dns.h"
#include "openthread/instance.h"
#include "openthread/netdata.h"
#include "openthread/tasklet.h"
#include "esp_openthread_sleep.h"
esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *config)
{
#if CONFIG_IEEE802154_SLEEP_ENABLE
ESP_RETURN_ON_ERROR(esp_openthread_sleep_init(), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread esp pm_lock");
#endif
ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread platform driver");
esp_openthread_lock_acquire(portMAX_DELAY);
ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread instance");
#if CONFIG_OPENTHREAD_DNS64_CLIENT
ESP_RETURN_ON_ERROR(esp_openthread_dns64_client_init(), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread dns64 client");
#endif
esp_openthread_lock_release();
return ESP_OK;
}
esp_err_t esp_openthread_launch_mainloop(void)
{
esp_openthread_mainloop_context_t mainloop;
otInstance *instance = esp_openthread_get_instance();
esp_err_t error = ESP_OK;
while (true) {
FD_ZERO(&mainloop.read_fds);
FD_ZERO(&mainloop.write_fds);
FD_ZERO(&mainloop.error_fds);
mainloop.max_fd = -1;
mainloop.timeout.tv_sec = 10;
mainloop.timeout.tv_usec = 0;
esp_openthread_lock_acquire(portMAX_DELAY);
esp_openthread_platform_update(&mainloop);
if (otTaskletsArePending(instance)) {
mainloop.timeout.tv_sec = 0;
mainloop.timeout.tv_usec = 0;
}
#if CONFIG_IEEE802154_SLEEP_ENABLE
esp_openthread_sleep_process();
#endif
esp_openthread_lock_release();
if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds,
&mainloop.timeout) >= 0) {
esp_openthread_lock_acquire(portMAX_DELAY);
#if CONFIG_IEEE802154_SLEEP_ENABLE
esp_openthread_wakeup_process();
#endif
error = esp_openthread_platform_process(instance, &mainloop);
while (otTaskletsArePending(instance)) {
otTaskletsProcess(instance);
}
esp_openthread_lock_release();
if (error != ESP_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "esp_openthread_platform_process failed");
break;
}
} else {
error = ESP_FAIL;
ESP_LOGE(OT_PLAT_LOG_TAG, "OpenThread system polling failed");
break;
}
}
return error;
}
esp_err_t esp_openthread_deinit(void)
{
otInstanceFinalize(esp_openthread_get_instance());
return esp_openthread_platform_deinit();
}
static void stub_task(void *context)
{
// this is a empty function used for ot-task signal pending
}
void otTaskletsSignalPending(otInstance *aInstance)
{
esp_openthread_task_queue_post(stub_task, NULL);
}
@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_check.h"
#include "openthread/instance.h"
#include "openthread/thread.h"
#include "esp_openthread.h"
#include "esp_ieee802154.h"
#if CONFIG_IEEE802154_SLEEP_ENABLE
#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) {
goto error;
}
esp_pm_lock_acquire(s_pm_lock);
ESP_LOGI(TAG, "Enable ieee802154 light sleep, the wake up source is ESP timer");
return err;
error:
/*lock should release first and then delete*/
if (s_pm_lock != NULL) {
esp_pm_lock_release(s_pm_lock);
esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
}
return err;
}
void esp_openthread_sleep_process(void)
{
otInstance *instance = esp_openthread_get_instance();
otLinkModeConfig linkMode = otThreadGetLinkMode(instance);
bool s_ot_sed_ssed = false;
if (linkMode.mRxOnWhenIdle == false && linkMode.mDeviceType == false && linkMode.mNetworkData == false) {
s_ot_sed_ssed = true;
}
if (esp_ieee802154_get_state() == ESP_IEEE802154_RADIO_SLEEP && s_ot_sed_ssed) {
esp_ieee802154_sleep_cb();
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_cb();
s_ot_sleep = false;
}
}
#endif // CONFIG_IEEE802154_SLEEP_ENABLE
@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_IEEE802154_SLEEP_ENABLE
/**
* @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
@@ -273,7 +273,7 @@ otError otPlatRadioEnable(otInstance *aInstance)
otError otPlatRadioDisable(otInstance *aInstance)
{
esp_ieee802154_disable();
// radio will be disabled in esp_openthread_radio_deinit()
return OT_ERROR_NONE;
}