refactor(gptimer)!: removed the legacy driver

also provide idy.py hints instructions
This commit is contained in:
morris
2025-05-22 13:46:09 +08:00
parent 4a80901841
commit a04df4631e
22 changed files with 57 additions and 2161 deletions

View File

@ -31,11 +31,6 @@ if(CONFIG_SOC_DAC_SUPPORTED)
"deprecated/${target}/dac_legacy.c") "deprecated/${target}/dac_legacy.c")
endif() endif()
# GPTimer legacy driver
if(CONFIG_SOC_GPTIMER_SUPPORTED)
list(APPEND srcs "deprecated/timer_legacy.c")
endif()
# I2C related source files # I2C related source files
if(CONFIG_SOC_I2C_SUPPORTED) if(CONFIG_SOC_I2C_SUPPORTED)
list(APPEND srcs "i2c/i2c.c") list(APPEND srcs "i2c/i2c.c")

View File

@ -102,23 +102,6 @@ menu "Driver Configurations"
This configuration option allows the user to bypass the conflict check mechanism with legacy code. This configuration option allows the user to bypass the conflict check mechanism with legacy code.
endmenu # Legacy MCPWM Driver Configurations endmenu # Legacy MCPWM Driver Configurations
menu "Legacy Timer Group Driver Configurations"
depends on SOC_GPTIMER_SUPPORTED
config GPTIMER_SUPPRESS_DEPRECATE_WARN
bool "Suppress legacy driver deprecated warning"
default n
help
Whether to suppress the deprecation warnings when using legacy timer group driver (driver/timer.h).
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
you can enable this option.
config GPTIMER_SKIP_LEGACY_CONFLICT_CHECK
bool "Skip legacy conflict check"
default n
help
This configuration option allows the user to bypass the conflict check mechanism with legacy code.
endmenu # Legacy Timer Group Driver Configurations
menu "Legacy RMT Driver Configurations" menu "Legacy RMT Driver Configurations"
depends on SOC_RMT_SUPPORTED depends on SOC_RMT_SUPPORTED
config RMT_SUPPRESS_DEPRECATE_WARN config RMT_SUPPRESS_DEPRECATE_WARN

View File

@ -1,383 +0,0 @@
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "driver/timer_types_legacy.h"
#if !CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN
#warning "legacy timer group driver is deprecated, please migrate to driver/gptimer.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Read the counter value of hardware timer.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param timer_val Pointer to accept timer counter value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *timer_val);
/**
* @brief Read the counter value of hardware timer, in unit of a given scale.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param time Pointer, type of double*, to accept timer counter value, in seconds.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double *time);
/**
* @brief Set counter value to hardware timer.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param load_val Counter value to write to the hardware timer.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val);
/**
* @brief Start the counter of hardware timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Pause the counter of hardware timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Set counting mode for hardware timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param counter_dir Counting direction of timer, count-up or count-down
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir);
/**
* @brief Enable or disable counter reload function when alarm event occurs.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param reload Counter reload mode.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload);
/**
* @brief Set hardware divider of the source clock to the timer group.
* By default, the source clock is APB clock running at 80 MHz.
* For more information, please check Chapter Reset and Clock in Chip Technical Reference Manual.
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param divider Timer clock divider value. The divider's range is from from 2 to 65536.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint32_t divider);
/**
* @brief Set timer alarm value.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param alarm_value A 64-bit value to set the alarm value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value);
/**
* @brief Get timer alarm value.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param alarm_value Pointer of A 64-bit value to accept the alarm value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *alarm_value);
/**
* @brief Enable or disable generation of timer alarm events.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param alarm_en To enable or disable timer alarm function.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en);
/**
* @brief Add ISR handle callback for the corresponding timer.
*
* @param group_num Timer group number
* @param timer_num Timer index of timer group
* @param isr_handler Interrupt handler function, it is a callback function.
* @param arg Parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
*
* @note This ISR handler will be called from an ISR.
* This ISR handler do not need to handle interrupt status, and should be kept short.
* If you want to realize some specific applications or write the whole ISR, you can
* call timer_isr_register(...) to register ISR.
*
* The callback should return a bool value to determine whether need to do YIELD at
* the end of the ISR.
*
* If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set,
* the handler function must be declared with IRAM_ATTR attribute
* and can only call functions in IRAM or ROM. It cannot call other timer APIs.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *arg, int intr_alloc_flags);
/**
* @brief Remove ISR handle callback for the corresponding timer.
*
* @param group_num Timer group number
* @param timer_num Timer index of timer group
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_isr_callback_remove(timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Register Timer interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
*
* @param group_num Timer group number
* @param timer_num Timer index of timer group
* @param fn Interrupt handler function.
* @param arg Parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @note If use this function to register ISR, you need to write the whole ISR.
* In the interrupt handler, you need to call timer_spinlock_take(..) before
* your handling, and call timer_spinlock_give(...) after your handling.
*
* If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set,
* the handler function must be declared with IRAM_ATTR attribute
* and can only call functions in IRAM or ROM. It cannot call other timer APIs.
* Use direct register access to configure timers from inside the ISR in this case.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void *), void *arg, int intr_alloc_flags, timer_isr_handle_t *handle);
/** @brief Initializes and configure the timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param config Pointer to timer initialization parameters.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer_config_t *config);
/** @brief Deinitializes the timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_deinit(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Get timer configure value.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param config Pointer of struct to accept timer parameters.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config);
/** @brief Enable timer group interrupt, by enable mask
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_mask Timer interrupt enable mask.
* - TIMER_INTR_T0: t0 interrupt
* - TIMER_INTR_T1: t1 interrupt
* - TIMER_INTR_WDT: watchdog interrupt
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
/** @brief Disable timer group interrupt, by disable mask
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_mask Timer interrupt disable mask.
* - TIMER_INTR_T0: t0 interrupt
* - TIMER_INTR_T1: t1 interrupt
* - TIMER_INTR_WDT: watchdog interrupt
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
/** @brief Enable timer interrupt
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Disable timer interrupt
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Clear timer interrupt status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
*/
void timer_group_clr_intr_status_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Enable alarm interrupt, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
*/
void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Get the current counter value, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
* @return
* - Counter value
*/
uint64_t timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Set the alarm threshold for the timer, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
* @param alarm_val Alarm threshold.
*
*/
void timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val);
/** @brief Enable/disable a counter, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
* @param counter_en Enable/disable.
*
*/
void timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en);
/** @brief Get interrupt status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
*
* @return
* - Interrupt status
*/
uint32_t timer_group_get_intr_status_in_isr(timer_group_t group_num);
/** @brief Get auto reload enable status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index
*
* @return
* - True Auto reload enabled
* - False Auto reload disabled
*/
bool timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num);
#ifdef __cplusplus
}
#endif

