gptimer.c 20 KB

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