Procházet zdrojové kódy

feat(timer): refator timer group driver

1. add hal and low-level layer for timer group
2. add callback functions to handle interrupt
3. add timer deinit function
4. add timer spinlock take function
chenjianqiang před 6 roky
rodič
revize
9f9da9ec96

+ 3 - 3
components/app_trace/test/test_trace.c

@@ -145,7 +145,7 @@ static void esp_apptrace_test_timer_isr(void *arg)
     }
 
     tim_arg->data.wr_cnt++;
-    timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id);
+    timer_group_clr_intr_status_in_isr(tim_arg->group, tim_arg->id);
     timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id);
 }
 
@@ -153,7 +153,7 @@ static void esp_apptrace_test_timer_isr_crash(void *arg)
 {
     esp_apptrace_test_timer_arg_t *tim_arg = (esp_apptrace_test_timer_arg_t *)arg;
 
-    timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id);
+    timer_group_clr_intr_status_in_isr(tim_arg->group, tim_arg->id);
     timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id);
     if (tim_arg->data.wr_cnt < ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH) {
         uint32_t *ts = (uint32_t *)(tim_arg->data.buf + sizeof(uint32_t));
@@ -810,7 +810,7 @@ static void esp_sysview_test_timer_isr(void *arg)
 
     //ESP_APPTRACE_TEST_LOGI("tim-%d: IRQ %d/%d\n", tim_arg->id, tim_arg->group, tim_arg->timer);
 
-    timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id);
+    timer_group_clr_intr_status_in_isr(tim_arg->group, tim_arg->id);
     timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id);
 }
 

+ 160 - 105
components/driver/include/driver/timer.h

@@ -1,4 +1,4 @@
-// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef _DRIVER_TIMER_H_
-#define _DRIVER_TIMER_H_
+#pragma once
+
 #include "esp_err.h"
 #include "esp_attr.h"
 #include "soc/soc.h"
@@ -25,79 +25,9 @@
 extern "C" {
 #endif
 
-
 #define TIMER_BASE_CLK   (APB_CLK_FREQ)  /*!< Frequency of the clock on the input of the timer groups */
 
-/**
- * @brief Selects a Timer-Group out of 2 available groups
- */
-typedef enum {
-    TIMER_GROUP_0 = 0, /*!<Hw timer group 0*/
-    TIMER_GROUP_1 = 1, /*!<Hw timer group 1*/
-    TIMER_GROUP_MAX,
-} timer_group_t;
-
-/**
- * @brief Decides the direction of counter
- */
-typedef enum {
-    TIMER_COUNT_DOWN = 0, /*!< Descending Count from cnt.high|cnt.low*/
-    TIMER_COUNT_UP = 1,   /*!< Ascending Count from Zero*/
-    TIMER_COUNT_MAX
-} timer_count_dir_t;
-
-/**
- * @brief Decides whether to enable alarm mode
- */
-typedef enum {
-    TIMER_ALARM_DIS = 0,  /*!< Disable timer alarm*/
-    TIMER_ALARM_EN = 1,   /*!< Enable timer alarm*/
-    TIMER_ALARM_MAX
-} timer_alarm_t;
-
-/**
- * @brief Select interrupt type if running in alarm mode.
- */
-typedef enum {
-    TIMER_INTR_LEVEL = 0,  /*!< Interrupt mode: level mode*/
-    //TIMER_INTR_EDGE = 1, /*!< Interrupt mode: edge mode, Not supported Now*/
-    TIMER_INTR_MAX
-} timer_intr_mode_t;
-
-/**
- * @brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
- */
-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;
-
-#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
-/**
- * @brief Select timer source clock.
- */
-typedef enum {
-    TIMER_SRC_CLK_APB = 0,  /*!< Select APB as the source clock*/
-    TIMER_SRC_CLK_XTAL = 1, /*!< Select XTAL as the source clock*/
-} timer_src_clk_t;
-#endif
-
-/**
- * @brief Data structure with timer's configuration settings
- */
-typedef struct {
-    bool alarm_en;      /*!< Timer alarm enable */
-    bool counter_en;    /*!< Counter enable */
-    timer_intr_mode_t intr_type; /*!< Interrupt mode */
-    timer_count_dir_t counter_dir; /*!< Counter direction  */
-    bool auto_reload;   /*!< Timer auto-reload */
-    uint32_t divider;   /*!< Counter clock divider. The divider's range is from from 2 to 65536. */
-#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
-    timer_src_clk_t clk_sel;  /*!< Use XTAL as source clock. */
-#endif
-} timer_config_t;
-
+typedef void (*timer_isr_t)(void *);
 
 /**
  * @brief Interrupt handle, used in order to free the isr after use.
@@ -116,7 +46,7 @@ typedef intr_handle_t timer_isr_handle_t;
  *     - 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);
+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.
@@ -129,7 +59,7 @@ esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num
  *     - 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);
+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.
@@ -231,7 +161,7 @@ esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num,
  *     - 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);
+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.
@@ -246,6 +176,43 @@ esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num,
  */
 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.
+ *
+ *       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.
@@ -259,7 +226,11 @@ 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,
+ * @note If use this function to reigster 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.
@@ -268,7 +239,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
  *     - 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);
+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.
  *
@@ -280,7 +251,18 @@ esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, voi
  *     - 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);
+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.
  *
@@ -344,54 +326,127 @@ 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. */
+/** @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.
+ *
+ * @return
+ *     - None
+ */
+void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num) __attribute__((deprecated));
 
-/**
- * Clear interrupt status bit.
+/** @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.
+ *
+ * @return
+ *     - None
  */
-void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num);
+void timer_group_clr_intr_status_in_isr(timer_group_t group_num, timer_idx_t timer_num);
 
-/**
- * Enable alarm.
+/** @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.
+ *
+ * @return
+ *     - None
  */
 void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num);
 
-/**
- * Get the current counter value.
+/** @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);
 
-/**
- * Set the alarm threshold for the timer.
+/** @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.
+ *
+ * @return
+ *     - None
  */
 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.
+/** @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.
+ *
+ * @return
+ *     - None
  */
 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.
+/** @brief Get the masked interrupt status, just used in ISR
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ *
+ * @return
+ *     - Interrupt status
  */
-timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num);
+timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num) __attribute__((deprecated));
 
-/**
- * Clear interrupt.
+/** @brief Get interrupt status, just used in ISR
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ *
+ * @return
+ *     - Interrupt status
  */
-void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask);
+uint32_t timer_group_get_intr_status_in_isr(timer_group_t group_num);
 
-/**
- * Get auto reload enable status.
+/** @brief Clear the masked interrupt status, just used in ISR
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param intr_mask Masked interrupt.
+ *
+ * @return
+ *     - None
+ */
+void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask) __attribute__((deprecated));
+
+/** @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);
 
-/** @endcond */
+/** @brief Take timer spinlock to enter critical protect
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ *
+ * @return
+ *     - ESP_OK Success
+ *     - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_spinlock_take(timer_group_t group_num);
+
+/** @brief Give timer spinlock to exit critical protect
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ *
+ * @return
+ *     - ESP_OK Success
+ *     - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_spinlock_give(timer_group_t group_num);
 
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* _TIMER_H_ */

+ 2 - 2
components/driver/test/test_timer.c