View File

@ -1,144 +0,0 @@
/*
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h"
#include "hal/timer_types.h"
#include "esp_intr_alloc.h"
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Timer-Group ID
*/
typedef enum {
TIMER_GROUP_0 = 0, /*!< Hw timer group 0 */
#if SOC_TIMER_GROUPS > 1
TIMER_GROUP_1 = 1, /*!< Hw timer group 1 */
#endif
TIMER_GROUP_MAX /*!< Maximum number of Hw timer groups */
} timer_group_t;
/**
* @brief Timer ID
*/
typedef enum {
TIMER_0 = 0, /*!< Select timer0 of GROUPx*/
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1
TIMER_1 = 1, /*!< Select timer1 of GROUPx*/
#endif
TIMER_MAX,
} timer_idx_t;
/**
* @brief Interrupt types of the timer.
*/
typedef enum {
TIMER_INTR_T0 = 1 << 0, /*!< interrupt of timer 0 */
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1
TIMER_INTR_T1 = 1 << 1, /*!< interrupt of timer 1 */
TIMER_INTR_WDT = 1 << 2, /*!< interrupt of watchdog */
#else
TIMER_INTR_WDT = 1 << 1, /*!< interrupt of watchdog */
#endif
TIMER_INTR_NONE = 0
} timer_intr_t;
/**
* @brief Timer count direction
*/
typedef enum {
TIMER_COUNT_DOWN = GPTIMER_COUNT_DOWN, /*!< Descending Count from cnt.high|cnt.low*/
TIMER_COUNT_UP = GPTIMER_COUNT_UP, /*!< Ascending Count from Zero*/
TIMER_COUNT_MAX /*!< Maximum number of timer count directions */
} timer_count_dir_t;
/**
* @brief Timer start/stop command
*/
typedef enum {
TIMER_PAUSE, /*!< Pause timer counter*/
TIMER_START, /*!< Start timer counter*/
} timer_start_t;
/**
* @brief Timer alarm command
*/
typedef enum {
TIMER_ALARM_DIS = 0, /*!< Disable timer alarm*/
TIMER_ALARM_EN = 1, /*!< Enable timer alarm*/
TIMER_ALARM_MAX
} timer_alarm_t;
/**
* @brief Timer interrupt type
*/
typedef enum {
TIMER_INTR_LEVEL = 0, /*!< Interrupt mode: level mode*/
TIMER_INTR_MAX
} timer_intr_mode_t;
/**
* @brief Timer autoreload command
*/
typedef enum {
TIMER_AUTORELOAD_DIS = 0, /*!< Disable auto-reload: hardware will not load counter value after an alarm event*/
TIMER_AUTORELOAD_EN = 1, /*!< Enable auto-reload: hardware will load counter value after an alarm event*/
TIMER_AUTORELOAD_MAX,
} timer_autoreload_t;
#if SOC_GPTIMER_SUPPORTED
/**
* @brief Timer group clock source
*/
typedef soc_periph_tg_clk_src_legacy_t timer_src_clk_t;
#else
/**
* @brief Default type
*/
typedef int timer_src_clk_t;
#endif
/**
* @brief Interrupt handler callback function
*
* @return
* - True Do task yield at the end of ISR
* - False Not do task yield at the end of ISR
*
* @note If you called FreeRTOS functions in callback, you need to return true or false based on
* the return value of argument `pxHigherPriorityTaskWoken`.
* For example, `xQueueSendFromISR` is called in callback, if the return value `pxHigherPriorityTaskWoken`
* of any FreeRTOS calls is pdTRUE, return true; otherwise return false.
*/
typedef bool (*timer_isr_t)(void *);
/**
* @brief Interrupt handle, used in order to free the isr after use.
*/
typedef intr_handle_t timer_isr_handle_t;
/**
* @brief Timer configurations
*/
typedef struct {
timer_alarm_t alarm_en; /*!< Timer alarm enable */
timer_start_t counter_en; /*!< Counter enable */
timer_intr_mode_t intr_type; /*!< Interrupt mode */
timer_count_dir_t counter_dir; /*!< Counter direction */
timer_autoreload_t auto_reload; /*!< Timer auto-reload */
timer_src_clk_t clk_src; /*!< Selects source clock. */
uint32_t divider; /*!< Counter clock divider */
} timer_config_t;
#ifdef __cplusplus
}
#endif

