diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index cdff8a1b43..6ab7e10958 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -246,9 +246,9 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will * be returned here. * - * @note 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. + * @note 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 @@ -258,7 +258,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ 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. @@ -284,28 +284,30 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer /** @brief Enable timer group interrupt, by enable mask * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param en_mask Timer interrupt enable mask. - * Use TIMG_T0_INT_ENA_M to enable t0 interrupt - * Use TIMG_T1_INT_ENA_M to enable t1 interrupt + * @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, uint32_t en_mask); +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 disable_mask Timer interrupt disable mask. - * Use TIMG_T0_INT_ENA_M to disable t0 interrupt - * Use TIMG_T1_INT_ENA_M to disable t1 interrupt + * @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, uint32_t disable_mask); +esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask); /** @brief Enable timer interrupt * @@ -329,6 +331,52 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num); */ esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num); +/** @cond */ +/* Utilities functions that can be used in the ISR */ +/* Preview, don't treat them as stable API. */ + +/** + * Clear interrupt status bit. + */ +void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Enable alarm. + */ +void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Get the current counter value. + */ +uint64_t timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Set the alarm threshold for the timer. + */ +void timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val); + +/** + * Enable/disable a counter. + */ +void timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en); + +/** + * Get the masked interrupt status. + */ +timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num); + +/** + * Clear interrupt. + */ +void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask); + +/** + * Get auto reload enable status. + */ +bool timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** @endcond */ + #ifdef __cplusplus } #endif diff --git a/components/driver/timer.c b/components/driver/timer.c index 6a82d87fa9..67f0fffb32 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -19,6 +19,7 @@ #include "freertos/xtensa_api.h" #include "driver/timer.h" #include "driver/periph_ctrl.h" +#include "hal/timer_ll.h" static const char* TIMER_TAG = "timer_group"; #define TIMER_CHECK(a, str, ret_val) \ @@ -35,7 +36,7 @@ static const char* TIMER_TAG = "timer_group"; #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" -static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1}; +DRAM_ATTR static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1}; static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; #define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux); @@ -171,7 +172,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ return ESP_OK; } -esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, +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) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); @@ -253,7 +254,7 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer return ESP_OK; } -esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask) +esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t en_mask) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&timer_spinlock[group_num]); @@ -262,7 +263,7 @@ esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask) return ESP_OK; } -esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask) +esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t disable_mask) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&timer_spinlock[group_num]); @@ -275,14 +276,54 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); - return timer_group_intr_enable(group_num, BIT(timer_num)); + return timer_group_intr_enable(group_num, TIMER_LL_GET_INTR(timer_num)); } esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); - return timer_group_intr_disable(group_num, BIT(timer_num)); + return timer_group_intr_disable(group_num, TIMER_LL_GET_INTR(timer_num)); } +timer_intr_t IRAM_ATTR timer_group_intr_get_in_isr(timer_group_t group_num) +{ + return timer_ll_intr_status_get(TG[group_num]); +} +void IRAM_ATTR timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + timer_ll_intr_status_clear(TG[group_num], TIMER_LL_GET_INTR(timer_num)); +} + +void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + timer_ll_set_alarm_enable(TG[group_num], timer_num, true); +} + +uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + uint64_t val; + timer_ll_get_counter_value(TG[group_num], timer_num, &val); + 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(TG[group_num], timer_num, 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_set_counter_enable(TG[group_num], timer_num, counter_en); +} + +void IRAM_ATTR timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask) +{ + timer_ll_intr_status_clear(TG[group_num], intr_mask); +} + +bool IRAM_ATTR timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + return timer_ll_get_auto_reload(TG[group_num], timer_num); +} diff --git a/components/soc/esp32/include/hal/timer_ll.h b/components/soc/esp32/include/hal/timer_ll.h index cc0cd69c52..d74c00ee7b 100644 --- a/components/soc/esp32/include/hal/timer_ll.h +++ b/components/soc/esp32/include/hal/timer_ll.h @@ -24,6 +24,65 @@ extern "C" { #include "hal/timer_types.h" #include "soc/timer_periph.h" +//Helper macro to get corresponding interrupt of a timer +#define TIMER_LL_GET_INTR(TIMER_IDX) ((TIMER_IDX)==TIMER_0? TIMER_INTR_T0: TIMER_INTR_T1) + +#define TIMER_LL_GET_HW(TIMER_GROUP) ((TIMER_GROUP)==0? &TIMERG0: &TIMERG1) + +_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); + +/** + * @brief Enable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt enable mask + * + * @return None + */ +static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val |= intr_mask; +} + +/** + * @brief Disable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt disable mask + * + * @return None + */ +static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val &= (~intr_mask); +} + +/** + * @brief Get timer interrupt status. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Masked interrupt status + */ +static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw) +{ + return hw->int_raw.val; +} + +/** + * @brief Clear timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt mask to clear + * + * @return None + */ +static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_clr_timers.val = intr_mask; +} /** * @brief Get counter vaule from time-base counter @@ -40,8 +99,6 @@ static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_ *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low); } - - /** * @brief Set counter status, enable or disable counter. * @@ -56,7 +113,6 @@ static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer hw->hw_timer[timer_num].config.enable = counter_en; } - /** * @brief Get auto reload mode. * diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index d555a2115e..f1564eee9d 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -20,6 +20,8 @@ extern "C" { #include #include +#include + /** * @brief Select a hardware timer from timer groups @@ -39,6 +41,16 @@ typedef enum { } timer_start_t; +/** + * @brief Interrupt types of the timer. + */ +//this is compatible with the value of esp32. +typedef enum { + TIMER_INTR_T0 = BIT(0), /*!< interrupt of timer 0 */ + TIMER_INTR_T1 = BIT(1), /*!< interrupt of timer 1 */ + TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */ +} timer_intr_t; + #ifdef __cplusplus } #endif