@@ -38,13 +38,13 @@ static void test_timer_group_isr(void *para)
     uint64_t alarm_value;
     alarm_flag = true;
     if (timer_group_get_auto_reload_in_isr(timer_group, timer_idx)) {
-        timer_group_intr_clr_in_isr(timer_group, timer_idx);
+        timer_group_clr_intr_status_in_isr(timer_group, timer_idx);
         ets_printf("This is TG%d timer[%d] reload-timer alarm!\n", timer_group, timer_idx);
         timer_get_counter_value(timer_group, timer_idx, &timer_val);
         timer_get_counter_time_sec(timer_group, timer_idx, &time);
         ets_printf("time: %.8f S\n", time);
     } else {
-        timer_group_intr_clr_in_isr(timer_group, timer_idx);
+        timer_group_clr_intr_status_in_isr(timer_group, timer_idx);
         ets_printf("This is TG%d timer[%d] count-up-timer alarm!\n", timer_group, timer_idx);
         timer_get_counter_value(timer_group, timer_idx, &timer_val);
         timer_get_counter_time_sec(timer_group, timer_idx, &time);

+ 263 - 100
components/driver/timer.c

@@ -11,6 +11,7 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
 #include <string.h>
 #include "esp_log.h"
 #include "esp_err.h"
@@ -19,10 +20,11 @@
 #include "freertos/xtensa_api.h"
 #include "driver/timer.h"
 #include "driver/periph_ctrl.h"
-#include "hal/timer_ll.h"
+#include "hal/timer_hal.h"
 #include "soc/rtc.h"
 
-static const char* TIMER_TAG = "timer_group";
+static const char *TIMER_TAG = "timer_group";
+
 #define TIMER_CHECK(a, str, ret_val) \
     if (!(a)) { \
         ESP_LOGE(TIMER_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
@@ -32,48 +34,58 @@ 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"
-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);
 #define TIMER_EXIT_CRITICAL(mux)       portEXIT_CRITICAL_SAFE(mux);
 
-esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* timer_val)
+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_obj_t;
+
+static timer_obj_t *p_timer_obj[TIMER_GROUP_MAX][TIMER_MAX] = {0};
+static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
+
+esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *timer_val)
 {
     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);
     TIMER_CHECK(timer_val != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
-    portENTER_CRITICAL_SAFE(&timer_spinlock[group_num]);
-#ifdef CONFIG_IDF_TARGET_ESP32
-    TG[group_num]->hw_timer[timer_num].update = 1;
-#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-    TG[group_num]->hw_timer[timer_num].update.update = 1;
-#endif
-    *timer_val = ((uint64_t) TG[group_num]->hw_timer[timer_num].cnt_high << 32)
-        | (TG[group_num]->hw_timer[timer_num].cnt_low);
-    portEXIT_CRITICAL_SAFE(&timer_spinlock[group_num]);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    timer_hal_get_counter_value(&(p_timer_obj[group_num][timer_num]->hal), timer_val);
+    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_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double *time)
 {
     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);
     TIMER_CHECK(time != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
-
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     uint64_t timer_val;
     esp_err_t err = timer_get_counter_value(group_num, timer_num, &timer_val);
     if (err == ESP_OK) {
-        uint16_t div = TG[group_num]->hw_timer[timer_num].config.divider;
+        uint16_t div;
+        timer_hal_get_divider(&(p_timer_obj[group_num][timer_num]->hal), &div);
 #ifdef CONFIG_IDF_TARGET_ESP32
         *time = (double)timer_val * div / TIMER_BASE_CLK;
 #elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-        if(TG[group_num]->hw_timer[timer_num].config.use_xtal) {
+        if (timer_hal_get_use_xtal(&(p_timer_obj[group_num][timer_num]->hal))) {
             *time = (double)timer_val * div / ((int)rtc_clk_xtal_freq_get() * 1000000);
         } else {
             *time = (double)timer_val * div / rtc_clk_apb_freq_get();
@@ -87,10 +99,9 @@ esp_err_t timer_set_counter_value(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);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);
-    TG[group_num]->hw_timer[timer_num].load_low = (uint32_t) load_val;
-    TG[group_num]->hw_timer[timer_num].reload = 1;
+    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;
 }
@@ -99,8 +110,9 @@ esp_err_t timer_start(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);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->hw_timer[timer_num].config.enable = 1;
+    timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), TIMER_START);
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
@@ -109,8 +121,9 @@ esp_err_t timer_pause(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);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->hw_timer[timer_num].config.enable = 0;
+    timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), TIMER_PAUSE);
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
@@ -120,8 +133,9 @@ esp_err_t timer_set_counter_mode(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);
     TIMER_CHECK(counter_dir < TIMER_COUNT_MAX, TIMER_COUNT_DIR_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->hw_timer[timer_num].config.increase = counter_dir;
+    timer_hal_set_counter_increase(&(p_timer_obj[group_num][timer_num]->hal), counter_dir);
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
@@ -131,8 +145,9 @@ esp_err_t timer_set_auto_reload(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);
     TIMER_CHECK(reload < TIMER_AUTORELOAD_MAX, TIMER_AUTORELOAD_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->hw_timer[timer_num].config.autoreload = reload;
+    timer_hal_set_auto_reload(&(p_timer_obj[group_num][timer_num]->hal), reload);
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
@@ -142,11 +157,9 @@ esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint
     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);
     TIMER_CHECK(divider > 1 && divider < 65537, DIVIDER_RANGE_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    int timer_en = TG[group_num]->hw_timer[timer_num].config.enable;
-    TG[group_num]->hw_timer[timer_num].config.enable = 0;
-    TG[group_num]->hw_timer[timer_num].config.divider = (uint16_t) divider;
-    TG[group_num]->hw_timer[timer_num].config.enable = timer_en;
+    timer_hal_set_divider(&(p_timer_obj[group_num][timer_num]->hal), (uint16_t) divider);
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
@@ -155,22 +168,22 @@ esp_err_t timer_set_alarm_value(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);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
-    TG[group_num]->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
+    timer_hal_set_alarm_value(&(p_timer_obj[group_num][timer_num]->hal), 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_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *alarm_value)
 {
     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);
     TIMER_CHECK(alarm_value != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
-    portENTER_CRITICAL_SAFE(&timer_spinlock[group_num]);
-    *alarm_value = ((uint64_t) TG[group_num]->hw_timer[timer_num].alarm_high << 32)
-                | (TG[group_num]->hw_timer[timer_num].alarm_low);
-    portEXIT_CRITICAL_SAFE(&timer_spinlock[group_num]);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    timer_hal_get_alarm_value(&(p_timer_obj[group_num][timer_num]->hal), alarm_value);
+    TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
 
@@ -179,42 +192,100 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
     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);
     TIMER_CHECK(alarm_en < TIMER_ALARM_MAX, TIMER_ALARM_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->hw_timer[timer_num].config.alarm_en = alarm_en;
+    timer_hal_set_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal), alarm_en);
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
 
+static void IRAM_ATTR timer_isr_default(void *arg)
+{
+    timer_obj_t *timer_obj = (timer_obj_t *)arg;
+    if (timer_obj == NULL) {
+        return;
+    }
+    if (timer_obj->timer_isr_fun.fn == NULL) {
+        return;
+    }
+
+    TIMER_ENTER_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]);
+    {
+        uint32_t intr_status = 0;
+        timer_hal_get_intr_status(&(timer_obj->hal), &intr_status);
+        if (intr_status & BIT(timer_obj->hal.idx)) {
+            timer_obj->timer_isr_fun.fn(timer_obj->timer_isr_fun.args);
+            //Clear intrrupt status
+            timer_hal_clear_intr_status(&(timer_obj->hal));
+            //After the alarm has been triggered, we need enable it again, so it is triggered the next time.
+            timer_hal_set_alarm_enable(&(timer_obj->hal), TIMER_ALARM_EN);
+        }
+    }
+    TIMER_EXIT_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]);
+}
+
+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)
+{
+    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);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+
+    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;
+    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));
+    timer_enable_intr(group_num, timer_num);
+
+    return ESP_OK;
+}
+
+esp_err_t timer_isr_callback_remove(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);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+
+    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_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)
+                             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);
     TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
 
     int intr_source = 0;
     uint32_t status_reg = 0;
     int mask = 0;