View File

@ -1,488 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "driver/timer_types_legacy.h"
#include "hal/timer_hal.h"
#include "hal/timer_ll.h"
#include "hal/check.h"
#include "soc/timer_periph.h"
#include "soc/soc_caps.h"
#include "esp_clk_tree.h"
#include "soc/timer_group_reg.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/periph_ctrl.h"
static const char *TIMER_TAG = "timer_group";
#define TIMER_GROUP_NUM_ERROR "TIMER GROUP NUM ERROR"
#define TIMER_NUM_ERROR "HW TIMER NUM ERROR"
#define TIMER_PARAM_ADDR_ERROR "HW TIMER PARAM ADDR ERROR"
#define TIMER_NEVER_INIT_ERROR "HW TIMER NEVER INIT ERROR"
#define TIMER_COUNT_DIR_ERROR "HW TIMER COUNTER DIR ERROR"
#define TIMER_AUTORELOAD_ERROR "HW TIMER AUTORELOAD ERROR"
#define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR"
#define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR"
#define DIVIDER_RANGE_ERROR "HW TIMER divider outside of [2, 65536] range error"
#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux);
#define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL_SAFE(mux);
#if SOC_PERIPH_CLK_CTRL_SHARED
#define GPTIMER_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define GPTIMER_CLOCK_SRC_ATOMIC()
#endif
typedef struct {
timer_isr_t fn; /*!< isr function */
void *args; /*!< isr function args */
timer_isr_handle_t timer_isr_handle; /*!< interrupt handle */
timer_group_t isr_timer_group; /*!< timer group of interrupt triggered */
} timer_isr_func_t;
typedef struct {
timer_hal_context_t hal;
timer_isr_func_t timer_isr_fun;
timer_src_clk_t clk_src;
gptimer_count_direction_t direction;
uint32_t divider;
uint64_t alarm_value;
bool alarm_en;
bool auto_reload_en;
bool counter_en;
} timer_obj_t;
static timer_obj_t *p_timer_obj[TIMER_GROUP_MAX][TIMER_MAX] = {0};
static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = { [0 ... TIMER_GROUP_MAX - 1] = portMUX_INITIALIZER_UNLOCKED, };
esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *timer_val)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_val != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
*timer_val = timer_hal_capture_and_get_counter_value(&p_timer_obj[group_num][timer_num]->hal);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double *time)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(time != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
uint64_t timer_val = timer_hal_capture_and_get_counter_value(&p_timer_obj[group_num][timer_num]->hal);
uint32_t div = p_timer_obj[group_num][timer_num]->divider;
// get clock source frequency
uint32_t counter_src_hz = 0;
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)p_timer_obj[group_num][timer_num]->clk_src,
ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz),
TIMER_TAG, "get clock source frequency failed");
*time = (double)timer_val * div / counter_src_hz;
return ESP_OK;
}
esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_hal_set_counter_value(&(p_timer_obj[group_num][timer_num]->hal), load_val);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_counter(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, true);
p_timer_obj[group_num][timer_num]->counter_en = true;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_counter(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, false);
p_timer_obj[group_num][timer_num]->counter_en = false;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(counter_dir < TIMER_COUNT_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_COUNT_DIR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_set_count_direction(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, counter_dir);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(reload < TIMER_AUTORELOAD_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_AUTORELOAD_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_auto_reload(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, reload);
p_timer_obj[group_num][timer_num]->auto_reload_en = reload;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint32_t divider)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(divider > 1 && divider < 65537, ESP_ERR_INVALID_ARG, TIMER_TAG, DIVIDER_RANGE_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_set_clock_prescale(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, divider);
p_timer_obj[group_num][timer_num]->divider = divider;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_set_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_value);
p_timer_obj[group_num][timer_num]->alarm_value = alarm_value;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *alarm_value)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(alarm_value != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
*alarm_value = p_timer_obj[group_num][timer_num]->alarm_value;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(alarm_en < TIMER_ALARM_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_ALARM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_alarm(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_en);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
static void IRAM_ATTR timer_isr_default(void *arg)
{
bool is_awoken = false;
timer_obj_t *timer_obj = (timer_obj_t *)arg;
if (timer_obj == NULL || timer_obj->timer_isr_fun.fn == NULL) {
return;
}
uint32_t timer_id = timer_obj->hal.timer_id;
timer_hal_context_t *hal = &timer_obj->hal;
TIMER_ENTER_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]);
uint32_t intr_status = timer_ll_get_intr_status(hal->dev);
uint64_t old_alarm_value = timer_obj->alarm_value;
if (intr_status & TIMER_LL_EVENT_ALARM(timer_id)) {
// Clear interrupt status
timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_id));
// call user registered callback
is_awoken = timer_obj->timer_isr_fun.fn(timer_obj->timer_isr_fun.args);
// re-enable alarm if required
uint64_t new_alarm_value = timer_obj->alarm_value;
bool reenable_alarm = (new_alarm_value != old_alarm_value) || timer_obj->auto_reload_en;
timer_ll_enable_alarm(hal->dev, timer_id, reenable_alarm);
}
TIMER_EXIT_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]);
if (is_awoken) {
portYIELD_FROM_ISR();
}
}
esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_intr(p_timer_obj[group_num][timer_num]->hal.dev, TIMER_LL_EVENT_ALARM(timer_num), true);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_intr(p_timer_obj[group_num][timer_num]->hal.dev, TIMER_LL_EVENT_ALARM(timer_num), false);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num,
void (*fn)(void *), void *arg, int intr_alloc_flags, timer_isr_handle_t *handle)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(fn != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
timer_hal_context_t *hal = &p_timer_obj[group_num][timer_num]->hal;
return esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_num].timer_irq_id[timer_num],
intr_alloc_flags,
(uint32_t)timer_ll_get_intr_status_reg(hal->dev),
TIMER_LL_EVENT_ALARM(timer_num), fn, arg, handle);
}
esp_err_t timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *args, int intr_alloc_flags)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
esp_err_t ret = ESP_OK;
timer_disable_intr(group_num, timer_num);
p_timer_obj[group_num][timer_num]->timer_isr_fun.fn = isr_handler;
p_timer_obj[group_num][timer_num]->timer_isr_fun.args = args;
p_timer_obj[group_num][timer_num]->timer_isr_fun.isr_timer_group = group_num;
ret = timer_isr_register(group_num, timer_num, timer_isr_default, (void *)p_timer_obj[group_num][timer_num],
intr_alloc_flags, &(p_timer_obj[group_num][timer_num]->timer_isr_fun.timer_isr_handle));
ESP_RETURN_ON_ERROR(ret, TIMER_TAG, "register interrupt service failed");
timer_enable_intr(group_num, timer_num);
return ret;
}
esp_err_t timer_isr_callback_remove(timer_group_t group_num, timer_idx_t timer_num)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
timer_disable_intr(group_num, timer_num);
p_timer_obj[group_num][timer_num]->timer_isr_fun.fn = NULL;
p_timer_obj[group_num][timer_num]->timer_isr_fun.args = NULL;
esp_intr_free(p_timer_obj[group_num][timer_num]->timer_isr_fun.timer_isr_handle);
return ESP_OK;
}
esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer_config_t *config)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(config != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(config->divider > 1 && config->divider < 65537, ESP_ERR_INVALID_ARG, TIMER_TAG, DIVIDER_RANGE_ERROR);
ESP_RETURN_ON_FALSE(config->intr_type < TIMER_INTR_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, "only support Level Interrupt");
if (p_timer_obj[group_num][timer_num] == NULL) {
p_timer_obj[group_num][timer_num] = (timer_obj_t *) heap_caps_calloc(1, sizeof(timer_obj_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num], ESP_ERR_NO_MEM, TIMER_TAG, "no mem for timer object");
}
timer_hal_context_t *hal = &p_timer_obj[group_num][timer_num]->hal;
PERIPH_RCC_ACQUIRE_ATOMIC(timer_group_periph_signals.groups[group_num].module, ref_count) {
if (ref_count == 0) {
timer_ll_enable_bus_clock(group_num, true);
timer_ll_reset_register(group_num);
}
}
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_hal_init(hal, group_num, timer_num);
timer_hal_set_counter_value(hal, 0);
timer_src_clk_t clk_src = TIMER_SRC_CLK_DEFAULT;
if (config->clk_src) {
clk_src = config->clk_src;
}
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true));
GPTIMER_CLOCK_SRC_ATOMIC() {
// although `clk_src` is of `timer_src_clk_t` type, but it's binary compatible with `gptimer_clock_source_t`,
// as the underlying enum entries come from the same `soc_module_clk_t`
timer_ll_set_clock_source(group_num, timer_num, (gptimer_clock_source_t)clk_src);
timer_ll_enable_clock(group_num, timer_num, true);
}
timer_ll_set_clock_prescale(hal->dev, timer_num, config->divider);
timer_ll_set_count_direction(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, config->counter_dir);
timer_ll_enable_intr(hal->dev, TIMER_LL_EVENT_ALARM(timer_num), false);
timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_num));
timer_ll_enable_alarm(hal->dev, timer_num, config->alarm_en);
timer_ll_enable_auto_reload(hal->dev, timer_num, config->auto_reload);
timer_ll_enable_counter(hal->dev, timer_num, config->counter_en);
p_timer_obj[group_num][timer_num]->clk_src = clk_src;
p_timer_obj[group_num][timer_num]->alarm_en = config->alarm_en;
p_timer_obj[group_num][timer_num]->auto_reload_en = config->auto_reload;
p_timer_obj[group_num][timer_num]->direction = config->counter_dir;
p_timer_obj[group_num][timer_num]->counter_en = config->counter_en;
p_timer_obj[group_num][timer_num]->divider = config->divider;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_deinit(timer_group_t group_num, timer_idx_t timer_num)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
timer_hal_context_t *hal = &p_timer_obj[group_num][timer_num]->hal;
// disable the source clock
GPTIMER_CLOCK_SRC_ATOMIC() {
timer_ll_enable_clock(group_num, hal->timer_id, false);
}
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)p_timer_obj[group_num][timer_num]->clk_src, false));
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_intr(hal->dev, TIMER_LL_EVENT_ALARM(timer_num), false);
timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_num));
timer_hal_deinit(hal);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
PERIPH_RCC_RELEASE_ATOMIC(timer_group_periph_signals.groups[group_num].module, ref_count) {
if (ref_count == 0) {
timer_ll_enable_bus_clock(group_num, false);
}
}
free(p_timer_obj[group_num][timer_num]);
p_timer_obj[group_num][timer_num] = NULL;
return ESP_OK;
}
esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(config != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
config->alarm_en = p_timer_obj[group_num][timer_num]->alarm_en;
config->auto_reload = p_timer_obj[group_num][timer_num]->auto_reload_en;
config->counter_dir = p_timer_obj[group_num][timer_num]->direction;
config->counter_en = p_timer_obj[group_num][timer_num]->counter_en;
config->divider = p_timer_obj[group_num][timer_num]->divider;
config->intr_type = TIMER_INTR_LEVEL;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t en_mask)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_intr(p_timer_obj[group_num][0]->hal.dev, en_mask, true);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t disable_mask)
{
ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
timer_ll_enable_intr(p_timer_obj[group_num][0]->hal.dev, disable_mask, false);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
}
uint32_t IRAM_ATTR timer_group_get_intr_status_in_isr(timer_group_t group_num)
{
uint32_t intr_status = 0;
if (p_timer_obj[group_num][TIMER_0] != NULL) {
intr_status = timer_ll_get_intr_status(TIMER_LL_GET_HW(group_num)) & TIMER_LL_EVENT_ALARM(0);
}
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1
else if (p_timer_obj[group_num][TIMER_1] != NULL) {
intr_status = timer_ll_get_intr_status(TIMER_LL_GET_HW(group_num)) & TIMER_LL_EVENT_ALARM(1);
}
#endif
return intr_status;
}
void IRAM_ATTR timer_group_clr_intr_status_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
timer_ll_clear_intr_status(p_timer_obj[group_num][timer_num]->hal.dev, TIMER_LL_EVENT_ALARM(timer_num));
}
void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
timer_ll_enable_alarm(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, true);
}
uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
timer_ll_trigger_soft_capture(p_timer_obj[group_num][timer_num]->hal.dev, timer_num);
uint64_t val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num);
return val;
}
void IRAM_ATTR timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val)
{
timer_ll_set_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_val);
p_timer_obj[group_num][timer_num]->alarm_value = alarm_val;
}
void IRAM_ATTR timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en)
{
timer_ll_enable_counter(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, counter_en);
p_timer_obj[group_num][timer_num]->counter_en = counter_en;
}
bool IRAM_ATTR timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
return p_timer_obj[group_num][timer_num]->auto_reload_en;
}
#if !CONFIG_GPTIMER_SKIP_LEGACY_CONFLICT_CHECK
/**
* @brief This function will be called during start up, to check that this legacy timer group driver is not running along with the gptimer driver
*/
__attribute__((constructor))
static void check_legacy_timer_driver_conflict(void)
{
// This function was declared as weak here. gptimer driver has one implementation.
// So if gptimer driver is not linked in, then `gptimer_new_timer()` should be NULL at runtime.
extern __attribute__((weak)) esp_err_t gptimer_new_timer(const void *config, void **ret_timer);
if ((void *)gptimer_new_timer != NULL) {
ESP_EARLY_LOGE(TIMER_TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver");
abort();
}
ESP_EARLY_LOGW(TIMER_TAG, "legacy driver is deprecated, please migrate to `driver/gptimer.h`");
}
#endif //CONFIG_GPTIMER_SKIP_LEGACY_CONFLICT_CHECK

View File

@ -66,12 +66,6 @@ components/driver/test_apps/legacy_sigma_delta_driver:
depends_components: depends_components:
- esp_driver_gpio - esp_driver_gpio
components/driver/test_apps/legacy_timer_driver:
disable:
- if: SOC_GPTIMER_SUPPORTED != 1
depends_filepatterns:
- components/driver/deprecated/**/*timer*
components/driver/test_apps/legacy_twai: components/driver/test_apps/legacy_twai:
disable: disable:
- if: SOC_TWAI_SUPPORTED != 1 or SOC_TWAI_SUPPORT_FD == 1 - if: SOC_TWAI_SUPPORTED != 1 or SOC_TWAI_SUPPORT_FD == 1

View File

@ -1,8 +0,0 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(legacy_timer_driver_test)

View File

@ -1,2 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- |

View File

@ -1,8 +0,0 @@
set(srcs "test_app_main.c"
"test_legacy_timer.c")
# 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}
PRIV_REQUIRES unity driver
WHOLE_ARCHIVE)

