mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 21:24:32 +02:00
Merge branch 'feat/etm_sleep_retention' into 'master'
feat(etm): support sleep retention Closes IDF-8462 See merge request espressif/esp-idf!33787
This commit is contained in:
@@ -27,24 +27,21 @@ static esp_err_t gptimer_create_sleep_retention_link_cb(void *arg)
|
||||
{
|
||||
gptimer_group_t *group = (gptimer_group_t *)arg;
|
||||
int group_id = group->group_id;
|
||||
sleep_retention_module_t module = group->sleep_retention_module;
|
||||
esp_err_t err = sleep_retention_entries_create(tg_timer_reg_retention_info[group_id].regdma_entry_array,
|
||||
tg_timer_reg_retention_info[group_id].array_size,
|
||||
REGDMA_LINK_PRI_GPTIMER, module);
|
||||
ESP_RETURN_ON_ERROR(err, TAG, "create retention link failed");
|
||||
return ESP_OK;
|
||||
REGDMA_LINK_PRI_GPTIMER, tg_timer_reg_retention_info[group_id].module);
|
||||
return err;
|
||||
}
|
||||
|
||||
void gptimer_create_retention_module(gptimer_group_t *group)
|
||||
{
|
||||
sleep_retention_module_t module = group->sleep_retention_module;
|
||||
int group_id = group->group_id;
|
||||
sleep_retention_module_t module = tg_timer_reg_retention_info[group_id].module;
|
||||
_lock_acquire(&s_platform.mutex);
|
||||
if (group->retention_link_created == false) {
|
||||
if ((sleep_retention_get_inited_modules() & BIT(module)) && !(sleep_retention_get_created_modules() & BIT(module))) {
|
||||
if (sleep_retention_module_allocate(module) != ESP_OK) {
|
||||
// even though the sleep retention module create failed, GPTimer driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "create retention module for group %d retention, power domain can't turn off", group->group_id);
|
||||
} else {
|
||||
group->retention_link_created = true;
|
||||
ESP_LOGW(TAG, "create retention link failed %d, power domain won't be turned off during sleep", group_id);
|
||||
}
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
@@ -97,9 +94,7 @@ gptimer_group_t *gptimer_acquire_group_handle(int group_id)
|
||||
},
|
||||
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM)
|
||||
};
|
||||
if (sleep_retention_module_init(module, &init_param) == ESP_OK) {
|
||||
group->sleep_retention_module = module;
|
||||
} else {
|
||||
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
|
||||
// even though the sleep retention module init failed, RMT driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id);
|
||||
}
|
||||
@@ -132,11 +127,12 @@ void gptimer_release_group_handle(gptimer_group_t *group)
|
||||
}
|
||||
}
|
||||
#if GPTIMER_USE_RETENTION_LINK
|
||||
if (group->sleep_retention_module) {
|
||||
if (group->retention_link_created) {
|
||||
sleep_retention_module_free(group->sleep_retention_module);
|
||||
}
|
||||
sleep_retention_module_deinit(group->sleep_retention_module);
|
||||
sleep_retention_module_t module = tg_timer_reg_retention_info[group_id].module;
|
||||
if (sleep_retention_get_created_modules() & BIT(module)) {
|
||||
sleep_retention_module_free(module);
|
||||
}
|
||||
if (sleep_retention_get_inited_modules() & BIT(module)) {
|
||||
sleep_retention_module_deinit(module);
|
||||
}
|
||||
#endif
|
||||
free(group);
|
||||
|
@@ -59,10 +59,6 @@ typedef struct gptimer_group_t {
|
||||
int group_id;
|
||||
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
|
||||
gptimer_t *timers[SOC_TIMER_GROUP_TIMERS_PER_GROUP];
|
||||
#if GPTIMER_USE_RETENTION_LINK
|
||||
sleep_retention_module_t sleep_retention_module; // sleep retention module
|
||||
bool retention_link_created; // mark if the retention link is created
|
||||
#endif
|
||||
} gptimer_group_t;
|
||||
|
||||
typedef enum {
|
||||
|
@@ -10,6 +10,8 @@
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "driver/gpio_etm.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_private/sleep_cpu.h"
|
||||
@@ -117,3 +119,135 @@ TEST_CASE("gptimer can work after light sleep", "[gptimer]")
|
||||
test_gptimer_sleep_retention(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SOC_TIMER_SUPPORT_ETM
|
||||
/**
|
||||
* @brief Test the GPTimer and ETM subsystem can still work after light sleep
|
||||
*
|
||||
* @param back_up_before_sleep Whether to back up GPTimer registers before sleep
|
||||
*/
|
||||
static void test_gptimer_etm_sleep_retention(bool back_up_before_sleep)
|
||||
{
|
||||
const uint32_t output_gpio = 1;
|
||||
// GPTimer alarm ---> ETM channel A ---> GPTimer alarm re-enable
|
||||
// GPTimer alarm ---> ETM channel B ---> GPIO toggle
|
||||
printf("allocate etm channel\r\n");
|
||||
esp_etm_channel_config_t etm_config = {
|
||||
.flags.allow_pd = back_up_before_sleep,
|
||||
};
|
||||
esp_etm_channel_handle_t etm_channel_a, etm_channel_b;
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_b));
|
||||
|
||||
printf("initialize gpio\r\n");
|
||||
gpio_config_t task_gpio_config = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << output_gpio,
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&task_gpio_config));
|
||||
|
||||
printf("create a gptimer\r\n");
|
||||
gptimer_handle_t gptimer = NULL;
|
||||
gptimer_config_t timer_config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us
|
||||
.flags.backup_before_sleep = back_up_before_sleep,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));
|
||||
|
||||
printf("get gptimer etm event and task handle\r\n");
|
||||
esp_etm_event_handle_t gptimer_event = NULL;
|
||||
gptimer_etm_event_config_t gptimer_etm_event_conf = {
|
||||
.event_type = GPTIMER_ETM_EVENT_ALARM_MATCH,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_etm_event(gptimer, &gptimer_etm_event_conf, &gptimer_event));
|
||||
esp_etm_task_handle_t gptimer_task = NULL;
|
||||
gptimer_etm_task_config_t gptimer_etm_task_conf = {
|
||||
.task_type = GPTIMER_ETM_TASK_EN_ALARM,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, & gptimer_task));
|
||||
|
||||
printf("connect event and task to the channel a\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gptimer_event, gptimer_task));
|
||||
|
||||
printf("enable etm channels\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_b));
|
||||
|
||||
printf("set timer alarm action\r\n");
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 0,
|
||||
.alarm_count = 100, // 100us per alarm event
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
|
||||
// before going to sleep, ensure the gptimer is not enabled yet, otherwise it will acquire power management lock
|
||||
|
||||
esp_sleep_context_t sleep_ctx;
|
||||
esp_sleep_set_sleep_context(&sleep_ctx);
|
||||
printf("go to light sleep for 2 seconds\r\n");
|
||||
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||
TEST_ESP_OK(sleep_cpu_configure(true));
|
||||
#endif
|
||||
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000));
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
|
||||
printf("Waked up! Let's see if GPTimer and ETM can still work...\r\n");
|
||||
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||
TEST_ESP_OK(sleep_cpu_configure(false));
|
||||
#endif
|
||||
|
||||
printf("check if the sleep happened as expected\r\n");
|
||||
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
|
||||
#if SOC_RMT_SUPPORT_SLEEP_RETENTION
|
||||
// check if the power domain also is powered down
|
||||
TEST_ASSERT_EQUAL(back_up_before_sleep ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
|
||||
#endif
|
||||
esp_sleep_set_sleep_context(NULL);
|
||||
|
||||
printf("enable and start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
printf("allocate GPIO etm task\r\n");
|
||||
esp_etm_task_handle_t gpio_task = NULL;
|
||||
gpio_etm_task_config_t gpio_task_config = {
|
||||
.action = GPIO_ETM_TASK_ACTION_TOG,
|
||||
};
|
||||
TEST_ESP_OK(gpio_new_etm_task(&gpio_task_config, &gpio_task));
|
||||
// set gpio number for the gpio etm primitives
|
||||
TEST_ESP_OK(gpio_etm_task_add_gpio(gpio_task, output_gpio));
|
||||
printf("connect event and task to the channel b\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, gptimer_event, gpio_task));
|
||||
|
||||
// delay sometime for us to view the waveform, should see a 5KHz square waveform
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
// delete gptimer
|
||||
TEST_ESP_OK(gptimer_stop(gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
|
||||
// delete etm primitives
|
||||
TEST_ESP_OK(gpio_etm_task_rm_gpio(gpio_task, output_gpio));
|
||||
TEST_ESP_OK(esp_etm_del_task(gpio_task));
|
||||
TEST_ESP_OK(esp_etm_del_task(gptimer_task));
|
||||
TEST_ESP_OK(esp_etm_del_event(gptimer_event));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_b));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_b));
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer and ETM can work after light sleep", "[gptimer]")
|
||||
{
|
||||
test_gptimer_etm_sleep_retention(false);
|
||||
#if SOC_TIMER_SUPPORT_SLEEP_RETENTION && SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
test_gptimer_etm_sleep_retention(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // SOC_TIMER_SUPPORT_ETM
|
||||
|
@@ -75,7 +75,7 @@ rmt_group_t *rmt_acquire_group_handle(int group_id)
|
||||
rmt_ll_reset_register(group_id);
|
||||
}
|
||||
#if RMT_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id);
|
||||
sleep_retention_module_t module = rmt_reg_retention_info[group_id].module;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
@@ -85,9 +85,7 @@ rmt_group_t *rmt_acquire_group_handle(int group_id)
|
||||
},
|
||||
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM)
|
||||
};
|
||||
if (sleep_retention_module_init(module, &init_param) == ESP_OK) {
|
||||
group->sleep_retention_module = module;
|
||||
} else {
|
||||
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
|
||||
// even though the sleep retention module init failed, RMT driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id);
|
||||
}
|
||||
@@ -147,11 +145,12 @@ void rmt_release_group_handle(rmt_group_t *group)
|
||||
|
||||
if (do_deinitialize) {
|
||||
#if RMT_USE_RETENTION_LINK
|
||||
if (group->sleep_retention_module) {
|
||||
if (group->retention_link_created) {
|
||||
sleep_retention_module_free(group->sleep_retention_module);
|
||||
}
|
||||
sleep_retention_module_deinit(group->sleep_retention_module);
|
||||
sleep_retention_module_t module = rmt_reg_retention_info[group_id].module;
|
||||
if (sleep_retention_get_created_modules() & BIT(module)) {
|
||||
sleep_retention_module_free(module);
|
||||
}
|
||||
if (sleep_retention_get_inited_modules() & BIT(module)) {
|
||||
sleep_retention_module_deinit(module);
|
||||
}
|
||||
#endif
|
||||
free(group);
|
||||
@@ -303,24 +302,21 @@ static esp_err_t rmt_create_sleep_retention_link_cb(void *arg)
|
||||
{
|
||||
rmt_group_t *group = (rmt_group_t *)arg;
|
||||
int group_id = group->group_id;
|
||||
sleep_retention_module_t module = group->sleep_retention_module;
|
||||
esp_err_t err = sleep_retention_entries_create(rmt_reg_retention_info[group_id].regdma_entry_array,
|
||||
rmt_reg_retention_info[group_id].array_size,
|
||||
REGDMA_LINK_PRI_RMT, module);
|
||||
REGDMA_LINK_PRI_RMT, rmt_reg_retention_info[group_id].module);
|
||||
return err;
|
||||
}
|
||||
|
||||
void rmt_create_retention_module(rmt_group_t *group)
|
||||
{
|
||||
sleep_retention_module_t module = group->sleep_retention_module;
|
||||
|
||||
int group_id = group->group_id;
|
||||
sleep_retention_module_t module = rmt_reg_retention_info[group_id].module;
|
||||
_lock_acquire(&s_platform.mutex);
|
||||
if (group->retention_link_created == false) {
|
||||
if ((sleep_retention_get_inited_modules() & BIT(module)) && !(sleep_retention_get_created_modules() & BIT(module))) {
|
||||
if (sleep_retention_module_allocate(module) != ESP_OK) {
|
||||
// even though the sleep retention module create failed, RMT driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "create retention link failed, power domain can't be turned off");
|
||||
} else {
|
||||
group->retention_link_created = true;
|
||||
ESP_LOGW(TAG, "create retention link failed, power domain won't be turned off during sleep");
|
||||
}
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
|
@@ -119,10 +119,6 @@ struct rmt_group_t {
|
||||
rmt_rx_channel_t *rx_channels[SOC_RMT_RX_CANDIDATES_PER_GROUP]; // array of RMT RX channels
|
||||
rmt_sync_manager_t *sync_manager; // sync manager, this can be extended into an array if there're more sync controllers in one RMT group
|
||||
int intr_priority; // RMT interrupt priority
|
||||
#if RMT_USE_RETENTION_LINK
|
||||
sleep_retention_module_t sleep_retention_module; // sleep retention module
|
||||
bool retention_link_created; // mark if the retention link is created
|
||||
#endif
|
||||
};
|
||||
|
||||
struct rmt_channel_t {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/etm_periph.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
@@ -25,10 +25,13 @@
|
||||
#include "hal/etm_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/etm_interface.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
|
||||
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#define ETM_USE_RETENTION_LINK (SOC_ETM_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
|
||||
|
||||
#if !SOC_RCC_IS_INDEPENDENT
|
||||
// Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section
|
||||
#define ETM_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
#else
|
||||
@@ -70,6 +73,32 @@ struct esp_etm_channel_t {
|
||||
// ETM driver platform, it's always a singleton
|
||||
static etm_platform_t s_platform;
|
||||
|
||||
#if ETM_USE_RETENTION_LINK
|
||||
static esp_err_t etm_create_sleep_retention_link_cb(void *arg)
|
||||
{
|
||||
etm_group_t *group = (etm_group_t *)arg;
|
||||
int group_id = group->group_id;
|
||||
esp_err_t err = sleep_retention_entries_create(etm_reg_retention_info[group_id].regdma_entry_array,
|
||||
etm_reg_retention_info[group_id].array_size,
|
||||
REGDMA_LINK_PRI_ETM, etm_reg_retention_info[group_id].module);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void etm_create_retention_module(etm_group_t *group)
|
||||
{
|
||||
int group_id = group->group_id;
|
||||
sleep_retention_module_t module = etm_reg_retention_info[group_id].module;
|
||||
_lock_acquire(&s_platform.mutex);
|
||||
if ((sleep_retention_get_inited_modules() & BIT(module)) && !(sleep_retention_get_created_modules() & BIT(module))) {
|
||||
if (sleep_retention_module_allocate(module) != ESP_OK) {
|
||||
// even though the sleep retention module create failed, ETM driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "create retention link failed %d, power domain won't be turned off during sleep", group_id);
|
||||
}
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
}
|
||||
#endif // ETM_USE_RETENTION_LINK
|
||||
|
||||
static etm_group_t *etm_acquire_group_handle(int group_id)
|
||||
{
|
||||
bool new_group = false;
|
||||
@@ -90,7 +119,22 @@ static etm_group_t *etm_acquire_group_handle(int group_id)
|
||||
etm_ll_enable_bus_clock(group_id, true);
|
||||
etm_ll_reset_register(group_id);
|
||||
}
|
||||
|
||||
#if ETM_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = etm_reg_retention_info[group_id].module;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
.handle = etm_create_sleep_retention_link_cb,
|
||||
.arg = group,
|
||||
},
|
||||
},
|
||||
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM)
|
||||
};
|
||||
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
|
||||
// even though the sleep retention module init failed, ETM driver may still work, so just warning here
|
||||
ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id);
|
||||
}
|
||||
#endif // ETM_USE_RETENTION_LINK
|
||||
// initialize HAL context
|
||||
etm_hal_init(&group->hal);
|
||||
}
|
||||
@@ -129,6 +173,15 @@ static void etm_release_group_handle(etm_group_t *group)
|
||||
_lock_release(&s_platform.mutex);
|
||||
|
||||
if (do_deinitialize) {
|
||||
#if ETM_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = etm_reg_retention_info[group_id].module;
|
||||
if (sleep_retention_get_created_modules() & BIT(module)) {
|
||||
sleep_retention_module_free(module);
|
||||
}
|
||||
if (sleep_retention_get_inited_modules() & BIT(module)) {
|
||||
sleep_retention_module_deinit(module);
|
||||
}
|
||||
#endif
|
||||
free(group);
|
||||
ESP_LOGD(TAG, "del group (%d)", group_id);
|
||||
}
|
||||
@@ -192,6 +245,9 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_etm_channel_t *chan = NULL;
|
||||
ESP_GOTO_ON_FALSE(config && ret_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid args");
|
||||
#if !SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "not able to power down in light sleep");
|
||||
#endif // SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
chan = heap_caps_calloc(1, sizeof(esp_etm_channel_t), ETM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(chan, ESP_ERR_NO_MEM, err, TAG, "no mem for channel");
|
||||
@@ -201,6 +257,12 @@ esp_err_t esp_etm_new_channel(const esp_etm_channel_config_t *config, esp_etm_ch
|
||||
int group_id = group->group_id;
|
||||
int chan_id = chan->chan_id;
|
||||
|
||||
#if ETM_USE_RETENTION_LINK
|
||||
if (config->flags.allow_pd != 0) {
|
||||
etm_create_retention_module(group);
|
||||
}
|
||||
#endif // ETM_USE_RETENTION_LINK
|
||||
|
||||
chan->fsm = ETM_CHAN_FSM_INIT;
|
||||
ESP_LOGD(TAG, "new etm channel (%d,%d) at %p", group_id, chan_id, chan);
|
||||
*ret_chan = chan;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -32,7 +32,11 @@ typedef struct esp_etm_task_t *esp_etm_task_handle_t;
|
||||
* @brief ETM channel configuration
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
/// Extra configuration flags for ETM channel
|
||||
struct etm_chan_flags {
|
||||
uint32_t allow_pd : 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode.
|
||||
This can save power, but at the expense of more RAM being consumed to save register context. */
|
||||
} flags; /*!< ETM channel flags */
|
||||
} esp_etm_channel_config_t;
|
||||
|
||||
/**
|
||||
|
@@ -38,8 +38,6 @@ extern "C" {
|
||||
#define RMT_LL_MAX_FILTER_VALUE 255
|
||||
#define RMT_LL_MAX_IDLE_VALUE 32767
|
||||
|
||||
#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0)
|
||||
|
||||
typedef enum {
|
||||
RMT_LL_MEM_OWNER_SW = 0,
|
||||
RMT_LL_MEM_OWNER_HW = 1,
|
||||
|
@@ -38,8 +38,6 @@ extern "C" {
|
||||
#define RMT_LL_MAX_FILTER_VALUE 255
|
||||
#define RMT_LL_MAX_IDLE_VALUE 32767
|
||||
|
||||
#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0)
|
||||
|
||||
typedef enum {
|
||||
RMT_LL_MEM_OWNER_SW = 0,
|
||||
RMT_LL_MEM_OWNER_HW = 1,
|
||||
|
@@ -38,8 +38,6 @@ extern "C" {
|
||||
#define RMT_LL_MAX_FILTER_VALUE 255
|
||||
#define RMT_LL_MAX_IDLE_VALUE 32767
|
||||
|
||||
#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0)
|
||||
|
||||
typedef enum {
|
||||
RMT_LL_MEM_OWNER_SW = 0,
|
||||
RMT_LL_MEM_OWNER_HW = 1,
|
||||
|
@@ -33,8 +33,6 @@ extern "C" {
|
||||
#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel))
|
||||
#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel))
|
||||
|
||||
#define RMT_LL_SLEEP_RETENTION_MODULE_ID(group_id) (SLEEP_RETENTION_MODULE_RMT0)
|
||||
|
||||
#define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023
|
||||
#define RMT_LL_MAX_FILTER_VALUE 255
|
||||
#define RMT_LL_MAX_IDLE_VALUE 32767
|
||||
|
@@ -47,6 +47,10 @@ if(CONFIG_SOC_EMAC_SUPPORTED)
|
||||
list(APPEND srcs "${target_folder}/emac_periph.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_ETM_SUPPORTED)
|
||||
list(APPEND srcs "${target_folder}/etm_periph.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_GDMA_SUPPORTED)
|
||||
list(APPEND srcs "${target_folder}/gdma_periph.c")
|
||||
endif()
|
||||
|
44
components/soc/esp32c5/etm_periph.c
Normal file
44
components/soc/esp32c5/etm_periph.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/etm_periph.h"
|
||||
#include "soc/soc_etm_reg.h"
|
||||
|
||||
/**
|
||||
* ETM Registers to be saved during sleep retention
|
||||
* - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG
|
||||
*/
|
||||
#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1)
|
||||
|
||||
static const regdma_entries_config_t etm_regdma_entries[] = {
|
||||
// backup stage: save the status of enabled channels
|
||||
// restore stage: store the enabled channels
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00),
|
||||
SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
[1] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01),
|
||||
SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[2] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02),
|
||||
SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
};
|
||||
|
||||
const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_ETM0,
|
||||
.regdma_entry_array = etm_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(etm_regdma_entries)
|
||||
},
|
||||
};
|
@@ -463,6 +463,10 @@ config SOC_ETM_CHANNELS_PER_GROUP
|
||||
int
|
||||
default 50
|
||||
|
||||
config SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GPIO_PORT
|
||||
int
|
||||
default 1
|
||||
|
@@ -37,6 +37,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_UART0 = 14,
|
||||
SLEEP_RETENTION_MODULE_UART1 = 15,
|
||||
SLEEP_RETENTION_MODULE_I2S0 = 16,
|
||||
SLEEP_RETENTION_MODULE_ETM0 = 17,
|
||||
|
||||
/* modem module, which includes WiFi, BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_WIFI_MAC = 26,
|
||||
@@ -76,6 +77,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0),
|
||||
SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1),
|
||||
SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0),
|
||||
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
|
||||
|
||||
SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0),
|
||||
SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1),
|
||||
@@ -97,6 +99,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_UART0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_UART1 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_ETM0 \
|
||||
)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -191,6 +191,7 @@
|
||||
/*-------------------------- ETM CAPS --------------------------------------*/
|
||||
#define SOC_ETM_GROUPS 1U // Number of ETM groups
|
||||
#define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group
|
||||
#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-C5 has 1 GPIO peripheral
|
||||
|
@@ -60,6 +60,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = {
|
||||
|
||||
const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_RMT0,
|
||||
.regdma_entry_array = rmt_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(rmt_regdma_entries)
|
||||
},
|
||||
|
44
components/soc/esp32c6/etm_periph.c
Normal file
44
components/soc/esp32c6/etm_periph.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/etm_periph.h"
|
||||
#include "soc/soc_etm_reg.h"
|
||||
|
||||
/**
|
||||
* ETM Registers to be saved during sleep retention
|
||||
* - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG
|
||||
*/
|
||||
#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1)
|
||||
|
||||
static const regdma_entries_config_t etm_regdma_entries[] = {
|
||||
// backup stage: save the status of enabled channels
|
||||
// restore stage: store the enabled channels
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00),
|
||||
SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
[1] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01),
|
||||
SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[2] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02),
|
||||
SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
};
|
||||
|
||||
const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_ETM0,
|
||||
.regdma_entry_array = etm_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(etm_regdma_entries)
|
||||
},
|
||||
};
|
@@ -459,6 +459,10 @@ config SOC_ETM_CHANNELS_PER_GROUP
|
||||
int
|
||||
default 50
|
||||
|
||||
config SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GPIO_PORT
|
||||
int
|
||||
default 1
|
||||
|
@@ -37,6 +37,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_UART0 = 14,
|
||||
SLEEP_RETENTION_MODULE_UART1 = 15,
|
||||
SLEEP_RETENTION_MODULE_I2S0 = 16,
|
||||
SLEEP_RETENTION_MODULE_ETM0 = 17,
|
||||
|
||||
/* Modem module, which includes WiFi, BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_WIFI_MAC = 26,
|
||||
@@ -70,6 +71,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0),
|
||||
SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1),
|
||||
SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0),
|
||||
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
|
||||
/* modem module, which includes WiFi, BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC),
|
||||
SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB),
|
||||
@@ -93,6 +95,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_UART0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_UART1 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_ETM0 \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -178,6 +178,7 @@
|
||||
/*-------------------------- ETM CAPS --------------------------------------*/
|
||||
#define SOC_ETM_GROUPS 1U // Number of ETM groups
|
||||
#define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group
|
||||
#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-C6 has 1 GPIO peripheral
|
||||
|
@@ -60,6 +60,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = {
|
||||
|
||||
const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_RMT0,
|
||||
.regdma_entry_array = rmt_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(rmt_regdma_entries)
|
||||
},
|
||||
|
44
components/soc/esp32c61/etm_periph.c
Normal file
44
components/soc/esp32c61/etm_periph.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/etm_periph.h"
|
||||
#include "soc/soc_etm_reg.h"
|
||||
|
||||
/**
|
||||
* ETM Registers to be saved during sleep retention
|
||||
* - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG
|
||||
*/
|
||||
#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1)
|
||||
|
||||
static const regdma_entries_config_t etm_regdma_entries[] = {
|
||||
// backup stage: save the status of enabled channels
|
||||
// restore stage: store the enabled channels
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00),
|
||||
SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
[1] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01),
|
||||
SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[2] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02),
|
||||
SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
};
|
||||
|
||||
const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_ETM0,
|
||||
.regdma_entry_array = etm_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(etm_regdma_entries)
|
||||
},
|
||||
};
|
@@ -33,6 +33,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_I2C0 = 12,
|
||||
SLEEP_RETENTION_MODULE_UART0 = 14,
|
||||
SLEEP_RETENTION_MODULE_UART1 = 15,
|
||||
SLEEP_RETENTION_MODULE_ETM0 = 16,
|
||||
|
||||
/* Modem module, which includes WiFi, BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_WIFI_MAC = 26,
|
||||
@@ -62,6 +63,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_I2C0 = BIT(SLEEP_RETENTION_MODULE_I2C0),
|
||||
SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0),
|
||||
SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1),
|
||||
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
|
||||
/* modem module, which includes WiFi, BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC),
|
||||
SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB),
|
||||
@@ -81,6 +83,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_I2C0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_UART0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_UART1 \
|
||||
| SLEEP_RETENTION_MODULE_BM_ETM0 \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -154,6 +154,7 @@
|
||||
/*-------------------------- ETM CAPS --------------------------------------*/
|
||||
#define SOC_ETM_GROUPS 1U // Number of ETM groups
|
||||
#define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group
|
||||
// #define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-C61 has 1 GPIO peripheral
|
||||
|
44
components/soc/esp32h2/etm_periph.c
Normal file
44
components/soc/esp32h2/etm_periph.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/etm_periph.h"
|
||||
#include "soc/soc_etm_reg.h"
|
||||
|
||||
/**
|
||||
* ETM Registers to be saved during sleep retention
|
||||
* - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG
|
||||
*/
|
||||
#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1)
|
||||
|
||||
static const regdma_entries_config_t etm_regdma_entries[] = {
|
||||
// backup stage: save the status of enabled channels
|
||||
// restore stage: store the enabled channels
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00),
|
||||
SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
[1] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01),
|
||||
SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[2] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02),
|
||||
SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
};
|
||||
|
||||
const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_ETM0,
|
||||
.regdma_entry_array = etm_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(etm_regdma_entries)
|
||||
},
|
||||
};
|
@@ -467,6 +467,10 @@ config SOC_ETM_CHANNELS_PER_GROUP
|
||||
int
|
||||
default 50
|
||||
|
||||
config SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GPIO_PORT
|
||||
int
|
||||
default 1
|
||||
|
@@ -38,6 +38,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_UART0 = 15,
|
||||
SLEEP_RETENTION_MODULE_UART1 = 16,
|
||||
SLEEP_RETENTION_MODULE_I2S0 = 17,
|
||||
SLEEP_RETENTION_MODULE_ETM0 = 18,
|
||||
|
||||
/* Modem module, which includes BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_BLE_MAC = 28,
|
||||
@@ -70,6 +71,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0),
|
||||
SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1),
|
||||
SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0),
|
||||
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
|
||||
/* modem module, which includes BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC),
|
||||
SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB),
|
||||
@@ -92,6 +94,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_UART0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_UART1 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_ETM0 \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -181,6 +181,7 @@
|
||||
/*-------------------------- ETM CAPS --------------------------------------*/
|
||||
#define SOC_ETM_GROUPS 1U // Number of ETM groups
|
||||
#define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group
|
||||
#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-H2 has 1 GPIO peripheral
|
||||
|
@@ -60,6 +60,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = {
|
||||
|
||||
const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_RMT0,
|
||||
.regdma_entry_array = rmt_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(rmt_regdma_entries)
|
||||
},
|
||||
|
44
components/soc/esp32p4/etm_periph.c
Normal file
44
components/soc/esp32p4/etm_periph.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/etm_periph.h"
|
||||
#include "soc/soc_etm_reg.h"
|
||||
|
||||
/**
|
||||
* ETM Registers to be saved during sleep retention
|
||||
* - Channel configuration registers, e.g.: SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_TASK_ID_REG
|
||||
*/
|
||||
#define ETM_RETENTION_REGS_CNT ((SOC_ETM_CH49_TASK_ID_REG - SOC_ETM_CH0_EVT_ID_REG) / 4 + 1)
|
||||
|
||||
static const regdma_entries_config_t etm_regdma_entries[] = {
|
||||
// backup stage: save the status of enabled channels
|
||||
// restore stage: store the enabled channels
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x00),
|
||||
SOC_ETM_CH_ENA_AD0_REG, SOC_ETM_CH_ENA_AD0_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0),
|
||||
},
|
||||
[1] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x01),
|
||||
SOC_ETM_CH_ENA_AD1_REG, SOC_ETM_CH_ENA_AD1_SET_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0),
|
||||
},
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[2] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_ETM_LINK(0x02),
|
||||
SOC_ETM_CH0_EVT_ID_REG, SOC_ETM_CH0_EVT_ID_REG, ETM_RETENTION_REGS_CNT, 0, 0),
|
||||
.owner = ENTRY(0),
|
||||
},
|
||||
};
|
||||
|
||||
const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_ETM0,
|
||||
.regdma_entry_array = etm_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(etm_regdma_entries)
|
||||
},
|
||||
};
|
@@ -595,6 +595,10 @@ config SOC_ETM_CHANNELS_PER_GROUP
|
||||
int
|
||||
default 50
|
||||
|
||||
config SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GPIO_PORT
|
||||
int
|
||||
default 1
|
||||
|
@@ -46,6 +46,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_I2S2 = 21,
|
||||
SLEEP_RETENTION_MODULE_I2C0 = 22,
|
||||
SLEEP_RETENTION_MODULE_I2C1 = 23,
|
||||
SLEEP_RETENTION_MODULE_ETM0 = 24,
|
||||
|
||||
SLEEP_RETENTION_MODULE_MAX = 31
|
||||
} periph_retention_module_t;
|
||||
@@ -79,6 +80,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0),
|
||||
SLEEP_RETENTION_MODULE_BM_I2S1 = BIT(SLEEP_RETENTION_MODULE_I2S1),
|
||||
SLEEP_RETENTION_MODULE_BM_I2S2 = BIT(SLEEP_RETENTION_MODULE_I2S2),
|
||||
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
|
||||
|
||||
SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1
|
||||
} periph_retention_module_bitmap_t;
|
||||
@@ -100,9 +102,10 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_UART3 \
|
||||
| SLEEP_RETENTION_MODULE_BM_UART4 \
|
||||
| SLEEP_RETENTION_MODULE_BM_RMT0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S1 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S2 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S1 \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S2 \
|
||||
| SLEEP_RETENTION_MODULE_BM_ETM0 \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -221,6 +221,7 @@
|
||||
/*-------------------------- ETM CAPS --------------------------------------*/
|
||||
#define SOC_ETM_GROUPS 1U // Number of ETM groups
|
||||
#define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group
|
||||
#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1 // Support sleep retention
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-P4 has 1 GPIO peripheral
|
||||
|
@@ -76,6 +76,7 @@ static const regdma_entries_config_t rmt_regdma_entries[] = {
|
||||
|
||||
const rmt_reg_retention_info_t rmt_reg_retention_info[SOC_RMT_GROUPS] = {
|
||||
[0] = {
|
||||
.module = SLEEP_RETENTION_MODULE_RMT0,
|
||||
.regdma_entry_array = rmt_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(rmt_regdma_entries)
|
||||
},
|
||||
|
32
components/soc/include/soc/etm_periph.h
Normal file
32
components/soc/include/soc/etm_periph.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/regdma.h"
|
||||
|
||||
#if SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
typedef struct {
|
||||
periph_retention_module_t module;
|
||||
const regdma_entries_config_t *regdma_entry_array;
|
||||
uint32_t array_size;
|
||||
} etm_reg_retention_info_t;
|
||||
|
||||
extern const etm_reg_retention_info_t etm_reg_retention_info[SOC_ETM_GROUPS];
|
||||
#endif // SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -54,6 +54,7 @@ extern "C" {
|
||||
#define REGDMA_TG0_TIMER_LINK(_pri) ((0x1C << 8) | _pri)
|
||||
#define REGDMA_TG1_TIMER_LINK(_pri) ((0x1D << 8) | _pri)
|
||||
#define REGDMA_I2S_LINK(_pri) ((0x1E << 8) | _pri)
|
||||
#define REGDMA_ETM_LINK(_pri) ((0x1F << 8) | _pri)
|
||||
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
|
||||
|
||||
#define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0
|
||||
@@ -68,6 +69,7 @@ extern "C" {
|
||||
#define REGDMA_LINK_PRI_IEEE802154 REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_GDMA REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_RMT REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_ETM REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_I2C REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_I2S REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
|
@@ -10,6 +10,10 @@
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/regdma.h"
|
||||
|
||||
#if SOC_RMT_SUPPORT_SLEEP_RETENTION
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -32,6 +36,7 @@ extern const rmt_signal_conn_t rmt_periph_signals;
|
||||
|
||||
#if SOC_RMT_SUPPORT_SLEEP_RETENTION
|
||||
typedef struct {
|
||||
periph_retention_module_t module;
|
||||
const regdma_entries_config_t *regdma_entry_array;
|
||||
uint32_t array_size;
|
||||
} rmt_reg_retention_info_t;
|
||||
|
@@ -32,6 +32,7 @@ The following sections of this document cover the typical steps to configure and
|
||||
- :ref:`etm-event` - describes how to allocate a new ETM event handle or fetch an existing handle from various peripherals.
|
||||
- :ref:`etm-task` - describes how to allocate a new ETM task handle or fetch an existing handle from various peripherals.
|
||||
- :ref:`etm-channel-control` - describes common ETM channel control functions.
|
||||
- :ref:`etm-power-management` - describes the options and strategies provided by the driver in order to save power.
|
||||
- :ref:`etm-thread-safety` - lists which APIs are guaranteed to be thread-safe by the driver.
|
||||
- :ref:`etm-kconfig-options` - lists the supported Kconfig options that can be used to make a different effect on driver behavior.
|
||||
|
||||
@@ -131,6 +132,17 @@ To check if the ETM channels are set with proper events and tasks, you can call
|
||||
|
||||
The digital ID printed in the dump information is defined in the ``soc/soc_etm_source.h`` file.
|
||||
|
||||
.. _etm-power-management:
|
||||
|
||||
Power Management
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
When power management is enabled, i.e., :ref:`CONFIG_PM_ENABLE` is on, the system may adjust or disable the clock source, and power off the ETM peripheral before going to sleep. As a result, the existing connection between events and tasks will be lost, and the ETM channels can't work correctly after wake up. So by default, the driver will acquire a power management lock internally to forbid the system from powering off the ETM peripheral.
|
||||
|
||||
.. only:: SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
If you want to save more power, you can set :cpp:member:`esp_etm_channel_config_t::etm_chan_flags::allow_pd` to ``true``. Then ETM registers will be backed up before sleep and restored after wake up. Please note, enabling this option will increase the memory consumption for saving the register context.
|
||||
|
||||
.. _etm-thread-safety:
|
||||
|
||||
Thread Safety
|
||||
|
@@ -148,10 +148,11 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
|
||||
- INT_MTX
|
||||
- TEE/APM
|
||||
- IO_MUX / GPIO
|
||||
- Timer Group 0 & Timer Group 1
|
||||
- SPI0/1
|
||||
- SYSTIMER
|
||||
:SOC_TIMER_SUPPORT_SLEEP_RETENTION: - GPTimer
|
||||
:SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT
|
||||
:SOC_ETM_SUPPORT_SLEEP_RETENTION: - ETM
|
||||
:SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C
|
||||
:SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S
|
||||
:SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
|
||||
@@ -160,7 +161,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
|
||||
|
||||
.. list::
|
||||
|
||||
- ETM
|
||||
- ASSIST_DEBUG
|
||||
- Trace
|
||||
- Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA
|
||||
|
@@ -32,6 +32,7 @@ ETM 模块具有多个通道,这些通道支持用户根据需要进行配置
|
||||
- :ref:`etm-event` - 介绍如何分配新的 ETM 事件句柄,以及如何从不同外设获取现有句柄。
|
||||
- :ref:`etm-task` - 介绍如何分配新的 ETM 任务句柄,以及如何从不同外设获取现有句柄。
|
||||
- :ref:`etm-channel-control` - 介绍常见的 ETM 通道控制函数。
|
||||
- :ref:`etm-power-management` - 介绍了驱动针对功耗管理提供的选项和策略。
|
||||
- :ref:`etm-thread-safety` - 列出了驱动程序中始终线程安全的 API。
|
||||
- :ref:`etm-kconfig-options` - 列出了 ETM 支持的 Kconfig 选项,这些选项对驱动程序的行为会产生不同影响。
|
||||
|
||||
@@ -131,6 +132,17 @@ ETM 通道分析
|
||||
|
||||
以上输出信息打印的数字 ID 在 ``soc/soc_etm_source.h`` 文件中定义。
|
||||
|
||||
.. _etm-power-management:
|
||||
|
||||
电源管理
|
||||
^^^^^^^^
|
||||
|
||||
当启用电源管理时,即 :ref:`CONFIG_PM_ENABLE` 打开的时候,系统可能会调整或禁用时钟源,并在进入睡眠前关闭 ETM 外设依赖的电源。这会导致事件和任务之间的连接信息被丢失,ETM 通道在唤醒后无法正常工作。因此,默认情况下,驱动程序会获取电源管理锁,以禁止系统关闭 ETM 外设。
|
||||
|
||||
.. only:: SOC_ETM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
如果你想节省更多电量,可以将 :cpp:member:`esp_etm_channel_config_t::etm_chan_flags::allow_pd` 设置为 ``true``。ETM 寄存器将在睡眠前备份,并在唤醒后恢复。请注意,启用此选项会增加内存消耗,用于保存寄存器上下文。
|
||||
|
||||
.. _etm-thread-safety:
|
||||
|
||||
线程安全
|
||||
|
@@ -148,19 +148,19 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
|
||||
- INT_MTX
|
||||
- TEE/APM
|
||||
- IO_MUX / GPIO
|
||||
- Timer Group 0 & Timer Group 1
|
||||
- SPI0/1
|
||||
- SYSTIMER
|
||||
:SOC_TIMER_SUPPORT_SLEEP_RETENTION: - GPTimer
|
||||
:SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT
|
||||
:SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C
|
||||
:SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S
|
||||
:SOC_ETM_SUPPORT_SLEEP_RETENTION: - ETM
|
||||
:SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
|
||||
|
||||
以下外设尚未支持:
|
||||
|
||||
.. list::
|
||||
|
||||
- ETM
|
||||
- ASSIST_DEBUG
|
||||
- Trace
|
||||
- Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA
|
||||
|
Reference in New Issue
Block a user