-    switch(group_num) {
-        case TIMER_GROUP_0:
-        default:
-            if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
-                intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;
-            } else {
-                intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;
-            }
-            status_reg = TIMG_INT_ST_TIMERS_REG(0);
-            mask = 1<<timer_num;
-            break;
-        case TIMER_GROUP_1:
-            if((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
-                intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;
-            } else {
-                intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;
-            }
-            status_reg = TIMG_INT_ST_TIMERS_REG(1);
-            mask = 1<<timer_num;
-            break;
+    switch (group_num) {
+    case TIMER_GROUP_0:
+    default:
+        if ((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
+            intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;
+        } else {
+            intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;
+        }
+        timer_hal_get_intr_status_reg(&(p_timer_obj[TIMER_GROUP_0][timer_num]->hal), &status_reg);
+        mask = 1 << timer_num;
+        break;
+    case TIMER_GROUP_1:
+        if ((intr_alloc_flags & ESP_INTR_FLAG_EDGE) == 0) {
+            intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;
+        } else {
+            intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;
+        }
+        timer_hal_get_intr_status_reg(&(p_timer_obj[TIMER_GROUP_1][timer_num]->hal), &status_reg);
+        mask = 1 << timer_num;
+        break;
     }
     return esp_intr_alloc_intrstatus(intr_source, intr_alloc_flags, status_reg, mask, fn, arg, handle);
 }
@@ -226,32 +297,59 @@ esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer
     TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
     TIMER_CHECK(config->divider > 1 && config->divider < 65537, DIVIDER_RANGE_ERROR, ESP_ERR_INVALID_ARG);
 
-    if(group_num == 0) {
+    if (group_num == TIMER_GROUP_0) {
         periph_module_enable(PERIPH_TIMG0_MODULE);
-    } else if(group_num == 1) {
+    } else if (group_num == TIMER_GROUP_1) {
         periph_module_enable(PERIPH_TIMG1_MODULE);
     }
+
+    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);
+        if (p_timer_obj[group_num][timer_num] == NULL) {
+            ESP_LOGE(TIMER_TAG, "TIMER driver malloc error");
+            return ESP_FAIL;
+        }
+    }
+
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    //Some applications use a software reset, at the reset time, timer_group happens to generate an interrupt.
-    //but software reset does not clear interrupt status. This is not safe for application when enable the interrupt of timer_group.
-    //we need to disable the interrupt and clear the interrupt status here.
-    TG[group_num]->int_ena.val &= (~BIT(timer_num));
-#ifdef CONFIG_IDF_TARGET_ESP32
-    TG[group_num]->int_clr_timers.val = BIT(timer_num);
-#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-    TG[group_num]->int_clr.val = BIT(timer_num);
-#endif
-    TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload;
-    TG[group_num]->hw_timer[timer_num].config.divider = (uint16_t) config->divider;
-    TG[group_num]->hw_timer[timer_num].config.enable = config->counter_en;
-    TG[group_num]->hw_timer[timer_num].config.increase = config->counter_dir;
-    TG[group_num]->hw_timer[timer_num].config.alarm_en = config->alarm_en;
-    TG[group_num]->hw_timer[timer_num].config.level_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 1 : 0);
-    TG[group_num]->hw_timer[timer_num].config.edge_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 0 : 1);
+    timer_hal_init(&(p_timer_obj[group_num][timer_num]->hal), group_num, timer_num);
+    timer_hal_intr_disable(&(p_timer_obj[group_num][timer_num]->hal));
+    timer_hal_clear_intr_status(&(p_timer_obj[group_num][timer_num]->hal));
+    timer_hal_set_auto_reload(&(p_timer_obj[group_num][timer_num]->hal), config->auto_reload);
+    timer_hal_set_divider(&(p_timer_obj[group_num][timer_num]->hal), config->divider);
+    timer_hal_set_counter_increase(&(p_timer_obj[group_num][timer_num]->hal), config->counter_dir);
+    timer_hal_set_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal), config->alarm_en);
+    if (config->intr_type == TIMER_INTR_LEVEL) {
+        timer_hal_set_level_int_enable(&(p_timer_obj[group_num][timer_num]->hal), true);
+    }
+    // currently edge interrupt is not supported
+    // if (config->intr_type == TIMER_INTR_EDGE) {
+    //     timer_hal_set_edge_int_enable(&(p_timer_obj[group_num][timer_num]->hal), true);
+    // }
+    timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), config->counter_en);
 #ifdef CONFIG_IDF_TARGET_ESP32S2BETA
-    TG[group_num]->hw_timer[timer_num].config.use_xtal = config->clk_sel;
+    timer_hal_set_use_xtal(&(p_timer_obj[group_num][timer_num]->hal), config->clk_src);
 #endif
     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)
+{
+    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);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), TIMER_PAUSE);
+    timer_hal_intr_disable(&(p_timer_obj[group_num][timer_num]->hal));
+    timer_hal_clear_intr_status(&(p_timer_obj[group_num][timer_num]->hal));
+    TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+
+    heap_caps_free(p_timer_obj[group_num][timer_num]);
+    p_timer_obj[group_num][timer_num] = NULL;
+
     return ESP_OK;
 }
 
@@ -260,15 +358,26 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer
     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);
     TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    config->alarm_en = TG[group_num]->hw_timer[timer_num].config.alarm_en;
-    config->auto_reload = TG[group_num]->hw_timer[timer_num].config.autoreload;
-    config->counter_dir = TG[group_num]->hw_timer[timer_num].config.increase;
-    config->divider =  (TG[group_num]->hw_timer[timer_num].config.divider == 0 ?
-        65536 : TG[group_num]->hw_timer[timer_num].config.divider);
-    config->counter_en = TG[group_num]->hw_timer[timer_num].config.enable;
-    if(TG[group_num]->hw_timer[timer_num].config.level_int_en) {
+    config->alarm_en = timer_hal_get_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal));
+    config->auto_reload = timer_hal_get_auto_reload(&(p_timer_obj[group_num][timer_num]->hal));
+    config->counter_dir = timer_hal_get_counter_increase(&(p_timer_obj[group_num][timer_num]->hal));
+    config->counter_en = timer_hal_get_counter_enable(&(p_timer_obj[group_num][timer_num]->hal));
+
+    uint16_t div;
+    timer_hal_get_divider(&(p_timer_obj[group_num][timer_num]->hal), &div);
+    if (div == 0) {
+        config->divider = 65536;
+    } else {
+        config->divider = div;
+    }
+
+    if (timer_hal_get_level_int_enable(&(p_timer_obj[group_num][timer_num]->hal))) {
         config->intr_type = TIMER_INTR_LEVEL;
+    } else {
+        config->intr_type = TIMER_INTR_MAX;
     }
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
@@ -277,18 +386,28 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer
 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]);
-    TG[group_num]->int_ena.val |= en_mask;
-    portEXIT_CRITICAL(&timer_spinlock[group_num]);
+    TIMER_CHECK(p_timer_obj[group_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    for (int i = 0; i < TIMER_MAX; i++) {
+        if (en_mask & BIT(i)) {
+            timer_hal_intr_enable(&(p_timer_obj[group_num][i]->hal));
+        }
+    }
+    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)
 {
     TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
-    portENTER_CRITICAL(&timer_spinlock[group_num]);
-    TG[group_num]->int_ena.val &= (~disable_mask);
-    portEXIT_CRITICAL(&timer_spinlock[group_num]);
+    TIMER_CHECK(p_timer_obj[group_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    for (int i = 0; i < TIMER_MAX; i++) {
+        if (disable_mask & BIT(i)) {
+            timer_hal_intr_disable(&(p_timer_obj[group_num][i]->hal));
+        }
+    }
+    TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
     return ESP_OK;
 }
 
@@ -296,55 +415,99 @@ 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, TIMER_LL_GET_INTR(timer_num));
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    timer_hal_intr_enable(&(p_timer_obj[group_num][timer_num]->hal));
+    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)
 {
     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, TIMER_LL_GET_INTR(timer_num));
+    TIMER_CHECK(p_timer_obj[group_num][timer_num] != NULL, TIMER_NEVER_INIT_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    timer_hal_intr_disable(&(p_timer_obj[group_num][timer_num]->hal));
+    TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+    return ESP_OK;
 }
 
+/* This function is deprecated */
 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]);
+    return timer_group_get_intr_status_in_isr(group_num);
 }
 
+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) {
+        timer_hal_get_intr_status(&(p_timer_obj[group_num][TIMER_0]->hal), &intr_status);
+    } else if (p_timer_obj[group_num][TIMER_1] != NULL) {
+        timer_hal_get_intr_status(&(p_timer_obj[group_num][TIMER_1]->hal), &intr_status);
+    }
+    return intr_status;
+}
+
+/* This function is deprecated */
 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));
+    timer_group_clr_intr_status_in_isr(group_num, timer_num);
+}
+
+void IRAM_ATTR timer_group_clr_intr_status_in_isr(timer_group_t group_num, timer_idx_t timer_num)
+{
+    timer_hal_clear_intr_status(&(p_timer_obj[group_num][timer_num]->hal));
 }
 
 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);
+    timer_hal_set_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal), 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);
+    timer_hal_get_counter_value(&(p_timer_obj[group_num][timer_num]->hal), &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);
+    timer_hal_set_alarm_value(&(p_timer_obj[group_num][timer_num]->hal), 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);
+    timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), counter_en);
 }
 
+/* This function is deprecated */
 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);
+    for (uint32_t timer_idx = 0; timer_idx < TIMER_MAX; timer_idx++) {
+        if (intr_mask & BIT(timer_idx)) {
+            timer_group_clr_intr_status_in_isr(group_num, timer_idx);
+        }
+    }
 }
 
 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);
