esp_timer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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. #endif
  40. #include "sdkconfig.h"
  41. #ifdef CONFIG_ESP_TIMER_PROFILING
  42. #define WITH_PROFILING 1
  43. #endif
  44. #ifndef NDEBUG
  45. // Enable built-in checks in queue.h in debug builds
  46. #define INVARIANTS
  47. #endif
  48. #include "sys/queue.h"
  49. #define EVENT_ID_DELETE_TIMER 0xF0DE1E1E
  50. typedef enum {
  51. FL_DISPATCH_METHOD = (1 << 0), //!< 0=Callback is called from timer task, 1=Callback is called from timer ISR
  52. FL_SKIP_UNHANDLED_EVENTS = (1 << 1), //!< 0=NOT skip unhandled events for periodic timers, 1=Skip unhandled events for periodic timers
  53. } flags_t;
  54. struct esp_timer {
  55. uint64_t alarm;
  56. uint64_t period:56;
  57. flags_t flags:8;
  58. union {
  59. esp_timer_cb_t callback;
  60. uint32_t event_id;
  61. };
  62. void* arg;
  63. #if WITH_PROFILING
  64. const char* name;
  65. size_t times_triggered;
  66. size_t times_armed;
  67. size_t times_skipped;
  68. uint64_t total_callback_run_time;
  69. #endif // WITH_PROFILING
  70. LIST_ENTRY(esp_timer) list_entry;
  71. };
  72. static inline bool is_initialized(void);
  73. static esp_err_t timer_insert(esp_timer_handle_t timer);
  74. static esp_err_t timer_remove(esp_timer_handle_t timer);
  75. static bool timer_armed(esp_timer_handle_t timer);
  76. static void timer_list_lock(void);
  77. static void timer_list_unlock(void);
  78. #if WITH_PROFILING
  79. static void timer_insert_inactive(esp_timer_handle_t timer);
  80. static void timer_remove_inactive(esp_timer_handle_t timer);
  81. #endif // WITH_PROFILING
  82. __attribute__((unused)) static const char* TAG = "esp_timer";
  83. // list of currently armed timers
  84. static LIST_HEAD(esp_timer_list, esp_timer) s_timers =
  85. LIST_HEAD_INITIALIZER(s_timers);
  86. #if WITH_PROFILING
  87. // list of unarmed timers, used only to be able to dump statistics about
  88. // all the timers
  89. static LIST_HEAD(esp_inactive_timer_list, esp_timer) s_inactive_timers =
  90. LIST_HEAD_INITIALIZER(s_timers);
  91. #endif
  92. // task used to dispatch timer callbacks
  93. static TaskHandle_t s_timer_task;
  94. // lock protecting s_timers, s_inactive_timers
  95. static portMUX_TYPE s_timer_lock = portMUX_INITIALIZER_UNLOCKED;
  96. esp_err_t esp_timer_create(const esp_timer_create_args_t* args,
  97. esp_timer_handle_t* out_handle)
  98. {
  99. if (!is_initialized()) {
  100. return ESP_ERR_INVALID_STATE;
  101. }
  102. if (args == NULL || args->callback == NULL || out_handle == NULL) {
  103. return ESP_ERR_INVALID_ARG;
  104. }
  105. esp_timer_handle_t result = (esp_timer_handle_t) calloc(1, sizeof(*result));
  106. if (result == NULL) {
  107. return ESP_ERR_NO_MEM;
  108. }
  109. result->callback = args->callback;
  110. result->arg = args->arg;
  111. result->flags = (args->dispatch_method ? FL_DISPATCH_METHOD : 0) |
  112. (args->skip_unhandled_events ? FL_SKIP_UNHANDLED_EVENTS : 0);
  113. #if WITH_PROFILING
  114. result->name = args->name;
  115. timer_insert_inactive(result);
  116. #endif
  117. *out_handle = result;
  118. return ESP_OK;
  119. }
  120. esp_err_t IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us)
  121. {
  122. if (timer == NULL) {
  123. return ESP_ERR_INVALID_ARG;
  124. }
  125. if (!is_initialized() || timer_armed(timer)) {
  126. return ESP_ERR_INVALID_STATE;
  127. }
  128. timer_list_lock();
  129. timer->alarm = esp_timer_get_time() + timeout_us;
  130. timer->period = 0;
  131. #if WITH_PROFILING
  132. timer->times_armed++;
  133. #endif
  134. esp_err_t err = timer_insert(timer);
  135. timer_list_unlock();
  136. return err;
  137. }
  138. esp_err_t IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period_us)
  139. {
  140. if (timer == NULL) {
  141. return ESP_ERR_INVALID_ARG;
  142. }
  143. if (!is_initialized() || timer_armed(timer)) {
  144. return ESP_ERR_INVALID_STATE;
  145. }
  146. timer_list_lock();
  147. period_us = MAX(period_us, esp_timer_impl_get_min_period_us());
  148. timer->alarm = esp_timer_get_time() + period_us;
  149. timer->period = period_us;
  150. #if WITH_PROFILING
  151. timer->times_armed++;
  152. timer->times_skipped = 0;
  153. #endif
  154. esp_err_t err = timer_insert(timer);
  155. timer_list_unlock();
  156. return err;
  157. }
  158. esp_err_t IRAM_ATTR esp_timer_stop(esp_timer_handle_t timer)
  159. {
  160. if (timer == NULL) {
  161. return ESP_ERR_INVALID_ARG;
  162. }
  163. if (!is_initialized() || !timer_armed(timer)) {
  164. return ESP_ERR_INVALID_STATE;
  165. }
  166. return timer_remove(timer);
  167. }
  168. esp_err_t esp_timer_delete(esp_timer_handle_t timer)
  169. {
  170. if (timer == NULL) {
  171. return ESP_ERR_INVALID_ARG;
  172. }
  173. if (timer_armed(timer)) {
  174. return ESP_ERR_INVALID_STATE;
  175. }
  176. timer_list_lock();
  177. timer->event_id = EVENT_ID_DELETE_TIMER;
  178. timer->alarm = esp_timer_get_time();
  179. timer->period = 0;
  180. timer_insert(timer);
  181. timer_list_unlock();
  182. return ESP_OK;
  183. }
  184. static IRAM_ATTR esp_err_t timer_insert(esp_timer_handle_t timer)
  185. {
  186. #if WITH_PROFILING
  187. timer_remove_inactive(timer);
  188. #endif
  189. esp_timer_handle_t it, last = NULL;
  190. if (LIST_FIRST(&s_timers) == NULL) {
  191. LIST_INSERT_HEAD(&s_timers, timer, list_entry);
  192. } else {
  193. LIST_FOREACH(it, &s_timers, list_entry) {
  194. if (timer->alarm < it->alarm) {
  195. LIST_INSERT_BEFORE(it, timer, list_entry);
  196. break;
  197. }
  198. last = it;
  199. }
  200. if (it == NULL) {
  201. assert(last);
  202. LIST_INSERT_AFTER(last, timer, list_entry);
  203. }
  204. }
  205. if (timer == LIST_FIRST(&s_timers)) {
  206. esp_timer_impl_set_alarm(timer->alarm);
  207. }
  208. return ESP_OK;
  209. }
  210. static IRAM_ATTR esp_err_t timer_remove(esp_timer_handle_t timer)
  211. {
  212. timer_list_lock();
  213. LIST_REMOVE(timer, list_entry);
  214. timer->alarm = 0;
  215. timer->period = 0;
  216. #if WITH_PROFILING
  217. timer_insert_inactive(timer);
  218. #endif
  219. timer_list_unlock();
  220. return ESP_OK;
  221. }
  222. #if WITH_PROFILING
  223. static IRAM_ATTR void timer_insert_inactive(esp_timer_handle_t timer)
  224. {
  225. /* May be locked or not, depending on where this is called from.
  226. * Lock recursively.
  227. */
  228. timer_list_lock();
  229. esp_timer_handle_t head = LIST_FIRST(&s_inactive_timers);
  230. if (head == NULL) {
  231. LIST_INSERT_HEAD(&s_inactive_timers, timer, list_entry);
  232. } else {
  233. /* Insert as head element as this is the fastest thing to do.
  234. * Removal is O(1) anyway.
  235. */
  236. LIST_INSERT_BEFORE(head, timer, list_entry);
  237. }
  238. timer_list_unlock();
  239. }
  240. static IRAM_ATTR void timer_remove_inactive(esp_timer_handle_t timer)
  241. {
  242. timer_list_lock();
  243. LIST_REMOVE(timer, list_entry);
  244. timer_list_unlock();
  245. }
  246. #endif // WITH_PROFILING
  247. static IRAM_ATTR bool timer_armed(esp_timer_handle_t timer)
  248. {
  249. return timer->alarm > 0;
  250. }
  251. static IRAM_ATTR void timer_list_lock(void)
  252. {
  253. portENTER_CRITICAL_SAFE(&s_timer_lock);
  254. }
  255. static IRAM_ATTR void timer_list_unlock(void)
  256. {
  257. portEXIT_CRITICAL_SAFE(&s_timer_lock);
  258. }
  259. static void timer_process_alarm(esp_timer_dispatch_t dispatch_method)
  260. {
  261. /* unused, provision to allow running callbacks from ISR */
  262. (void) dispatch_method;
  263. timer_list_lock();
  264. esp_timer_handle_t it;
  265. while (1) {
  266. it = LIST_FIRST(&s_timers);
  267. int64_t now = esp_timer_impl_get_time();
  268. if (it == NULL || it->alarm > now) {
  269. break;
  270. }
  271. LIST_REMOVE(it, list_entry);
  272. if (it->event_id == EVENT_ID_DELETE_TIMER) {
  273. free(it);
  274. it = NULL;
  275. } else {
  276. if (it->period > 0) {
  277. int skipped = (now - it->alarm) / it->period;
  278. if ((it->flags & FL_SKIP_UNHANDLED_EVENTS) && (skipped > 1)) {
  279. it->alarm = now + it->period;
  280. #if WITH_PROFILING
  281. it->times_skipped += skipped;
  282. #endif
  283. } else {
  284. it->alarm += it->period;
  285. }
  286. timer_insert(it);
  287. } else {
  288. it->alarm = 0;
  289. #if WITH_PROFILING
  290. timer_insert_inactive(it);
  291. #endif
  292. }
  293. #if WITH_PROFILING
  294. uint64_t callback_start = now;
  295. #endif
  296. esp_timer_cb_t callback = it->callback;
  297. void* arg = it->arg;
  298. timer_list_unlock();
  299. (*callback)(arg);
  300. timer_list_lock();
  301. #if WITH_PROFILING
  302. it->times_triggered++;
  303. it->total_callback_run_time += esp_timer_impl_get_time() - callback_start;
  304. #endif
  305. }
  306. }
  307. if (it) {
  308. esp_timer_impl_set_alarm(it->alarm);
  309. }
  310. timer_list_unlock();
  311. }
  312. static void timer_task(void* arg)
  313. {
  314. while (true){
  315. ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
  316. // all deferred events are processed at a time
  317. timer_process_alarm(ESP_TIMER_TASK);
  318. }
  319. }
  320. static void IRAM_ATTR timer_alarm_handler(void* arg)
  321. {
  322. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  323. vTaskNotifyGiveFromISR(s_timer_task, &xHigherPriorityTaskWoken);
  324. if (xHigherPriorityTaskWoken == pdTRUE) {
  325. portYIELD_FROM_ISR();
  326. }
  327. }
  328. static IRAM_ATTR inline bool is_initialized(void)
  329. {
  330. return s_timer_task != NULL;
  331. }
  332. esp_err_t esp_timer_init(void)
  333. {
  334. esp_err_t err;
  335. if (is_initialized()) {
  336. return ESP_ERR_INVALID_STATE;
  337. }
  338. int ret = xTaskCreatePinnedToCore(&timer_task, "esp_timer",
  339. ESP_TASK_TIMER_STACK, NULL, ESP_TASK_TIMER_PRIO, &s_timer_task, PRO_CPU_NUM);
  340. if (ret != pdPASS) {
  341. err = ESP_ERR_NO_MEM;
  342. goto out;
  343. }
  344. err = esp_timer_impl_init(&timer_alarm_handler);
  345. if (err != ESP_OK) {
  346. goto out;
  347. }
  348. #if CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
  349. // [refactor-todo] this logic, "esp_rtc_get_time_us() - g_startup_time", is also
  350. // the weak definition of esp_system_get_time; find a way to remove this duplication.
  351. esp_timer_private_advance(esp_rtc_get_time_us() - g_startup_time);
  352. #endif
  353. return ESP_OK;
  354. out:
  355. if (s_timer_task) {
  356. vTaskDelete(s_timer_task);
  357. s_timer_task = NULL;
  358. }
  359. return ESP_ERR_NO_MEM;
  360. }
  361. esp_err_t esp_timer_deinit(void)
  362. {
  363. if (!is_initialized()) {
  364. return ESP_ERR_INVALID_STATE;
  365. }
  366. /* Check if there are any active timers */
  367. if (!LIST_EMPTY(&s_timers)) {
  368. return ESP_ERR_INVALID_STATE;
  369. }
  370. /* We can only check if there are any timers which are not deleted if
  371. * profiling is enabled.
  372. */
  373. #if WITH_PROFILING
  374. if (!LIST_EMPTY(&s_inactive_timers)) {
  375. return ESP_ERR_INVALID_STATE;
  376. }
  377. #endif
  378. esp_timer_impl_deinit();
  379. vTaskDelete(s_timer_task);
  380. s_timer_task = NULL;
  381. return ESP_OK;
  382. }
  383. static void print_timer_info(esp_timer_handle_t t, char** dst, size_t* dst_size)
  384. {
  385. #if WITH_PROFILING
  386. size_t cb;
  387. // name is optional, might be missed.
  388. if (t->name) {
  389. cb = snprintf(*dst, *dst_size, "%-20.20s ", t->name);
  390. } else {
  391. cb = snprintf(*dst, *dst_size, "timer@%-10p ", t);
  392. }
  393. cb += snprintf(*dst + cb, *dst_size + cb, "%-10lld %-12lld %-12d %-12d %-12d %-12lld\n",
  394. (uint64_t)t->period, t->alarm, t->times_armed,
  395. t->times_triggered, t->times_skipped, t->total_callback_run_time);
  396. /* keep this in sync with the format string, used in esp_timer_dump */
  397. #define TIMER_INFO_LINE_LEN 90
  398. #else
  399. size_t cb = snprintf(*dst, *dst_size, "timer@%-14p %-10lld %-12lld\n", t, (uint64_t)t->period, t->alarm);
  400. #define TIMER_INFO_LINE_LEN 46
  401. #endif
  402. *dst += cb;
  403. *dst_size -= cb;
  404. }
  405. esp_err_t esp_timer_dump(FILE* stream)
  406. {
  407. /* Since timer lock is a critical section, we don't want to print directly
  408. * to stdout, since that may cause a deadlock if stdout is interrupt-driven
  409. * (via the UART driver). Allocate sufficiently large chunk of memory first,
  410. * print to it, then dump this memory to stdout.
  411. */
  412. esp_timer_handle_t it;
  413. /* First count the number of timers */
  414. size_t timer_count = 0;
  415. timer_list_lock();
  416. LIST_FOREACH(it, &s_timers, list_entry) {
  417. ++timer_count;
  418. }
  419. #if WITH_PROFILING
  420. LIST_FOREACH(it, &s_inactive_timers, list_entry) {
  421. ++timer_count;
  422. }
  423. #endif
  424. timer_list_unlock();
  425. /* Allocate the memory for this number of timers. Since we have unlocked,
  426. * we may find that there are more timers. There's no bulletproof solution
  427. * for this (can't allocate from a critical section), but we allocate
  428. * slightly more and the output will be truncated if that is not enough.
  429. */
  430. size_t buf_size = TIMER_INFO_LINE_LEN * (timer_count + 3);
  431. char* print_buf = calloc(1, buf_size + 1);
  432. if (print_buf == NULL) {
  433. return ESP_ERR_NO_MEM;
  434. }
  435. /* Print to the buffer */
  436. timer_list_lock();
  437. char* pos = print_buf;
  438. LIST_FOREACH(it, &s_timers, list_entry) {
  439. print_timer_info(it, &pos, &buf_size);
  440. }
  441. #if WITH_PROFILING
  442. LIST_FOREACH(it, &s_inactive_timers, list_entry) {
  443. print_timer_info(it, &pos, &buf_size);
  444. }
  445. #endif
  446. timer_list_unlock();
  447. fprintf(stream, "Timer stats:\n");
  448. #if WITH_PROFILING
  449. fprintf(stream, "%-20s %-10s %-12s %-12s %-12s %-12s %-12s\n",
  450. "Name", "Period", "Alarm", "Times_armed", "Times_trigg", "Times_skip", "Cb_exec_time");
  451. #else
  452. fprintf(stream, "%-20s %-10s %-12s\n", "Name", "Period", "Alarm");
  453. #endif
  454. /* Print the buffer */
  455. fputs(print_buf, stream);
  456. free(print_buf);
  457. return ESP_OK;
  458. }
  459. int64_t IRAM_ATTR esp_timer_get_next_alarm(void)
  460. {
  461. int64_t next_alarm = INT64_MAX;
  462. timer_list_lock();
  463. esp_timer_handle_t it = LIST_FIRST(&s_timers);
  464. if (it) {
  465. next_alarm = it->alarm;
  466. }
  467. timer_list_unlock();
  468. return next_alarm;
  469. }
  470. // Provides strong definition for system time functions relied upon
  471. // by core components.
  472. #if CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
  473. int64_t IRAM_ATTR esp_system_get_time(void)
  474. {
  475. return esp_timer_get_time();
  476. }
  477. uint32_t IRAM_ATTR esp_system_get_time_resolution(void)
  478. {
  479. return 1000;
  480. }
  481. #endif