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,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); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 morris
					morris