+    return timer_hal_get_auto_reload(&(p_timer_obj[group_num][timer_num]->hal));
+}
+
+esp_err_t timer_spinlock_take(timer_group_t group_num)
+{
+    TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
+    return ESP_OK;
 }
 
+esp_err_t timer_spinlock_give(timer_group_t group_num)
+{
+    TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
+    TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
+    return ESP_OK;
+}

+ 2 - 2
components/esp32/int_wdt.c

@@ -93,8 +93,8 @@ void esp_int_wdt_init(void) {
     timer_ll_wdt_feed(&TIMERG1);
     timer_ll_wdt_set_protect(&TIMERG1, true);
 
-    timer_ll_intr_status_clear(&TIMERG1, TIMER_INTR_WDT);
-    timer_group_intr_enable(TIMER_GROUP_1, TIMER_INTR_WDT);
+    timer_ll_wdt_clear_intr_status(&TIMERG1);
+    timer_ll_wdt_enable_intr(&TIMERG1);
 }
 
 void esp_int_wdt_cpu_init(void)

+ 1 - 1
components/esp32/panic.c

@@ -313,7 +313,7 @@ void panicHandler(XtExcFrame *frame)
         disableAllWdts();
         if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
             frame->exccause == PANIC_RSN_INTWDT_CPU1) {
-            timer_group_clr_intr_sta_in_isr(TIMER_GROUP_1, TIMER_INTR_WDT);
+            timer_ll_wdt_clear_intr_status(&TIMERG1);
         }
 #if CONFIG_ESP32_APPTRACE_ENABLE
 #if CONFIG_SYSVIEW_ENABLE

+ 1 - 1
components/esp32/task_wdt.c

@@ -143,7 +143,7 @@ static void task_wdt_isr(void *arg)
     timer_ll_wdt_feed(&TIMERG0);
     timer_ll_wdt_set_protect(&TIMERG0, true);
     //Acknowledge interrupt
-    timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_INTR_WDT);
+    timer_ll_wdt_clear_intr_status(&TIMERG0);
     //We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty
     //bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case,
     //something bad already happened and reporting this is considered more important

+ 4 - 4
components/esp32/test/test_intr_alloc.c

@@ -58,19 +58,19 @@ static void timer_isr(void *arg)
     int timer_idx = (int)arg;
     count[timer_idx]++;
     if (timer_idx==0) {
-        timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
+        timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
         timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);
     }
     if (timer_idx==1) {
-        timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1);
+        timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
         timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1);
     }
     if (timer_idx==2) {
-        timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_0);
+        timer_group_clr_intr_status_in_isr(TIMER_GROUP_1, TIMER_0);
         timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_0);
     }
     if (timer_idx==3) {
-        timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_1);
+        timer_group_clr_intr_status_in_isr(TIMER_GROUP_1, TIMER_1);
         timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_1);
     }
 //  ets_printf("int %d\n", timer_idx);

+ 2 - 2
components/esp32/test/test_reset_reason.c

@@ -280,12 +280,12 @@ static void timer_group_test_first_stage(void)
     //Start timer
     timer_start(TIMER_GROUP_0, TIMER_0);
     //Waiting for timer_group to generate an interrupt
-    while( !(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0) &&
+    while( !(timer_group_get_intr_status_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0) &&
             loop_cnt++ < 100) {
         vTaskDelay(200);
     }
     //TIMERG0.int_raw.t0 == 1 means an interruption has occurred
-    TEST_ASSERT(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0);
+    TEST_ASSERT(timer_group_get_intr_status_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0);
     esp_restart();
 }
 

+ 1 - 1
components/esp_event/test/test_event.c

@@ -304,7 +304,7 @@ void IRAM_ATTR test_event_on_timer_alarm(void* para)
        from the timer that reported the interrupt */
     uint64_t timer_counter_value =
         timer_group_get_counter_value_in_isr(TIMER_GROUP_0, TIMER_0);
-    timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
     timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
     timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, TIMER_0, timer_counter_value);
 

+ 1 - 1
components/esp_ringbuf/test/test_ringbuf.c

@@ -356,7 +356,7 @@ static int iterations;
 static void ringbuffer_isr(void *arg)
 {
     //Clear timer interrupt
-    timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
     timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID());
 
     //Test sending to buffer from ISR from ISR

+ 1 - 1
components/freemodbus/port/porttimer.c

@@ -71,7 +71,7 @@ static void IRAM_ATTR vTimerGroupIsr(void *param)
 {
     assert((int)param == usTimerIndex);
     // Retrieve the counter value from the timer that reported the interrupt
-    timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex);
+    timer_group_clr_intr_status_in_isr(usTimerGroupIndex, usTimerIndex);
     (void)pxMBPortCBTimerExpired(); // Timer callback function
     // Enable alarm
     timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex);

+ 1 - 1
components/freemodbus/port/porttimer_m.c

@@ -67,7 +67,7 @@ static void IRAM_ATTR vTimerGroupIsr(void *param)
 {
     assert((int)param == usTimerIndex);
     // Retrieve the the counter value from the timer that reported the interrupt
-    timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex);
+    timer_group_clr_intr_status_in_isr(usTimerGroupIndex, usTimerIndex);
     (void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function
     // Enable alarm
     timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex);

+ 1 - 1
components/freertos/test/test_freertos_eventgroups.c

@@ -144,7 +144,7 @@ static bool test_clear_bits;
 static void IRAM_ATTR event_group_isr(void *arg)
 {
     portBASE_TYPE task_woken = pdFALSE;
-    timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
     timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID());
 
     if(test_set_bits){

+ 1 - 1
components/freertos/test/test_freertos_task_notify.c

@@ -103,7 +103,7 @@ static void receiver_task (void* arg){
 static void IRAM_ATTR sender_ISR (void *arg)
 {
     int curcore = xPortGetCoreID();
-    timer_group_intr_clr_in_isr(TIMER_GROUP_0, curcore);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, curcore);
     timer_group_set_counter_enable_in_isr(TIMER_GROUP_0, curcore, TIMER_PAUSE);
     //Re-enable alarm
     timer_group_enable_alarm_in_isr(TIMER_GROUP_0, curcore);

+ 1 - 1
components/freertos/test/test_suspend_scheduler.c

@@ -26,7 +26,7 @@ static volatile unsigned isr_count;
    mutex semaphore to wake up another counter task */
 static void timer_group0_isr(void *vp_arg)
 {
-    timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
     timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);
     portBASE_TYPE higher_awoken = pdFALSE;
     isr_count++;

+ 2 - 1
components/freertos/test/test_task_suspend_resume.c

@@ -123,7 +123,8 @@ volatile bool timer_isr_fired;
 void IRAM_ATTR timer_group0_isr(void *vp_arg)
 {
     // Clear interrupt
-    timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_0|TIMER_1);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
 
     timer_isr_fired = true;
     TaskHandle_t handle = vp_arg;

+ 1 - 0
components/soc/CMakeLists.txt

@@ -22,6 +22,7 @@ list(APPEND srcs
     "src/hal/pcnt_hal.c"
     "src/hal/i2s_hal.c"
     "src/hal/sigmadelta_hal.c"
+    "src/hal/timer_hal.c"
     )
 
 # TODO: SPI Flash HAL for ESP32S2Beta also

+ 279 - 41
components/soc/esp32/include/hal/timer_ll.h

@@ -21,82 +21,111 @@
 extern "C" {
 #endif
 
+#include <stdlib.h>
 #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");
 
+typedef struct {
+    timg_dev_t *dev;
+    timer_idx_t idx;
+} timer_ll_context_t;
+
+// Get timer group instance with giving group number
+#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1))
+
 /**
- * @brief Enable timer interrupt.
+ * @brief Set timer clock prescale value
  *
  * @param hw Beginning address of the peripheral registers.
- * @param intr_mask Interrupt enable mask
+ * @param timer_num The timer number
+ * @param divider Prescale value
  *
  * @return None
  */
-static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask)
+static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint16_t divider)
 {
-    hw->int_ena.val |= intr_mask;
+    int timer_en = hw->hw_timer[timer_num].config.enable;
+    hw->hw_timer[timer_num].config.enable = 0;
+    hw->hw_timer[timer_num].config.divider = divider;
+    hw->hw_timer[timer_num].config.enable = timer_en;
 }
 
 /**
- * @brief Disable timer interrupt.
+ * @brief Get timer clock prescale value
  *
  * @param hw Beginning address of the peripheral registers.
- * @param intr_mask Interrupt disable mask
+ * @param timer_num The timer number
+ * @param divider Pointer to accept the prescale value
  *
  * @return None
  */
-static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask)
+static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint16_t *divider)
 {
-    hw->int_ena.val &= (~intr_mask);
+    *divider = hw->hw_timer[timer_num].config.divider;
 }
 
 /**
- * @brief Get timer interrupt status.
+ * @brief Load counter value into time-base counter
  *
  * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ * @param load_val Counter value
  *
- * @return Masked interrupt status
+ * @return None
  */