View File

@ -1,40 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#define TEST_MEMORY_LEAK_THRESHOLD (-600)
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
unity_run_menu();
}

View File

@ -1,18 +0,0 @@
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
@idf_parametrize('target', ['supported_targets'], indirect=['target'])
def test_legacy_timer_driver(dut: Dut) -> None:
dut.run_all_single_board_cases(timeout=120)

View File

@ -1,5 +0,0 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -1,3 +0,0 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN=y

View File

@ -30,7 +30,6 @@ typedef struct {
uint32_t intr_shared: 1; /*!< Set true, the timer interrupt number can be shared with other peripherals */ uint32_t intr_shared: 1; /*!< Set true, the timer interrupt number can be shared with other peripherals */
uint32_t allow_pd: 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode. 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. */ This can save power, but at the expense of more RAM being consumed to save register context. */
uint32_t backup_before_sleep: 1; /*!< @deprecated, same meaning as allow_pd */
} flags; /*!< GPTimer config flags*/ } flags; /*!< GPTimer config flags*/
} gptimer_config_t; } gptimer_config_t;

View File

@ -137,7 +137,7 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
TAG, "invalid interrupt priority:%d", config->intr_priority); TAG, "invalid interrupt priority:%d", config->intr_priority);
} }
bool allow_pd = (config->flags.allow_pd == 1) || (config->flags.backup_before_sleep == 1); bool allow_pd = config->flags.allow_pd == 1;
#if !SOC_TIMER_SUPPORT_SLEEP_RETENTION #if !SOC_TIMER_SUPPORT_SLEEP_RETENTION
ESP_RETURN_ON_FALSE(allow_pd == false, ESP_ERR_NOT_SUPPORTED, TAG, "not able to power down in light sleep"); ESP_RETURN_ON_FALSE(allow_pd == false, ESP_ERR_NOT_SUPPORTED, TAG, "not able to power down in light sleep");
#endif // SOC_TIMER_SUPPORT_SLEEP_RETENTION #endif // SOC_TIMER_SUPPORT_SLEEP_RETENTION

