Select one of the symbols to view example projects that use it.
 
Outline
#include <stdlib.h>
#include <sys/lock.h>
#include "sdkconfig.h"
#define LOG_LOCAL_LEVEL
#include "freertos/FreeRTOS.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "driver/gptimer.h"
#include "esp_memory_utils.h"
#include "gptimer_priv.h"
TAG
gptimer_register_to_group(gptimer_t *)
gptimer_unregister_from_group(gptimer_t *)
gptimer_destroy(gptimer_t *)
gptimer_new_timer(const gptimer_config_t *, gptimer_handle_t *)
gptimer_del_timer(gptimer_handle_t)
gptimer_set_raw_count(gptimer_handle_t, unsigned long long)
gptimer_get_raw_count(gptimer_handle_t, unsigned long long *)
gptimer_get_resolution(gptimer_handle_t, uint32_t *)
gptimer_get_captured_count(gptimer_handle_t, uint64_t *)
gptimer_register_event_callbacks(gptimer_handle_t, const gptimer_event_callbacks_t *, void *)
gptimer_set_alarm_action(gptimer_handle_t, const gptimer_alarm_config_t *)
gptimer_enable(gptimer_handle_t)
gptimer_disable(gptimer_handle_t)
gptimer_start(gptimer_handle_t)
gptimer_stop(gptimer_handle_t)
gptimer_default_isr(void *)
Files
loading...
SourceVuESP-IDF Framework and ExamplesESP-IDFcomponents/esp_driver_gptimer/src/gptimer.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */ #include <stdlib.h> #include <sys/lock.h> #include "sdkconfig.h" #if CONFIG_GPTIMER_ENABLE_DEBUG_LOG // The local log level must be defined before including esp_log.h // Set the maximum log level for this source file #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG/* ... */ #endif #include "freertos/FreeRTOS.h" #include "esp_attr.h" #include "esp_err.h" #include "esp_log.h" #include "esp_check.h" #include "driver/gptimer.h" #include "esp_memory_utils.h" #include "gptimer_priv.h"8 includes static const char *TAG = "gptimer"; static void gptimer_default_isr(void *args); #if GPTIMER_USE_RETENTION_LINK static esp_err_t gptimer_create_sleep_retention_link_cb(void *timer) { int group_id = ((gptimer_t *)timer)->group->group_id; int timer_id = ((gptimer_t *)timer)->timer_id; esp_err_t err = sleep_retention_entries_create(tg_timer_reg_retention_info[group_id][timer_id].regdma_entry_array, tg_timer_reg_retention_info[group_id][timer_id].array_size, REGDMA_LINK_PRI_GPTIMER, tg_timer_reg_retention_info[group_id][timer_id].module); return err; }{...} static void gptimer_create_retention_module(gptimer_t *timer) { int group_id = timer->group->group_id; int timer_id = timer->timer_id; sleep_retention_module_t module = tg_timer_reg_retention_info[group_id][timer_id].module; if (sleep_retention_is_module_inited(module) && !sleep_retention_is_module_created(module)) { if (sleep_retention_module_allocate(module) != ESP_OK) { // even though the sleep retention module create failed, GPTimer driver should still work, so just warning here ESP_LOGW(TAG, "create retention link failed on TimerGroup%d Timer%d, power domain won't be turned off during sleep", group_id, timer_id); }{...} }{...} }{...} /* ... */#endif // GPTIMER_USE_RETENTION_LINK static esp_err_t gptimer_register_to_group(gptimer_t *timer) { gptimer_group_t *group = NULL; int timer_id = -1; for (int i = 0; i < SOC_TIMER_GROUPS; i++) { group = gptimer_acquire_group_handle(i); ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", i); // loop to search free timer in the group portENTER_CRITICAL(&group->spinlock); for (int j = 0; j < SOC_TIMER_GROUP_TIMERS_PER_GROUP; j++) { if (!group->timers[j]) { timer_id = j; group->timers[j] = timer; break; }{...} }{...} portEXIT_CRITICAL(&group->spinlock); if (timer_id < 0) { gptimer_release_group_handle(group); }{...} else { timer->timer_id = timer_id; timer->group = group; break; }{...} }{...} ESP_RETURN_ON_FALSE(timer_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free timer"); #if GPTIMER_USE_RETENTION_LINK sleep_retention_module_t module = tg_timer_reg_retention_info[group->group_id][timer_id].module; sleep_retention_module_init_param_t init_param = { .cbs = { .create = { .handle = gptimer_create_sleep_retention_link_cb, .arg = (void *)timer }{...}, }{...}, .depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM) }{...}; if (sleep_retention_module_init(module, &init_param) != ESP_OK) { // even though the sleep retention module init failed, RMT driver should still work, so just warning here ESP_LOGW(TAG, "init sleep retention failed on TimerGroup%d Timer%d, power domain may be turned off during sleep", group->group_id, timer_id); }{...} #endif/* ... */ // GPTIMER_USE_RETENTION_LINK return ESP_OK; }{ ... } static void gptimer_unregister_from_group(gptimer_t *timer) { gptimer_group_t *group = timer->group; int timer_id = timer->timer_id; portENTER_CRITICAL(&group->spinlock); group->timers[timer_id] = NULL; portEXIT_CRITICAL(&group->spinlock); #if GPTIMER_USE_RETENTION_LINK sleep_retention_module_t module = tg_timer_reg_retention_info[group->group_id][timer_id].module; if (sleep_retention_is_module_created(module)) { sleep_retention_module_free(module); }{...} if (sleep_retention_is_module_inited(module)) { sleep_retention_module_deinit(module); }{...} #endif/* ... */ // timer has a reference on group, release it now gptimer_release_group_handle(group); }{ ... } static esp_err_t gptimer_destroy(gptimer_t *timer) { if (timer->pm_lock) { ESP_RETURN_ON_ERROR(esp_pm_lock_delete(timer->pm_lock), TAG, "delete pm_lock failed"); }{...} if (timer->intr) { ESP_RETURN_ON_ERROR(esp_intr_free(timer->intr), TAG, "delete interrupt service failed"); }{...} if (timer->group) { gptimer_unregister_from_group(timer); }{...} free(timer); return ESP_OK; }{ ... } esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer) { #if CONFIG_GPTIMER_ENABLE_DEBUG_LOG esp_log_level_set(TAG, ESP_LOG_DEBUG); #endif esp_err_t ret = ESP_OK; gptimer_t *timer = NULL; ESP_RETURN_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(config->resolution_hz, ESP_ERR_INVALID_ARG, TAG, "invalid timer resolution:%"PRIu32, config->resolution_hz); if (config->intr_priority) { ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & GPTIMER_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", config->intr_priority); }{...} bool allow_pd = (config->flags.allow_pd == 1) || (config->flags.backup_before_sleep == 1); #if !SOC_TIMER_SUPPORT_SLEEP_RETENTION ESP_RETURN_ON_FALSE(allow_pd == false, ESP_ERR_NOT_SUPPORTED, TAG, "not able to power down in light sleep"); #endif // SOC_TIMER_SUPPORT_SLEEP_RETENTION timer = heap_caps_calloc(1, sizeof(gptimer_t), GPTIMER_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for gptimer"); // register timer to the group (because one group can have several timers) ESP_GOTO_ON_ERROR(gptimer_register_to_group(timer), err, TAG, "register timer failed"); gptimer_group_t *group = timer->group; int group_id = group->group_id; int timer_id = timer->timer_id; if (allow_pd) { #if GPTIMER_USE_RETENTION_LINK gptimer_create_retention_module(timer); #endif // GPTIMER_USE_RETENTION_LINK }{...} // initialize HAL layer timer_hal_init(&timer->hal, group_id, timer_id); // select clock source, set clock resolution ESP_GOTO_ON_ERROR(gptimer_select_periph_clock(timer, config->clk_src, config->resolution_hz), err, TAG, "set periph clock failed"); // initialize counter value to zero timer_hal_set_counter_value(&timer->hal, 0); // set counting direction timer_ll_set_count_direction(timer->hal.dev, timer_id, config->direction); // interrupt register is shared by all timers in the same group portENTER_CRITICAL(&group->spinlock); timer_ll_enable_intr(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer_id), false); // disable interrupt timer_ll_clear_intr_status(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer_id)); // clear pending interrupt event portEXIT_CRITICAL(&group->spinlock); // initialize other members of timer timer->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; // put the timer driver to the init state atomic_init(&timer->fsm, GPTIMER_FSM_INIT); timer->direction = config->direction; timer->intr_priority = config->intr_priority; timer->flags.intr_shared = config->flags.intr_shared; ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, resolution=%"PRIu32"Hz", group_id, timer_id, timer, timer->resolution_hz); *ret_timer = timer; return ESP_OK; err: if (timer) { gptimer_destroy(timer); }{...} return ret; }{ ... } esp_err_t gptimer_del_timer(gptimer_handle_t timer) { ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(atomic_load(&timer->fsm) == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state"); gptimer_group_t *group = timer->group; gptimer_clock_source_t clk_src = timer->clk_src; int group_id = group->group_id; int timer_id = timer->timer_id; timer_hal_context_t *hal = &timer->hal; ESP_LOGD(TAG, "del timer (%d,%d)", group_id, timer_id); // disable the source clock GPTIMER_CLOCK_SRC_ATOMIC() { timer_ll_enable_clock(hal->dev, hal->timer_id, false); }{...} timer_hal_deinit(hal); // recycle memory resource ESP_RETURN_ON_ERROR(gptimer_destroy(timer), TAG, "destroy gptimer failed"); switch (clk_src) { #if SOC_TIMER_GROUP_SUPPORT_RC_FAST case GPTIMER_CLK_SRC_RC_FAST: periph_rtc_dig_clk8m_disable(); break;/* ... */ #endif // SOC_TIMER_GROUP_SUPPORT_RC_FAST default: break;... }{...} return ESP_OK; }{ ... } esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, unsigned long long value) { ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); portENTER_CRITICAL_SAFE(&timer->spinlock); timer_hal_set_counter_value(&timer->hal, value); portEXIT_CRITICAL_SAFE(&timer->spinlock); return ESP_OK; }{ ... } esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *value) { ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); portENTER_CRITICAL_SAFE(&timer->spinlock); *value = timer_hal_capture_and_get_counter_value(&timer->hal); portEXIT_CRITICAL_SAFE(&timer->spinlock); return ESP_OK; }{ ... } esp_err_t gptimer_get_resolution(gptimer_handle_t timer, uint32_t *out_resolution) { ESP_RETURN_ON_FALSE(timer && out_resolution, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); *out_resolution = timer->resolution_hz; return ESP_OK; }{ ... } esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value) { ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); portENTER_CRITICAL_SAFE(&timer->spinlock); *value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id); portEXIT_CRITICAL_SAFE(&timer->spinlock); return ESP_OK; }{ ... } esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data) { gptimer_group_t *group = NULL; ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); group = timer->group; int group_id = group->group_id; int timer_id = timer->timer_id; #if CONFIG_GPTIMER_ISR_IRAM_SAFE if (cbs->on_alarm) { ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_alarm), ESP_ERR_INVALID_ARG, TAG, "on_alarm callback not in IRAM"); }{...} if (user_data) { ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM"); }{...} #endif/* ... */ // lazy install interrupt service if (!timer->intr) { ESP_RETURN_ON_FALSE(atomic_load(&timer->fsm) == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state"); // if user wants to control the interrupt allocation more precisely, we can expose more flags in `gptimer_config_t` int isr_flags = timer->flags.intr_shared ? ESP_INTR_FLAG_SHARED | GPTIMER_INTR_ALLOC_FLAGS : GPTIMER_INTR_ALLOC_FLAGS; if (timer->intr_priority) { isr_flags |= 1 << (timer->intr_priority); }{...} ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_id].timer_irq_id[timer_id], isr_flags, (uint32_t)timer_ll_get_intr_status_reg(timer->hal.dev), TIMER_LL_EVENT_ALARM(timer_id), gptimer_default_isr, timer, &timer->intr), TAG, "install interrupt service failed"); }{...} // enable/disable GPTimer interrupt events portENTER_CRITICAL(&group->spinlock); timer_ll_enable_intr(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer->timer_id), cbs->on_alarm != NULL); // enable timer interrupt portEXIT_CRITICAL(&group->spinlock); timer->on_alarm = cbs->on_alarm; timer->user_ctx = user_data; return ESP_OK; }{ ... } esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config) { ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); if (config) { #if CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM ESP_RETURN_ON_FALSE_ISR(esp_ptr_internal(config), ESP_ERR_INVALID_ARG, TAG, "alarm config struct not in internal RAM"); #endif // When auto_reload is enabled, alarm_count should not be equal to reload_count bool valid_auto_reload = !config->flags.auto_reload_on_alarm || config->alarm_count != config->reload_count; ESP_RETURN_ON_FALSE_ISR(valid_auto_reload, ESP_ERR_INVALID_ARG, TAG, "reload count can't equal to alarm count"); portENTER_CRITICAL_SAFE(&timer->spinlock); timer->reload_count = config->reload_count; timer->alarm_count = config->alarm_count; timer->flags.auto_reload_on_alarm = config->flags.auto_reload_on_alarm; timer->flags.alarm_en = true; timer_ll_set_reload_value(timer->hal.dev, timer->timer_id, config->reload_count); timer_ll_set_alarm_value(timer->hal.dev, timer->timer_id, config->alarm_count); portEXIT_CRITICAL_SAFE(&timer->spinlock); }{...} else { portENTER_CRITICAL_SAFE(&timer->spinlock); timer->flags.auto_reload_on_alarm = false; timer->flags.alarm_en = false; portEXIT_CRITICAL_SAFE(&timer->spinlock); }{...} portENTER_CRITICAL_SAFE(&timer->spinlock); timer_ll_enable_auto_reload(timer->hal.dev, timer->timer_id, timer->flags.auto_reload_on_alarm); timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, timer->flags.alarm_en); portEXIT_CRITICAL_SAFE(&timer->spinlock); return ESP_OK; }{ ... } esp_err_t gptimer_enable(gptimer_handle_t timer) { ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); gptimer_fsm_t expected_fsm = GPTIMER_FSM_INIT; ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE), ESP_ERR_INVALID_STATE, TAG, "timer not in init state"); // acquire power manager lock if (timer->pm_lock) { ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(timer->pm_lock), TAG, "acquire pm_lock failed"); }{...} // enable interrupt service if (timer->intr) { ESP_RETURN_ON_ERROR(esp_intr_enable(timer->intr), TAG, "enable interrupt service failed"); }{...} return ESP_OK; }{ ... } esp_err_t gptimer_disable(gptimer_handle_t timer) { ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE; ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_INIT), ESP_ERR_INVALID_STATE, TAG, "timer not in enable state"); // disable interrupt service if (timer->intr) { ESP_RETURN_ON_ERROR(esp_intr_disable(timer->intr), TAG, "disable interrupt service failed"); }{...} // release power manager lock if (timer->pm_lock) { ESP_RETURN_ON_ERROR(esp_pm_lock_release(timer->pm_lock), TAG, "release pm_lock failed"); }{...} return ESP_OK; }{ ... } esp_err_t gptimer_start(gptimer_handle_t timer) { ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE; if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_RUN_WAIT)) { // the register used by the following LL functions are shared with other API, // which is possible to run along with this function, so we need to protect portENTER_CRITICAL_SAFE(&timer->spinlock); timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, timer->flags.alarm_en); // Note here, if the alarm target is set very close to the current counter value // an alarm interrupt may be triggered very quickly after we start the timer timer_ll_enable_counter(timer->hal.dev, timer->timer_id, true); atomic_store(&timer->fsm, GPTIMER_FSM_RUN); portEXIT_CRITICAL_SAFE(&timer->spinlock); }{...} else { ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "timer is not ready for a new start"); }{...} return ESP_OK; }{ ... } esp_err_t gptimer_stop(gptimer_handle_t timer) { ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); gptimer_fsm_t expected_fsm = GPTIMER_FSM_RUN; if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE_WAIT)) { // disable counter, alarm, auto-reload portENTER_CRITICAL_SAFE(&timer->spinlock); timer_ll_enable_counter(timer->hal.dev, timer->timer_id, false); timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, false); atomic_store(&timer->fsm, GPTIMER_FSM_ENABLE); portEXIT_CRITICAL_SAFE(&timer->spinlock); }{...} else { ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "timer is not running"); }{...} return ESP_OK; }{ ... } static void gptimer_default_isr(void *args) { bool need_yield = false; gptimer_t *timer = (gptimer_t *)args; gptimer_group_t *group = timer->group; gptimer_alarm_cb_t on_alarm_cb = timer->on_alarm; uint32_t intr_status = timer_ll_get_intr_status(timer->hal.dev); if (intr_status & TIMER_LL_EVENT_ALARM(timer->timer_id)) { // Note: when alarm event happens, the alarm will be disabled automatically by hardware gptimer_alarm_event_data_t edata = { .count_value = timer_hal_capture_and_get_counter_value(&timer->hal), .alarm_value = timer->alarm_count, }{...}; portENTER_CRITICAL_ISR(&group->spinlock); timer_ll_clear_intr_status(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer->timer_id)); // for auto-reload, we need to re-enable the alarm manually if (timer->flags.auto_reload_on_alarm) { timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, true); }{...} portEXIT_CRITICAL_ISR(&group->spinlock); if (on_alarm_cb) { if (on_alarm_cb(timer, &edata, timer->user_ctx)) { need_yield = true; }{...} }{...} }{...} if (need_yield) { portYIELD_FROM_ISR(); }{...} }{ ... }
Details
Show:
from
Types: Columns:
This file uses the notable symbols shown below. Click anywhere in the file to view more details.