Merge branch 'feature/lp_core_etm_v5.3' into 'release/v5.3'

feat(lp-core): added support for using ETM events as wake-up source (v5.3)

See merge request espressif/esp-idf!32455
This commit is contained in:
Marius Vikhammer 2024-07-31 16:11:47 +08:00
commit 59666823e4
21 changed files with 400 additions and 7 deletions

View File

@ -27,6 +27,7 @@ typedef enum {
ETM_TRIG_PERIPH_MCPWM, /*!< ETM trigger source: MCPWM */
ETM_TRIG_PERIPH_ANA_CMPR, /*!< ETM trigger source: Analog Comparator */
ETM_TRIG_PERIPH_TSENS, /*!< ETM trigger source: Temperature Sensor */
ETM_TRIG_PERIPH_LP_CORE, /*!< ETM trigger source: Low-Power Core */
} etm_trigger_peripheral_t;
/**

View File

@ -92,6 +92,24 @@ static inline void lp_aon_ll_inform_wakeup_type(bool dslp)
}
}
/**
* @brief Get the flag that marks whether LP CPU is awakened by ETM
*
* @return Return true if lpcore is woken up by soc_etm
*/
static inline bool lp_aon_ll_get_lpcore_etm_wakeup_flag(void)
{
return REG_GET_BIT(LP_AON_LPCORE_REG, LP_AON_LPCORE_ETM_WAKEUP_FLAG);
}
/**
* @brief Clear the flag that marks whether LP CPU is awakened by soc_etm
*/
static inline void lp_aon_ll_clear_lpcore_etm_wakeup_flag(void)
{
REG_SET_BIT(LP_AON_LPCORE_REG, LP_AON_LPCORE_ETM_WAKEUP_FLAG_CLR);
}
#ifdef __cplusplus
}
#endif

View File

@ -148,6 +148,15 @@ static inline void lp_core_ll_request_sleep(void)
PMU.lp_ext.pwr1.sleep_req = 1;
}
/**
* @brief Clear the ETM wakeup interrupt sources on the LP core
*
*/
static inline void lp_core_ll_clear_etm_wakeup_status(void)
{
LP_SYS.sys_ctrl.lp_core_etm_wakeup_flag_clr = 1;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_LP_CORE_SUPPORTED
#if SOC_LP_CORE_SUPPORT_ETM
/**
* @brief LP-Core event types enum
*/
typedef enum {
LP_CORE_EVENT_ERR_INTR, /*!< Exception triggered on LP-Core */
LP_CORE_EVENT_START_INTR, /*!< LP-Core clock has been turned on */
LP_CORE_EVENT_MAX, /*!< Maximum number of LP-Core events */
} lp_core_etm_event_type_t;
/**
* @brief LP-Core task types enum
*/
typedef enum {
LP_CORE_TASK_WAKEUP_CPU, /*!< LP-Core wake-up task */
LP_CORE_TASK_MAX, /*!< Maximum number of LP-Core tasks */
} lp_core_etm_task_type_t;
#endif //SOC_LP_CORE_SUPPORT_ETM
#endif //SOC_LP_CORE_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@ -1486,3 +1486,7 @@ config SOC_CAPS_NO_RESET_BY_ANA_BOD
config SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR
bool
default y
config SOC_LP_CORE_SUPPORT_ETM
bool
default y

View File

@ -591,3 +591,4 @@
/*------------------------------------- ULP CAPS -------------------------------------*/
#define SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR (1) /*!< LP Core interrupts all map to a single entry in vector table */
#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */

View File

@ -1734,3 +1734,7 @@ config SOC_LCDCAM_CAM_PERIPH_NUM
config SOC_LCDCAM_CAM_DATA_WIDTH_MAX
int
default 16
config SOC_LP_CORE_SUPPORT_ETM
bool
default y

View File

@ -684,3 +684,6 @@
#define SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV (1)
#define SOC_LCDCAM_CAM_PERIPH_NUM (1U)
#define SOC_LCDCAM_CAM_DATA_WIDTH_MAX (16U)
/*------------------------------------- ULP CAPS -------------------------------------*/
#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */

View File

@ -69,6 +69,10 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND srcs "lp_core/lp_core_spi.c")
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_ETM)
list(APPEND srcs "lp_core/lp_core_etm.c")
endif()
endif()
idf_component_register(SRCS ${srcs}

View File

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "esp_etm.h"
#include "hal/lp_core_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LP-Core ETM event configuration
*/
typedef struct {
lp_core_etm_event_type_t event_type; /*!< LP-Core ETM event type */
} lp_core_etm_event_config_t;
/**
* @brief LP-Core ETM task configuration
*/
typedef struct {
lp_core_etm_task_type_t task_type; /*!< LP-Core ETM task type */
} lp_core_etm_task_config_t;
/**
* @brief Create a ETM event for LP-Core
*
* @note The created ETM event object can be deleted later by calling `esp_etm_del_event`
*
* @param[in] config LP-Core ETM event configuration
* @param[out] out_event Returned ETM event handle
* @return
* - ESP_OK: Get ETM event successfully
* - ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument
* - ESP_FAIL: Get ETM event failed because of other error
*/
esp_err_t lp_core_new_etm_event(const lp_core_etm_event_config_t *config, esp_etm_event_handle_t *out_event);
/**
* @brief Create a ETM task for LP-Core
*
* @note The created ETM task object can be deleted later by calling `esp_etm_del_task`
*
* @param[in] config LP-Core ETM task configuration
* @param[out] out_task Returned ETM task handle
* @return
* - ESP_OK: Get ETM task successfully
* - ESP_ERR_INVALID_ARG: Get ETM task failed because of invalid argument
* - ESP_FAIL: Get ETM task failed because of other error
*/
esp_err_t lp_core_new_etm_task(const lp_core_etm_task_config_t *config, esp_etm_task_handle_t *out_task);
#ifdef __cplusplus
}
#endif

