mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-10 16:14:34 +02:00
gptimer: support etm event and task
This commit is contained in:
@@ -3,7 +3,7 @@ idf_build_get_property(target IDF_TARGET)
|
||||
set(srcs
|
||||
"gpio/gpio.c"
|
||||
"gpio/rtc_io.c"
|
||||
"gptimer.c"
|
||||
"gptimer/gptimer.c"
|
||||
"sdspi_crc.c"
|
||||
"sdspi_host.c"
|
||||
"sdspi_transaction.c"
|
||||
@@ -25,6 +25,10 @@ if(CONFIG_SOC_LEDC_SUPPORTED)
|
||||
list(APPEND srcs "ledc.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_TIMER_SUPPORT_ETM)
|
||||
list(APPEND srcs "gptimer/gptimer_etm.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_I2C_SUPPORTED)
|
||||
list(APPEND srcs "i2c.c")
|
||||
endif()
|
||||
|
@@ -15,8 +15,6 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_pm.h"
|
||||
@@ -28,70 +26,15 @@
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
|
||||
// If ISR handler is allowed to run whilst cache is disabled,
|
||||
// Make sure all the code and related variables used by the handler are in the SRAM
|
||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE || CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
|
||||
#define GPTIMER_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define GPTIMER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
||||
#define GPTIMER_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
|
||||
#else
|
||||
#define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
|
||||
#endif
|
||||
|
||||
#define GPTIMER_PM_LOCK_NAME_LEN_MAX 16
|
||||
#include "gptimer_priv.h"
|
||||
|
||||
static const char *TAG = "gptimer";
|
||||
|
||||
typedef struct gptimer_platform_t gptimer_platform_t;
|
||||
typedef struct gptimer_group_t gptimer_group_t;
|
||||
typedef struct gptimer_t gptimer_t;
|
||||
|
||||
struct gptimer_platform_t {
|
||||
typedef struct gptimer_platform_t {
|
||||
_lock_t mutex; // platform level mutex lock
|
||||
gptimer_group_t *groups[SOC_TIMER_GROUPS]; // timer group pool
|
||||
int group_ref_counts[SOC_TIMER_GROUPS]; // reference count used to protect group install/uninstall
|
||||
};
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GPTIMER_FSM_INIT,
|
||||
GPTIMER_FSM_ENABLE,
|
||||
} gptimer_fsm_t;
|
||||
|
||||
struct gptimer_t {
|
||||
gptimer_group_t *group;
|
||||
int timer_id;
|
||||
uint32_t resolution_hz;
|
||||
uint64_t reload_count;
|
||||
uint64_t alarm_count;
|
||||
gptimer_count_direction_t direction;
|
||||
timer_hal_context_t hal;
|
||||
gptimer_fsm_t fsm;
|
||||
intr_handle_t intr;
|
||||
portMUX_TYPE spinlock; // to protect per-timer resources concurrent accessed by task and ISR handler
|
||||
gptimer_alarm_cb_t on_alarm;
|
||||
void *user_ctx;
|
||||
gptimer_clock_source_t clk_src;
|
||||
esp_pm_lock_handle_t pm_lock; // power management lock
|
||||
#if CONFIG_PM_ENABLE
|
||||
char pm_lock_name[GPTIMER_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
||||
#endif
|
||||
struct {
|
||||
uint32_t intr_shared: 1;
|
||||
uint32_t auto_reload_on_alarm: 1;
|
||||
uint32_t alarm_en: 1;
|
||||
} flags;
|
||||
};
|
||||
} gptimer_platform_t;
|
||||
|
||||
// gptimer driver platform, it's always a singleton
|
||||
static gptimer_platform_t s_platform;
|
||||
@@ -239,6 +182,16 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *valu
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
||||
*value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id);
|
||||
portEXIT_CRITICAL_SAFE(&timer->spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data)
|
||||
{
|
||||
gptimer_group_t *group = NULL;
|
92
components/driver/gptimer/gptimer_etm.c
Normal file
92
components/driver/gptimer/gptimer_etm.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/lock.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "gptimer_priv.h"
|
||||
#include "hal/timer_ll.h"
|
||||
#include "esp_private/etm_interface.h"
|
||||
|
||||
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
|
||||
static const char *TAG = "gptimer-etm";
|
||||
|
||||
static esp_err_t gptimer_del_etm_event(esp_etm_event_t *event)
|
||||
{
|
||||
free(event);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t gptimer_del_etm_task(esp_etm_task_t *task)
|
||||
{
|
||||
free(task);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gptimer_new_etm_event(gptimer_handle_t timer, gptimer_etm_event_type_t event_type, esp_etm_event_handle_t *out_event)
|
||||
{
|
||||
esp_etm_event_t *event = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(timer && out_event, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE(event_type < GPTIMER_ETM_EVENT_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid event type");
|
||||
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");
|
||||
|
||||
gptimer_group_t *group = timer->group;
|
||||
int group_id = group->group_id;
|
||||
int timer_id = timer->timer_id;
|
||||
uint32_t event_id = TIMER_LL_ETM_EVENT_TABLE(group_id, timer_id, 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_GPTIMER;
|
||||
event->del = gptimer_del_etm_event;
|
||||
*out_event = event;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (event) {
|
||||
gptimer_del_etm_event(event);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t gptimer_new_etm_task(gptimer_handle_t timer, gptimer_etm_task_type_t task_type, esp_etm_task_handle_t *out_task)
|
||||
{
|
||||
esp_etm_task_t *task = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(timer && out_task, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE(task_type < GPTIMER_ETM_TASK_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid task type");
|
||||
task = heap_caps_calloc(1, sizeof(esp_etm_task_t), ETM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(task, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM task");
|
||||
|
||||
gptimer_group_t *group = timer->group;
|
||||
int group_id = group->group_id;
|
||||
int timer_id = timer->timer_id;
|
||||
uint32_t task_id = TIMER_LL_ETM_TASK_TABLE(group_id, timer_id, 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_GPTIMER;
|
||||
task->del = gptimer_del_etm_task;
|
||||
*out_task = task;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (task) {
|
||||
gptimer_del_etm_task(task);
|
||||
}
|
||||
return ret;
|
||||
}
|
79
components/driver/gptimer/gptimer_priv.h
Normal file
79
components/driver/gptimer/gptimer_priv.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_pm.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/timer_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// If ISR handler is allowed to run whilst cache is disabled,
|
||||
// Make sure all the code and related variables used by the handler are in the SRAM
|
||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE || CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
|
||||
#define GPTIMER_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define GPTIMER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
||||
#define GPTIMER_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
|
||||
#else
|
||||
#define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
|
||||
#endif
|
||||
|
||||
#define GPTIMER_PM_LOCK_NAME_LEN_MAX 16
|
||||
|
||||
typedef struct gptimer_t gptimer_t;
|
||||
|
||||
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];
|
||||
} gptimer_group_t;
|
||||
|
||||
typedef enum {
|
||||
GPTIMER_FSM_INIT,
|
||||
GPTIMER_FSM_ENABLE,
|
||||
} gptimer_fsm_t;
|
||||
|
||||
struct gptimer_t {
|
||||
gptimer_group_t *group;
|
||||
int timer_id;
|
||||
uint32_t resolution_hz;
|
||||
uint64_t reload_count;
|
||||
uint64_t alarm_count;
|
||||
gptimer_count_direction_t direction;
|
||||
timer_hal_context_t hal;
|
||||
gptimer_fsm_t fsm;
|
||||
intr_handle_t intr;
|
||||
portMUX_TYPE spinlock; // to protect per-timer resources concurrent accessed by task and ISR handler
|
||||
gptimer_alarm_cb_t on_alarm;
|
||||
void *user_ctx;
|
||||
gptimer_clock_source_t clk_src;
|
||||
esp_pm_lock_handle_t pm_lock; // power management lock
|
||||
#if CONFIG_PM_ENABLE
|
||||
char pm_lock_name[GPTIMER_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
||||
#endif
|
||||
struct {
|
||||
uint32_t intr_shared: 1;
|
||||
uint32_t auto_reload_on_alarm: 1;
|
||||
uint32_t alarm_en: 1;
|
||||
} flags;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -9,44 +9,13 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "hal/timer_types.h"
|
||||
#include "driver/gptimer_types.h"
|
||||
#include "driver/gptimer_etm.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of General Purpose Timer handle
|
||||
*/
|
||||
typedef struct gptimer_t *gptimer_handle_t;
|
||||
|
||||
/**
|
||||
* @brief GPTimer alarm event data
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t count_value; /*!< Current count value */
|
||||
uint64_t alarm_value; /*!< Current alarm value */
|
||||
} gptimer_alarm_event_data_t;
|
||||
|
||||
/**
|
||||
* @brief Timer alarm callback prototype
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer`
|
||||
* @param[in] edata Alarm event data, fed by driver
|
||||
* @param[in] user_ctx User data, passed from `gptimer_register_event_callbacks`
|
||||
* @return Whether a high priority task has been waken up by this function
|
||||
*/
|
||||
typedef bool (*gptimer_alarm_cb_t) (gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Group of supported GPTimer callbacks
|
||||
* @note The callbacks are all running under ISR environment
|
||||
* @note When CONFIG_GPTIMER_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||
*/
|
||||
typedef struct {
|
||||
gptimer_alarm_cb_t on_alarm; /*!< Timer alarm callback */
|
||||
} gptimer_event_callbacks_t;
|
||||
|
||||
/**
|
||||
* @brief General Purpose Timer configuration
|
||||
*/
|
||||
@@ -60,17 +29,6 @@ typedef struct {
|
||||
} flags; /*!< GPTimer config flags*/
|
||||
} gptimer_config_t;
|
||||
|
||||
/**
|
||||
* @brief General Purpose Timer alarm configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t alarm_count; /*!< Alarm target count value */
|
||||
uint64_t reload_count; /*!< Alarm reload count value, effect only when `auto_reload_on_alarm` is set to true */
|
||||
struct {
|
||||
uint32_t auto_reload_on_alarm: 1; /*!< Reload the count value by hardware, immediately at the alarm event */
|
||||
} flags; /*!< Alarm config flags*/
|
||||
} gptimer_alarm_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create a new General Purpose Timer, and return the handle
|
||||
*
|
||||
@@ -135,6 +93,31 @@ esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, uint64_t value);
|
||||
*/
|
||||
esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, uint64_t *value);
|
||||
|
||||
/**
|
||||
* @brief Get GPTimer captured count value
|
||||
*
|
||||
* @note The capture action can be issued either by external event or by software (see also `gptimer_get_raw_count`).
|
||||
* @note This function is allowed to run within ISR context
|
||||
* @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM`
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer`
|
||||
* @param[out] value Returned captured count value
|
||||
* @return
|
||||
* - ESP_OK: Get GPTimer captured count value successfully
|
||||
* - ESP_ERR_INVALID_ARG: Get GPTimer captured count value failed because of invalid argument
|
||||
* - ESP_FAIL: Get GPTimer captured count value failed because of other error
|
||||
*/
|
||||
esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value);
|
||||
|
||||
/**
|
||||
* @brief Group of supported GPTimer callbacks
|
||||
* @note The callbacks are all running under ISR environment
|
||||
* @note When CONFIG_GPTIMER_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||
*/
|
||||
typedef struct {
|
||||
gptimer_alarm_cb_t on_alarm; /*!< Timer alarm callback */
|
||||
} gptimer_event_callbacks_t;
|
||||
|
||||
/**
|
||||
* @brief Set callbacks for GPTimer
|
||||
*
|
||||
@@ -153,6 +136,17 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, uint64_t *value);
|
||||
*/
|
||||
esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief General Purpose Timer alarm configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t alarm_count; /*!< Alarm target count value */
|
||||
uint64_t reload_count; /*!< Alarm reload count value, effect only when `auto_reload_on_alarm` is set to true */
|
||||
struct {
|
||||
uint32_t auto_reload_on_alarm: 1; /*!< Reload the count value by hardware, immediately at the alarm event */
|
||||
} flags; /*!< Alarm config flags*/
|
||||
} gptimer_alarm_config_t;
|
||||
|
||||
/**
|
||||
* @brief Set alarm event actions for GPTimer.
|
||||
*
|
||||
|
49
components/driver/include/driver/gptimer_etm.h
Normal file
49
components/driver/include/driver/gptimer_etm.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_etm.h"
|
||||
#include "driver/gptimer_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the ETM event for GPTimer
|
||||
*
|
||||
* @note The created ETM event object can be deleted later by calling `esp_etm_del_event`
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer`
|
||||
* @param[in] event_type GPTimer ETM event type
|
||||
* @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 gptimer_new_etm_event(gptimer_handle_t timer, gptimer_etm_event_type_t event_type, esp_etm_event_handle_t *out_event);
|
||||
|
||||
/**
|
||||
* @brief Get the ETM task for GPTimer
|
||||
*
|
||||
* @note The created ETM task object can be deleted later by calling `esp_etm_del_task`
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer`
|
||||
* @param[in] task_type GPTimer ETM task type
|
||||
* @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 gptimer_new_etm_task(gptimer_handle_t timer, gptimer_etm_task_type_t task_type, esp_etm_task_handle_t *out_task);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
42
components/driver/include/driver/gptimer_types.h
Normal file
42
components/driver/include/driver/gptimer_types.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "hal/timer_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of General Purpose Timer handle
|
||||
*/
|
||||
typedef struct gptimer_t *gptimer_handle_t;
|
||||
|
||||
/**
|
||||
* @brief GPTimer alarm event data
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t count_value; /*!< Current count value */
|
||||
uint64_t alarm_value; /*!< Current alarm value */
|
||||
} gptimer_alarm_event_data_t;
|
||||
|
||||
/**
|
||||
* @brief Timer alarm callback prototype
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer`
|
||||
* @param[in] edata Alarm event data, fed by driver
|
||||
* @param[in] user_ctx User data, passed from `gptimer_register_event_callbacks`
|
||||
* @return Whether a high priority task has been waken up by this function
|
||||
*/
|
||||
typedef bool (*gptimer_alarm_cb_t) (gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -4,6 +4,7 @@ entries:
|
||||
if GPTIMER_CTRL_FUNC_IN_IRAM = y:
|
||||
gptimer: gptimer_set_raw_count (noflash)
|
||||
gptimer: gptimer_get_raw_count (noflash)
|
||||
gptimer: gptimer_get_captured_count (noflash)
|
||||
gptimer: gptimer_set_alarm_action (noflash)
|
||||
gptimer: gptimer_start (noflash)
|
||||
gptimer: gptimer_stop (noflash)
|
||||
|
@@ -5,6 +5,9 @@ if(CONFIG_SOC_GPIO_SUPPORT_ETM)
|
||||
list(APPEND srcs "test_gpio_etm.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_TIMER_SUPPORT_ETM)
|
||||
list(APPEND srcs "test_gptimer_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
|
||||
|
440
components/esp_hw_support/test_apps/etm/main/test_gptimer_etm.c
Normal file
440
components/esp_hw_support/test_apps/etm/main/test_gptimer_etm.c
Normal file
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* 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 "esp_attr.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "driver/gpio_etm.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
static bool on_gptimer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_etm_alarm_event_with_interrupt_enabled", "[etm]")
|
||||
{
|
||||
const uint32_t output_gpio = 1;
|
||||
// GPTimer alarm ---> ETM channel A ---> GPIO toggle
|
||||
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));
|
||||
|
||||
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("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
|
||||
};
|
||||
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;
|
||||
TEST_ESP_OK(gptimer_new_etm_event(gptimer, GPTIMER_ETM_EVENT_ALARM_MATCH, &gptimer_event));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gptimer_event, gpio_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 = 100, // 100us 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));
|
||||
|
||||
printf("enable and start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
// 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_event(gptimer_event));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_a));
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_etm_alarm_event_without_interrupt", "[etm]")
|
||||
{
|
||||
const uint32_t output_gpio = 1;
|
||||
// GPTimer alarm ---> ETM channel A ---> GPIO toggle
|
||||
// GPTimer alarm ---> ETM channel B ---> GPTimer alarm reenable
|
||||
printf("allocate etm channel\r\n");
|
||||
esp_etm_channel_config_t etm_config = {};
|
||||
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("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("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
|
||||
};
|
||||
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;
|
||||
TEST_ESP_OK(gptimer_new_etm_event(gptimer, GPTIMER_ETM_EVENT_ALARM_MATCH, &gptimer_event));
|
||||
esp_etm_task_handle_t gptimer_task = NULL;
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, GPTIMER_ETM_TASK_EN_ALARM, &gptimer_task));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gptimer_event, gpio_task));
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, gptimer_event, gptimer_task));
|
||||
|
||||
printf("enable etm channel\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));
|
||||
|
||||
printf("enable and start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
// 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_auto_reload_by_etm", "[etm]")
|
||||
{
|
||||
const uint32_t output_gpio = 1;
|
||||
// GPTimer alarm ---> ETM channel A ---> GPIO toggle
|
||||
// GPTimer alarm ---> ETM channel B ---> GPTimer alarm reenable
|
||||
// GPTimer alarm ---> ETM channel C ---> GPTimer reload
|
||||
printf("allocate etm channel\r\n");
|
||||
esp_etm_channel_config_t etm_config = {};
|
||||
esp_etm_channel_handle_t etm_channel_a, etm_channel_b, etm_channel_c;
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_b));
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_c));
|
||||
|
||||
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("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
|
||||
};
|
||||
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_alarm = NULL;
|
||||
TEST_ESP_OK(gptimer_new_etm_event(gptimer, GPTIMER_ETM_EVENT_ALARM_MATCH, &gptimer_event_alarm));
|
||||
esp_etm_task_handle_t gptimer_task_en_alarm = NULL;
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, GPTIMER_ETM_TASK_EN_ALARM, &gptimer_task_en_alarm));
|
||||
esp_etm_task_handle_t gptimer_task_reload = NULL;
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, GPTIMER_ETM_TASK_RELOAD, &gptimer_task_reload));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gptimer_event_alarm, gpio_task));
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, gptimer_event_alarm, gptimer_task_en_alarm));
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_c, gptimer_event_alarm, gptimer_task_reload));
|
||||
|
||||
printf("enable etm channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_b));
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_c));
|
||||
|
||||
printf("dump the etm channel usage\r\n");
|
||||
TEST_ESP_OK(esp_etm_dump(stdout));
|
||||
|
||||
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 = false, // reload will be done by ETM channel C
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
|
||||
printf("enable and start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
// 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_en_alarm));
|
||||
TEST_ESP_OK(esp_etm_del_task(gptimer_task_reload));
|
||||
TEST_ESP_OK(esp_etm_del_event(gptimer_event_alarm));
|
||||
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_channel_disable(etm_channel_c));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_b));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_c));
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_etm_task_capture", "[etm]")
|
||||
{
|
||||
const uint32_t input_gpio = 0;
|
||||
// GPIO Posedge ---> ETM channel A ---> GPTimer capture
|
||||
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));
|
||||
|
||||
printf("allocate GPIO etm event\r\n");
|
||||
esp_etm_event_handle_t gpio_event = NULL;
|
||||
gpio_etm_event_config_t gpio_event_config = {
|
||||
.edge = GPIO_ETM_EVENT_EDGE_POS,
|
||||
};
|
||||
TEST_ESP_OK(gpio_new_etm_event(&gpio_event_config, &gpio_event));
|
||||
// set gpio number for the gpio etm primitives
|
||||
TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_event, input_gpio));
|
||||
|
||||
printf("initialize gpio\r\n");
|
||||
gpio_config_t task_gpio_config = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT, // we want to simulate the edge signal by software, so it should be input and output
|
||||
.pin_bit_mask = 1ULL << input_gpio,
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&task_gpio_config));
|
||||
TEST_ESP_OK(gpio_set_level(input_gpio, 0));
|
||||
|
||||
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 task handle\r\n");
|
||||
esp_etm_task_handle_t gptimer_task = NULL;
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, GPTIMER_ETM_TASK_CAPTURE, &gptimer_task));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gpio_event, gptimer_task));
|
||||
|
||||
printf("enable etm channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
|
||||
printf("enable and start gptimer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
|
||||
// simulate the edge signal by software
|
||||
TEST_ESP_OK(gpio_set_level(input_gpio, 1));
|
||||
TEST_ESP_OK(gpio_set_level(input_gpio, 0));
|
||||
|
||||
uint64_t capture_value = 0;
|
||||
TEST_ESP_OK(gptimer_get_captured_count(gptimer, &capture_value));
|
||||
printf("capture value: %llu\r\n", capture_value);
|
||||
// should be around 500us
|
||||
TEST_ASSERT_UINT_WITHIN(1000, 500000, capture_value);
|
||||
|
||||
// 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(esp_etm_del_task(gptimer_task));
|
||||
TEST_ESP_OK(esp_etm_del_event(gpio_event));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_a));
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_start_stop_by_etm_task", "[etm]")
|
||||
{
|
||||
const uint32_t input_gpio = 0;
|
||||
// GPIO pos edge ---> ETM channel A ---> GPTimer start
|
||||
// GPIO neg edge ---> ETM channel B ---> GPTimer stop
|
||||
printf("allocate etm channel\r\n");
|
||||
esp_etm_channel_config_t etm_config = {};
|
||||
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("allocate GPIO etm events\r\n");
|
||||
esp_etm_event_handle_t gpio_event_pos, gpio_event_neg;
|
||||
gpio_etm_event_config_t gpio_event_config = {
|
||||
.edge = GPIO_ETM_EVENT_EDGE_POS,
|
||||
};
|
||||
TEST_ESP_OK(gpio_new_etm_event(&gpio_event_config, &gpio_event_pos));
|
||||
gpio_event_config.edge = GPIO_ETM_EVENT_EDGE_NEG;
|
||||
TEST_ESP_OK(gpio_new_etm_event(&gpio_event_config, &gpio_event_neg));
|
||||
|
||||
// set gpio number for the gpio etm primitives
|
||||
TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_event_pos, input_gpio));
|
||||
TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_event_neg, input_gpio));
|
||||
|
||||
printf("initialize gpio\r\n");
|
||||
gpio_config_t task_gpio_config = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT, // we want to simulate the edge signal by software, so it should be input and output
|
||||
.pin_bit_mask = 1ULL << input_gpio,
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&task_gpio_config));
|
||||
|
||||
// put the gpio into initial state
|
||||
TEST_ESP_OK(gpio_set_level(input_gpio, 0));
|
||||
|
||||
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 task handle\r\n");
|
||||
esp_etm_task_handle_t gptimer_task_start, gptimer_task_stop;
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, GPTIMER_ETM_TASK_START_COUNT, &gptimer_task_start));
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, GPTIMER_ETM_TASK_STOP_COUNT, &gptimer_task_stop));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gpio_event_pos, gptimer_task_start));
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, gpio_event_neg, gptimer_task_stop));
|
||||
|
||||
printf("enable etm channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_b));
|
||||
|
||||
printf("enable timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
|
||||
// trigger an pos-edge, this should start the gptimer
|
||||
TEST_ESP_OK(gpio_set_level(input_gpio, 1));
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
uint64_t cur_count_val = 0;
|
||||
TEST_ESP_OK(gptimer_get_raw_count(gptimer, &cur_count_val));
|
||||
printf("cur_count_val: %llu\r\n", cur_count_val);
|
||||
TEST_ASSERT_UINT_WITHIN(900, 500000, cur_count_val);
|
||||
|
||||
// trigger an neg-edge, this should stop the gptimer
|
||||
TEST_ESP_OK(gpio_set_level(input_gpio, 0));
|
||||
uint64_t count_val_0 = 0;
|
||||
TEST_ESP_OK(gptimer_get_raw_count(gptimer, &count_val_0));
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
uint64_t count_val_1 = 0;
|
||||
TEST_ESP_OK(gptimer_get_raw_count(gptimer, &count_val_1));
|
||||
TEST_ASSERT_EQUAL(count_val_0, count_val_1);
|
||||
|
||||
// delete gptimer
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
|
||||
// delete etm primitives
|
||||
TEST_ESP_OK(esp_etm_del_task(gptimer_task_start));
|
||||
TEST_ESP_OK(esp_etm_del_task(gptimer_task_stop));
|
||||
TEST_ESP_OK(esp_etm_del_event(gpio_event_pos));
|
||||
TEST_ESP_OK(esp_etm_del_event(gpio_event_neg));
|
||||
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));
|
||||
}
|
@@ -14,6 +14,7 @@
|
||||
#include "hal/timer_types.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/pcr_struct.h"
|
||||
#include "soc/soc_etm_source.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -23,6 +24,32 @@ extern "C" {
|
||||
#define TIMER_LL_GET_HW(group_id) ((group_id == 0) ? (&TIMERG0) : (&TIMERG1))
|
||||
#define TIMER_LL_EVENT_ALARM(timer_id) (1 << (timer_id))
|
||||
|
||||
#define TIMER_LL_ETM_TASK_TABLE(group, timer, task) \
|
||||
(uint32_t [2][1][GPTIMER_ETM_TASK_MAX]){{{ \
|
||||
[GPTIMER_ETM_TASK_START_COUNT] = TIMER0_TASK_CNT_START_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_STOP_COUNT] = TIMER0_TASK_CNT_STOP_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_EN_ALARM] = TIMER0_TASK_ALARM_START_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_RELOAD] = TIMER0_TASK_CNT_RELOAD_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_CAPTURE] = TIMER0_TASK_CNT_CAP_TIMER0, \
|
||||
}}, \
|
||||
{{ \
|
||||
[GPTIMER_ETM_TASK_START_COUNT] = TIMER1_TASK_CNT_START_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_STOP_COUNT] = TIMER1_TASK_CNT_STOP_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_EN_ALARM] = TIMER1_TASK_ALARM_START_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_RELOAD] = TIMER1_TASK_CNT_RELOAD_TIMER0, \
|
||||
[GPTIMER_ETM_TASK_CAPTURE] = TIMER1_TASK_CNT_CAP_TIMER0, \
|
||||
}}, \
|
||||
}[group][timer][task]
|
||||
|
||||
#define TIMER_LL_ETM_EVENT_TABLE(group, timer, event) \
|
||||
(uint32_t [2][1][GPTIMER_ETM_EVENT_MAX]){{{ \
|
||||
[GPTIMER_ETM_EVENT_ALARM_MATCH] = TIMER0_EVT_CNT_CMP_TIMER0, \
|
||||
}}, \
|
||||
{{ \
|
||||
[GPTIMER_ETM_EVENT_ALARM_MATCH] = TIMER1_EVT_CNT_CMP_TIMER0, \
|
||||
}}, \
|
||||
}[group][timer][event]
|
||||
|
||||
/**
|
||||
* @brief Set clock source for timer
|
||||
*
|
||||
|
@@ -26,6 +26,26 @@ typedef enum {
|
||||
GPTIMER_COUNT_UP, /*!< Increase count value */
|
||||
} gptimer_count_direction_t;
|
||||
|
||||
/**
|
||||
* @brief GPTimer specific tasks that supported by the ETM module
|
||||
*/
|
||||
typedef enum {
|
||||
GPTIMER_ETM_TASK_START_COUNT, /*!< Start the counter */
|
||||
GPTIMER_ETM_TASK_STOP_COUNT, /*!< Stop the counter */
|
||||
GPTIMER_ETM_TASK_EN_ALARM, /*!< Enable the alarm */
|
||||
GPTIMER_ETM_TASK_RELOAD, /*!< Reload preset value into counter */
|
||||
GPTIMER_ETM_TASK_CAPTURE, /*!< Capture current count value into specific register */
|
||||
GPTIMER_ETM_TASK_MAX, /*!< Maximum number of tasks */
|
||||
} gptimer_etm_task_type_t;
|
||||
|
||||
/**
|
||||
* @brief GPTimer specific events that supported by the ETM module
|
||||
*/
|
||||
typedef enum {
|
||||
GPTIMER_ETM_EVENT_ALARM_MATCH, /*!< Count value matches the alarm target value */
|
||||
GPTIMER_ETM_EVENT_MAX, /*!< Maximum number of events */
|
||||
} gptimer_etm_event_type_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user