-static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw)
+static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val)
 {
-    return hw->int_raw.val;
+    hw->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);
+    hw->hw_timer[timer_num].load_low = (uint32_t) load_val;
+    hw->hw_timer[timer_num].reload = 1;
 }
 
 /**
- * @brief Clear timer interrupt.
+ * @brief Get counter value from time-base counter
  *
  * @param hw Beginning address of the peripheral registers.
- * @param intr_mask Interrupt mask to clear
+ * @param timer_num The timer number
+ * @param timer_val Pointer to accept the counter value
  *
  * @return None
  */
-static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask)
+FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
 {
-    hw->int_clr_timers.val = intr_mask;
+    hw->hw_timer[timer_num].update = 1;
+    *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
 }
 
 /**
- * @brief Get counter vaule from time-base counter
+ * @brief Set counter mode, include increment mode and decrement mode.
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param timer_val Pointer to accept the counter value
+ * @param increase_en True to increment mode, fasle to decrement mode
  *
  * @return None
  */
-static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
+static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en)
 {
-    hw->hw_timer[timer_num].update = 1;
-    *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
+    hw->hw_timer[timer_num].config.increase = increase_en;
+}
+
+/**
+ * @brief Get counter mode, include increment mode and decrement mode.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Increment mode
+ *     - false Decrement mode
+ */
+static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.increase;
 }
 
 /**
@@ -104,25 +133,55 @@ static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param counter_en Counter enable status
+ * @param counter_en True to enable counter, false to disable counter
  *
  * @return None
  */
-static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, timer_start_t counter_en)
+FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en)
 {
     hw->hw_timer[timer_num].config.enable = counter_en;
 }
 
 /**
- * @brief Get auto reload mode.
+ * @brief Get counter status.
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param reload Pointer to accept the auto reload mode
+ *
+ * @return
+ *     - true Enable counter
+ *     - false Disable conuter
+ */
+static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.enable;
+}
+
+/**
+ * @brief Set auto reload mode.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
  *
  * @return None
  */
-static inline bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
+static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en)
+{
+    hw->hw_timer[timer_num].config.autoreload = auto_reload_en;
+}
+
+/**
+ * @brief Get auto reload mode.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Enable auto reload mode
+ *     - false Disable auto reload mode
+ */
+FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
 {
     return hw->hw_timer[timer_num].config.autoreload;
 }
@@ -136,7 +195,7 @@ static inline bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_nu
  *
  * @return None
  */
-static inline void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
+FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
 {
     hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
     hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
@@ -161,11 +220,11 @@ static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_nu
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param alarm_en true to enable, false to disable
+ * @param alarm_en True to enable alarm, false to disable alarm
  *
  * @return None
  */
-static inline void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
+FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
 {
     hw->hw_timer[timer_num].config.alarm_en = alarm_en;
 }
@@ -175,35 +234,158 @@ static inline void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_n
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param alarm_en Pointer to accept the alarm status
+ *
+ * @return
+ *     - true Enable alarm
+ *     - false Disable alarm
+ */
+static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.alarm_en;
+}
+
+/**
+ * @brief Enable timer interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return None
+ */
+FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    hw->int_ena.val |= BIT(timer_num);
+}
+
+/**
+ * @brief Disable timer interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return None
+ */
+FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    hw->int_ena.val &= (~BIT(timer_num));
+}
+
+/**
+ * @brief Disable timer interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return None
+ */
+FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    hw->int_clr_timers.val |= BIT(timer_num);
+}
+
+/**
+ * @brief Get interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param intr_status Interrupt status
+ *
+ * @return None
+ */
+FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status)
+{
+    *intr_status = hw->int_st_timers.val;
+}
+
+/**
+ * @brief Set the level interrupt status, enable or disable the level interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ * @param level_int_en True to enable level interrupt, false to disable level interrupt
+ *
+ * @return None
+ */
+static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en)
+{
+    hw->hw_timer[timer_num].config.level_int_en = level_int_en;
+}
+
+/**
+ * @brief Get the level interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Enable level interrupt
+ *     - false Disable level interrupt
+ */
+static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.level_int_en;
+}
+
+/**
+ * @brief Set the edge interrupt status, enable or disable the edge interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
+ *
+ * @return None
+ */
+static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en)
+{
+    hw->hw_timer[timer_num].config.edge_int_en = edge_int_en;
+}
+
+/**
+ * @brief Get the edge interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Enable edge interrupt
+ *     - false Disable edge interrupt
+ */
+static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.edge_int_en;
+}
+
+/**
+ * @brief Get interrupt status register address.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param intr_status_reg Interrupt status register address
  *
  * @return None
  */
-static inline void timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool *alarm_en)
+static inline void timer_ll_get_intr_status_reg(timg_dev_t *hw, uint32_t *intr_status_reg)
 {
-    *alarm_en = hw->hw_timer[timer_num].config.alarm_en;
+    *intr_status_reg = (uint32_t)&(hw->int_st_timers.val);
 }
 
 /* WDT operations */
 
 /**
- * Unlock/lock the WDT register in case of mis-operations.
+ * @brief Unlock/lock the WDT register in case of mis-operations.
  *
  * @param hw Beginning address of the peripheral registers.
  * @param protect true to lock, false to unlock before operations.
  */
-
 FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect)
 {
     hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE);
 }
 
 /**
- * Initialize WDT.
+ * @brief Initialize WDT.
  *
  * @param hw Beginning address of the peripheral registers.
  *
- * @note Call ``timer_ll_wdt_set_protect first``
+ * @note Call `timer_ll_wdt_set_protect` first
  */
 FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw)
 {
@@ -214,16 +396,34 @@ FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw)
     hw->wdt_config0.edge_int_en = 0;
 }
 
+/**
+ * @brief Set the WDT tick time.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param tick_time_us Tick time.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us)
 {
     hw->wdt_config1.clk_prescale=80*tick_time_us;
 }
 
+/**
+ * @brief Feed the WDT.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw)
 {
     hw->wdt_feed = 1;
 }
 
+/**
+ * @brief Set the WDT timeout.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param stage Stage number of WDT.
+ * @param timeout_Tick tick threshold of timeout.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick)
 {
     switch (stage) {
@@ -249,6 +449,13 @@ _Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdo
 _Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
 _Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
 
+/**
+ * @brief Set the WDT timeout behavior.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param stage Stage number of WDT.
+ * @param behavior Behavior of WDT, please see enum timer_wdt_behavior_t.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior)
 {
     switch (stage) {
@@ -269,16 +476,47 @@ FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int sta
     }
 }
 
+/**
+ * @brief Enable/Disable the WDT enable.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param enable True to enable WDT, false to disable WDT.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable)
 {
     hw->wdt_config0.en = enable;
 }
 
+/**
+ * @brief Enable/Disable the WDT flashboot mode.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable)
 {
     hw->wdt_config0.flashboot_mod_en = enable;
 }
 
+/**
+ * @brief Clear the WDT interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ */
+FORCE_INLINE_ATTR void timer_ll_wdt_clear_intr_status(timg_dev_t* hw)
+{
+    hw->int_clr_timers.wdt = 1;
+}
+
+/**
+ * @brief Enable the WDT interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ */
+FORCE_INLINE_ATTR void timer_ll_wdt_enable_intr(timg_dev_t* hw)
+{
+    hw->int_ena.wdt = 1;
+}
 
 #ifdef __cplusplus
 }

+ 306 - 41
components/soc/esp32s2beta/include/hal/timer_ll.h