View File

@ -153,7 +153,7 @@ static void test_gptimer_etm_sleep_retention(bool back_up_before_sleep)
.clk_src = GPTIMER_CLK_SRC_DEFAULT, .clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP, .direction = GPTIMER_COUNT_UP,
.resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us .resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us
.flags.backup_before_sleep = back_up_before_sleep, .flags.allow_pd = back_up_before_sleep,
}; };
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer)); TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));

View File

@ -119,12 +119,18 @@ GPIO
- Channel configuration was done by channel allocation, in :cpp:func:`sdm_new_channel`. In the new driver, only the ``density`` can be changed at runtime, by :cpp:func:`sdm_channel_set_pulse_density`. Other parameters like ``gpio number`` and ``prescale`` are only allowed to set during channel allocation. - Channel configuration was done by channel allocation, in :cpp:func:`sdm_new_channel`. In the new driver, only the ``density`` can be changed at runtime, by :cpp:func:`sdm_channel_set_pulse_density`. Other parameters like ``gpio number`` and ``prescale`` are only allowed to set during channel allocation.
- Before further channel operations, users should **enable** the channel in advance, by calling :cpp:func:`sdm_channel_enable`. This function helps to manage some system level services, like **Power Management**. - Before further channel operations, users should **enable** the channel in advance, by calling :cpp:func:`sdm_channel_enable`. This function helps to manage some system level services, like **Power Management**.
Timer Group Driver .. _deprecate_gptimer_legacy_driver:
------------------
.. only:: not SOC_SDM_SUPPORTED
.. _deprecate_gptimer_legacy_driver:
Legacy Timer Group Driver is Deprecated
---------------------------------------
Timer Group driver has been redesigned into :doc:`GPTimer <../../../api-reference/peripherals/gptimer>`, which aims to unify and simplify the usage of general purpose timer. Timer Group driver has been redesigned into :doc:`GPTimer <../../../api-reference/peripherals/gptimer>`, which aims to unify and simplify the usage of general purpose timer.
Although it is recommended to use the new driver APIs, the legacy driver is still available in the previous include path ``driver/timer.h``. However, by default, including ``driver/timer.h`` triggers the build warning below. The warning can be suppressed by the Kconfig option :ref:`CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN`. Although it is recommended to use the new driver APIs, the legacy driver is still available in the previous include path ``driver/timer.h``. However, by default, including ``driver/timer.h`` triggers the build warning below. The warning can be suppressed by the Kconfig option ``CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN``.
.. code-block:: text .. code-block:: text

