driver: add hardware timer code.
1. add timer driver code 2. add timer example code 3. replace api for enable interrupt in task_wdt.c
This commit is contained in:
parent
d0c9c1de57
commit
a3c4a70ba3
6 changed files with 841 additions and 2 deletions
343
components/driver/include/driver/timer.h
Normal file
343
components/driver/include/driver/timer.h
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
// 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_ */
|
276
components/driver/timer.c
Normal file
276
components/driver/timer.c
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
// Copyright 2015-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.
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_intr.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/xtensa_api.h"
|
||||||
|
#include "driver/timer.h"
|
||||||
|
#include "driver/periph_ctrl.h"
|
||||||
|
|
||||||
|
static const char* TIMER_TAG = "TIMER_GROUP";
|
||||||
|
#define TIMER_CHECK(a, str, ret_val) if (!(a)) { \
|
||||||
|
ESP_LOGE(TIMER_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||||
|
return (ret_val); \
|
||||||
|
}
|
||||||
|
#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_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"
|
||||||
|
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(mux);
|
||||||
|
#define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux);
|
||||||
|
|
||||||
|
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(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].update = 1;
|
||||||
|
*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(&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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].update = 1;
|
||||||
|
uint64_t timer_val = ((uint64_t) TG[group_num]->hw_timer[timer_num].cnt_high << 32)
|
||||||
|
| (TG[group_num]->hw_timer[timer_num].cnt_low);
|
||||||
|
uint16_t div = TG[group_num]->hw_timer[timer_num].config.divider;
|
||||||
|
*time = (double)timer_val * div / TIMER_BASE_CLK;
|
||||||
|
portEXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_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_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_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.enable = 1;
|
||||||
|
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num)
|
||||||
|
{
|
||||||
|
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_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.enable = 0;
|
||||||
|
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir)
|
||||||
|
{
|
||||||
|
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_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.increase = counter_dir;
|
||||||
|
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload)
|
||||||
|
{
|
||||||
|
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_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.autoreload = reload;
|
||||||
|
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider)
|
||||||
|
{
|
||||||
|
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_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 = divider;
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.enable = timer_en;
|
||||||
|
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value)
|
||||||
|
{
|
||||||
|
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_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_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)
|
||||||
|
{
|
||||||
|
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(&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(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en)
|
||||||
|
{
|
||||||
|
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_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.alarm_en = alarm_en;
|
||||||
|
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, int timer_intr_num,
|
||||||
|
timer_intr_mode_t intr_type, void (*fn)(void*), void * arg)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
ESP_INTR_DISABLE(timer_intr_num);
|
||||||
|
int intr_source = 0;
|
||||||
|
switch(group_num) {
|
||||||
|
case TIMER_GROUP_0:
|
||||||
|
default:
|
||||||
|
if(intr_type == TIMER_INTR_LEVEL) {
|
||||||
|
intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;
|
||||||
|
} else {
|
||||||
|
intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIMER_GROUP_1:
|
||||||
|
if(intr_type == TIMER_INTR_LEVEL) {
|
||||||
|
intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;
|
||||||
|
} else {
|
||||||
|
intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
intr_matrix_set(xPortGetCoreID(), intr_source, timer_intr_num);
|
||||||
|
xt_set_interrupt_handler(timer_intr_num, fn, arg);
|
||||||
|
ESP_INTR_ENABLE(timer_intr_num);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
if(group_num == 0) {
|
||||||
|
periph_module_enable(PERIPH_TIMG0_MODULE);
|
||||||
|
} else if(group_num == 1) {
|
||||||
|
periph_module_enable(PERIPH_TIMG1_MODULE);
|
||||||
|
}
|
||||||
|
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload;
|
||||||
|
TG[group_num]->hw_timer[timer_num].config.divider = 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_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
|
||||||
|
{
|
||||||
|
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_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->counter_dir = 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->intr_type =TIMER_INTR_LEVEL;
|
||||||
|
}
|
||||||
|
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_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]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_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]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)
|
||||||
|
{
|
||||||
|
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||||
|
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||||
|
return timer_group_intr_enable(group_num, BIT(timer_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)
|
||||||
|
{
|
||||||
|
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||||
|
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||||
|
return timer_group_intr_disable(group_num, BIT(timer_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "soc/timer_group_struct.h"
|
#include "soc/timer_group_struct.h"
|
||||||
#include "soc/timer_group_reg.h"
|
#include "soc/timer_group_reg.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "driver/timer.h"
|
||||||
|
|
||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
|
|
||||||
|
@ -204,7 +205,7 @@ void esp_task_wdt_init() {
|
||||||
intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
|
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);
|
xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
|
||||||
TIMERG0.int_clr_timers.wdt=1;
|
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);
|
ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
examples/13_timer_group/Makefile
Normal file
9
examples/13_timer_group/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
5
examples/13_timer_group/main/component.mk
Normal file
5
examples/13_timer_group/main/component.mk
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||||
|
|
205
examples/13_timer_group/main/timer_group.c
Normal file
205
examples/13_timer_group/main/timer_group.c
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue