|
|
@@ -9,131 +9,119 @@
|
|
|
#include "freertos/task.h"
|
|
|
#include "freertos/queue.h"
|
|
|
#include "driver/timer.h"
|
|
|
+#include "esp_log.h"
|
|
|
|
|
|
-#define TIMER_DIVIDER (16) // Hardware timer clock divider
|
|
|
-#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
|
|
|
+#define TIMER_RESOLUTION_HZ 1000000 // 1MHz resolution
|
|
|
+#define TIMER_ALARM_PERIOD_S 0.5 // Alarm period 0.5s
|
|
|
|
|
|
-typedef struct {
|
|
|
- int timer_group;
|
|
|
- int timer_idx;
|
|
|
- int alarm_interval;
|
|
|
- bool auto_reload;
|
|
|
-} example_timer_info_t;
|
|
|
+static const char *TAG = "example";
|
|
|
|
|
|
/**
|
|
|
* @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;
|
|
|
+ uint64_t timer_count_value;
|
|
|
} example_timer_event_t;
|
|
|
|
|
|
-static xQueueHandle s_timer_queue;
|
|
|
-
|
|
|
-/*
|
|
|
- * A simple helper function to print the raw timer counter value
|
|
|
- * and the counter value converted to seconds
|
|
|
+/**
|
|
|
+ * @brief Timer user data, will be pass to timer alarm callback
|
|
|
*/
|
|
|
-static void inline print_timer_counter(uint64_t counter_value)
|
|
|
-{
|
|
|
- printf("Counter: 0x%08x%08x\r\n", (uint32_t) (counter_value >> 32),
|
|
|
- (uint32_t) (counter_value));
|
|
|
- printf("Time : %.8f s\r\n", (double) counter_value / TIMER_SCALE);
|
|
|
-}
|
|
|
+typedef struct {
|
|
|
+ xQueueHandle user_queue;
|
|
|
+ int timer_group;
|
|
|
+ int timer_idx;
|
|
|
+ int alarm_value;
|
|
|
+ bool auto_reload;
|
|
|
+} example_timer_user_data_t;
|
|
|
|
|
|
static bool IRAM_ATTR timer_group_isr_callback(void *args)
|
|
|
{
|
|
|
BaseType_t high_task_awoken = pdFALSE;
|
|
|
- example_timer_info_t *info = (example_timer_info_t *) args;
|
|
|
-
|
|
|
- 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 task */
|
|
|
+ example_timer_user_data_t *user_data = (example_timer_user_data_t *) args;
|
|
|
+ // fetch current count value
|
|
|
+ uint64_t timer_count_value = timer_group_get_counter_value_in_isr(user_data->timer_group, user_data->timer_idx);
|
|
|
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
|
|
|
+ .timer_count_value = timer_count_value,
|
|
|
};
|
|
|
|
|
|
- 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);
|
|
|
+ // set new alarm value if necessary
|
|
|
+ if (!user_data->auto_reload) {
|
|
|
+ user_data->alarm_value += TIMER_ALARM_PERIOD_S * TIMER_RESOLUTION_HZ;
|
|
|
+ timer_group_set_alarm_value_in_isr(user_data->timer_group, user_data->timer_idx, user_data->alarm_value);
|
|
|
}
|
|
|
|
|
|
- /* Now just send the event data back to the main program task */
|
|
|
- xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken);
|
|
|
+ // Send the event data back to the main program task
|
|
|
+ xQueueSendFromISR(user_data->user_queue, &evt, &high_task_awoken);
|
|
|
|
|
|
- return high_task_awoken == pdTRUE; // return whether we need to yield at the end of ISR
|
|
|
+ return high_task_awoken == pdTRUE; // return whether a task switch is needed
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @brief Initialize selected timer of timer group
|
|
|
- *
|
|
|
- * @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_tg_timer_init(int group, int timer, bool auto_reload, int timer_interval_sec)
|
|
|
+static void example_tg_timer_init(example_timer_user_data_t *user_data)
|
|
|
{
|
|
|
- /* Select and initialize basic parameters of the timer */
|
|
|
+ int group = user_data->timer_group;
|
|
|
+ int timer = user_data->timer_idx;
|
|
|
+
|
|
|
timer_config_t config = {
|
|
|
- .divider = TIMER_DIVIDER,
|
|
|
+ .clk_src = TIMER_SRC_CLK_APB,
|
|
|
+ .divider = APB_CLK_FREQ / TIMER_RESOLUTION_HZ,
|
|
|
.counter_dir = TIMER_COUNT_UP,
|
|
|
.counter_en = TIMER_PAUSE,
|
|
|
.alarm_en = TIMER_ALARM_EN,
|
|
|
- .auto_reload = auto_reload,
|
|
|
- }; // default clock source is APB
|
|
|
- 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(group, timer, 0);
|
|
|
-
|
|
|
- /* Configure the alarm value and the interrupt on alarm. */
|
|
|
- timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);
|
|
|
- timer_enable_intr(group, timer);
|
|
|
-
|
|
|
- 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);
|
|
|
+ .auto_reload = user_data->auto_reload,
|
|
|
+ };
|
|
|
+ ESP_ERROR_CHECK(timer_init(group, timer, &config));
|
|
|
+
|
|
|
+ // For the timer counter to a initial value
|
|
|
+ ESP_ERROR_CHECK(timer_set_counter_value(group, timer, 0));
|
|
|
+ // Set alarm value and enable alarm interrupt
|
|
|
+ ESP_ERROR_CHECK(timer_set_alarm_value(group, timer, user_data->alarm_value));
|
|
|
+ ESP_ERROR_CHECK(timer_enable_intr(group, timer));
|
|
|
+ // Hook interrupt callback
|
|
|
+ ESP_ERROR_CHECK(timer_isr_callback_add(group, timer, timer_group_isr_callback, user_data, 0));
|
|
|
+ // Start timer
|
|
|
+ ESP_ERROR_CHECK(timer_start(group, timer));
|
|
|
+}
|
|
|
+
|
|
|
+static void example_tg_timer_deinit(int group, int timer)
|
|
|
+{
|
|
|
+ ESP_ERROR_CHECK(timer_isr_callback_remove(group, timer));
|
|
|
+ ESP_ERROR_CHECK(timer_deinit(group, timer));
|
|
|
}
|
|
|
|
|
|
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) {
|
|
|
- example_timer_event_t evt;
|
|
|
- xQueueReceive(s_timer_queue, &evt, portMAX_DELAY);
|
|
|
-
|
|
|
- /* Print information that the timer reported an event */
|
|
|
- if (evt.info.auto_reload) {
|
|
|
- printf("Timer Group with auto reload\n");
|
|
|
- } else {
|
|
|
- printf("Timer Group without auto reload\n");
|
|
|
- }
|
|
|
- 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");
|
|
|
- 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.info.timer_group, evt.info.timer_idx, &task_counter_value);
|
|
|
- print_timer_counter(task_counter_value);
|
|
|
+ example_timer_user_data_t *user_data = calloc(1, sizeof(example_timer_user_data_t));
|
|
|
+ assert(user_data);
|
|
|
+ user_data->user_queue = xQueueCreate(10, sizeof(example_timer_event_t));
|
|
|
+ assert(user_data->user_queue);
|
|
|
+ user_data->timer_group = 0;
|
|
|
+ user_data->timer_idx = 0;
|
|
|
+ user_data->alarm_value = TIMER_ALARM_PERIOD_S * TIMER_RESOLUTION_HZ;
|
|
|
+
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "Init timer with auto-reload");
|
|
|
+ user_data->auto_reload = true;
|
|
|
+ example_tg_timer_init(user_data);
|
|
|
+
|
|
|
+ example_timer_event_t evt;
|
|
|
+ uint32_t test_count = 4;
|
|
|
+ while (test_count--) {
|
|
|
+ xQueueReceive(user_data->user_queue, &evt, portMAX_DELAY);
|
|
|
+ ESP_LOGI(TAG, "Timer auto reloaded, count value in ISR: %llu", evt.timer_count_value);
|
|
|
}
|
|
|
+ example_tg_timer_deinit(user_data->timer_group, user_data->timer_idx);
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "Init timer without auto-reload");
|
|
|
+ user_data->auto_reload = false;
|
|
|
+ example_tg_timer_init(user_data);
|
|
|
+
|
|
|
+ test_count = 4;
|
|
|
+ while (test_count--) {
|
|
|
+ xQueueReceive(user_data->user_queue, &evt, portMAX_DELAY);
|
|
|
+ ESP_LOGI(TAG, "Timer alarmed at %llu", evt.timer_count_value);
|
|
|
+ }
|
|
|
+ example_tg_timer_deinit(user_data->timer_group, user_data->timer_idx);
|
|
|
+
|
|
|
+ vQueueDelete(user_data->user_queue);
|
|
|
+ free(user_data);
|
|
|
}
|