View File

@ -49,3 +49,8 @@ Major Changes in Usage
- ``i2c_slave_transmit`` has been replaced by ``i2c_slave_write``. - ``i2c_slave_transmit`` has been replaced by ``i2c_slave_write``.
- ``i2c_slave_write_ram`` has been removed。 - ``i2c_slave_write_ram`` has been removed。
- ``i2c_slave_read_ram`` has been removed。 - ``i2c_slave_read_ram`` has been removed。
Legacy Timer Group Driver is Removed
------------------------------------
The legacy timer group driver ``driver/timer.h`` is deprecated since version 5.0 (see :ref:`deprecate_gptimer_legacy_driver`). Starting from version 6.0, the legacy driver is completely removed. The new driver is placed in the :component:`esp_driver_gptimer`, and the header file path is ``driver/gptimer.h``.

View File

@ -119,12 +119,18 @@ GPIO
- 更新前,通道配置由通道分配在 :cpp:func:`sdm_new_channel` 完成。在新驱动中,只有 ``density`` 可在运行时由 :cpp:func:`sdm_channel_set_pulse_density` 更新。其他参数如 ``gpio number````prescale`` 只能在通道分配时进行设置。 - 更新前,通道配置由通道分配在 :cpp:func:`sdm_new_channel` 完成。在新驱动中,只有 ``density`` 可在运行时由 :cpp:func:`sdm_channel_set_pulse_density` 更新。其他参数如 ``gpio number````prescale`` 只能在通道分配时进行设置。
- 在进行下一步通道操作前,用户应通过调用 :cpp:func:`sdm_channel_enable` 提前 **使能** 该通道。该函数有助于管理一些系统级服务,如 **电源管理** - 在进行下一步通道操作前,用户应通过调用 :cpp:func:`sdm_channel_enable` 提前 **使能** 该通道。该函数有助于管理一些系统级服务,如 **电源管理**
定时器组驱动 .. _deprecate_gptimer_legacy_driver:
-----------------------------------------
.. only:: not SOC_SDM_SUPPORTED
.. _deprecate_gptimer_legacy_driver:
旧版定时器组驱动被弃用
----------------------
为统一和简化通用定时器的使用,定时器组驱动已更新为 :doc:`GPTimer <../../../api-reference/peripherals/gptimer>` 为统一和简化通用定时器的使用,定时器组驱动已更新为 :doc:`GPTimer <../../../api-reference/peripherals/gptimer>`
尽管我们推荐使用新的驱动 API 旧版驱动仍然可用,其头文件引用路径为 ``driver/timer.h``。但是,引用 ``driver/timer.h`` 会默认触发如下编译警告,可通过配置 Kconfig 选项 :ref:`CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN` 关闭该警告。 尽管我们推荐使用新的驱动 API 旧版驱动仍然可用,其头文件引用路径为 ``driver/timer.h``。但是,引用 ``driver/timer.h`` 会默认触发如下编译警告,可通过配置 Kconfig 选项 ``CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN`` 关闭该警告。
.. code-block:: text .. code-block:: text

