mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
systimer: support etm event
This commit is contained in:
parent
00b6ec28b2
commit
560ea9b754
@ -9,6 +9,10 @@ if(CONFIG_SOC_TIMER_SUPPORT_ETM)
|
||||
list(APPEND srcs "test_gptimer_etm.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_SYSTIMER_SUPPORT_ETM)
|
||||
list(APPEND srcs "test_systimer_etm.c")
|
||||
endif()
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
|
132
components/esp_hw_support/test_apps/etm/main/test_systimer_etm.c
Normal file
132
components/esp_hw_support/test_apps/etm/main/test_systimer_etm.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_etm.h"
|
||||
#include "driver/gpio_etm.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_systick_etm.h"
|
||||
|
||||
TEST_CASE("rtos_systick_etm_event", "[etm]")
|
||||
{
|
||||
// systimer alarm ---> EMT channel ---> GPIO toggle
|
||||
const uint32_t output_gpio = 1;
|
||||
printf("allocate etm channels\r\n");
|
||||
esp_etm_channel_config_t etm_config = {};
|
||||
esp_etm_channel_handle_t etm_channel_a = NULL;
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a));
|
||||
|
||||
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));
|
||||
|
||||
// bind GPIO to the task
|
||||
TEST_ESP_OK(gpio_etm_task_add_gpio(gpio_task, output_gpio));
|
||||
|
||||
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("acquire systick etm event\r\n");
|
||||
esp_etm_event_handle_t systick_event = NULL;
|
||||
TEST_ESP_OK(esp_systick_new_etm_alarm_event(0, &systick_event));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, systick_event, gpio_task));
|
||||
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
|
||||
// should see a 500Hz square wave on the GPIO (if RTOS systick is set to 1000Hz)
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
// 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_event(systick_event));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_a));
|
||||
}
|
||||
|
||||
static void periodic_timer_callback(void *arg)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("esp_timer_etm_event", "[etm]")
|
||||
{
|
||||
// systimer alarm ---> EMT channel ---> GPIO toggle
|
||||
const uint32_t output_gpio = 1;
|
||||
printf("allocate etm channels\r\n");
|
||||
esp_etm_channel_config_t etm_config = {};
|
||||
esp_etm_channel_handle_t etm_channel_a = NULL;
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a));
|
||||
|
||||
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));
|
||||
|
||||
// bind GPIO to the task
|
||||
TEST_ESP_OK(gpio_etm_task_add_gpio(gpio_task, output_gpio));
|
||||
|
||||
printf("initialize gpio\r\n");
|
||||
gpio_config_t task_gpio_config = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << output_gpio,
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&task_gpio_config));
|
||||
|
||||
// put the GPIO into initial state
|
||||
TEST_ESP_OK(gpio_set_level(output_gpio, 1));
|
||||
|
||||
printf("acquire esp_timer etm event\r\n");
|
||||
esp_etm_event_handle_t esp_timer_event = NULL;
|
||||
TEST_ESP_OK(esp_timer_new_etm_alarm_event(&esp_timer_event));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, esp_timer_event, gpio_task));
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
|
||||
printf("create a periodic esp_timer\r\b");
|
||||
const esp_timer_create_args_t periodic_timer_args = {
|
||||
.callback = periodic_timer_callback,
|
||||
.name = "periodic"
|
||||
};
|
||||
esp_timer_handle_t periodic_timer = NULL;
|
||||
TEST_ESP_OK(esp_timer_create(&periodic_timer_args, &periodic_timer));
|
||||
TEST_ESP_OK(esp_timer_start_periodic(periodic_timer, 500000));
|
||||
|
||||
// should see a 1Hz square wave on the GPIO
|
||||
vTaskDelay(pdMS_TO_TICKS(1200));
|
||||
|
||||
// check the final GPIO level
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(output_gpio));
|
||||
|
||||
TEST_ESP_OK(esp_timer_stop(periodic_timer));
|
||||
TEST_ESP_OK(esp_timer_delete(periodic_timer));
|
||||
|
||||
// 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_event(esp_timer_event));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_a));
|
||||
}
|
@ -192,8 +192,10 @@ wdt_hal_is_enabled = 0x400003bc;
|
||||
***************************************/
|
||||
|
||||
/* Functions */
|
||||
systimer_hal_init = 0x400003c0;
|
||||
systimer_hal_deinit = 0x400003c4;
|
||||
/* The following ROM functions are commented out because they're patched in the esp_rom_systimer.c */
|
||||
/* systimer_hal_init = 0x400003c0; */
|
||||
/* systimer_hal_deinit = 0x400003c4; */
|
||||
|
||||
systimer_hal_set_tick_rate_ops = 0x400003c8;
|
||||
systimer_hal_get_counter_value = 0x400003cc;
|
||||
systimer_hal_get_time = 0x400003d0;
|
||||
|
@ -64,4 +64,20 @@ void systimer_hal_counter_value_advance(systimer_hal_context_t *hal, uint32_t co
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C2
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C6
|
||||
void systimer_hal_init(systimer_hal_context_t *hal)
|
||||
{
|
||||
hal->dev = &SYSTIMER;
|
||||
systimer_ll_enable_clock(hal->dev, true);
|
||||
systimer_ll_enable_etm(&SYSTIMER, true);
|
||||
}
|
||||
|
||||
void systimer_hal_deinit(systimer_hal_context_t *hal)
|
||||
{
|
||||
systimer_ll_enable_etm(&SYSTIMER, false);
|
||||
systimer_ll_enable_clock(hal->dev, false);
|
||||
hal->dev = NULL;
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C6
|
||||
|
||||
#endif // CONFIG_HAL_SYSTIMER_USE_ROM_IMPL
|
||||
|
@ -49,6 +49,10 @@ else()
|
||||
list(APPEND srcs "eh_frame_parser.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_SYSTIMER_SUPPORT_ETM)
|
||||
list(APPEND srcs "systick_etm.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_REQUIRES spi_flash esp_timer
|
||||
|
31
components/esp_system/include/esp_systick_etm.h
Normal file
31
components/esp_system/include/esp_systick_etm.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_etm.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the ETM event handle of systick hardware's alarm/heartbeat event
|
||||
*
|
||||
* @note The created ETM event object can be deleted later by calling `esp_etm_del_event`
|
||||
*
|
||||
* @param[in] core_id CPU core ID
|
||||
* @param[out] out_event Returned ETM event handle
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t esp_systick_new_etm_alarm_event(int core_id, esp_etm_event_handle_t *out_event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
47
components/esp_system/systick_etm.c
Normal file
47
components/esp_system/systick_etm.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_systick_etm.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc_etm_source.h"
|
||||
#include "hal/systimer_ll.h"
|
||||
#include "esp_private/etm_interface.h"
|
||||
|
||||
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
|
||||
static const char *TAG = "systick-etm";
|
||||
|
||||
static esp_err_t systick_etm_event_del(esp_etm_event_t *event)
|
||||
{
|
||||
free(event);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_systick_new_etm_alarm_event(int core_id, esp_etm_event_handle_t *out_event)
|
||||
{
|
||||
esp_etm_event_t *event = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(out_event && core_id < SOC_CPU_CORES_NUM, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
event = heap_caps_calloc(1, sizeof(esp_etm_event_t), ETM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(event, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM event");
|
||||
|
||||
// fill the ETM event object
|
||||
uint32_t event_id = SYSTIMER_EVT_CNT_CMP0 + SYSTIMER_LL_ALARM_OS_TICK_CORE0 + core_id;
|
||||
event->event_id = event_id;
|
||||
event->trig_periph = ETM_TRIG_PERIPH_SYSTIMER;
|
||||
event->del = systick_etm_event_del;
|
||||
*out_event = event;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (event) {
|
||||
systick_etm_event_del(event);
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -10,6 +10,10 @@ elseif(CONFIG_ESP_TIMER_IMPL_SYSTIMER)
|
||||
list(APPEND srcs "src/esp_timer_impl_systimer.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_SYSTIMER_SUPPORT_ETM)
|
||||
list(APPEND srcs "src/esp_timer_etm.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS private_include
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_etm.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -311,6 +312,21 @@ void esp_timer_isr_dispatch_need_yield(void);
|
||||
*/
|
||||
bool esp_timer_is_active(esp_timer_handle_t timer);
|
||||
|
||||
/**
|
||||
* @brief Get the ETM event handle of esp_timer underlying alarm event
|
||||
*
|
||||
* @note The created ETM event object can be deleted later by calling `esp_etm_del_event`
|
||||
*
|
||||
* @note The ETM event is generated by the underlying hardware -- systimer,
|
||||
* therefore, if the esp_timer is not clocked by systimer, then no ETM event will be generated.
|
||||
*
|
||||
* @param[out] out_event Returned ETM event handle
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t esp_timer_new_etm_alarm_event(esp_etm_event_handle_t *out_event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
46
components/esp_timer/src/esp_timer_etm.c
Normal file
46
components/esp_timer/src/esp_timer_etm.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_timer.h"
|
||||
#include "soc/soc_etm_source.h"
|
||||
#include "hal/systimer_ll.h"
|
||||
#include "esp_private/etm_interface.h"
|
||||
|
||||
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
|
||||
static const char *TAG = "esptimer-etm";
|
||||
|
||||
static esp_err_t esp_timer_etm_event_del(esp_etm_event_t *event)
|
||||
{
|
||||
free(event);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_new_etm_alarm_event(esp_etm_event_handle_t *out_event)
|
||||
{
|
||||
esp_etm_event_t *event = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(out_event, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
event = heap_caps_calloc(1, sizeof(esp_etm_event_t), ETM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(event, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM event");
|
||||
|
||||
// fill the ETM event object
|
||||
uint32_t event_id = SYSTIMER_EVT_CNT_CMP0 + SYSTIMER_LL_ALARM_CLOCK;
|
||||
event->event_id = event_id;
|
||||
event->trig_periph = ETM_TRIG_PERIPH_SYSTIMER;
|
||||
event->del = esp_timer_etm_event_del;
|
||||
*out_event = event;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (event) {
|
||||
esp_timer_etm_event_del(event);
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -42,6 +42,13 @@ static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
|
||||
return (PCR.systimer_func_clk_conf.systimer_func_clk_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
|
||||
}
|
||||
|
||||
/********************** ETM *****************************/
|
||||
|
||||
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
|
||||
{
|
||||
dev->conf.etm_en = en;
|
||||
}
|
||||
|
||||
/******************* Counter *************************/
|
||||
|
||||
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
|
||||
|
@ -16,10 +16,16 @@ void systimer_hal_init(systimer_hal_context_t *hal)
|
||||
{
|
||||
hal->dev = &SYSTIMER;
|
||||
systimer_ll_enable_clock(hal->dev, true);
|
||||
#if SOC_SYSTIMER_SUPPORT_ETM
|
||||
systimer_ll_enable_etm(&SYSTIMER, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void systimer_hal_deinit(systimer_hal_context_t *hal)
|
||||
{
|
||||
#if SOC_SYSTIMER_SUPPORT_ETM
|
||||
systimer_ll_enable_etm(&SYSTIMER, false);
|
||||
#endif
|
||||
systimer_ll_enable_clock(hal->dev, false);
|
||||
hal->dev = NULL;
|
||||
}
|
||||
|
@ -699,6 +699,10 @@ config SOC_SYSTIMER_ALARM_MISS_COMPENSATE
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_SYSTIMER_SUPPORT_ETM
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_TIMER_GROUPS
|
||||
int
|
||||
default 2
|
||||
|
@ -349,6 +349,7 @@
|
||||
#define SOC_SYSTIMER_SUPPORT_RC_FAST 1 // Systimer can use RC_FAST clock source
|
||||
#define SOC_SYSTIMER_INT_LEVEL 1 // Systimer peripheral uses level interrupt
|
||||
#define SOC_SYSTIMER_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
|
||||
#define SOC_SYSTIMER_SUPPORT_ETM 1 // Systimer comparator can generate ETM event
|
||||
|
||||
/*--------------------------- TIMER GROUP CAPS ---------------------------------------*/
|
||||
#define SOC_TIMER_GROUPS (2)
|
||||
|
35
tools/mocks/esp_hw_support/include/esp_etm.h
Normal file
35
tools/mocks/esp_hw_support/include/esp_etm.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* NOTE: this is not the original header file from the esp_hw_support component.
|
||||
* It is a stripped-down copy to support mocking.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ETM channel handle
|
||||
*/
|
||||
typedef struct esp_etm_channel_t *esp_etm_channel_handle_t;
|
||||
|
||||
/**
|
||||
* @brief ETM event handle
|
||||
*/
|
||||
typedef struct esp_etm_event_t *esp_etm_event_handle_t;
|
||||
|
||||
/**
|
||||
* @brief ETM task handle
|
||||
*/
|
||||
typedef struct esp_etm_task_t *esp_etm_task_handle_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -4,6 +4,10 @@ message(STATUS "building ESP TIMER MOCKS")
|
||||
|
||||
idf_component_get_property(original_esp_timer_dir esp_timer COMPONENT_OVERRIDEN_DIR)
|
||||
|
||||
idf_component_mock(INCLUDE_DIRS "${original_esp_timer_dir}/include"
|
||||
set(include_dirs
|
||||
"${original_esp_timer_dir}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../esp_hw_support/include")
|
||||
|
||||
idf_component_mock(INCLUDE_DIRS ${include_dirs}
|
||||
REQUIRES esp_common
|
||||
MOCK_HEADER_FILES ${original_esp_timer_dir}/include/esp_timer.h)
|
||||
|
Loading…
Reference in New Issue
Block a user