1.. _timer: 2 3================ 4Timer (lv_timer) 5================ 6 7LVGL has a built-in Timer system. You can register a function to have it 8be called periodically. The Timers are handled and called in 9:cpp:func:`lv_timer_handler`, which needs to be called every few milliseconds. 10See :ref:`timer_handler` for more information. 11 12By default, LVGL itself uses Timers to: 13 14- refresh each display --- during the creation of each :ref:`Display`, a Timer is 15 created for that Display. That Timer refreshes the display based on the configured 16 value of :c:macro:`LV_DEF_REFR_PERIOD`, and also sends all display-related events, 17 like :cpp:enumerator:`LV_EVENT_REFR_START`, :cpp:enumerator:`LV_EVENT_REFR_READY`, 18 etc. 19- read input devices --- during the creation of each :ref:`indev`, a Timer is 20 created for that Input Device based on the configured value of 21 :c:macro:`LV_DEF_REFR_PERIOD`. That Timer causes that input device to be read and 22 also sends all input-device-related events, like :cpp:enumerator:`LV_EVENT_CLICKED`, 23 :cpp:enumerator:`LV_EVENT_PRESSED`, etc. 24- update system-monitor values --- if :c:macro:`LV_USE_SYSMON` is set to ``1`` in 25 ``lv_conf.h``, one or more timers are created to periodically compute and 26 monitor system performance statistics and LVGL's memory usage. 27 28Timers are non-preemptive, which means a Timer cannot interrupt another 29Timer. Therefore, you can call any LVGL related function in a Timer. 30 31 32 33Creating a Timer 34**************** 35 36To create a new Timer, use 37:cpp:expr:`lv_timer_create(timer_cb, period_ms, user_data)`. It returns an 38:cpp:type:`lv_timer_t` ``*`` which can be used later to modify the 39parameters of the Timer, pause it, or delete it when it is no longer needed. 40:cpp:func:`lv_timer_create_basic` can also be used to create a new Timer without 41specifying any parameters. 42 43A Timer callback should have this prototype: ``void (*lv_timer_cb_t)(lv_timer_t *)``. 44 45For example: 46 47.. code-block:: c 48 49 void my_timer(lv_timer_t * timer) 50 { 51 /* Use the user_data */ 52 uint32_t * user_data = lv_timer_get_user_data(timer); 53 printf("my_timer called with user data: %d\n", *user_data); 54 55 /* Do something with LVGL */ 56 if(something_happened) { 57 something_happened = false; 58 lv_button_create(lv_screen_active()); 59 } 60 } 61 62 ... 63 64 static uint32_t user_data = 10; 65 lv_timer_t * timer = lv_timer_create(my_timer, 500, &user_data); 66 67 68 69Ready and Reset 70*************** 71 72:cpp:expr:`lv_timer_ready(timer)` makes a Timer run on the next call of 73:cpp:func:`lv_timer_handler`. 74 75:cpp:expr:`lv_timer_reset(timer)` resets the period of a Timer. It will be 76called again after its currently-set period (in milliseconds) has elapsed. 77 78 79 80Setting Parameters 81****************** 82 83You can modify these Timer parameters at any time during its life: 84 85- :cpp:expr:`lv_timer_set_cb(timer, new_cb)` 86- :cpp:expr:`lv_timer_set_period(timer, new_period_ms)` 87- :cpp:expr:`lv_timer_set_user_data(timer, user_data)` 88 89 90 91Repeat Count 92************ 93 94When a Timer is created, its repeat-count is set to ``-1`` to cause it to repeat 95indefinitely. You can make a Timer repeat only a given number of times with 96:cpp:expr:`lv_timer_set_repeat_count(timer, count)`. By default, once the Timer has 97run ``count`` times, it will be automatically deleted. 98 99You can use :cpp:expr:`lv_timer_set_auto_delete(timer, false)` if you want the timer 100to instead be paused after it has run ``count`` times. This can be handy if you 101reuse that timer repeatedly and want to avoid the CPU and :cpp:func:`lv_malloc` 102overhead of repeatedly creating and deleting a timer. If you use this option, you 103will need to set its repeat count (to either ``-1`` or a positive repeat count, since 104it will have decremented to ``0``) and :ref:`resume <timer_pause_and_resume>` it to 105make it active again. 106 107 108 109.. _timer_pause_and_resume: 110 111Pause and Resume 112**************** 113 114:cpp:expr:`lv_timer_pause(timer)` pauses the specified Timer. 115 116:cpp:expr:`lv_timer_resume(timer)` resumes the specified Timer. 117 118 119 120Measuring Idle Time 121******************* 122 123You can get the idle percentage time of :cpp:func:`lv_timer_handler` with 124:cpp:func:`lv_timer_get_idle`. Note that it does not measure the idle time of 125the overall system, only of :cpp:func:`lv_timer_handler`. This can be misleading if 126you are using an operating system and DMA and/or GPU are used during rendering, as it 127does not actually measure the time the OS spends in an idle thread. 128 129If you are using an OS and wish to get the time the CPU is spending in an idle 130thread, one way of doing so is configuring :c:macro:`LV_USE_SYSMON` and 131:c:macro:`LV_USE_PERF_MONITOR` to ``1`` in ``lv_conf.h`` (if they are not already), 132and setting the macro :c:macro:`LV_SYSMON_GET_IDLE` to the name of a function that 133fetches the percent of CPU time spent in the OS's idle thread. An example of such 134a function is :cpp:func:`lv_os_get_idle_percent` in ``lv_freertos.c``. While the 135configuration is set this way, some system performance statistics (including CPU 136load) will appear on the display in a partially-transparent label whose location is 137set by the :c:macro:`LV_USE_PERF_MONITOR_POS` macro. 138 139 140 141Enable and Disable 142****************** 143 144You can temporarily disable Timer handling with :cpp:expr:`lv_timer_enable(false)`. 145Be advised: this also pauses handling of Timers that refresh Display(s) and read 146from input devices, so don't forget to re-enable it with 147:cpp:expr:`lv_timer_enable(true)` as soon as the need for the pause is over. 148 149 150 151Timer Handler Resume Callback 152***************************** 153 154When the Timer system has been disabled (causing :cpp:func:`lv_timer_handler` to 155return early before it has processed any timers), if you want to take some action 156when the Timer system is re-enabled again, set a resume callback using 157:cpp:expr:`lv_timer_handler_set_resume_cb(cb, user_data)`. The callback should have 158this prototype: ``void (*lv_timer_handler_resume_cb_t)(void*)``. 159 160 161 162Asynchronous calls 163****************** 164 165There are several cases in which you may not want to perform an action immediately. 166Some examples are: 167 168- you cannot delete a Widget because something else is still using it, 169- you don't want to block execution now, or 170- you detect the need to delete a Widget in a thread other than the thread making 171 LVGL calls (e.g. in a case where you are using a :ref:`Gateway Thread <Gateway 172 Thread>` to make all LVGL calls in a multi-threaded environment). 173 174For these cases, 175:cpp:expr:`lv_async_call(my_function, data_p)` can be used to call ``my_function`` on 176the next invocation of :cpp:func:`lv_timer_handler`. As a side effect, this also 177ensures it is called in a thread in which it is safe to make LVGL calls. 178``data_p`` will be passed to the function when it's called. Note that only the data's 179pointer is saved, so whatever it is pointing to needs to remain valid until the 180function is called, so it can point to ``static``, global or dynamically allocated 181data. If you want to cancel an asynchronous call, call 182:cpp:expr:`lv_async_call_cancel(my_function, data_p)`, which will remove all 183asynchronous calls matching ``my_function`` and ``data_p``. 184 185Note that if :cpp:expr:`lv_async_call(my_function, data_p)` is called from a thread 186other than the one that normally makes LVGL calls, you are still obligated to protect 187the LVGL data structure using a MUTEX. 188 189For example: 190 191.. code-block:: c 192 193 void my_screen_clean_up(void * scr) 194 { 195 /* Free some resources related to `scr`*/ 196 197 /* Finally delete the screen */ 198 lv_obj_delete(scr); 199 } 200 201 ... 202 203 /* Do something with the Widget on the current screen */ 204 205 /* Delete screen on next call of `lv_timer_handler`, not right now. */ 206 lv_lock(); 207 lv_async_call(my_screen_clean_up, lv_screen_active()); 208 lv_unlock(); 209 210 /* The screen is still valid so you can do other things with it */ 211 212If you just want to delete a Widget and don't need to clean anything up 213in ``my_screen_cleanup`` you could just use :cpp:expr:`lv_obj_delete_async(widget)` which 214will delete the Widget on the next call to :cpp:func:`lv_timer_handler`. 215 216 217 218.. _timer_api: 219 220API 221*** 222