View File

@ -49,3 +49,8 @@ I2C 从机在 v5.4 上已经被重新设计。在当前版本上,老的 I2C
- ``i2c_slave_transmit`` 已被 ``i2c_slave_write`` 取代. - ``i2c_slave_transmit`` 已被 ``i2c_slave_write`` 取代.
- ``i2c_slave_write_ram`` 被移除。 - ``i2c_slave_write_ram`` 被移除。
- ``i2c_slave_read_ram`` 被移除。 - ``i2c_slave_read_ram`` 被移除。
旧版定时器组驱动被移除
----------------------
旧版的定时器组驱动 ``driver/timer.h`` 在 5.0 的版本中就已经被弃用 (参考 :ref:`deprecate_gptimer_legacy_driver`)。从 6.0 版本开始,旧版驱动被完全移除。新驱动位于 :component:`esp_driver_gptimer` 组件中,头文件引用路径为 ``driver/gptimer.h``

View File

@ -469,3 +469,30 @@
- -
re: "spi_hal: The clock_speed_hz should less than" re: "spi_hal: The clock_speed_hz should less than"
hint: "When operating in full-duplex mode at high frequencies, the device may not read data correctly.\nTry using IOMUX pins to increase the frequency limit or switch to half-duplex mode.\nNote that the SPI master can only operate at divisors of 80 MHz, and the driver always selects the closest available frequency to your configuration.\nSpecify SPI_DEVICE_NO_DUMMY to bypass this check. This allows higher output speeds but may result in unreliable data reads." hint: "When operating in full-duplex mode at high frequencies, the device may not read data correctly.\nTry using IOMUX pins to increase the frequency limit or switch to half-duplex mode.\nNote that the SPI master can only operate at divisors of 80 MHz, and the driver always selects the closest available frequency to your configuration.\nSpecify SPI_DEVICE_NO_DUMMY to bypass this check. This allows higher output speeds but may result in unreliable data reads."
-
re: "has no member named 'io_loop_back'"
hint: "If you want to bind different driver objects to the same GPIO, just set them with the same GPIO number."
-
re: "has no member named '{}'"
hint: "Please include 'driver/gpio.h' and call 'gpio_set_pull_mode' to set the correct pull mode."
variables:
-
re_variables: ['pull_up']
hint_variables: []
-
re_variables: ['pull_down']
hint_variables: []
-
re: "has no member named 'io_od_mode'"
hint: "Please include 'driver/gpio.h' and call 'gpio_od_enable' to enable the open-drain mode."
-
re: "fatal error: {}: No such file or directory"
hint: "The {} driver is removed. It should be replaced by '{}' in the '{}' component. Please read the migration guide for more details."
variables:
-
re_variables: ['driver/timer.h']
hint_variables: ['legacy timer group', 'driver/gptimer.h', 'esp_driver_gptimer']