esp_timer.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. // Copyright 2017 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <sys/param.h>
  15. #include <string.h>
  16. #include "soc/soc.h"
  17. #include "esp_types.h"
  18. #include "esp_attr.h"
  19. #include "esp_err.h"
  20. #include "esp_task.h"
  21. #include "esp_log.h"
  22. #include "freertos/FreeRTOS.h"
  23. #include "freertos/task.h"
  24. #include "freertos/semphr.h"
  25. #include "soc/spinlock.h"
  26. #include "esp_timer.h"
  27. #include "esp_timer_impl.h"
  28. #include "esp_private/startup_internal.h"
  29. #include "esp_private/esp_timer_private.h"
  30. #include "esp_private/system_internal.h"
  31. #if CONFIG_IDF_TARGET_ESP32
  32. #include "esp32/rtc.h"
  33. #elif CONFIG_IDF_TARGET_ESP32S2
  34. #include "esp32s2/rtc.h"
  35. #elif CONFIG_IDF_TARGET_ESP32S3
  36. #include "esp32s3/rtc.h"
  37. #elif CONFIG_IDF_TARGET_ESP32C3
  38. #include "esp32c3/rtc.h"
  39. #elif CONFIG_IDF_TARGET_ESP32H2
  40. #include "esp32h2/rtc.h"
  41. #endif
  42. #include "sdkconfig.h"
  43. #ifdef CONFIG_ESP_TIMER_PROFILING
  44. #define WITH_PROFILING 1
  45. #endif
  46. #ifndef NDEBUG
  47. // Enable built-in checks in queue.h in debug builds
  48. #define INVARIANTS
  49. #endif
  50. #include "sys/queue.h"
  51. #define EVENT_ID_DELETE_TIMER 0xF0DE1E1E
  52. typedef enum {
  53. FL_ISR_DISPATCH_METHOD = (1 << 0), //!< 0=Callback is called from timer task, 1=Callback is called from timer ISR
  54. FL_SKIP_UNHANDLED_EVENTS = (1 << 1), //!< 0=NOT skip unhandled events for periodic timers, 1=Skip unhandled events for periodic timers
  55. } flags_t;
  56. struct esp_timer {
  57. uint64_t alarm;
  58. uint64_t period:56;
  59. flags_t flags:8;
  60. union {
  61. esp_timer_cb_t callback;
  62. uint32_t event_id;
  63. };
  64. void* arg;
  65. #if WITH_PROFILING
  66. const char* name;
  67. size_t times_triggered;
  68. size_t times_armed;
  69. size_t times_skipped;
  70. uint64_t total_callback_run_time;
  71. #endif // WITH_PROFILING
  72. LIST_ENTRY(esp_timer) list_entry;
  73. };
  74. static inline bool is_initialized(void);
  75. static esp_err_t timer_insert(esp_timer_handle_t timer, bool without_update_alarm);
  76. static esp_err_t timer_remove(esp_timer_handle_t timer);
  77. static bool timer_armed(esp_timer_handle_t timer);
  78. static void timer_list_lock(esp_timer_dispatch_t timer_type);
  79. static void timer_list_unlock(esp_timer_dispatch_t timer_type);
  80. #if WITH_PROFILING
  81. static void timer_insert_inactive(esp_timer_handle_t timer);
  82. static void timer_remove_inactive(esp_timer_handle_t timer);
  83. #endif // WITH_PROFILING
  84. __attribute__((unused)) static const char* TAG = "esp_timer";
  85. // lists of currently armed timers for two dispatch methods: ISR and TASK
  86. static LIST_HEAD(esp_timer_list, esp_timer) s_timers[ESP_TIMER_MAX] = {
  87. [0 ... (ESP_TIMER_MAX - 1)] = LIST_HEAD_INITIALIZER(s_timers)
  88. };
  89. #if WITH_PROFILING
  90. // lists of unarmed timers for two dispatch methods: ISR and TASK,
  91. // used only to be able to dump statistics about all the timers
  92. static LIST_HEAD(esp_inactive_timer_list, esp_timer) s_inactive_timers[ESP_TIMER_MAX] = {
  93. [0 ... (ESP_TIMER_MAX - 1)] = LIST_HEAD_INITIALIZER(s_timers)
  94. };
  95. #endif
  96. // task used to dispatch timer callbacks
  97. static TaskHandle_t s_timer_task;
  98. // lock protecting s_timers, s_inactive_timers
  99. static portMUX_TYPE s_timer_lock[ESP_TIMER_MAX] = {
  100. [0 ... (ESP_TIMER_MAX - 1)] = portMUX_INITIALIZER_UNLOCKED
  101. };
  102. #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
  103. // For ISR dispatch method, a callback function of the timer may require a context switch
  104. static volatile BaseType_t s_isr_dispatch_need_yield = pdFALSE;
  105. #endif // CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
  106. esp_err_t esp_timer_create(const esp_timer_create_args_t* args,
  107. esp_timer_handle_t* out_handle)
  108. {
  109. if (!is_initialized()) {
  110. return ESP_ERR_INVALID_STATE;
  111. }
  112. if (args == NULL || args->callback == NULL || out_handle == NULL ||
  113. args->dispatch_method < 0 || args->dispatch_method >= ESP_TIMER_MAX) {
  114. return ESP_ERR_INVALID_ARG;
  115. }
  116. esp_timer_handle_t result = (esp_timer_handle_t) calloc(1, sizeof(*result));
  117. if (result == NULL) {
  118. return ESP_ERR_NO_MEM;
  119. }
  120. result->callback = args->callback;
  121. result->arg = args->arg;
  122. result->flags = (args->dispatch_method ? FL_ISR_DISPATCH_METHOD : 0) |
  123. (args->skip_unhandled_events ? FL_SKIP_UNHANDLED_EVENTS : 0);
  124. #if WITH_PROFILING
  125. result->name = args->name;
  126. esp_timer_dispatch_t dispatch_method = result->flags & FL_ISR_DISPATCH_METHOD;
  127. timer_list_lock(dispatch_method);
  128. timer_insert_inactive(result);
  129. timer_list_unlock(dispatch_method);
  130. #endif
  131. *out_handle = result;
  132. return ESP_OK;
  133. }
  134. esp_err_t IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us)
  135. {
  136. if (timer == NULL) {
  137. return ESP_ERR_INVALID_ARG;
  138. }
  139. if (!is_initialized() || timer_armed(timer)) {
  140. return ESP_ERR_INVALID_STATE;
  141. }
  142. int64_t alarm = esp_timer_get_time() + timeout_us;
  143. esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
  144. timer_list_lock(dispatch_method);
  145. timer->alarm = alarm;
  146. timer->period = 0;
  147. #if WITH_PROFILING
  148. timer->times_armed++;
  149. #endif
  150. esp_err_t err = timer_insert(timer, false);
  151. timer_list_unlock(dispatch_method);
  152. return err;
  153. }
  154. esp_err_t IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period_us)
  155. {
  156. if (timer == NULL) {
  157. return ESP_ERR_INVALID_ARG;
  158. }
  159. if (!is_initialized() || timer_armed(timer)) {
  160. return ESP_ERR_INVALID_STATE;
  161. }
  162. period_us = MAX(period_us, esp_timer_impl_get_min_period_us());
  163. int64_t alarm = esp_timer_get_time() + period_us;
  164. esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
  165. timer_list_lock(dispatch_method);
  166. timer->alarm = alarm;
  167. timer->period = period_us;
  168. #if WITH_PROFILING
  169. timer->times_armed++;
  170. timer->times_skipped = 0;
  171. #endif
  172. esp_err_t err = timer_insert(timer, false);
  173. timer_list_unlock(dispatch_method);
  174. return err;
  175. }
  176. esp_err_t IRAM_ATTR esp_timer_stop(esp_timer_handle_t timer)
  177. {
  178. if (timer == NULL) {
  179. return ESP_ERR_INVALID_ARG;
  180. }
  181. if (!is_initialized() || !timer_armed(timer)) {
  182. return ESP_ERR_INVALID_STATE;
  183. }
  184. return timer_remove(timer);
  185. }
  186. esp_err_t esp_timer_delete(esp_timer_handle_t timer)
  187. {
  188. if (timer == NULL) {
  189. return ESP_ERR_INVALID_ARG;
  190. }
  191. if (timer_armed(timer)) {
  192. return ESP_ERR_INVALID_STATE;
  193. }
  194. // A case for the timer with ESP_TIMER_ISR:
  195. // This ISR timer was removed from the ISR list in esp_timer_stop() or in timer_process_alarm() -> LIST_REMOVE(it, list_entry)
  196. // and here this timer will be added to another the TASK list, see below.
  197. // We do this because we want to free memory of the timer in a task context instead of an isr context.
  198. int64_t alarm = esp_timer_get_time();
  199. timer_list_lock(ESP_TIMER_TASK);
  200. timer->flags &= ~FL_ISR_DISPATCH_METHOD;
  201. timer->event_id = EVENT_ID_DELETE_TIMER;
  202. timer->alarm = alarm;
  203. timer->period = 0;
  204. timer_insert(timer, false);
  205. timer_list_unlock(ESP_TIMER_TASK);
  206. return ESP_OK;
  207. }
  208. static IRAM_ATTR esp_err_t timer_insert(esp_timer_handle_t timer, bool without_update_alarm)
  209. {
  210. #if WITH_PROFILING
  211. timer_remove_inactive(timer);
  212. #endif
  213. esp_timer_handle_t it, last = NULL;
  214. esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
  215. if (LIST_FIRST(&s_timers[dispatch_method]) == NULL) {
  216. LIST_INSERT_HEAD(&s_timers[dispatch_method], timer, list_entry);
  217. } else {
  218. LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
  219. if (timer->alarm < it->alarm) {
  220. LIST_INSERT_BEFORE(it, timer, list_entry);
  221. break;
  222. }
  223. last = it;
  224. }
  225. if (it == NULL) {
  226. assert(last);
  227. LIST_INSERT_AFTER(last, timer, list_entry);
  228. }
  229. }
  230. if (without_update_alarm == false && timer == LIST_FIRST(&s_timers[dispatch_method])) {
  231. esp_timer_impl_set_alarm_id(timer->alarm, dispatch_method);
  232. }
  233. return ESP_OK;
  234. }
  235. static IRAM_ATTR esp_err_t timer_remove(esp_timer_handle_t timer)
  236. {
  237. esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
  238. timer_list_lock(dispatch_method);
  239. esp_timer_handle_t first_timer = LIST_FIRST(&s_timers[dispatch_method]);
  240. LIST_REMOVE(timer, list_entry);
  241. timer->alarm = 0;
  242. timer->period = 0;
  243. if (timer == first_timer) { // if this timer was the first in the list.
  244. uint64_t next_timestamp = UINT64_MAX;
  245. first_timer = LIST_FIRST(&s_timers[dispatch_method]);
  246. if (first_timer) { // if after removing the timer from the list, this list is not empty.
  247. next_timestamp = first_timer->alarm;
  248. }
  249. esp_timer_impl_set_alarm_id(next_timestamp, dispatch_method);
  250. }
  251. #if WITH_PROFILING
  252. timer_insert_inactive(timer);
  253. #endif
  254. timer_list_unlock(dispatch_method);
  255. return ESP_OK;
  256. }
  257. #if WITH_PROFILING
  258. static IRAM_ATTR void timer_insert_inactive(esp_timer_handle_t timer)
  259. {
  260. /* May be locked or not, depending on where this is called from.
  261. * Lock recursively.
  262. */
  263. esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
  264. esp_timer_handle_t head = LIST_FIRST(&s_inactive_timers[dispatch_method]);
  265. if (head == NULL) {
  266. LIST_INSERT_HEAD(&s_inactive_timers[dispatch_method], timer, list_entry);
  267. } else {
  268. /* Insert as head element as this is the fastest thing to do.
  269. * Removal is O(1) anyway.
  270. */
  271. LIST_INSERT_BEFORE(head, timer, list_entry);
  272. }
  273. }
  274. static IRAM_ATTR void timer_remove_inactive(esp_timer_handle_t timer)
  275. {
  276. LIST_REMOVE(timer, list_entry);
  277. }
  278. #endif // WITH_PROFILING
  279. static IRAM_ATTR bool timer_armed(esp_timer_handle_t timer)
  280. {
  281. return timer->alarm > 0;
  282. }
  283. static IRAM_ATTR void timer_list_lock(esp_timer_dispatch_t timer_type)
  284. {
  285. portENTER_CRITICAL_SAFE(&s_timer_lock[timer_type]);
  286. }
  287. static IRAM_ATTR void timer_list_unlock(esp_timer_dispatch_t timer_type)
  288. {
  289. portEXIT_CRITICAL_SAFE(&s_timer_lock[timer_type]);
  290. }
  291. #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
  292. static IRAM_ATTR bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
  293. #else
  294. static bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
  295. #endif
  296. {
  297. timer_list_lock(dispatch_method);
  298. bool processed = false;
  299. esp_timer_handle_t it;
  300. while (1) {
  301. it = LIST_FIRST(&s_timers[dispatch_method]);
  302. int64_t now = esp_timer_impl_get_time();
  303. if (it == NULL || it->alarm > now) {
  304. break;
  305. }
  306. processed = true;
  307. LIST_REMOVE(it, list_entry);
  308. if (it->event_id == EVENT_ID_DELETE_TIMER) {
  309. // It is handled only by ESP_TIMER_TASK (see esp_timer_delete()).
  310. // All the ESP_TIMER_ISR timers which should be deleted are moved by esp_timer_delete() to the ESP_TIMER_TASK list.
  311. // We want to free memory of the timer in a task context instead of an isr context.
  312. free(it);
  313. it = NULL;
  314. } else {
  315. if (it->period > 0) {
  316. int skipped = (now - it->alarm) / it->period;
  317. if ((it->flags & FL_SKIP_UNHANDLED_EVENTS) && (skipped > 1)) {
  318. it->alarm = now + it->period;
  319. #if WITH_PROFILING
  320. it->times_skipped += skipped;
  321. #endif
  322. } else {
  323. it->alarm += it->period;
  324. }
  325. timer_insert(it, true);
  326. } else {
  327. it->alarm = 0;
  328. #if WITH_PROFILING
  329. timer_insert_inactive(it);
  330. #endif
  331. }
  332. #if WITH_PROFILING
  333. uint64_t callback_start = now;
  334. #endif
  335. esp_timer_cb_t callback = it->callback;
  336. void* arg = it->arg;
  337. timer_list_unlock(dispatch_method);
  338. (*callback)(arg);
  339. timer_list_lock(dispatch_method);
  340. #if WITH_PROFILING
  341. it->times_triggered++;
  342. it->total_callback_run_time += esp_timer_impl_get_time() - callback_start;
  343. #endif
  344. }
  345. } // while(1)
  346. if (it) {
  347. if (dispatch_method == ESP_TIMER_TASK || (dispatch_method != ESP_TIMER_TASK && processed == true)) {
  348. esp_timer_impl_set_alarm_id(it->alarm, dispatch_method);
  349. }
  350. } else {
  351. if (processed) {
  352. esp_timer_impl_set_alarm_id(UINT64_MAX, dispatch_method);
  353. }
  354. }
  355. timer_list_unlock(dispatch_method);
  356. return processed;
  357. }
  358. static void timer_task(void* arg)
  359. {
  360. while (true){
  361. ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
  362. // all deferred events are processed at a time
  363. timer_process_alarm(ESP_TIMER_TASK);
  364. }
  365. }
  366. #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
  367. IRAM_ATTR void esp_timer_isr_dispatch_need_yield(void)
  368. {
  369. assert(xPortInIsrContext());
  370. s_isr_dispatch_need_yield = pdTRUE;
  371. }
  372. #endif
  373. static void IRAM_ATTR timer_alarm_handler(void* arg)
  374. {
  375. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  376. bool isr_timers_processed = false;
  377. #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
  378. // process timers with ISR dispatch method
  379. isr_timers_processed = timer_process_alarm(ESP_TIMER_ISR);
  380. xHigherPriorityTaskWoken = s_isr_dispatch_need_yield;
  381. s_isr_dispatch_need_yield = pdFALSE;
  382. #endif
  383. if (isr_timers_processed == false) {
  384. vTaskNotifyGiveFromISR(s_timer_task, &xHigherPriorityTaskWoken);
  385. }
  386. if (xHigherPriorityTaskWoken == pdTRUE) {
  387. portYIELD_FROM_ISR();
  388. }
  389. }
  390. static IRAM_ATTR inline bool is_initialized(void)
  391. {
  392. return s_timer_task != NULL;
  393. }
  394. esp_err_t esp_timer_init(void)
  395. {
  396. esp_err_t err;
  397. if (is_initialized()) {
  398. return ESP_ERR_INVALID_STATE;
  399. }
  400. int ret = xTaskCreatePinnedToCore(&timer_task, "esp_timer",
  401. ESP_TASK_TIMER_STACK, NULL, ESP_TASK_TIMER_PRIO, &s_timer_task, PRO_CPU_NUM);
  402. if (ret != pdPASS) {
  403. err = ESP_ERR_NO_MEM;
  404. goto out;
  405. }
  406. err = esp_timer_impl_init(&timer_alarm_handler);
  407. if (err != ESP_OK) {
  408. goto out;
  409. }
  410. #if CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
  411. esp_timer_impl_init_system_time();
  412. #endif
  413. return ESP_OK;
  414. out:
  415. if (s_timer_task) {
  416. vTaskDelete(s_timer_task);
  417. s_timer_task = NULL;
  418. }
  419. return ESP_ERR_NO_MEM;
  420. }
  421. esp_err_t esp_timer_deinit(void)
  422. {
  423. if (!is_initialized()) {
  424. return ESP_ERR_INVALID_STATE;
  425. }
  426. /* Check if there are any active timers */
  427. for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
  428. if (!LIST_EMPTY(&s_timers[dispatch_method])) {
  429. return ESP_ERR_INVALID_STATE;
  430. }
  431. }
  432. /* We can only check if there are any timers which are not deleted if
  433. * profiling is enabled.
  434. */
  435. #if WITH_PROFILING
  436. for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
  437. if (!LIST_EMPTY(&s_inactive_timers[dispatch_method])) {
  438. return ESP_ERR_INVALID_STATE;
  439. }
  440. }
  441. #endif
  442. esp_timer_impl_deinit();
  443. vTaskDelete(s_timer_task);
  444. s_timer_task = NULL;
  445. return ESP_OK;
  446. }
  447. static void print_timer_info(esp_timer_handle_t t, char** dst, size_t* dst_size)
  448. {
  449. #if WITH_PROFILING
  450. size_t cb;
  451. // name is optional, might be missed.
  452. if (t->name) {
  453. cb = snprintf(*dst, *dst_size, "%-20.20s ", t->name);
  454. } else {
  455. cb = snprintf(*dst, *dst_size, "timer@%-10p ", t);
  456. }
  457. cb += snprintf(*dst + cb, *dst_size + cb, "%-10lld %-12lld %-12d %-12d %-12d %-12lld\n",
  458. (uint64_t)t->period, t->alarm, t->times_armed,
  459. t->times_triggered, t->times_skipped, t->total_callback_run_time);
  460. /* keep this in sync with the format string, used in esp_timer_dump */
  461. #define TIMER_INFO_LINE_LEN 90
  462. #else
  463. size_t cb = snprintf(*dst, *dst_size, "timer@%-14p %-10lld %-12lld\n", t, (uint64_t)t->period, t->alarm);
  464. #define TIMER_INFO_LINE_LEN 46
  465. #endif
  466. *dst += cb;
  467. *dst_size -= cb;
  468. }
  469. esp_err_t esp_timer_dump(FILE* stream)
  470. {
  471. /* Since timer lock is a critical section, we don't want to print directly
  472. * to stdout, since that may cause a deadlock if stdout is interrupt-driven
  473. * (via the UART driver). Allocate sufficiently large chunk of memory first,
  474. * print to it, then dump this memory to stdout.
  475. */
  476. esp_timer_handle_t it;
  477. /* First count the number of timers */
  478. size_t timer_count = 0;
  479. for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
  480. timer_list_lock(dispatch_method);
  481. LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
  482. ++timer_count;
  483. }
  484. #if WITH_PROFILING
  485. LIST_FOREACH(it, &s_inactive_timers[dispatch_method], list_entry) {
  486. ++timer_count;
  487. }
  488. #endif
  489. timer_list_unlock(dispatch_method);
  490. }
  491. /* Allocate the memory for this number of timers. Since we have unlocked,
  492. * we may find that there are more timers. There's no bulletproof solution
  493. * for this (can't allocate from a critical section), but we allocate
  494. * slightly more and the output will be truncated if that is not enough.
  495. */
  496. size_t buf_size = TIMER_INFO_LINE_LEN * (timer_count + 3);
  497. char* print_buf = calloc(1, buf_size + 1);
  498. if (print_buf == NULL) {
  499. return ESP_ERR_NO_MEM;
  500. }
  501. /* Print to the buffer */
  502. char* pos = print_buf;
  503. for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
  504. timer_list_lock(dispatch_method);
  505. LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
  506. print_timer_info(it, &pos, &buf_size);
  507. }
  508. #if WITH_PROFILING
  509. LIST_FOREACH(it, &s_inactive_timers[dispatch_method], list_entry) {
  510. print_timer_info(it, &pos, &buf_size);
  511. }
  512. #endif
  513. timer_list_unlock(dispatch_method);
  514. }
  515. if (stream != NULL) {
  516. fprintf(stream, "Timer stats:\n");
  517. #if WITH_PROFILING
  518. fprintf(stream, "%-20s %-10s %-12s %-12s %-12s %-12s %-12s\n",
  519. "Name", "Period", "Alarm", "Times_armed", "Times_trigg", "Times_skip", "Cb_exec_time");
  520. #else
  521. fprintf(stream, "%-20s %-10s %-12s\n", "Name", "Period", "Alarm");
  522. #endif
  523. /* Print the buffer */
  524. fputs(print_buf, stream);
  525. }
  526. free(print_buf);
  527. return ESP_OK;
  528. }
  529. int64_t IRAM_ATTR esp_timer_get_next_alarm(void)
  530. {
  531. int64_t next_alarm = INT64_MAX;
  532. for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
  533. timer_list_lock(dispatch_method);
  534. esp_timer_handle_t it = LIST_FIRST(&s_timers[dispatch_method]);
  535. if (it) {
  536. if (next_alarm > it->alarm) {
  537. next_alarm = it->alarm;
  538. }
  539. }
  540. timer_list_unlock(dispatch_method);
  541. }
  542. return next_alarm;
  543. }
  544. int64_t IRAM_ATTR esp_timer_get_next_alarm_for_wake_up(void)
  545. {
  546. int64_t next_alarm = INT64_MAX;
  547. for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
  548. timer_list_lock(dispatch_method);
  549. esp_timer_handle_t it;
  550. LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
  551. if (it == NULL) {
  552. break;
  553. }
  554. // timers with the SKIP_UNHANDLED_EVENTS flag do not want to wake up CPU from a sleep mode.
  555. if ((it->flags & FL_SKIP_UNHANDLED_EVENTS) == 0) {
  556. if (next_alarm > it->alarm) {
  557. next_alarm = it->alarm;
  558. }
  559. break;
  560. }
  561. }
  562. timer_list_unlock(dispatch_method);
  563. }
  564. return next_alarm;
  565. }
  566. bool esp_timer_is_active(esp_timer_handle_t timer)
  567. {
  568. return timer_armed(timer);
  569. }