2016-11-22 18:15:27 +00:00
|
|
|
/* 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 "driver/periph_ctrl.h"
|
|
|
|
#include "driver/timer.h"
|
|
|
|
|
2017-09-25 04:20:12 +00:00
|
|
|
#define TIMER_DIVIDER 16 // Hardware timer clock divider
|
|
|
|
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
|
|
|
|
#define TIMER_INTERVAL0_SEC (3.4179) // sample test interval for the first timer
|
|
|
|
#define TIMER_INTERVAL1_SEC (5.78) // sample test interval for the second timer
|
|
|
|
#define TEST_WITHOUT_RELOAD 0 // testing will be done without auto reload
|
|
|
|
#define TEST_WITH_RELOAD 1 // testing will be done with auto reload
|
2016-11-22 18:15:27 +00:00
|
|
|
|
2017-09-25 04:20:12 +00:00
|
|
|
/*
|
|
|
|
* A sample structure to pass events
|
|
|
|
* from the timer interrupt handler to the main program.
|
|
|
|
*/
|
2016-11-22 18:15:27 +00:00
|
|
|
typedef struct {
|
2017-09-25 04:20:12 +00:00
|
|
|
int type; // the type of timer's event
|
|
|
|
int timer_group;
|
|
|
|
int timer_idx;
|
|
|
|
uint64_t timer_counter_value;
|
2016-11-22 18:15:27 +00:00
|
|
|
} timer_event_t;
|
|
|
|
|
|
|
|
xQueueHandle timer_queue;
|
|
|
|
|
|
|
|
/*
|
2017-09-25 04:20:12 +00:00
|
|
|
* A simple helper function to print the raw timer counter value
|
|
|
|
* and the counter value converted to seconds
|
2016-11-22 18:15:27 +00:00
|
|
|
*/
|
2017-09-25 04:20:12 +00:00
|
|
|
static void inline print_timer_counter(uint64_t counter_value)
|
2016-11-22 18:15:27 +00:00
|
|
|
{
|
2017-09-25 04:20:12 +00:00
|
|
|
printf("Counter: 0x%08x%08x\n", (uint32_t) (counter_value >> 32),
|
|
|
|
(uint32_t) (counter_value));
|
|
|
|
printf("Time : %.8f s\n", (double) counter_value / TIMER_SCALE);
|
2016-11-22 18:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-09-25 04:20:12 +00:00
|
|
|
* Timer group0 ISR handler
|
|
|
|
*
|
|
|
|
* Note:
|
|
|
|
* We don't call the timer API here because they are not declared with IRAM_ATTR.
|
|
|
|
* If we're okay with the timer irq not being serviced while SPI flash cache is disabled,
|
|
|
|
* we can allocate this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API.
|
2016-11-22 18:15:27 +00:00
|
|
|
*/
|
|
|
|
void IRAM_ATTR timer_group0_isr(void *para)
|
|
|
|
{
|
|
|
|
int timer_idx = (int) para;
|
2017-09-25 04:20:12 +00:00
|
|
|
|
|
|
|
/* Retrieve the interrupt status and the counter value
|
|
|
|
from the timer that reported the interrupt */
|
2019-06-06 06:20:39 +00:00
|
|
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
2016-11-22 18:15:27 +00:00
|
|
|
uint32_t intr_status = TIMERG0.int_st_timers.val;
|
2017-09-25 04:20:12 +00:00
|
|
|
TIMERG0.hw_timer[timer_idx].update = 1;
|
2019-06-06 06:20:39 +00:00
|
|
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
|
|
|
uint32_t intr_status = TIMERG0.int_st.val;
|
|
|
|
TIMERG0.hw_timer[timer_idx].update.update = 1;
|
|
|
|
#endif
|
2017-09-25 04:20:12 +00:00
|
|
|
uint64_t timer_counter_value =
|
|
|
|
((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32
|
|
|
|
| TIMERG0.hw_timer[timer_idx].cnt_low;
|
2016-11-22 18:15:27 +00:00
|
|
|
|
2017-09-25 04:20:12 +00:00
|
|
|
/* Prepare basic event data
|
|
|
|
that will be then sent back to the main program task */
|
|
|
|
timer_event_t evt;
|
|
|
|
evt.timer_group = 0;
|
|
|
|
evt.timer_idx = timer_idx;
|
|
|
|
evt.timer_counter_value = timer_counter_value;
|
2016-11-22 18:15:27 +00:00
|
|
|
|
2017-09-25 04:20:12 +00:00
|
|
|
/* Clear the interrupt
|
|
|
|
and update the alarm time for the timer with without reload */
|
|
|
|
if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
|
2016-11-22 18:15:27 +00:00
|
|
|
evt.type = TEST_WITHOUT_RELOAD;
|
2019-06-06 06:20:39 +00:00
|
|
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
2017-09-25 04:20:12 +00:00
|
|
|
TIMERG0.int_clr_timers.t0 = 1;
|
2019-06-06 06:20:39 +00:00
|
|
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
|
|
|
TIMERG0.int_clr.t0 = 1;
|
|
|
|
#endif
|
2017-09-25 04:20:12 +00:00
|
|
|
timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
|
|
|
|
TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_counter_value >> 32);
|
|
|
|
TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value;
|
|
|
|
} else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) {
|
2016-11-22 18:15:27 +00:00
|
|
|
evt.type = TEST_WITH_RELOAD;
|
2019-06-06 06:20:39 +00:00
|
|
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
2017-09-25 04:20:12 +00:00
|
|
|
TIMERG0.int_clr_timers.t1 = 1;
|
2019-06-06 06:20:39 +00:00
|
|
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
|
|
|
TIMERG0.int_clr.t1 = 1;
|
|
|
|
#endif
|
2017-09-25 04:20:12 +00:00
|
|
|
} else {
|
|
|
|
evt.type = -1; // not supported even type
|
2016-11-22 18:15:27 +00:00
|
|
|
}
|
2017-09-25 04:20:12 +00:00
|
|
|
|
|
|
|
/* After the alarm has been triggered
|
|
|
|
we need enable it again, so it is triggered the next time */
|
|
|
|
TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN;
|
|
|
|
|
|
|
|
/* Now just send the event data back to the main program task */
|
|
|
|
xQueueSendFromISR(timer_queue, &evt, NULL);
|
2016-11-22 18:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-09-25 04:20:12 +00:00
|
|
|
* Initialize selected timer of the timer group 0
|
|
|
|
*
|
|
|
|
* timer_idx - the timer number to initialize
|
|
|
|
* auto_reload - should the timer auto reload on alarm?
|
|
|
|
* timer_interval_sec - the interval of alarm to set
|
2016-11-22 18:15:27 +00:00
|
|
|
*/
|
2017-09-25 04:20:12 +00:00
|
|
|
static void example_tg0_timer_init(int timer_idx,
|
|
|
|
bool auto_reload, double timer_interval_sec)
|
2016-11-22 18:15:27 +00:00
|
|
|
{
|
2017-09-25 04:20:12 +00:00
|
|
|
/* Select and initialize basic parameters of the timer */
|
2016-11-22 18:15:27 +00:00
|
|
|
timer_config_t config;
|
|
|
|
config.divider = TIMER_DIVIDER;
|
2017-09-25 04:20:12 +00:00
|
|
|
config.counter_dir = TIMER_COUNT_UP;
|
2016-11-22 18:15:27 +00:00
|
|
|
config.counter_en = TIMER_PAUSE;
|
2017-09-25 04:20:12 +00:00
|
|
|
config.alarm_en = TIMER_ALARM_EN;
|
|
|
|
config.intr_type = TIMER_INTR_LEVEL;
|
|
|
|
config.auto_reload = auto_reload;
|
2019-06-06 06:20:39 +00:00
|
|
|
#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
|
|
|
|
config.clk_sel = TIMER_SRC_CLK_APB;
|
|
|
|
#endif
|
2017-09-25 04:20:12 +00:00
|
|
|
timer_init(TIMER_GROUP_0, timer_idx, &config);
|
|
|
|
|
|
|
|
/* Timer's counter will initially start from value below.
|
|
|
|
Also, if auto_reload is set, this value will be automatically reload on alarm */
|
|
|
|
timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL);
|
|
|
|
|
|
|
|
/* Configure the alarm value and the interrupt on alarm. */
|
|
|
|
timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE);
|
|
|
|
timer_enable_intr(TIMER_GROUP_0, timer_idx);
|
|
|
|
timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr,
|
|
|
|
(void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
|
|
|
|
|
|
|
|
timer_start(TIMER_GROUP_0, timer_idx);
|
2016-11-22 18:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-09-25 04:20:12 +00:00
|
|
|
* The main task of this example program
|
2016-11-22 18:15:27 +00:00
|
|
|
*/
|
2017-09-25 04:20:12 +00:00
|
|
|
static void timer_example_evt_task(void *arg)
|
2016-11-22 18:15:27 +00:00
|
|
|
{
|
2017-09-25 04:20:12 +00:00
|
|
|
while (1) {
|
|
|
|
timer_event_t evt;
|
|
|
|
xQueueReceive(timer_queue, &evt, portMAX_DELAY);
|
|
|
|
|
|
|
|
/* Print information that the timer reported an event */
|
|
|
|
if (evt.type == TEST_WITHOUT_RELOAD) {
|
|
|
|
printf("\n Example timer without reload\n");
|
|
|
|
} else if (evt.type == TEST_WITH_RELOAD) {
|
|
|
|
printf("\n Example timer with auto reload\n");
|
|
|
|
} else {
|
|
|
|
printf("\n UNKNOWN EVENT TYPE\n");
|
|
|
|
}
|
|
|
|
printf("Group[%d], timer[%d] alarm event\n", evt.timer_group, evt.timer_idx);
|
|
|
|
|
|
|
|
/* Print the timer values passed by event */
|
|
|
|
printf("------- EVENT TIME --------\n");
|
|
|
|
print_timer_counter(evt.timer_counter_value);
|
|
|
|
|
|
|
|
/* Print the timer values as visible by this task */
|
|
|
|
printf("-------- TASK TIME --------\n");
|
|
|
|
uint64_t task_counter_value;
|
|
|
|
timer_get_counter_value(evt.timer_group, evt.timer_idx, &task_counter_value);
|
|
|
|
print_timer_counter(task_counter_value);
|
|
|
|
}
|
2016-11-22 18:15:27 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 04:20:12 +00:00
|
|
|
/*
|
|
|
|
* In this example, we will test hardware timer0 and timer1 of timer group0.
|
2016-11-22 18:15:27 +00:00
|
|
|
*/
|
2019-07-16 09:33:30 +00:00
|
|
|
void app_main(void)
|
2016-11-22 18:15:27 +00:00
|
|
|
{
|
2016-12-19 10:17:54 +00:00
|
|
|
timer_queue = xQueueCreate(10, sizeof(timer_event_t));
|
2017-09-25 04:20:12 +00:00
|
|
|
example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC);
|
|
|
|
example_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD, TIMER_INTERVAL1_SEC);
|
2017-03-22 04:36:11 +00:00
|
|
|
xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL);
|
2016-11-22 18:15:27 +00:00
|
|
|
}
|
|
|
|
|