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