mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
timer_group: using isr callback in example
This commit is contained in:
parent
5a520cacf1
commit
fcbde13755
@ -1,10 +1,51 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Example: timer_group
|
||||
# Example: General Purpose Timer
|
||||
|
||||
This example uses the timer group driver to generate timer interrupts at two specified alarm intervals.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
Timer Group with auto reload
|
||||
Group[0], timer[0] alarm event
|
||||
------- EVENT TIME --------
|
||||
Counter: 0x0000000000000008
|
||||
Time : 0.00000160 s
|
||||
-------- TASK TIME --------
|
||||
Counter: 0x0000000000004ed8
|
||||
Time : 0.00403680 s
|
||||
Timer Group without auto reload
|
||||
Group[1], timer[0] alarm event
|
||||
------- EVENT TIME --------
|
||||
Counter: 0x00000000017d7848
|
||||
Time : 5.00000160 s
|
||||
-------- TASK TIME --------
|
||||
Counter: 0x00000000017dcb32
|
||||
Time : 5.00424680 s
|
||||
Timer Group with auto reload
|
||||
Group[0], timer[0] alarm event
|
||||
------- EVENT TIME --------
|
||||
Counter: 0x0000000000000008
|
||||
Time : 0.00000160 s
|
||||
-------- TASK TIME --------
|
||||
Counter: 0x0000000000004dd4
|
||||
Time : 0.00398480 s
|
||||
```
|
||||
|
||||
## Functionality Overview
|
||||
|
||||
* Two timers are configured
|
||||
@ -14,23 +55,6 @@ This example uses the timer group driver to generate timer interrupts at two spe
|
||||
* The other timer is configured to keep incrementing and is reloaded by the application each time the alarm happens
|
||||
* Alarms trigger subsequent interrupts, that is tracked with messages printed on the terminal:
|
||||
|
||||
```
|
||||
Example timer with auto reload
|
||||
Group[0], timer[1] alarm event
|
||||
------- EVENT TIME --------
|
||||
Counter: 0x000000000000000a
|
||||
Time : 0.00000200 s
|
||||
-------- TASK TIME --------
|
||||
Counter: 0x00000000000107ff
|
||||
Time : 0.01351660 s
|
||||
## Troubleshooting
|
||||
|
||||
Example timer without reload
|
||||
Group[0], timer[0] alarm event
|
||||
------- EVENT TIME --------
|
||||
Counter: 0x00000000092ae316
|
||||
Time : 30.76111800 s
|
||||
-------- TASK TIME --------
|
||||
Counter: 0x00000000092bd535
|
||||
Time : 30.77351460 s
|
||||
|
||||
```
|
||||
For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Timer group-hardware timer example
|
||||
/* General Purpose Timer example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
@ -7,32 +7,31 @@
|
||||
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"
|
||||
|
||||
#define TIMER_DIVIDER 16 // Hardware timer clock divider
|
||||
#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
|
||||
|
||||
/*
|
||||
* A sample structure to pass events
|
||||
* from the timer interrupt handler to the main program.
|
||||
*/
|
||||
typedef struct {
|
||||
int type; // the type of timer's event
|
||||
int timer_group;
|
||||
int timer_idx;
|
||||
uint64_t timer_counter_value;
|
||||
} timer_event_t;
|
||||
int alarm_interval;
|
||||
bool auto_reload;
|
||||
} example_timer_info_t;
|
||||
|
||||
xQueueHandle timer_queue;
|
||||
/**
|
||||
* @brief A sample structure to pass events from the timer ISR to task
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
example_timer_info_t info;
|
||||
uint64_t timer_counter_value;
|
||||
} example_timer_event_t;
|
||||
|
||||
static xQueueHandle s_timer_queue;
|
||||
|
||||
/*
|
||||
* A simple helper function to print the raw timer counter value
|
||||
@ -40,68 +39,47 @@ xQueueHandle timer_queue;
|
||||
*/
|
||||
static void inline print_timer_counter(uint64_t counter_value)
|
||||
{
|
||||
printf("Counter: 0x%08x%08x\n", (uint32_t) (counter_value >> 32),
|
||||
printf("Counter: 0x%08x%08x\r\n", (uint32_t) (counter_value >> 32),
|
||||
(uint32_t) (counter_value));
|
||||
printf("Time : %.8f s\n", (double) counter_value / TIMER_SCALE);
|
||||
printf("Time : %.8f s\r\n", (double) counter_value / TIMER_SCALE);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void IRAM_ATTR timer_group0_isr(void *para)
|
||||
static bool IRAM_ATTR timer_group_isr_callback(void *args)
|
||||
{
|
||||
timer_spinlock_take(TIMER_GROUP_0);
|
||||
int timer_idx = (int) para;
|
||||
BaseType_t high_task_awoken = pdFALSE;
|
||||
example_timer_info_t *info = (example_timer_info_t *) args;
|
||||
|
||||
/* Retrieve the interrupt status and the counter value
|
||||
from the timer that reported the interrupt */
|
||||
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);
|
||||
uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(info->timer_group, info->timer_idx);
|
||||
|
||||
/* 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;
|
||||
/* Prepare basic event data that will be then sent back to task */
|
||||
example_timer_event_t evt = {
|
||||
.info.timer_group = info->timer_group,
|
||||
.info.timer_idx = info->timer_idx,
|
||||
.info.auto_reload = info->auto_reload,
|
||||
.info.alarm_interval = info->alarm_interval,
|
||||
.timer_counter_value = timer_counter_value
|
||||
};
|
||||
|
||||
/* Clear the interrupt
|
||||
and update the alarm time for the timer with without reload */
|
||||
if (timer_intr & TIMER_INTR_T0) {
|
||||
evt.type = TEST_WITHOUT_RELOAD;
|
||||
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_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
|
||||
} else {
|
||||
evt.type = -1; // not supported even type
|
||||
if (!info->auto_reload) {
|
||||
timer_counter_value += info->alarm_interval * TIMER_SCALE;
|
||||
timer_group_set_alarm_value_in_isr(info->timer_group, info->timer_idx, timer_counter_value);
|
||||
}
|
||||
|
||||
/* After the alarm has been triggered
|
||||
we need enable it again, so it is triggered the next time */
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx);
|
||||
|
||||
/* Now just send the event data back to the main program task */
|
||||
xQueueSendFromISR(timer_queue, &evt, NULL);
|
||||
timer_spinlock_give(TIMER_GROUP_0);
|
||||
xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken);
|
||||
|
||||
return high_task_awoken == pdTRUE; // return whether we need to yield at the end of ISR
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize selected timer of the timer group 0
|
||||
/**
|
||||
* @brief Initialize selected timer of timer group
|
||||
*
|
||||
* 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
|
||||
* @param group Timer Group number, index from 0
|
||||
* @param timer timer ID, index from 0
|
||||
* @param auto_reload whether auto-reload on alarm event
|
||||
* @param timer_interval_sec interval of alarm
|
||||
*/
|
||||
static void example_tg0_timer_init(int timer_idx,
|
||||
bool auto_reload, double timer_interval_sec)
|
||||
static void example_tg_timer_init(int group, int timer, bool auto_reload, int timer_interval_sec)
|
||||
{
|
||||
/* Select and initialize basic parameters of the timer */
|
||||
timer_config_t config = {
|
||||
@ -111,39 +89,44 @@ static void example_tg0_timer_init(int timer_idx,
|
||||
.alarm_en = TIMER_ALARM_EN,
|
||||
.auto_reload = auto_reload,
|
||||
}; // default clock source is APB
|
||||
timer_init(TIMER_GROUP_0, timer_idx, &config);
|
||||
timer_init(group, timer, &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);
|
||||
timer_set_counter_value(group, timer, 0);
|
||||
|
||||
/* 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_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);
|
||||
timer_enable_intr(group, timer);
|
||||
|
||||
timer_start(TIMER_GROUP_0, timer_idx);
|
||||
example_timer_info_t *timer_info = calloc(1, sizeof(example_timer_info_t));
|
||||
timer_info->timer_group = group;
|
||||
timer_info->timer_idx = timer;
|
||||
timer_info->auto_reload = auto_reload;
|
||||
timer_info->alarm_interval = timer_interval_sec;
|
||||
timer_isr_callback_add(group, timer, timer_group_isr_callback, timer_info, 0);
|
||||
|
||||
timer_start(group, timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* The main task of this example program
|
||||
*/
|
||||
static void timer_example_evt_task(void *arg)
|
||||
void app_main(void)
|
||||
{
|
||||
s_timer_queue = xQueueCreate(10, sizeof(example_timer_event_t));
|
||||
|
||||
example_tg_timer_init(TIMER_GROUP_0, TIMER_0, true, 3);
|
||||
example_tg_timer_init(TIMER_GROUP_1, TIMER_0, false, 5);
|
||||
|
||||
while (1) {
|
||||
timer_event_t evt;
|
||||
xQueueReceive(timer_queue, &evt, portMAX_DELAY);
|
||||
example_timer_event_t evt;
|
||||
xQueueReceive(s_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");
|
||||
if (evt.info.auto_reload) {
|
||||
printf("Timer Group with auto reload\n");
|
||||
} else {
|
||||
printf("\n UNKNOWN EVENT TYPE\n");
|
||||
printf("Timer Group without auto reload\n");
|
||||
}
|
||||
printf("Group[%d], timer[%d] alarm event\n", evt.timer_group, evt.timer_idx);
|
||||
printf("Group[%d], timer[%d] alarm event\n", evt.info.timer_group, evt.info.timer_idx);
|
||||
|
||||
/* Print the timer values passed by event */
|
||||
printf("------- EVENT TIME --------\n");
|
||||
@ -152,18 +135,7 @@ static void timer_example_evt_task(void *arg)
|
||||
/* 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);
|
||||
timer_get_counter_value(evt.info.timer_group, evt.info.timer_idx, &task_counter_value);
|
||||
print_timer_counter(task_counter_value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In this example, we will test hardware timer0 and timer1 of timer group0.
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
timer_queue = xQueueCreate(10, sizeof(timer_event_t));
|
||||
example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC);
|
||||
example_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD, TIMER_INTERVAL1_SEC);
|
||||
xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user