@@ -21,82 +21,111 @@
 extern "C" {
 #endif
 
+#include <stdlib.h>
 #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");
 
+typedef struct {
+    timg_dev_t *dev;
+    timer_idx_t idx;
+} timer_ll_context_t;
+
+// Get timer group instance with giving group number
+#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1))
+
 /**
- * @brief Enable timer interrupt.
+ * @brief Set timer clock prescale value
  *
  * @param hw Beginning address of the peripheral registers.
- * @param intr_mask Interrupt enable mask
+ * @param timer_num The timer number
+ * @param divider Prescale value
  *
  * @return None
  */
-static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask)
+static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint16_t divider)
 {
-    hw->int_ena.val |= intr_mask;
+    int timer_en = hw->hw_timer[timer_num].config.enable;
+    hw->hw_timer[timer_num].config.enable = 0;
+    hw->hw_timer[timer_num].config.divider = divider;
+    hw->hw_timer[timer_num].config.enable = timer_en;
 }
 
 /**
- * @brief Disable timer interrupt.
+ * @brief Get timer clock prescale value
  *
  * @param hw Beginning address of the peripheral registers.
- * @param intr_mask Interrupt disable mask
+ * @param timer_num The timer number
+ * @param divider Pointer to accept the prescale value
  *
  * @return None
  */
-static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask)
+static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint16_t *divider)
 {
-    hw->int_ena.val &= (~intr_mask);
+    *divider = hw->hw_timer[timer_num].config.divider;
 }
 
 /**
- * @brief Get timer interrupt status.
+ * @brief Load counter value into time-base counter
  *
  * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ * @param load_val Counter value
  *
- * @return Masked interrupt status
+ * @return None
  */
-static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw)
+static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val)
 {
-    return hw->int_raw.val;
+    hw->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);
+    hw->hw_timer[timer_num].load_low = (uint32_t) load_val;
+    hw->hw_timer[timer_num].reload = 1;
 }
 
 /**
- * @brief Clear timer interrupt.
+ * @brief Get counter value from time-base counter
  *
  * @param hw Beginning address of the peripheral registers.
- * @param intr_mask Interrupt mask to clear
+ * @param timer_num The timer number
+ * @param timer_val Pointer to accept the counter value
  *
  * @return None
  */
-static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask)
+FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
 {
-    hw->int_clr.val = intr_mask;
+    hw->hw_timer[timer_num].update.update = 1;
+    *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
 }
 
 /**
- * @brief Get counter vaule from time-base counter
+ * @brief Set counter mode, include increment mode and decrement mode.
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param timer_val Pointer to accept the counter value
+ * @param increase_en True to increment mode, fasle to decrement mode
  *
  * @return None
  */
-static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
+static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en)
 {
-    hw->hw_timer[timer_num].update.update = 1;
-    *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
+    hw->hw_timer[timer_num].config.increase = increase_en;
+}
+
+/**
+ * @brief Get counter mode, include increment mode and decrement mode.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Increment mode
+ *     - false Decrement mode
+ */
+static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.increase;
 }
 
 /**
@@ -104,25 +133,55 @@ static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param counter_en Counter enable status
+ * @param counter_en True to enable counter, false to disable counter
  *
  * @return None
  */
-static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, timer_start_t counter_en)
+FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en)
 {
     hw->hw_timer[timer_num].config.enable = counter_en;
 }
 
 /**
- * @brief Get auto reload mode.
+ * @brief Get counter status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Enable counter
+ *     - false Disable conuter
+ */
+static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.enable;
+}
+
+/**
+ * @brief Set auto reload mode.
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param reload Pointer to accept the auto reload mode
+ * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
  *
  * @return None
  */
-static inline bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
+static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en)
+{
+    hw->hw_timer[timer_num].config.autoreload = auto_reload_en;
+}
+
+/**
+ * @brief Get auto reload mode.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Enable auto reload mode
+ *     - false Disable auto reload mode
+ */
+FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
 {
     return hw->hw_timer[timer_num].config.autoreload;
 }
@@ -136,7 +195,7 @@ static inline bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_nu
  *
  * @return None
  */
-static inline void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
+FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
 {
     hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
     hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
@@ -161,11 +220,11 @@ static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_nu
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param alarm_en true to enable, false to disable
+ * @param alarm_en True to enable alarm, false to disable alarm
  *
  * @return None
  */
-static inline void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
+FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
 {
     hw->hw_timer[timer_num].config.alarm_en = alarm_en;
 }
@@ -175,35 +234,185 @@ static inline void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_n
  *
  * @param hw Beginning address of the peripheral registers.
  * @param timer_num The timer number
- * @param alarm_en Pointer to accept the alarm status
+ *
+ * @return
+ *     - true Enable alarm
+ *     - false Disable alarm
+ */
+static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.alarm_en;
+}
+
+/**
+ * @brief Enable timer interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return None
+ */
+FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    hw->int_ena.val |= BIT(timer_num);
+}
+
+/**
+ * @brief Disable timer interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
  *
  * @return None
  */
-static inline void timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool *alarm_en)
+FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num)
 {
-    *alarm_en = hw->hw_timer[timer_num].config.alarm_en;
+    hw->int_ena.val &= (~BIT(timer_num));
+}
+
+/**
+ * @brief Disable timer interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return None
+ */
+FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    hw->int_clr.val |= BIT(timer_num);
+}
+
+/**
+ * @brief Get interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param intr_status Interrupt status
+ *
+ * @return None
+ */
+FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status)
+{
+    *intr_status = hw->int_st.val;
+}
+
+/**
+ * @brief Set the level interrupt status, enable or disable the level interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ * @param level_int_en True to enable level interrupt, false to disable level interrupt
+ *
+ * @return None
+ */
+static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en)
+{
+    hw->hw_timer[timer_num].config.level_int_en = level_int_en;
+}
+
+/**
+ * @brief Get the level interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Enable level interrupt
+ *     - false Disable level interrupt
+ */
+static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.level_int_en;
+}
+
+/**
+ * @brief Set the edge interrupt status, enable or disable the edge interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
+ *
+ * @return None
+ */
+static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en)
+{
+    hw->hw_timer[timer_num].config.edge_int_en = edge_int_en;
+}
+
+/**
+ * @brief Get the edge interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param timer_num The timer number
+ *
+ * @return
+ *     - true Enable edge interrupt
+ *     - false Disable edge interrupt
+ */
+static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.edge_int_en;
+}
+
+/**
+ * @brief Get interrupt status register address.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param intr_status_reg Interrupt status register address
+ *
+ * @return None
+ */
+static inline void timer_ll_get_intr_status_reg(timg_dev_t *hw, uint32_t *intr_status_reg)
+{
+    *intr_status_reg = (uint32_t)&(hw->int_st.val);
+}
+
+/**
+ * @brief Set clock source.
+ *
+ * @param hal Context of the HAL layer
+ * @param use_xtal_en True to use XTAL clock, flase to use APB clock
+ *
+ * @return None
+ */
+static inline void timer_ll_set_use_xtal(timg_dev_t *hw, timer_idx_t timer_num, bool use_xtal_en)
+{
+    hw->hw_timer[timer_num].config.use_xtal = use_xtal_en;
+}
+
+/**
+ * @brief Get clock source.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return
+ *     - true Use XTAL clock
+ *     - false Use APB clock
+ */
+static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num)
+{
+    return hw->hw_timer[timer_num].config.use_xtal;
 }
 
 /* WDT operations */
 
 /**
- * Unlock/lock the WDT register in case of mis-operations.
+ * @brief Unlock/lock the WDT register in case of mis-operations.
  *
  * @param hw Beginning address of the peripheral registers.
  * @param protect true to lock, false to unlock before operations.
  */
-
 FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect)
 {
     hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE);
 }
 
 /**
- * Initialize WDT.
+ * @brief Initialize WDT.
  *
  * @param hw Beginning address of the peripheral registers.
  *
- * @note Call ``timer_ll_wdt_set_protect first``
+ * @note Call `timer_ll_wdt_set_protect` first
  */
 FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw)
 {
@@ -214,16 +423,34 @@ FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw)
     hw->wdt_config0.edge_int_en = 0;
 }
 
+/**
+ * @brief Set the WDT tick time.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param tick_time_us Tick time.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us)
 {
     hw->wdt_config1.clk_prescale=80*tick_time_us;
 }
 
+/**
+ * @brief Feed the WDT.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw)
 {
     hw->wdt_feed = 1;
 }
 
+/**
+ * @brief Set the WDT timeout.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param stage Stage number of WDT.
+ * @param timeout_Tick tick threshold of timeout.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick)
 {
     switch (stage) {
@@ -249,6 +476,13 @@ _Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdo
 _Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
 _Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
 
+/**
+ * @brief Set the WDT timeout behavior.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param stage Stage number of WDT.
+ * @param behavior Behavior of WDT, please see enum timer_wdt_behavior_t.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior)
 {
     switch (stage) {
@@ -269,16 +503,47 @@ FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int sta
     }
 }
 
+/**
+ * @brief Enable/Disable the WDT enable.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param enable True to enable WDT, false to disable WDT.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable)
 {
     hw->wdt_config0.en = enable;
 }
 
+/**
+ * @brief Enable/Disable the WDT flashboot mode.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ * @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode.
+ */
 FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable)
 {
     hw->wdt_config0.flashboot_mod_en = enable;
 }
 
