--- /dev/null
+// Copyright 2010-2016 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.
+
+#ifndef _DRIVER_TIMER_H_
+#define _DRIVER_TIMER_H_
+#include "esp_err.h"
+#include "esp_attr.h"
+#include "soc/soc.h"
+#include "soc/timer_group_reg.h"
+#include "soc/timer_group_struct.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define TIMER_BASE_CLK (APB_CLK_FREQ)
+/**
+ * @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
+ */
+typedef enum {
+ TIMER_0 = 0, /*!<Select timer0 of GROUPx*/
+ TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
+ 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
+ */
+typedef enum {
+ TIMER_PAUSE = 0, /*!<Pause timer counter*/
+ TIMER_START = 1, /*!<Start timer counter*/
+} timer_start_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;
+
+/**
+ * @brief timer configure struct
+ */
+typedef struct {
+ bool alarm_en; /*!< Timer alarm enable */
+ bool counter_en; /*!< Counter enable */
+ timer_count_dir_t counter_dir; /*!< Counter direction */
+ timer_intr_mode_t intr_type; /*!< Interrupt mode */
+ bool auto_reload; /*!< Timer auto-reload */
+ uint16_t divider; /*!< Counter clock divider*/
+} timer_config_t;
+
+/**
+ * @brief Read the counter value of hardware timer.
+ *
+ * @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param timer_val Pointer to accept timer counter value.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* timer_val);
+
+/**
+ * @brief Read the counter value of hardware timer, in unit of a given scale.
+ *
+ * @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param time Pointer, type of double*, to accept timer counter value, in seconds.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double* time);
+
+/**
+ * @brief Set counter value to hardware timer.
+ *
+ * @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param load_val Counter value to write to the hardware timer.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val);
+
+/**
+ * @brief Start the counter of hardware timer.
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num);
+
+/**
+ * @brief Pause the counter of hardware timer.
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num);
+
+/**
+ * @brief Set counting mode for hardware timer.
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param counter_dir Counting direction of timer, count-up or count-down
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir);
+
+/**
+ * @brief Enable or disable counter reload function when alarm event occurs.
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param reload Counter reload mode.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload);
+
+/**
+ * @brief Set hardware timer source clock divider. Timer groups clock are divider from APB clock.
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param divider Timer clock divider value.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider);
+
+/**
+ * @brief Set timer alarm value.
+ *
+ * @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param alarm_value A 64-bit value to set the alarm value.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value);
+
+/**
+ * @brief Get timer alarm value.
+ *
+ * @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param alarm_value Pointer of A 64-bit value to accept the alarm value.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* alarm_value);
+
+/**
+ * @brief Get timer alarm value.
+ *
+ * @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param alarm_en To enable or disable timer alarm function.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en);
+
+
+/**
+ * @brief 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.
+ * @note
+ * Users should know that which CPU is running and then pick a INUM that is not used by system.
+ * We can find the information of INUM and interrupt level in soc.h.
+ *
+ * @param group_num Timer group number
+ * @param timer_num Timer index of timer group
+ * @param timer_intr_num TIMER interrupt number, check the info in soc.h, and please see the core-isa.h for more details
+ * @param intr_type Timer interrupt type
+ * @param fn Interrupt handler function.
+ * @note
+ * Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
+ * @param arg Parameter for handler function
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Function pointer error.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, int timer_intr_num, timer_intr_mode_t intr_type, void (*fn)(void*), void * arg);
+
+/** @brief Initializes and configure the timer.
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param config Pointer to timer initialization parameters.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t* config);
+
+/** @brief Get timer configure value.
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
+ * @param config Pointer of struct to accept timer parameters.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config);
+
+/** @brief Enable timer group interrupt, by enable mask
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param en_mask Timer interrupt enable mask.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask);
+
+/** @brief Disable timer group interrupt, by disable mask
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param disable_mask Timer interrupt disable mask.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask);
+
+/** @brief Enable timer interrupt
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num);
+
+/** @brief Disable timer interrupt
+ *
+ * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
+ * @param timer_num Timer index.
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TIMER_H_ */
--- /dev/null
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+#include <string.h>\r
+#include "esp_log.h"\r
+#include "esp_err.h"\r
+#include "esp_intr.h"\r
+#include "freertos/FreeRTOS.h"\r
+#include "freertos/xtensa_api.h"\r
+#include "driver/timer.h"\r
+#include "driver/periph_ctrl.h"\r
+\r
+static const char* TIMER_TAG = "TIMER_GROUP";\r
+#define TIMER_CHECK(a, str, ret_val) if (!(a)) { \\r
+ ESP_LOGE(TIMER_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \\r
+ return (ret_val); \\r
+ }\r
+#define TIMER_GROUP_NUM_ERROR "TIMER GROUP NUM ERROR"\r
+#define TIMER_NUM_ERROR "HW TIMER NUM ERROR"\r
+#define TIMER_PARAM_ADDR_ERROR "HW TIMER PARAM ADDR ERROR"\r
+#define TIMER_COUNT_DIR_ERROR "HW TIMER COUNTER DIR ERROR"\r
+#define TIMER_AUTORELOAD_ERROR "HW TIMER AUTORELOAD ERROR"\r
+#define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR"\r
+#define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR"\r
+static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};\r
+static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};\r
+\r
+#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux);\r
+#define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux);\r
+\r
+esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* timer_val)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_val != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
+ portENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].update = 1;\r
+ *timer_val = ((uint64_t) TG[group_num]->hw_timer[timer_num].cnt_high << 32)\r
+ | (TG[group_num]->hw_timer[timer_num].cnt_low);\r
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double* time)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(time != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
+\r
+ portENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].update = 1;\r
+ uint64_t timer_val = ((uint64_t) TG[group_num]->hw_timer[timer_num].cnt_high << 32)\r
+ | (TG[group_num]->hw_timer[timer_num].cnt_low);\r
+ uint16_t div = TG[group_num]->hw_timer[timer_num].config.divider;\r
+ *time = (double)timer_val * div / TIMER_BASE_CLK;\r
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);\r
+ TG[group_num]->hw_timer[timer_num].load_low = (uint32_t) load_val;\r
+ TG[group_num]->hw_timer[timer_num].reload = 1;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].config.enable = 1;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].config.enable = 0;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(counter_dir < TIMER_COUNT_MAX, TIMER_COUNT_DIR_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].config.increase = counter_dir;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(reload < TIMER_AUTORELOAD_MAX, TIMER_AUTORELOAD_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].config.autoreload = reload;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ int timer_en = TG[group_num]->hw_timer[timer_num].config.enable;\r
+ TG[group_num]->hw_timer[timer_num].config.enable = 0;\r
+ TG[group_num]->hw_timer[timer_num].config.divider = divider;\r
+ TG[group_num]->hw_timer[timer_num].config.enable = timer_en;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);\r
+ TG[group_num]->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* alarm_value)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(alarm_value != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
+ portENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ *alarm_value = ((uint64_t) TG[group_num]->hw_timer[timer_num].alarm_high << 32)\r
+ | (TG[group_num]->hw_timer[timer_num].alarm_low);\r
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(alarm_en < TIMER_ALARM_MAX, TIMER_ALARM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].config.alarm_en = alarm_en;\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, int timer_intr_num,\r
+ timer_intr_mode_t intr_type, void (*fn)(void*), void * arg)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
+\r
+ ESP_INTR_DISABLE(timer_intr_num);\r
+ int intr_source = 0;\r
+ switch(group_num) {\r
+ case TIMER_GROUP_0:\r
+ default:\r
+ if(intr_type == TIMER_INTR_LEVEL) {\r
+ intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;\r
+ } else {\r
+ intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;\r
+ }\r
+ break;\r
+ case TIMER_GROUP_1:\r
+ if(intr_type == TIMER_INTR_LEVEL) {\r
+ intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;\r
+ } else {\r
+ intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;\r
+ }\r
+ break;\r
+ }\r
+ intr_matrix_set(xPortGetCoreID(), intr_source, timer_intr_num);\r
+ xt_set_interrupt_handler(timer_intr_num, fn, arg);\r
+ ESP_INTR_ENABLE(timer_intr_num);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
+\r
+ if(group_num == 0) {\r
+ periph_module_enable(PERIPH_TIMG0_MODULE);\r
+ } else if(group_num == 1) {\r
+ periph_module_enable(PERIPH_TIMG1_MODULE);\r
+ }\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload;\r
+ TG[group_num]->hw_timer[timer_num].config.divider = config->divider;\r
+ TG[group_num]->hw_timer[timer_num].config.enable = config->counter_en;\r
+ TG[group_num]->hw_timer[timer_num].config.increase = config->counter_dir;\r
+ TG[group_num]->hw_timer[timer_num].config.alarm_en = config->alarm_en;\r
+ TG[group_num]->hw_timer[timer_num].config.level_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 1 : 0);\r
+ TG[group_num]->hw_timer[timer_num].config.edge_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 0 : 1);\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ config->alarm_en = TG[group_num]->hw_timer[timer_num].config.alarm_en;\r
+ config->auto_reload = TG[group_num]->hw_timer[timer_num].config.autoreload;\r
+ config->counter_dir = TG[group_num]->hw_timer[timer_num].config.increase;\r
+ config->counter_dir = TG[group_num]->hw_timer[timer_num].config.divider;\r
+ config->counter_en = TG[group_num]->hw_timer[timer_num].config.enable;\r
+ if(TG[group_num]->hw_timer[timer_num].config.level_int_en) {\r
+ config->intr_type =TIMER_INTR_LEVEL;\r
+ }\r
+ TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ portENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->int_ena.val |= en_mask;\r
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ portENTER_CRITICAL(&timer_spinlock[group_num]);\r
+ TG[group_num]->int_ena.val &= (~disable_mask);\r
+ portEXIT_CRITICAL(&timer_spinlock[group_num]);\r
+ return ESP_OK;\r
+}\r
+\r
+esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ return timer_group_intr_enable(group_num, BIT(timer_num));\r
+}\r
+\r
+esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)\r
+{\r
+ TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);\r
+ return timer_group_intr_disable(group_num, BIT(timer_num));\r
+}\r
+\r
+\r
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "esp_log.h"
+#include "driver/timer.h"
#include "esp_task_wdt.h"
intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
TIMERG0.int_clr_timers.wdt=1;
- TIMERG0.int_ena.wdt=1;
+ timer_group_intr_enable(TIMER_GROUP_0, BIT(2));
ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
}
-#endif
\ No newline at end of file
+#endif
--- /dev/null
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := timer_group
+
+include $(IDF_PATH)/make/project.mk
+
--- /dev/null
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
--- /dev/null
+/* Timer group-hardware timer example
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include "esp_types.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "soc/timer_group_struct.h"
+#include "driver/periph_ctrl.h"
+#include "driver/timer.h"
+
+#define TIMER_INTR_NUM_0 17 /*!< Interrupt number for hardware timer 0 */
+#define TIMER_INTR_NUM_1 18 /*!< Interrupt number for hardware timer 1*/
+#define TIMER_INTR_SEL TIMER_INTR_LEVEL /*!< Timer level interrupt */
+#define TIMER_GROUP TIMER_GROUP_0 /*!< Test on timer group 0 */
+#define TIMER_DIVIDER 16 /*!< Hardware timer clock divider */
+#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */
+#define TIMER_FINE_ADJ (1.4*(TIMER_BASE_CLK / TIMER_DIVIDER)/1000000) /*!< used to compensate alarm value */
+#define TIMER_INTERVAL0_SEC (3.4179) /*!< test interval for timer 0 */
+#define TIMER_INTERVAL1_SEC (5.78) /*!< test interval for timer 1 */
+#define TEST_WITHOUT_RELOAD 0 /*!< example of auto-reload mode */
+#define TEST_WITH_RELOAD 1 /*!< example without auto-reload mode */
+
+typedef struct {
+ int type; /*!< event type */
+ int group; /*!< timer group */
+ int idx; /*!< timer number */
+ uint64_t counter_val; /*!< timer counter value */
+ double time_sec; /*!< calculated time from counter value */
+} timer_event_t;
+
+xQueueHandle timer_queue;
+
+/*
+ * @brief Print a uint64_t value
+ */
+static void inline print_u64(uint64_t val)
+{
+ printf("0x%08x%08x\n", (uint32_t) (val >> 32), (uint32_t) (val));
+}
+
+void timer_evt_task(void *arg)
+{
+ while(1) {
+ timer_event_t evt;
+ xQueueReceive(timer_queue, &evt, portMAX_DELAY);
+ if(evt.type == TEST_WITHOUT_RELOAD) {
+ printf("\n\n example of count-up-timer \n");
+ } else if(evt.type == TEST_WITH_RELOAD) {
+ printf("\n\n example of reload-timer \n");
+
+ }
+ /*Show timer event from interrupt*/
+ printf("-------INTR TIME EVT--------\n");
+ printf("TG[%d] timer[%d] alarm evt\n", evt.group, evt.idx);
+ printf("reg: ");
+ print_u64(evt.counter_val);
+ printf("time: %.8f S\n", evt.time_sec);
+ /*Read timer value from task*/
+ printf("======TASK TIME======\n");
+ uint64_t timer_val;
+ timer_get_counter_value(evt.group, evt.idx, &timer_val);
+ double time;
+ timer_get_counter_time_sec(evt.group, evt.idx, &time);
+ printf("TG[%d] timer[%d] alarm evt\n", evt.group, evt.idx);
+ printf("reg: ");
+ print_u64(timer_val);
+ printf("time: %.8f S\n", time);
+ }
+}
+
+/*
+ * @brief timer group0 ISR handler
+ */
+void IRAM_ATTR timer_group0_isr(void *para)
+{
+ int timer_idx = (int) para;
+ uint32_t intr_status = TIMERG0.int_st_timers.val;
+ timer_event_t evt;
+ if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
+ /*Timer0 is an example that don't reload counter value*/
+ TIMERG0.hw_timer[timer_idx].update = 1;
+
+ /*We don't call a API here because they are not declared with IRAM_ATTR*/
+ TIMERG0.int_clr_timers.t0 = 1;
+ uint64_t timer_val = ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32
+ | TIMERG0.hw_timer[timer_idx].cnt_low;
+ double time = (double) timer_val / (TIMER_BASE_CLK / TIMERG0.hw_timer[timer_idx].config.divider);
+
+ /*Post an event to out example task*/
+ evt.type = TEST_WITHOUT_RELOAD;
+ evt.group = 0;
+ evt.idx = timer_idx;
+ evt.counter_val = timer_val;
+ evt.time_sec = time;
+ xQueueSendFromISR(timer_queue, &evt, NULL);
+
+ /*For a timer that will not reload, we need to set the next alarm value each time. */
+ timer_val +=
+ (uint64_t) (TIMER_INTERVAL0_SEC * (TIMER_BASE_CLK / TIMERG0.hw_timer[timer_idx].config.divider));
+ /*Fine adjust*/
+ timer_val -= TIMER_FINE_ADJ;
+ TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_val >> 32);
+ TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_val;
+ /*After set alarm, we set alarm_en bit if we want to enable alarm again.*/
+ TIMERG0.hw_timer[timer_idx].config.alarm_en = 1;
+
+ } else if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) {
+ /*Timer1 is an example that will reload counter value*/
+ TIMERG0.hw_timer[timer_idx].update = 1;
+ /*We don't call a API here because they are not declared with IRAM_ATTR*/
+ TIMERG0.int_clr_timers.t1 = 1;
+ uint64_t timer_val = ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32
+ | TIMERG0.hw_timer[timer_idx].cnt_low;
+ double time = (double) timer_val / (TIMER_BASE_CLK / TIMERG0.hw_timer[timer_idx].config.divider);
+ /*Post an event to out example task*/
+ evt.type = TEST_WITH_RELOAD;
+ evt.group = 0;
+ evt.idx = timer_idx;
+ evt.counter_val = timer_val;
+ evt.time_sec = time;
+ xQueueSendFromISR(timer_queue, &evt, NULL);
+ /*For a auto-reload timer, we still need to set alarm_en bit if we want to enable alarm again.*/
+ TIMERG0.hw_timer[timer_idx].config.alarm_en = 1;
+ }
+}
+
+/*
+ * @brief timer group0 hardware timer0 init
+ */
+void tg0_timer0_init()
+{
+ int timer_group = TIMER_GROUP_0;
+ int timer_idx = TIMER_0;
+ timer_config_t config;
+ config.alarm_en = 1;
+ config.auto_reload = 0;
+ config.counter_dir = TIMER_COUNT_UP;
+ config.divider = TIMER_DIVIDER;
+ config.intr_type = TIMER_INTR_SEL;
+ config.counter_en = TIMER_PAUSE;
+ /*Configure timer*/
+ timer_init(timer_group, timer_idx, &config);
+ /*Stop timer counter*/
+ timer_pause(timer_group, timer_idx);
+ /*Load counter value */
+ timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
+ /*Set alarm value*/
+ timer_set_alarm_value(timer_group, timer_idx, TIMER_INTERVAL0_SEC * TIMER_SCALE - TIMER_FINE_ADJ);
+ /*Enable timer interrupt*/
+ timer_enable_intr(timer_group, timer_idx);
+ /*Set ISR handler*/
+ timer_isr_register(timer_group, timer_idx, TIMER_INTR_NUM_0, TIMER_INTR_SEL, timer_group0_isr, (void*) timer_idx);
+ /*Start timer counter*/
+ timer_start(timer_group, timer_idx);
+}
+
+/*
+ * @brief timer group0 hardware timer1 init
+ */
+void tg0_timer1_init()
+{
+ int timer_group = TIMER_GROUP_0;
+ int timer_idx = TIMER_1;
+ timer_config_t config;
+ config.alarm_en = 1;
+ config.auto_reload = 1;
+ config.counter_dir = TIMER_COUNT_UP;
+ config.divider = TIMER_DIVIDER;
+ config.intr_type = TIMER_INTR_SEL;
+ config.counter_en = TIMER_PAUSE;
+ /*Configure timer*/
+ timer_init(timer_group, timer_idx, &config);
+ /*Stop timer counter*/
+ timer_pause(timer_group, timer_idx);
+ /*Load counter value */
+ timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
+ /*Set alarm value*/
+ timer_set_alarm_value(timer_group, timer_idx, TIMER_INTERVAL1_SEC * TIMER_SCALE);
+ /*Enable timer interrupt*/
+ timer_enable_intr(timer_group, timer_idx);
+ /*Set ISR handler*/
+ timer_isr_register(timer_group, timer_idx, TIMER_INTR_NUM_1, TIMER_INTR_SEL, timer_group0_isr, (void*) timer_idx);
+ /*Start timer counter*/
+ timer_start(timer_group, timer_idx);
+}
+
+/**
+ * @brief In this test, we will test hardware timer0 and timer1 of timer group0.
+ */
+void app_main()
+{
+ tg0_timer0_init();
+ tg0_timer1_init();
+ timer_queue = xQueueCreate(10, sizeof(timer_event_t));
+ xTaskCreate(timer_evt_task, "timer_evt_task", 1024, NULL, 5, NULL);
+}
+