From fcbde13755b5bb0af973682976747a0191165ce9 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 1 Feb 2021 14:10:15 +0800 Subject: [PATCH] timer_group: using isr callback in example --- examples/peripherals/timer_group/README.md | 70 +++++--- .../main/timer_group_example_main.c | 162 ++++++++---------- 2 files changed, 114 insertions(+), 118 deletions(-) diff --git a/examples/peripherals/timer_group/README.md b/examples/peripherals/timer_group/README.md index c02ad8fe8e..d407c987ac 100644 --- a/examples/peripherals/timer_group/README.md +++ b/examples/peripherals/timer_group/README.md @@ -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. diff --git a/examples/peripherals/timer_group/main/timer_group_example_main.c b/examples/peripherals/timer_group/main/timer_group_example_main.c index f590cf0ab9..35f46e9b8b 100644 --- a/examples/peripherals/timer_group/main/timer_group_example_main.c +++ b/examples/peripherals/timer_group/main/timer_group_example_main.c @@ -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 -#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); -}