mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 04:59:55 +00:00 
			
		
		
		
	timer_group: using isr callback in example
This commit is contained in:
		| @@ -1,10 +1,51 @@ | |||||||
| | Supported Targets | ESP32 | | # Example: General Purpose Timer | ||||||
| | ----------------- | ----- | |  | ||||||
|  |  | ||||||
| # Example: timer_group |  | ||||||
|  |  | ||||||
| This example uses the timer group driver to generate timer interrupts at two specified alarm intervals. | 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 | ## Functionality Overview | ||||||
|  |  | ||||||
| * Two timers are configured | * 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 | * 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: | * Alarms trigger subsequent interrupts, that is tracked with messages printed on the terminal: | ||||||
|  |  | ||||||
| ``` | ## Troubleshooting | ||||||
|     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 |  | ||||||
|  |  | ||||||
|     Example timer without reload | For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. | ||||||
| Group[0], timer[0] alarm event |  | ||||||
| ------- EVENT TIME -------- |  | ||||||
| Counter: 0x00000000092ae316 |  | ||||||
| Time   : 30.76111800 s |  | ||||||
| -------- TASK TIME -------- |  | ||||||
| Counter: 0x00000000092bd535 |  | ||||||
| Time   : 30.77351460 s |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
|   | |||||||
| @@ -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.) |    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. |    CONDITIONS OF ANY KIND, either express or implied. | ||||||
| */ | */ | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include "esp_types.h" |  | ||||||
| #include "freertos/FreeRTOS.h" | #include "freertos/FreeRTOS.h" | ||||||
| #include "freertos/task.h" | #include "freertos/task.h" | ||||||
| #include "freertos/queue.h" | #include "freertos/queue.h" | ||||||
| #include "driver/periph_ctrl.h" |  | ||||||
| #include "driver/timer.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_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 { | typedef struct { | ||||||
|     int type;  // the type of timer's event |  | ||||||
|     int timer_group; |     int timer_group; | ||||||
|     int timer_idx; |     int timer_idx; | ||||||
|     uint64_t timer_counter_value; |     int alarm_interval; | ||||||
| } timer_event_t; |     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 |  * 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) | 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)); |            (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); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | static bool IRAM_ATTR timer_group_isr_callback(void *args) | ||||||
|  * 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) |  | ||||||
| { | { | ||||||
|     timer_spinlock_take(TIMER_GROUP_0); |     BaseType_t high_task_awoken = pdFALSE; | ||||||
|     int timer_idx = (int) para; |     example_timer_info_t *info = (example_timer_info_t *) args; | ||||||
|  |  | ||||||
|     /* Retrieve the interrupt status and the counter value |     uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(info->timer_group, info->timer_idx); | ||||||
|        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); |  | ||||||
|  |  | ||||||
|     /* Prepare basic event data |     /* Prepare basic event data that will be then sent back to task */ | ||||||
|        that will be then sent back to the main program task */ |     example_timer_event_t evt = { | ||||||
|     timer_event_t evt; |         .info.timer_group = info->timer_group, | ||||||
|     evt.timer_group = 0; |         .info.timer_idx = info->timer_idx, | ||||||
|     evt.timer_idx = timer_idx; |         .info.auto_reload = info->auto_reload, | ||||||
|     evt.timer_counter_value = timer_counter_value; |         .info.alarm_interval = info->alarm_interval, | ||||||
|  |         .timer_counter_value = timer_counter_value | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     /* Clear the interrupt |     if (!info->auto_reload) { | ||||||
|        and update the alarm time for the timer with without reload */ |         timer_counter_value += info->alarm_interval * TIMER_SCALE; | ||||||
|     if (timer_intr & TIMER_INTR_T0) { |         timer_group_set_alarm_value_in_isr(info->timer_group, info->timer_idx, timer_counter_value); | ||||||
|         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 |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* 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 */ |     /* Now just send the event data back to the main program task */ | ||||||
|     xQueueSendFromISR(timer_queue, &evt, NULL); |     xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken); | ||||||
|     timer_spinlock_give(TIMER_GROUP_0); |  | ||||||
|  |     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 |  * @param group Timer Group number, index from 0 | ||||||
|  * auto_reload - should the timer auto reload on alarm? |  * @param timer timer ID, index from 0 | ||||||
|  * timer_interval_sec - the interval of alarm to set |  * @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, | static void example_tg_timer_init(int group, int timer, bool auto_reload, int timer_interval_sec) | ||||||
|                                    bool auto_reload, double timer_interval_sec) |  | ||||||
| { | { | ||||||
|     /* Select and initialize basic parameters of the timer */ |     /* Select and initialize basic parameters of the timer */ | ||||||
|     timer_config_t config = { |     timer_config_t config = { | ||||||
| @@ -111,39 +89,44 @@ static void example_tg0_timer_init(int timer_idx, | |||||||
|         .alarm_en = TIMER_ALARM_EN, |         .alarm_en = TIMER_ALARM_EN, | ||||||
|         .auto_reload = auto_reload, |         .auto_reload = auto_reload, | ||||||
|     }; // default clock source is APB |     }; // 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. |     /* Timer's counter will initially start from value below. | ||||||
|        Also, if auto_reload is set, this value will be automatically reload on alarm */ |        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. */ |     /* Configure the alarm value and the interrupt on alarm. */ | ||||||
|     timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE); |     timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE); | ||||||
|     timer_enable_intr(TIMER_GROUP_0, timer_idx); |     timer_enable_intr(group, timer); | ||||||
|     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); |     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); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | void app_main(void) | ||||||
|  * The main task of this example program |  | ||||||
|  */ |  | ||||||
| static void timer_example_evt_task(void *arg) |  | ||||||
| { | { | ||||||
|  |     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) { |     while (1) { | ||||||
|         timer_event_t evt; |         example_timer_event_t evt; | ||||||
|         xQueueReceive(timer_queue, &evt, portMAX_DELAY); |         xQueueReceive(s_timer_queue, &evt, portMAX_DELAY); | ||||||
|  |  | ||||||
|         /* Print information that the timer reported an event */ |         /* Print information that the timer reported an event */ | ||||||
|         if (evt.type == TEST_WITHOUT_RELOAD) { |         if (evt.info.auto_reload) { | ||||||
|             printf("\n    Example timer without reload\n"); |             printf("Timer Group with auto reload\n"); | ||||||
|         } else if (evt.type == TEST_WITH_RELOAD) { |  | ||||||
|             printf("\n    Example timer with auto reload\n"); |  | ||||||
|         } else { |         } 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 */ |         /* Print the timer values passed by event */ | ||||||
|         printf("------- EVENT TIME --------\n"); |         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 */ |         /* Print the timer values as visible by this task */ | ||||||
|         printf("-------- TASK TIME --------\n"); |         printf("-------- TASK TIME --------\n"); | ||||||
|         uint64_t task_counter_value; |         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); |         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); |  | ||||||
| } |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 morris
					morris