1.. _connecting_lvgl: 2 3================================ 4Connecting LVGL to Your Hardware 5================================ 6 7 8.. _initializing_lvgl: 9 10Initializing LVGL 11***************** 12After you have: 13 14- :ref:`acquired LVGL <getting_lvgl>`, 15- added the appropriate LVGL files to your project, and 16- :ref:`created a lv_conf.h file <lv_conf>` for your project, 17 18you will need to complete a few more steps to get your project up and running with LVGL. 19 201. Initialize LVGL once early during system execution by calling :cpp:func:`lv_init`. 21 This needs to be done before making any other LVGL calls. 22 232. Initialize your drivers. 24 253. Connect the :ref:`tick_interface`. 26 274. Connect the :ref:`display_interface`. 28 295. Connect the :ref:`indev_interface`. 30 316. Drive LVGL time-related tasks by calling :cpp:func:`lv_timer_handler` every few 32 milliseconds to manage LVGL timers. See :ref:`timer_handler` for different ways 33 to do this. 34 357. Optionally set a theme with :cpp:func:`lv_display_set_theme`. 36 378. Thereafter #include "lvgl/lvgl.h" in source files wherever you need to use LVGL 38 functions. 39 40 41 42.. _tick_interface: 43 44Tick Interface 45************** 46 47LVGL needs awareness of what time it is (i.e. elapsed time in milliseconds) for 48all of its tasks for which time is a factor: refreshing displays, reading user 49input, firing events, animations, etc. 50 51.. image:: /misc/intro_data_flow.png 52 :scale: 75 % 53 :alt: LVGL Data Flow 54 :align: center 55 56There are two ways to provide this information to LVGL: 57 581. Supply LVGL with a callback function to retrieve elapsed system milliseconds by 59 calling :cpp:expr:`lv_tick_set_cb(my_get_milliseconds)`. 60 :cpp:expr:`my_get_milliseconds()` needs to return the number of milliseconds 61 elapsed since system start up. Many platforms have built-in functions that can 62 be used as they are. For example: 63 64 - SDL: ``lv_tick_set_cb(SDL_GetTicks);`` 65 - Arduino: ``lv_tick_set_cb(my_tick_get_cb);``, where ``my_tick_get_cb`` is: 66 ``static uint32_t my_tick_get_cb(void) { return millis(); }`` 67 - FreeRTOS: ``lv_tick_set_cb(xTaskGetTickCount);`` 68 - STM32: ``lv_tick_set_cb(HAL_GetTick);`` 69 - ESP32: ``lv_tick_set_cb(my_tick_get_cb);``, where ``my_tick_get_cb`` is a 70 wrapper for ``esp_timer_get_time() / 1000;`` 71 722. Call :cpp:expr:`lv_tick_inc(x)` periodically, where ``x`` is the elapsed 73 milliseconds since the last call. If :cpp:func:`lv_tick_inc` is called from an 74 ISR, it should be from either a high priority interrupt or an interrupt that 75 cannot be missed when the system is under high load. 76 77 .. note:: :cpp:func:`lv_tick_inc` is only one of two LVGL functions that may be 78 called from an interrupt if writing to a ``uint32_t`` value is atomic on your 79 platform. See below and the :ref:`threading` section to learn more. 80 81Either way, the writing of the ``uint32_t`` Tick value must be :ref:`atomic <atomic>`, 82which is usually the case with a 32- or 64-bit platform. If you are using a 16-bit 83system (causing the update of the Tick value to not be atomic) and your platform uses 84the Harvard instruction set, you can set a function like this as the callback passed 85to :cpp:expr:`lv_tick_set_cb(my_get_milliseconds)`: 86 87.. code-block:: c 88 89 /** 90 * @brief Safe read from 'elapsed_power_on_time_in_ms' 91 */ 92 uint32_t my_get_milliseconds() 93 { 94 register uint32_t u32result; 95 /* Disable priority 1-6 interrupts for 2 Fcys. */ 96 __builtin_disi(2); 97 u32result = elapsed_power_on_time_in_ms; /* Cost: 2 Fcys */ 98 /* Generally looks like this in assembly: 99 * mov elapsed_power_on_time_in_ms, W0 100 * mov 0x7898, W1 101 * requiring exactly 2 clock cycles. 102 * Now value is copied to register pair W0:W1 103 * where it can be written to any destination. */ 104 return u32result; 105 } 106 107 108Reliability 109----------- 110Advancing the tick value should be done in such a way that its timing is reliable and 111not dependent on anything that consumes an unknown amount of time. For an example of 112what *not* to do: this can "seem" to work, but LVGL's timing will be incorrect 113because the execution time of :c:func:`lv_timer_handler` varies from call to call and 114thus the delay it introduces cannot be known. 115 116.. code-block:: c 117 118 // Bad idea 119 lv_timer_handler(); 120 lv_tick_inc(5); 121 my_delay_ms(5); 122 123 124 125.. _display_interface: 126 127Display Interface 128***************** 129LVGL needs to be supplied with knowledge about each display panel you want it to use. 130Specifically: 131 132- its pixel format and size (:ref:`creating_a_display`), 133- where to render pixels for it (:ref:`draw_buffers`), and 134- how to send those rendered pixels to it (:ref:`flush_callback`). 135 136See the respective links for how to supply LVGL with this knowledge. 137 138 139 140.. _indev_interface: 141 142Input-Device Interface 143********************** 144LVGL needs to know how to get input from all user-input devices that will be used in 145your project. LVGL supports a wide variety of user-input devices: 146 147- touch-screens, 148- touch-pads, 149- mice, 150- crowns, 151- encoders, 152- keypads, 153- keyboards, 154- etc. 155 156See :ref:`indev_creation` to see how to do this. 157 158 159 160API 161*** 162:ref:`lv_tick_h` 163