View File

@ -126,7 +126,7 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
}
#endif
if (cfg->wakeup_source & (ULP_LP_CORE_WAKEUP_SOURCE_LP_UART | ULP_LP_CORE_WAKEUP_SOURCE_LP_IO | ULP_LP_CORE_WAKEUP_SOURCE_ETM)) {
if (cfg->wakeup_source & (ULP_LP_CORE_WAKEUP_SOURCE_LP_UART | ULP_LP_CORE_WAKEUP_SOURCE_LP_IO)) {
ESP_LOGE(TAG, "Wake-up source not yet supported");
return ESP_ERR_INVALID_ARG;
}

View File

@ -15,6 +15,10 @@
#include "hal/uart_ll.h"
#include "hal/rtc_io_ll.h"
#if !CONFIG_IDF_TARGET_ESP32P4
#include "hal/lp_aon_ll.h"
#endif
#if SOC_ETM_SUPPORTED
#include "hal/etm_ll.h"
#endif
@ -52,7 +56,11 @@ void ulp_lp_core_update_wakeup_cause(void)
if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_ETM) \
&& etm_ll_is_lpcore_wakeup_triggered()) {
lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_ETM;
etm_ll_clear_lpcore_wakeup_status();
#if CONFIG_IDF_TARGET_ESP32P4
lp_core_ll_clear_etm_wakeup_status();
#else
lp_aon_ll_clear_lpcore_etm_wakeup_flag();
#endif
}
#endif /* SOC_ETM_SUPPORTED */

View File

