gptimer.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. // #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG // uncomment this line to enable debug logs
  7. #include <stdlib.h>
  8. #include <sys/lock.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "esp_attr.h"
  11. #include "esp_err.h"
  12. #include "esp_heap_caps.h"
  13. #include "esp_intr_alloc.h"
  14. #include "esp_log.h"
  15. #include "esp_check.h"
  16. #include "esp_pm.h"
  17. #include "driver/gptimer.h"
  18. #include "hal/timer_types.h"
  19. #include "hal/timer_hal.h"
  20. #include "hal/timer_ll.h"
  21. #include "soc/timer_periph.h"
  22. #include "soc/soc_memory_types.h"
  23. #include "esp_private/periph_ctrl.h"
  24. #include "esp_private/esp_clk.h"
  25. // If ISR handler is allowed to run whilst cache is disabled,
  26. // Make sure all the code and related variables used by the handler are in the SRAM
  27. #if CONFIG_GPTIMER_ISR_IRAM_SAFE
  28. #define GPTIMER_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
  29. #define GPTIMER_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
  30. #else
  31. #define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
  32. #define GPTIMER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
  33. #endif //CONFIG_GPTIMER_ISR_IRAM_SAFE
  34. #if CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
  35. #define GPTIMER_CTRL_FUNC_ATTR IRAM_ATTR
  36. #else
  37. #define GPTIMER_CTRL_FUNC_ATTR
  38. #endif // CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
  39. #define GPTIMER_PM_LOCK_NAME_LEN_MAX 16
  40. static const char *TAG = "gptimer";
  41. typedef struct gptimer_platform_t gptimer_platform_t;
  42. typedef struct gptimer_group_t gptimer_group_t;
  43. typedef struct gptimer_t gptimer_t;
  44. struct gptimer_platform_t {
  45. _lock_t mutex; // platform level mutex lock
  46. gptimer_group_t *groups[SOC_TIMER_GROUPS]; // timer group pool
  47. int group_ref_counts[SOC_TIMER_GROUPS]; // reference count used to protect group install/uninstall
  48. };
  49. struct gptimer_group_t {
  50. int group_id;
  51. portMUX_TYPE spinlock; // to protect per-group register level concurrent access
  52. gptimer_t *timers[SOC_TIMER_GROUP_TIMERS_PER_GROUP];
  53. };
  54. typedef enum {
  55. GPTIMER_FSM_STOP,
  56. GPTIMER_FSM_START,
  57. } gptimer_lifecycle_fsm_t;
  58. struct gptimer_t {
  59. gptimer_group_t *group;
  60. int timer_id;
  61. unsigned int resolution_hz;
  62. unsigned long long reload_count;
  63. unsigned long long alarm_count;
  64. gptimer_count_direction_t direction;
  65. timer_hal_context_t hal;
  66. gptimer_lifecycle_fsm_t fsm; // access to fsm should be protect by spinlock, as fsm is also accessed from ISR handler
  67. intr_handle_t intr;
  68. _lock_t mutex; // to protect other resource allocation, like interrupt handle
  69. portMUX_TYPE spinlock; // to protect per-timer resources concurent accessed by task and ISR handler
  70. gptimer_alarm_cb_t on_alarm;
  71. void *user_ctx;
  72. esp_pm_lock_handle_t pm_lock; // power management lock
  73. #if CONFIG_PM_ENABLE
  74. char pm_lock_name[GPTIMER_PM_LOCK_NAME_LEN_MAX]; // pm lock name
  75. #endif
  76. struct {
  77. uint32_t intr_shared: 1;
  78. uint32_t auto_reload_on_alarm: 1;
  79. uint32_t alarm_en: 1;
  80. } flags;
  81. };
  82. // gptimer driver platform, it's always a singleton
  83. static gptimer_platform_t s_platform;
  84. static gptimer_group_t *gptimer_acquire_group_handle(int group_id);
  85. static void gptimer_release_group_handle(gptimer_group_t *group);
  86. static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t src_clk, uint32_t resolution_hz);
  87. static esp_err_t gptimer_install_interrupt(gptimer_t *timer);
  88. IRAM_ATTR static void gptimer_default_isr(void *args);
  89. esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer)
  90. {
  91. esp_err_t ret = ESP_OK;
  92. gptimer_group_t *group = NULL;
  93. gptimer_t *timer = NULL;
  94. int group_id = -1;
  95. int timer_id = -1;
  96. ESP_GOTO_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
  97. ESP_GOTO_ON_FALSE(config->resolution_hz, ESP_ERR_INVALID_ARG, err, TAG, "invalid timer resolution:%d", config->resolution_hz);
  98. timer = heap_caps_calloc(1, sizeof(gptimer_t), GPTIMER_MEM_ALLOC_CAPS);
  99. ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for gptimer");
  100. for (int i = 0; (i < SOC_TIMER_GROUPS) && (timer_id < 0); i++) {
  101. group = gptimer_acquire_group_handle(i);
  102. ESP_GOTO_ON_FALSE(group, ESP_ERR_NO_MEM, err, TAG, "no mem for group (%d)", group_id);
  103. // loop to search free timer in the group
  104. portENTER_CRITICAL(&group->spinlock);
  105. for (int j = 0; j < SOC_TIMER_GROUP_TIMERS_PER_GROUP; j++) {
  106. if (!group->timers[j]) {
  107. group_id = i;
  108. timer_id = j;
  109. group->timers[j] = timer;
  110. break;
  111. }
  112. }
  113. portEXIT_CRITICAL(&group->spinlock);
  114. if (timer_id < 0) {
  115. gptimer_release_group_handle(group);
  116. group = NULL;
  117. }
  118. }
  119. ESP_GOTO_ON_FALSE(timer_id != -1, ESP_ERR_NOT_FOUND, err, TAG, "no free timer");
  120. timer->timer_id = timer_id;
  121. timer->group = group;
  122. // initialize HAL layer
  123. timer_hal_init(&timer->hal, group_id, timer_id);
  124. // stop counter, alarm, auto-reload
  125. timer_ll_enable_counter(timer->hal.dev, timer_id, false);
  126. timer_ll_enable_auto_reload(timer->hal.dev, timer_id, false);
  127. timer_ll_enable_alarm(timer->hal.dev, timer_id, false);
  128. // select clock source, set clock resolution
  129. ESP_GOTO_ON_ERROR(gptimer_select_periph_clock(timer, config->clk_src, config->resolution_hz), err, TAG, "set periph clock failed");
  130. // initialize counter value to zero
  131. timer_hal_set_counter_value(&timer->hal, 0);
  132. // set counting direction
  133. timer_ll_set_count_direction(timer->hal.dev, timer_id, config->direction);
  134. // interrupt register is shared by all timers in the same group
  135. portENTER_CRITICAL(&group->spinlock);
  136. timer_ll_enable_intr(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer_id), false); // disable interrupt
  137. timer_ll_clear_intr_status(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer_id)); // clear pending interrupt event
  138. portEXIT_CRITICAL(&group->spinlock);
  139. // initialize other members of timer
  140. timer->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
  141. timer->fsm = GPTIMER_FSM_STOP;
  142. timer->direction = config->direction;
  143. timer->flags.intr_shared = config->flags.intr_shared;
  144. _lock_init(&timer->mutex);
  145. ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, resolution=%uHz", group_id, timer_id, timer, timer->resolution_hz);
  146. *ret_timer = timer;
  147. return ESP_OK;
  148. err:
  149. if (timer) {
  150. if (timer->pm_lock) {
  151. esp_pm_lock_delete(timer->pm_lock);
  152. }
  153. free(timer);
  154. }
  155. if (group) {
  156. gptimer_release_group_handle(group);
  157. }
  158. return ret;
  159. }
  160. esp_err_t gptimer_del_timer(gptimer_handle_t timer)
  161. {
  162. gptimer_group_t *group = NULL;
  163. bool valid_state = true;
  164. ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  165. portENTER_CRITICAL(&timer->spinlock);
  166. if (timer->fsm != GPTIMER_FSM_STOP) {
  167. valid_state = false;
  168. }
  169. portEXIT_CRITICAL(&timer->spinlock);
  170. ESP_RETURN_ON_FALSE(valid_state, ESP_ERR_INVALID_STATE, TAG, "can't delete timer as it's not in stop state");
  171. group = timer->group;
  172. int group_id = group->group_id;
  173. int timer_id = timer->timer_id;
  174. if (timer->intr) {
  175. esp_intr_free(timer->intr);
  176. ESP_LOGD(TAG, "uninstall interrupt service for timer (%d,%d)", group_id, timer_id);
  177. }
  178. if (timer->pm_lock) {
  179. esp_pm_lock_delete(timer->pm_lock);
  180. ESP_LOGD(TAG, "uninstall APB_FREQ_MAX lock for timer (%d,%d)", group_id, timer_id);
  181. }
  182. _lock_close(&timer->mutex);
  183. free(timer);
  184. ESP_LOGD(TAG, "del timer (%d,%d)", group_id, timer_id);
  185. portENTER_CRITICAL(&group->spinlock);
  186. group->timers[timer_id] = NULL;
  187. portEXIT_CRITICAL(&group->spinlock);
  188. // timer has a reference on group, release it now
  189. gptimer_release_group_handle(group);
  190. return ESP_OK;
  191. }
  192. GPTIMER_CTRL_FUNC_ATTR
  193. esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, unsigned long long value)
  194. {
  195. ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  196. portENTER_CRITICAL_SAFE(&timer->spinlock);
  197. timer_hal_set_counter_value(&timer->hal, value);
  198. portEXIT_CRITICAL_SAFE(&timer->spinlock);
  199. return ESP_OK;
  200. }
  201. GPTIMER_CTRL_FUNC_ATTR
  202. esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *value)
  203. {
  204. ESP_RETURN_ON_FALSE(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  205. portENTER_CRITICAL_SAFE(&timer->spinlock);
  206. *value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id);
  207. portEXIT_CRITICAL_SAFE(&timer->spinlock);
  208. return ESP_OK;
  209. }
  210. esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data)
  211. {
  212. gptimer_group_t *group = NULL;
  213. ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  214. group = timer->group;
  215. #if CONFIG_GPTIMER_ISR_IRAM_SAFE
  216. if (cbs->on_alarm) {
  217. ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_alarm), ESP_ERR_INVALID_ARG, TAG, "on_alarm callback not in IRAM");
  218. }
  219. if (user_data) {
  220. ESP_RETURN_ON_FALSE(esp_ptr_in_dram(user_data) ||
  221. esp_ptr_in_diram_dram(user_data) ||
  222. esp_ptr_in_rtc_dram_fast(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in DRAM");
  223. }
  224. #endif
  225. // lazy install interrupt service
  226. ESP_RETURN_ON_ERROR(gptimer_install_interrupt(timer), TAG, "install interrupt service failed");
  227. // enable/disable GPTimer interrupt events
  228. portENTER_CRITICAL_SAFE(&group->spinlock);
  229. timer_ll_enable_intr(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer->timer_id), cbs->on_alarm); // enable timer interrupt
  230. portEXIT_CRITICAL_SAFE(&group->spinlock);
  231. timer->on_alarm = cbs->on_alarm;
  232. timer->user_ctx = user_data;
  233. return ESP_OK;
  234. }
  235. GPTIMER_CTRL_FUNC_ATTR
  236. esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config)
  237. {
  238. ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  239. if (config) {
  240. // When auto_reload is enabled, alarm_count should not be equal to reload_count
  241. bool valid_auto_reload = !config->flags.auto_reload_on_alarm || config->alarm_count != config->reload_count;
  242. ESP_RETURN_ON_FALSE(valid_auto_reload, ESP_ERR_INVALID_ARG, TAG, "reload count can't equal to alarm count");
  243. timer->reload_count = config->reload_count;
  244. timer->alarm_count = config->alarm_count;
  245. timer->flags.auto_reload_on_alarm = config->flags.auto_reload_on_alarm;
  246. timer->flags.alarm_en = true;
  247. portENTER_CRITICAL_SAFE(&timer->spinlock);
  248. timer_ll_set_reload_value(timer->hal.dev, timer->timer_id, config->reload_count);
  249. timer_ll_set_alarm_value(timer->hal.dev, timer->timer_id, config->alarm_count);
  250. portEXIT_CRITICAL_SAFE(&timer->spinlock);
  251. } else {
  252. timer->flags.auto_reload_on_alarm = false;
  253. timer->flags.alarm_en = false;
  254. }
  255. portENTER_CRITICAL_SAFE(&timer->spinlock);
  256. timer_ll_enable_auto_reload(timer->hal.dev, timer->timer_id, timer->flags.auto_reload_on_alarm);
  257. timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, timer->flags.alarm_en);
  258. portEXIT_CRITICAL_SAFE(&timer->spinlock);
  259. return ESP_OK;
  260. }
  261. GPTIMER_CTRL_FUNC_ATTR
  262. esp_err_t gptimer_start(gptimer_handle_t timer)
  263. {
  264. ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  265. // acquire power manager lock
  266. if (timer->pm_lock) {
  267. ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(timer->pm_lock), TAG, "acquire APB_FREQ_MAX lock failed");
  268. }
  269. // interrupt interupt service
  270. if (timer->intr) {
  271. ESP_RETURN_ON_ERROR(esp_intr_enable(timer->intr), TAG, "enable interrupt service failed");
  272. }
  273. portENTER_CRITICAL_SAFE(&timer->spinlock);
  274. timer_ll_enable_counter(timer->hal.dev, timer->timer_id, true);
  275. timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, timer->flags.alarm_en);
  276. timer->fsm = GPTIMER_FSM_START;
  277. portEXIT_CRITICAL_SAFE(&timer->spinlock);
  278. return ESP_OK;
  279. }
  280. GPTIMER_CTRL_FUNC_ATTR
  281. esp_err_t gptimer_stop(gptimer_handle_t timer)
  282. {
  283. ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  284. // disable counter, alarm, autoreload
  285. portENTER_CRITICAL_SAFE(&timer->spinlock);
  286. timer_ll_enable_counter(timer->hal.dev, timer->timer_id, false);
  287. timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, false);
  288. timer->fsm = GPTIMER_FSM_STOP;
  289. portEXIT_CRITICAL_SAFE(&timer->spinlock);
  290. // disable interrupt service
  291. if (timer->intr) {
  292. ESP_RETURN_ON_ERROR(esp_intr_disable(timer->intr), TAG, "disable interrupt service failed");
  293. }
  294. // release power manager lock
  295. if (timer->pm_lock) {
  296. ESP_RETURN_ON_ERROR(esp_pm_lock_release(timer->pm_lock), TAG, "release APB_FREQ_MAX lock failed");
  297. }
  298. return ESP_OK;
  299. }
  300. static gptimer_group_t *gptimer_acquire_group_handle(int group_id)
  301. {
  302. // esp_log_level_set(TAG, ESP_LOG_DEBUG);
  303. bool new_group = false;
  304. gptimer_group_t *group = NULL;
  305. // prevent install timer group concurrently
  306. _lock_acquire(&s_platform.mutex);
  307. if (!s_platform.groups[group_id]) {
  308. group = heap_caps_calloc(1, sizeof(gptimer_group_t), GPTIMER_MEM_ALLOC_CAPS);
  309. if (group) {
  310. new_group = true;
  311. s_platform.groups[group_id] = group;
  312. // initialize timer group members
  313. group->group_id = group_id;
  314. group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
  315. // enable APB access timer registers
  316. periph_module_enable(timer_group_periph_signals.groups[group_id].module);
  317. }
  318. } else {
  319. group = s_platform.groups[group_id];
  320. }
  321. // someone acquired the group handle means we have a new object that refer to this group
  322. s_platform.group_ref_counts[group_id]++;
  323. _lock_release(&s_platform.mutex);
  324. if (new_group) {
  325. ESP_LOGD(TAG, "new group (%d) @%p", group_id, group);
  326. }
  327. return group;
  328. }
  329. static void gptimer_release_group_handle(gptimer_group_t *group)
  330. {
  331. int group_id = group->group_id;
  332. bool do_deinitialize = false;
  333. _lock_acquire(&s_platform.mutex);
  334. s_platform.group_ref_counts[group_id]--;
  335. if (s_platform.group_ref_counts[group_id] == 0) {
  336. assert(s_platform.groups[group_id]);
  337. do_deinitialize = true;
  338. s_platform.groups[group_id] = NULL;
  339. // Theoretically we need to disable the peripheral clock for the timer group
  340. // However, next time when we enable the peripheral again, the registers will be reset to default value, including the watchdog registers inside the group
  341. // Then the watchdog will go into reset state, e.g. the flash boot watchdog is enabled again and reset the system very soon
  342. // periph_module_disable(timer_group_periph_signals.groups[group_id].module);
  343. }
  344. _lock_release(&s_platform.mutex);
  345. if (do_deinitialize) {
  346. free(group);
  347. ESP_LOGD(TAG, "del group (%d)", group_id);
  348. }
  349. }
  350. static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t src_clk, uint32_t resolution_hz)
  351. {
  352. unsigned int counter_src_hz = 0;
  353. esp_err_t ret = ESP_OK;
  354. int timer_id = timer->timer_id;
  355. switch (src_clk) {
  356. case GPTIMER_CLK_SRC_APB:
  357. counter_src_hz = esp_clk_apb_freq();
  358. #if CONFIG_PM_ENABLE
  359. sprintf(timer->pm_lock_name, "gptimer_%d_%d", timer->group->group_id, timer_id); // e.g. gptimer_0_0
  360. ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, timer->pm_lock_name, &timer->pm_lock);
  361. ESP_RETURN_ON_ERROR(ret, TAG, "create APB_FREQ_MAX lock failed");
  362. ESP_LOGD(TAG, "install APB_FREQ_MAX lock for timer (%d,%d)", timer->group->group_id, timer_id);
  363. #endif
  364. break;
  365. #if SOC_TIMER_GROUP_SUPPORT_XTAL
  366. case GPTIMER_CLK_SRC_XTAL:
  367. counter_src_hz = esp_clk_xtal_freq();
  368. break;
  369. #endif
  370. default:
  371. ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "clock source %d is not support", src_clk);
  372. break;
  373. }
  374. timer_ll_set_clock_source(timer->hal.dev, timer_id, src_clk);
  375. unsigned int prescale = counter_src_hz / resolution_hz; // potential resolution loss here
  376. timer_ll_set_clock_prescale(timer->hal.dev, timer_id, prescale);
  377. timer->resolution_hz = counter_src_hz / prescale; // this is the real resolution
  378. if (timer->resolution_hz != resolution_hz) {
  379. ESP_LOGW(TAG, "resolution lost, expect %ul, real %ul", resolution_hz, timer->resolution_hz);
  380. }
  381. return ret;
  382. }
  383. static esp_err_t gptimer_install_interrupt(gptimer_t *timer)
  384. {
  385. esp_err_t ret = ESP_OK;
  386. gptimer_group_t *group = timer->group;
  387. int group_id = group->group_id;
  388. int timer_id = timer->timer_id;
  389. bool new_isr = false;
  390. if (!timer->intr) {
  391. _lock_acquire(&timer->mutex);
  392. if (!timer->intr) {
  393. // if user wants to control the interrupt allocation more precisely, we can expose more flags in `gptimer_config_t`
  394. int extra_isr_flags = timer->flags.intr_shared ? ESP_INTR_FLAG_SHARED : 0;
  395. ret = esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_id].timer_irq_id[timer_id], extra_isr_flags | GPTIMER_INTR_ALLOC_FLAGS,
  396. (uint32_t)timer_ll_get_intr_status_reg(timer->hal.dev), TIMER_LL_EVENT_ALARM(timer_id),
  397. gptimer_default_isr, timer, &timer->intr);
  398. new_isr = (ret == ESP_OK);
  399. }
  400. _lock_release(&timer->mutex);
  401. }
  402. if (new_isr) {
  403. ESP_LOGD(TAG, "install interrupt service for timer (%d,%d)", group_id, timer_id);
  404. }
  405. return ret;
  406. }
  407. // Put the default ISR handler in the IRAM for better performance
  408. IRAM_ATTR static void gptimer_default_isr(void *args)
  409. {
  410. bool need_yield = false;
  411. gptimer_t *timer = (gptimer_t *)args;
  412. gptimer_group_t *group = timer->group;
  413. gptimer_alarm_cb_t on_alarm_cb = timer->on_alarm;
  414. uint32_t intr_status = timer_ll_get_intr_status(timer->hal.dev);
  415. if (intr_status & TIMER_LL_EVENT_ALARM(timer->timer_id)) {
  416. // Note: when alarm event happends, the alarm will be disabled automatically by hardware
  417. gptimer_alarm_event_data_t edata = {
  418. .count_value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id),
  419. .alarm_value = timer->alarm_count,
  420. };
  421. portENTER_CRITICAL_ISR(&group->spinlock);
  422. timer_ll_clear_intr_status(timer->hal.dev, TIMER_LL_EVENT_ALARM(timer->timer_id));
  423. // for auto-reload, we need to re-enable the alarm manually
  424. if (timer->flags.auto_reload_on_alarm) {
  425. timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, true);
  426. }
  427. portEXIT_CRITICAL_ISR(&group->spinlock);
  428. if (on_alarm_cb) {
  429. if (on_alarm_cb(timer, &edata, timer->user_ctx)) {
  430. need_yield = true;
  431. }
  432. }
  433. }
  434. if (need_yield) {
  435. portYIELD_FROM_ISR();
  436. }
  437. }
  438. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  439. ///// The Following APIs are for internal use only (e.g. unit test) /////////////////////////////////////////////////
  440. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  441. esp_err_t gptimer_get_intr_handle(gptimer_handle_t timer, intr_handle_t *ret_intr_handle)
  442. {
  443. ESP_RETURN_ON_FALSE(timer && ret_intr_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  444. *ret_intr_handle = timer->intr;
  445. return ESP_OK;
  446. }
  447. esp_err_t gptimer_get_pm_lock(gptimer_handle_t timer, esp_pm_lock_handle_t *ret_pm_lock)
  448. {
  449. ESP_RETURN_ON_FALSE(timer && ret_pm_lock, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  450. *ret_pm_lock = timer->pm_lock;
  451. return ESP_OK;
  452. }
  453. /**
  454. * @brief This function will be called during start up, to check that gptimer driver is not running along with the legacy timer group driver
  455. */
  456. __attribute__((constructor))
  457. static void check_gptimer_driver_conflict(void)
  458. {
  459. extern int timer_group_driver_init_count;
  460. timer_group_driver_init_count++;
  461. if (timer_group_driver_init_count > 1) {
  462. ESP_EARLY_LOGE(TAG, "CONFLICT! The gptimer driver can't work along with the legacy timer group driver");
  463. abort();
  464. }
  465. }