+/**
+ * @brief Clear the WDT interrupt status.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ */
+FORCE_INLINE_ATTR void timer_ll_wdt_clear_intr_status(timg_dev_t* hw)
+{
+    hw->int_clr.wdt = 1;
+}
+
+/**
+ * @brief Enable the WDT interrupt.
+ *
+ * @param hw Beginning address of the peripheral registers.
+ */
+FORCE_INLINE_ATTR void timer_ll_wdt_enable_intr(timg_dev_t* hw)
+{
+    hw->int_ena.wdt = 1;
+}
 
 #ifdef __cplusplus
 }

+ 311 - 0
components/soc/include/hal/timer_hal.h

@@ -0,0 +1,311 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*******************************************************************************
+ * NOTICE
+ * The hal is not public api, don't use in application code.
+ * See readme.md in soc/include/hal/readme.md
+ ******************************************************************************/
+
+// The HAL layer for Timer Group.
+// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hal/timer_ll.h"
+#include "hal/timer_types.h"
+
+/**
+ * Context that should be maintained by both the driver and the HAL
+ */
+typedef struct {
+    timg_dev_t *dev;
+    timer_idx_t idx;
+} timer_hal_context_t;
+
+/**
+ * @brief Init the timer hal. This function should be called first before other hal layer function is called
+ *
+ * @param hal Context of the HAL layer
+ * @param group_num The timer group number
+ * @param timer_num The timer number
+ *
+ * @return None
+ */
+void timer_hal_init(timer_hal_context_t *hal, timer_group_t group_num, timer_idx_t timer_num);
+
+/**
+ * @brief Set timer clock prescale value
+ *
+ * @param hal Context of the HAL layer
+ * @param divider Prescale value
+ *
+ * @return None
+ */
+#define timer_hal_set_divider(hal, divider)  timer_ll_set_divider((hal)->dev, (hal)->idx, divider)
+
+/**
+ * @brief Get timer clock prescale value
+ *
+ * @param hal Context of the HAL layer
+ * @param divider Pointer to accept the prescale value
+ *
+ * @return None
+ */
+#define timer_hal_get_divider(hal, divider)  timer_ll_get_divider((hal)->dev, (hal)->idx, divider)
+
+/**
+ * @brief Load counter value into time-base counter
+ *
+ * @param hal Context of the HAL layer
+ * @param load_val Counter value
+ *
+ * @return None
+ */
+#define timer_hal_set_counter_value(hal, load_val)  timer_ll_set_counter_value((hal)->dev, (hal)->idx, load_val)
+
+/**
+ * @brief Get counter value from time-base counter
+ *
+ * @param hal Context of the HAL layer
+ * @param timer_val Pointer to accept the counter value
+ *
+ * @return None
+ */
+#define timer_hal_get_counter_value(hal, timer_val)  timer_ll_get_counter_value((hal)->dev, (hal)->idx, timer_val)
+
+/**
+ * @brief Set counter mode, include increment mode and decrement mode.
+ *
+ * @param hal Context of the HAL layer
+ * @param increase_en True to increment mode, fasle to decrement mode
+ *
+ * @return None
+ */
+#define timer_hal_set_counter_increase(hal, increase_en)  timer_ll_set_counter_increase((hal)->dev, (hal)->idx, increase_en)
+
+/**
+ * @brief Get counter mode, include increment mode and decrement mode.
+ *
+ * @param hal Context of the HAL layer
+ * @param counter_dir Pointer to accept the counter mode
+ *
+ * @return
+ *     - true Increment mode
+ *     - false Decrement mode
+ */
+#define timer_hal_get_counter_increase(hal)  timer_ll_get_counter_increase((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Set counter status, enable or disable counter.
+ *
+ * @param hal Context of the HAL layer
+ * @param counter_en True to enable counter, false to disable counter
+ *
+ * @return None
+ */
+#define timer_hal_set_counter_enable(hal, counter_en)  timer_ll_set_counter_enable((hal)->dev, (hal)->idx, counter_en)
+
+/**
+ * @brief Get counter status.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return
+ *     - true Enable counter
+ *     - false Disable conuter
+ */
+#define timer_hal_get_counter_enable(hal)  timer_ll_get_counter_enable((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Set auto reload mode.
+ *
+ * @param hal Context of the HAL layer
+ * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
+ *
+ * @return None
+ */
+#define timer_hal_set_auto_reload(hal, auto_reload_en)  timer_ll_set_auto_reload((hal)->dev, (hal)->idx, auto_reload_en)
+
+/**
+ * @brief Get auto reload mode.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return
+ *     - true Enable auto reload mode
+ *     - false Disable auto reload mode
+ */
+#define timer_hal_get_auto_reload(hal)  timer_ll_get_auto_reload((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Set the counter value to trigger the alarm.
+ *
+ * @param hal Context of the HAL layer
+ * @param alarm_value Counter value to trigger the alarm
+ *
+ * @return None
+ */
+#define timer_hal_set_alarm_value(hal, alarm_value)  timer_ll_set_alarm_value((hal)->dev, (hal)->idx, alarm_value)
+
+/**
+ * @brief Get the counter value to trigger the alarm.
+ *
+ * @param hal Context of the HAL layer
+ * @param alarm_value Pointer to accept the counter value to trigger the alarm
+ *
+ * @return None
+ */
+#define timer_hal_get_alarm_value(hal, alarm_value)  timer_ll_get_alarm_value((hal)->dev, (hal)->idx, alarm_value)
+
+/**
+ * @brief Set the alarm status, enable or disable the alarm.
+ *
+ * @param hal Context of the HAL layer
+ * @param alarm_en True to enable alarm, false to disable alarm
+ *
+ * @return None
+ */
+#define timer_hal_set_alarm_enable(hal, alarm_en)  timer_ll_set_alarm_enable((hal)->dev, (hal)->idx, alarm_en)
+
+/**
+ * @brief Get the alarm status.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return
+ *     - true Enable alarm
+ *     - false Disable alarm
+ */
+#define timer_hal_get_alarm_enable(hal)  timer_ll_get_alarm_enable((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Set the level interrupt status, enable or disable the level interrupt.
+ *
+ * @param hal Context of the HAL layer
+ * @param level_int_en True to enable level interrupt, false to disable level interrupt
+ *
+ * @return None
+ */
+#define timer_hal_set_level_int_enable(hal, level_int_en)  timer_ll_set_level_int_enable((hal)->dev, (hal)->idx, level_int_en)
+
+/**
+ * @brief Get the level interrupt status.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return
+ *     - true Enable level interrupt
+ *     - false Disable level interrupt
+ */
+#define timer_hal_get_level_int_enable(hal)  timer_ll_get_level_int_enable((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Set the edge interrupt status, enable or disable the edge interrupt.
+ *
+ * @param hal Context of the HAL layer
+ * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
+ *
+ * @return None
+ */
+#define timer_hal_set_edge_int_enable(hal, edge_int_en)  timer_ll_set_edge_int_enable((hal)->dev, (hal)->idx, edge_int_en)
+
+/**
+ * @brief Get the edge interrupt status.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return
+ *     - true Enable edge interrupt
+ *     - false Disable edge interrupt
+ */
+#define timer_hal_get_edge_int_enable(hal)  timer_ll_get_edge_int_enable((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Enable timer interrupt.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return None
+ */
+#define timer_hal_intr_enable(hal)  timer_ll_intr_enable((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Disable timer interrupt.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return None
+ */
+#define timer_hal_intr_disable(hal)  timer_ll_intr_disable((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Clear interrupt status.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return None
+ */
+#define timer_hal_clear_intr_status(hal)  timer_ll_clear_intr_status((hal)->dev, (hal)->idx)
+
+/**
+ * @brief Get interrupt status.
+ *
+ * @param hal Context of the HAL layer
+ * @param intr_status Interrupt status
+ *
+ * @return None
+ */
+#define timer_hal_get_intr_status(hal, intr_status)  timer_ll_get_intr_status((hal)->dev, intr_status)
+
+/**
+ * @brief Get interrupt status register address.
+ *
+ * @param hal Context of the HAL layer
+ * @param intr_status_reg Interrupt status register address
+ *
+ * @return None
+ */
+#define timer_hal_get_intr_status_reg(hal, intr_status_reg)  timer_ll_get_intr_status_reg((hal)->dev, intr_status_reg)
+
+#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
+/**
+ * @brief Set clock source.
+ *
+ * @param hal Context of the HAL layer
+ * @param use_xtal_en True to use XTAL clock, flase to use APB clock
+ *
+ * @return None
+ */
+#define timer_hal_set_use_xtal(hal, use_xtal_en)  timer_ll_set_use_xtal((hal)->dev, (hal)->idx, use_xtal_en)
+
+/**
+ * @brief Get clock source.
+ *
+ * @param hal Context of the HAL layer
+ *
+ * @return
+ *     - true Use XTAL clock
+ *     - false Use APB clock
+ */
+#define timer_hal_get_use_xtal(hal)  timer_ll_get_use_xtal((hal)->dev, (hal)->idx)
+#endif
+
+#ifdef __cplusplus
+}
+#endif