@ -0,0 +1,90 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "lp_core_etm.h"
#include "esp_private/etm_interface.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "soc/soc_etm_source.h"
#define LP_CORE_ETM_EVENT_TABLE(event) \
(uint32_t [LP_CORE_EVENT_MAX]){ \
[LP_CORE_EVENT_ERR_INTR] = ULP_EVT_ERR_INTR, \
[LP_CORE_EVENT_START_INTR] = ULP_EVT_START_INTR, \
}[event]
#define LP_CORE_ETM_TASK_TABLE(task) \
(uint32_t [LP_CORE_TASK_MAX]){ \
[LP_CORE_TASK_WAKEUP_CPU] = ULP_TASK_WAKEUP_CPU, \
}[task]
const static char* TAG = "lp-core-etm";
static esp_err_t lp_core_del_etm_event(esp_etm_event_t *event)
{
free(event);
return ESP_OK;
}
static esp_err_t lp_core_del_etm_task(esp_etm_task_t *task)
{
free(task);
return ESP_OK;
}
esp_err_t lp_core_new_etm_task(const lp_core_etm_task_config_t *config, esp_etm_task_handle_t *out_task)
{
esp_etm_task_t *task = NULL;
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(config && out_task, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(config->task_type < LP_CORE_TASK_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid task type");
task = heap_caps_calloc(1, sizeof(esp_etm_task_t), MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(task, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM task");
uint32_t task_id = LP_CORE_ETM_TASK_TABLE(config->task_type);
ESP_GOTO_ON_FALSE(task_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported task type");
// fill the ETM task object
task->task_id = task_id;
task->trig_periph = ETM_TRIG_PERIPH_LP_CORE;
task->del = lp_core_del_etm_task;
ESP_LOGD(TAG, "new task @%p, task_id=%"PRIu32, task, task_id);
*out_task = task;
return ESP_OK;
err:
if (task) {
lp_core_del_etm_task(task);
}
return ret;
}
esp_err_t lp_core_new_etm_event(const lp_core_etm_event_config_t *config, esp_etm_event_handle_t *out_event)
{
esp_etm_event_t *event = NULL;
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(config && out_event, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(config->event_type < LP_CORE_EVENT_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid event type");
event = heap_caps_calloc(1, sizeof(esp_etm_event_t), MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(event, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM event");
uint32_t event_id = LP_CORE_ETM_EVENT_TABLE(config->event_type);
ESP_GOTO_ON_FALSE(event_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported event type");
// fill the ETM event object
event->event_id = event_id;
event->trig_periph = ETM_TRIG_PERIPH_LP_CORE;
event->del = lp_core_del_etm_event;
*out_event = event;
return ESP_OK;
err:
if (event) {
lp_core_del_etm_event(event);
}
return ret;
}

View File

@ -8,6 +8,10 @@ if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND app_sources "test_lp_core_spi.c")
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_ETM AND CONFIG_SOC_ETM_SUPPORTED)
list(APPEND app_sources "test_lp_core_etm.c")
endif()
set(lp_core_sources "lp_core/test_main.c")
set(lp_core_sources_counter "lp_core/test_main_counter.c")

View File

@ -0,0 +1,130 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "lp_core_test_app_counter.h"
#include "ulp_lp_core.h"
#include "test_shared.h"
#include "unity.h"
#include "test_utils.h"
#include "esp_log.h"
#include "driver/gptimer.h"
#include "lp_core_etm.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
extern const uint8_t lp_core_main_counter_bin_start[] asm("_binary_lp_core_test_app_counter_bin_start");
extern const uint8_t lp_core_main_counter_bin_end[] asm("_binary_lp_core_test_app_counter_bin_end");
static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end)
{
TEST_ASSERT(ulp_lp_core_load_binary(firmware_start,
(firmware_end - firmware_start)) == ESP_OK);
TEST_ASSERT(ulp_lp_core_run(cfg) == ESP_OK);
}
#define STOP_TEST_ITERATIONS 50
#define TIMER_PERIOD_MS 10
static int timer_cb_count;
static bool on_gptimer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
{
timer_cb_count++;
if (timer_cb_count >= STOP_TEST_ITERATIONS) {
gptimer_stop(timer);
}
return false;
}
/**
* @brief Test connects ULP wakeup source to a GP timer alarm ETM event.
* At every wakeup the ULP program increments a counter and in the
* end we check that the ULP woke-up the expected number of times.
*/
TEST_CASE("LP core can be woken up by ETM event", "[ulp]")
{
// GPTimer alarm ---> ETM channel A ---> ULP wake-up
printf("allocate etm channel\r\n");
esp_etm_channel_config_t etm_config = {};
esp_etm_channel_handle_t etm_channel_a;
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a));
esp_etm_task_handle_t lp_core_task = NULL;
lp_core_etm_task_config_t lp_core_task_config = {
.task_type = LP_CORE_TASK_WAKEUP_CPU,
};
TEST_ESP_OK(lp_core_new_etm_task(&lp_core_task_config, &lp_core_task));
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
};
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));
printf("get gptimer etm event 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));
printf("connect event and task to the channel\r\n");
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gptimer_event, lp_core_task));
printf("enable etm channel\r\n");
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
printf("set timer alarm action\r\n");
gptimer_alarm_config_t alarm_config = {
.reload_count = 0,
.alarm_count = TIMER_PERIOD_MS * 1000, // 10ms per alarm event
.flags.auto_reload_on_alarm = true,
};
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
printf("register alarm callback\r\n");
gptimer_event_callbacks_t cbs = {
.on_alarm = on_gptimer_alarm_cb,
};
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
/* Load ULP firmware and start the coprocessor */
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_ETM,
#if ESP_ROM_HAS_LP_ROM
.skip_lp_rom_boot = true,
#endif //ESP_ROM_HAS_LP_ROM
};
load_and_start_lp_core_firmware(&cfg, lp_core_main_counter_bin_start, lp_core_main_counter_bin_end);
printf("enable and start timer\r\n");
TEST_ESP_OK(gptimer_enable(gptimer));
TEST_ESP_OK(gptimer_start(gptimer));
// Wait for more than the expected time for the test to complete
// To ensure that the ULP ran exactly as many times as we expected
vTaskDelay((TIMER_PERIOD_MS * STOP_TEST_ITERATIONS * 2) / portTICK_PERIOD_MS);
TEST_ASSERT_EQUAL(STOP_TEST_ITERATIONS, timer_cb_count);
TEST_ASSERT_EQUAL(STOP_TEST_ITERATIONS, ulp_counter);
TEST_ESP_OK(gptimer_disable(gptimer));
TEST_ESP_OK(gptimer_del_timer(gptimer));
TEST_ESP_OK(esp_etm_del_task(lp_core_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_del_channel(etm_channel_a));
}

View File

@ -264,6 +264,7 @@ INPUT = \
$(PROJECT_PATH)/components/hal/include/hal/uart_types.h \
$(PROJECT_PATH)/components/hal/include/hal/efuse_hal.h \
$(PROJECT_PATH)/components/hal/include/hal/eth_types.h \
$(PROJECT_PATH)/components/hal/include/hal/lp_core_types.h \
$(PROJECT_PATH)/components/heap/include/esp_heap_caps_init.h \
$(PROJECT_PATH)/components/heap/include/esp_heap_caps.h \
$(PROJECT_PATH)/components/heap/include/esp_heap_trace.h \

View File

@ -1,4 +1,4 @@
# TODO: IDF-9197 Use beta3 in doc temprory
# TODO: IDF-9197 Use beta3 in doc temporary
INPUT += \
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/mp/include/soc/soc_caps.h \
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/mp/include/soc/clk_tree_defs.h \
@ -6,6 +6,7 @@ INPUT += \
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/mp/include/soc/uart_channel.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_etm.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \

View File

@ -1,6 +1,7 @@
INPUT += \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_etm.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \

View File

@ -2,6 +2,7 @@ INPUT += \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_spi.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_etm.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \

View File

@ -233,10 +233,16 @@ Main CPU API Reference
.. include-build-file:: inc/lp_core_i2c.inc
.. include-build-file:: inc/lp_core_uart.inc
.. only:: CONFIG_SOC_LP_SPI_SUPPORTED
.. only:: SOC_LP_SPI_SUPPORTED
.. include-build-file:: inc/lp_core_spi.inc
.. only:: SOC_LP_CORE_SUPPORT_ETM
.. include-build-file:: inc/lp_core_etm.inc
.. include-build-file:: inc/lp_core_types.inc
LP Core API Reference
~~~~~~~~~~~~~~~~~~~~~~
@ -247,7 +253,7 @@ LP Core API Reference
.. include-build-file:: inc/ulp_lp_core_print.inc
.. include-build-file:: inc/ulp_lp_core_interrupts.inc
.. only:: CONFIG_SOC_LP_SPI_SUPPORTED
.. only:: SOC_LP_SPI_SUPPORTED
.. include-build-file:: inc/ulp_lp_core_spi.inc

View File

@ -197,10 +197,16 @@ API 参考
.. include-build-file:: inc/lp_core_i2c.inc
.. include-build-file:: inc/lp_core_uart.inc
.. only:: CONFIG_SOC_LP_SPI_SUPPORTED
.. only:: SOC_LP_SPI_SUPPORTED
.. include-build-file:: inc/lp_core_spi.inc
.. only:: SOC_LP_CORE_SUPPORT_ETM
.. include-build-file:: inc/lp_core_etm.inc
.. include-build-file:: inc/lp_core_types.inc
LP 内核 API 参考
~~~~~~~~~~~~~~~~~~~~~~
@ -211,7 +217,7 @@ LP 内核 API 参考
.. include-build-file:: inc/ulp_lp_core_print.inc
.. include-build-file:: inc/ulp_lp_core_interrupts.inc
.. only:: CONFIG_SOC_LP_SPI_SUPPORTED
.. only:: SOC_LP_SPI_SUPPORTED
.. include-build-file:: inc/ulp_lp_core_spi.inc