+ 74 - 4
components/soc/include/hal/timer_types.h

@@ -22,6 +22,14 @@ extern "C" {
 #include <stdbool.h>
 #include <esp_bit_defs.h>
 
+/**
+ * @brief Selects a Timer-Group out of 2 available groups
+ */
+typedef enum {
+    TIMER_GROUP_0 = 0, /*!<Hw timer group 0*/
+    TIMER_GROUP_1 = 1, /*!<Hw timer group 1*/
+    TIMER_GROUP_MAX,
+} timer_group_t;
 
 /**
  * @brief Select a hardware timer from timer groups
@@ -32,6 +40,15 @@ typedef enum {
     TIMER_MAX,
 } timer_idx_t;
 
+/**
+ * @brief Decides the direction of counter
+ */
+typedef enum {
+    TIMER_COUNT_DOWN = 0, /*!< Descending Count from cnt.high|cnt.low*/
+    TIMER_COUNT_UP = 1,   /*!< Ascending Count from Zero*/
+    TIMER_COUNT_MAX
+} timer_count_dir_t;
+
 /**
  * @brief Decides whether timer is on or paused
  */
@@ -48,6 +65,7 @@ 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_NONE = 0
 } timer_intr_t;
 FLAG_ATTR(timer_intr_t)
 
@@ -56,12 +74,64 @@ FLAG_ATTR(timer_intr_t)
  */
 //this is compatible with the value of esp32.
 typedef enum {
-    TIMER_WDT_OFF = 0,          ///< The stage is turned off
-    TIMER_WDT_INT = 1,          ///< The stage will trigger an interrupt
-    TIMER_WDT_RESET_CPU = 2,    ///< The stage will reset the CPU
-    TIMER_WDT_RESET_SYSTEM = 3, ///< The stage will reset the whole system
+    TIMER_WDT_OFF = 0,          /*!< The stage is turned off*/
+    TIMER_WDT_INT = 1,          /*!< The stage will trigger an interrupt*/
+    TIMER_WDT_RESET_CPU = 2,    /*!< The stage will reset the CPU*/
+    TIMER_WDT_RESET_SYSTEM = 3, /*!< The stage will reset the whole system*/
 } timer_wdt_behavior_t;
 
+/**
+ * @brief Decides whether to enable alarm mode
+ */
+typedef enum {
+    TIMER_ALARM_DIS = 0,  /*!< Disable timer alarm*/
+    TIMER_ALARM_EN = 1,   /*!< Enable timer alarm*/
+    TIMER_ALARM_MAX
+} timer_alarm_t;
+
+/**
+ * @brief Select interrupt type if running in alarm mode.
+ */
+typedef enum {
+    TIMER_INTR_LEVEL = 0,  /*!< Interrupt mode: level mode*/
+    //TIMER_INTR_EDGE = 1, /*!< Interrupt mode: edge mode, Not supported Now*/
+    TIMER_INTR_MAX
+} timer_intr_mode_t;
+
+/**
+ * @brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
+ */
+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;
+
+#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
+/**
+ * @brief Select timer source clock.
+ */
+typedef enum {
+    TIMER_SRC_CLK_APB = 0,  /*!< Select APB as the source clock*/
+    TIMER_SRC_CLK_XTAL = 1, /*!< Select XTAL as the source clock*/
+} timer_src_clk_t;
+#endif
+
+/**
+ * @brief Data structure with timer's configuration settings
+ */
+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 */
+    uint32_t divider;   /*!< Counter clock divider. The divider's range is from from 2 to 65536. */
+#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
+    timer_src_clk_t clk_src;  /*!< Use XTAL as source clock. */
+#endif
+} timer_config_t;
+
 #ifdef __cplusplus
 }
 #endif

+ 22 - 0
components/soc/src/hal/timer_hal.c

@@ -0,0 +1,22 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "esp_attr.h"
+#include "hal/timer_hal.h"
+
+void timer_hal_init(timer_hal_context_t *hal, timer_group_t group_num, timer_idx_t timer_num)
+{
+    hal->dev = TIMER_LL_GET_HW(group_num);
+    hal->idx = timer_num;
+}

+ 1 - 1
components/spi_flash/test/test_spi_flash.c

@@ -126,7 +126,7 @@ typedef struct {
 
 static void IRAM_ATTR timer_isr(void* varg) {
     block_task_arg_t* arg = (block_task_arg_t*) varg;
-    timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
+    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
     timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);
     ets_delay_us(arg->delay_time_us);
     arg->repeat_count++;

+ 1 - 0
docs/Doxyfile

@@ -109,6 +109,7 @@ INPUT = \
     ../../components/soc/include/hal/i2s_types.h \
     ../../components/soc/include/hal/rtc_io_types.h \
     ../../components/soc/include/hal/sigmadelta_types.h \
+    ../../components/soc/include/hal/timer_types.h \
     ../../components/soc/esp32/include/soc/adc_channel.h \
     ../../components/soc/esp32/include/soc/dac_channel.h \
     ../../components/soc/esp32/include/soc/touch_channel.h \

+ 6 - 4
examples/peripherals/timer_group/main/timer_group_example_main.c

@@ -55,11 +55,12 @@ static void inline print_timer_counter(uint64_t counter_value)
  */
 void IRAM_ATTR timer_group0_isr(void *para)
 {
+    timer_spinlock_take(TIMER_GROUP_0);
     int timer_idx = (int) para;
 
     /* Retrieve the interrupt status and the counter value
        from the timer that reported the interrupt */
-    timer_intr_t timer_intr = timer_group_intr_get_in_isr(TIMER_GROUP_0);
+    uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0);
     uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx);
 
     /* Prepare basic event data
@@ -73,12 +74,12 @@ void IRAM_ATTR timer_group0_isr(void *para)
        and update the alarm time for the timer with without reload */
     if (timer_intr & TIMER_INTR_T0) {
         evt.type = TEST_WITHOUT_RELOAD;
-        timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
+        timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
         timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
         timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value);
     } else if (timer_intr & TIMER_INTR_T1) {
         evt.type = TEST_WITH_RELOAD;
-        timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1);
+        timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
     } else {
         evt.type = -1; // not supported even type
     }
@@ -89,6 +90,7 @@ void IRAM_ATTR timer_group0_isr(void *para)
 
     /* Now just send the event data back to the main program task */
     xQueueSendFromISR(timer_queue, &evt, NULL);
+    timer_spinlock_give(TIMER_GROUP_0);
 }
 
 /*
@@ -110,7 +112,7 @@ static void example_tg0_timer_init(int timer_idx,
     config.intr_type = TIMER_INTR_LEVEL;
     config.auto_reload = auto_reload;
 #ifdef CONFIG_IDF_TARGET_ESP32S2BETA
-    config.clk_sel = TIMER_SRC_CLK_APB;
+    config.clk_src = TIMER_SRC_CLK_APB;
 #endif
     timer_init(TIMER_GROUP_0, timer_idx, &config);
 

+ 1 - 1
examples/system/sysview_tracing/main/sysview_tracing.c

@@ -126,7 +126,7 @@ static void example_timer_isr(void *arg)
         }
     }
     // re-start timer
-    timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->timer);
+    timer_group_clr_intr_status_in_isr(tim_arg->group, tim_arg->timer);
     timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->timer);
 }