feat(docs): reorganize docs (#7136)
This commit is contained in:
28
docs/intro/add-lvgl-to-your-project/building_lvgl.rst
Normal file
28
docs/intro/add-lvgl-to-your-project/building_lvgl.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
.. _building_lvgl:
|
||||
|
||||
=============
|
||||
Building LVGL
|
||||
=============
|
||||
|
||||
|
||||
Make and CMake
|
||||
**************
|
||||
|
||||
LVGL also supports ``make`` and ``CMake`` build systems out of the box.
|
||||
To add LVGL to your Makefile based build system add these lines to your
|
||||
main Makefile:
|
||||
|
||||
.. code-block:: make
|
||||
|
||||
LVGL_DIR_NAME ?= lvgl #The name of the lvgl folder (change this if you have renamed it)
|
||||
LVGL_DIR ?= ${shell pwd} #The path where the lvgl folder is
|
||||
include $(LVGL_DIR)/$(LVGL_DIR_NAME)/lvgl.mk
|
||||
|
||||
For integration with CMake take a look this section of the
|
||||
:ref:`Documentation <build_cmake>`.
|
||||
|
||||
|
||||
Managed builds
|
||||
**************
|
||||
TODO
|
||||
|
||||
93
docs/intro/add-lvgl-to-your-project/configuration.rst
Normal file
93
docs/intro/add-lvgl-to-your-project/configuration.rst
Normal file
@@ -0,0 +1,93 @@
|
||||
.. _configuration:
|
||||
|
||||
=============
|
||||
Configuration
|
||||
=============
|
||||
|
||||
|
||||
|
||||
.. _lv_conf:
|
||||
|
||||
lv_conf.h
|
||||
*********
|
||||
|
||||
|
||||
Creating lv_conf.h
|
||||
------------------
|
||||
|
||||
When setting up your project for the first time, copy ``lvgl/lv_conf_template.h`` to
|
||||
``lv_conf.h`` next to the ``lvgl`` folder. Change the first ``#if 0`` to ``1`` to
|
||||
enable the file's content and set the :c:macro:`LV_COLOR_DEPTH` define to align with
|
||||
the color depth used by your display panel. See comments in ``lv_conf.h`` for
|
||||
details.
|
||||
|
||||
The layout of the files should look like this::
|
||||
|
||||
lvgl/
|
||||
lv_conf.h
|
||||
other files and folders in your project
|
||||
|
||||
Alternatively, ``lv_conf.h`` can be copied to another place but then you
|
||||
should add the :c:macro:`LV_CONF_INCLUDE_SIMPLE` define to your compiler
|
||||
options (e.g. ``-DLV_CONF_INCLUDE_SIMPLE`` for GCC compiler) and set the
|
||||
include path manually (e.g. ``-I../include/gui``). In this case LVGL
|
||||
will attempt to include ``lv_conf.h`` simply with ``#include "lv_conf.h"``.
|
||||
|
||||
You can even use a different name for ``lv_conf.h``. The custom path can
|
||||
be set via the :c:macro:`LV_CONF_PATH` define. For example
|
||||
``-DLV_CONF_PATH="/home/joe/my_project/my_custom_conf.h"``. If this define
|
||||
is set :c:macro:`LV_CONF_SKIP` is assumed to be ``0``.
|
||||
|
||||
If :c:macro:`LV_CONF_SKIP` is defined, LVGL will not try to include
|
||||
``lv_conf.h``. Instead you can pass the config defines using build
|
||||
options. For example ``"-DLV_COLOR_DEPTH=32 -DLV_USE_BUTTON=1"``. Unset
|
||||
options will get a default value which is the same as the content of
|
||||
``lv_conf_template.h``.
|
||||
|
||||
LVGL also can be used via ``Kconfig`` and ``menuconfig``. You can use
|
||||
``lv_conf.h`` together with Kconfig as well, but keep in mind that the values
|
||||
from ``lv_conf.h`` or build settings (``-D...``) override the values
|
||||
set in Kconfig. To ignore the configs from ``lv_conf.h`` simply remove
|
||||
its content, or define :c:macro:`LV_CONF_SKIP`.
|
||||
|
||||
|
||||
.. _configuration_settings:
|
||||
|
||||
Configuration Settings
|
||||
----------------------
|
||||
|
||||
Once the ``lv_conf.h`` file is in place, you can modify this header to configure
|
||||
LVGL's behavior, disable unused modules and features, adjust the size of buffers, etc.
|
||||
|
||||
The comments in ``lv_conf.h`` explain the meaning of each setting. Be sure
|
||||
to at least set :c:macro:`LV_COLOR_DEPTH` according to your display's color
|
||||
depth. Note that the examples and demos explicitly need to be enabled
|
||||
in ``lv_conf.h`` if you need them.
|
||||
|
||||
TODO: Add all things related to ``lv_conf.h`` file and its contents.
|
||||
|
||||
|
||||
Multiple Instances of LVGL
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
It is possible to run multiple, independent isntances of LVGL. To enable its
|
||||
multi-instance feature, set :c:macro:`LV_GLOBAL_CUSTOM` in ``lv_conf.h``
|
||||
and provide a custom function to :cpp:func:`lv_global_default` using ``__thread`` or
|
||||
``pthread_key_t``. It will allow running multiple LVGL instances by storing LVGL's
|
||||
global variables in TLS (Thread-Local Storage).
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_global_t * lv_global_default(void)
|
||||
{
|
||||
static __thread lv_global_t lv_global;
|
||||
return &lv_global;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Kconfig
|
||||
*******
|
||||
TODO: Add how to use LVGL with Kconfig.
|
||||
|
||||
131
docs/intro/add-lvgl-to-your-project/connecting_lvgl.rst
Normal file
131
docs/intro/add-lvgl-to-your-project/connecting_lvgl.rst
Normal file
@@ -0,0 +1,131 @@
|
||||
.. _connecting_lvgl:
|
||||
|
||||
================================
|
||||
Connecting LVGL to Your Hardware
|
||||
================================
|
||||
|
||||
|
||||
.. _initializing_lvgl:
|
||||
|
||||
Initializing LVGL
|
||||
*****************
|
||||
After you have:
|
||||
|
||||
- :ref:`acquired LVGL <getting_lvgl>`,
|
||||
- added the appropriate LVGL files to your project, and
|
||||
- :ref:`created a lv_conf.h file <lv_conf>` for your project,
|
||||
|
||||
you will need to complete a few more steps to get your project up and running with LVGL.
|
||||
|
||||
1. Initialize LVGL once early during system execution by calling :cpp:func:`lv_init`.
|
||||
This needs to be done before making any other LVGL calls.
|
||||
|
||||
2. Initialize your drivers.
|
||||
|
||||
3. Connect the :ref:`tick_interface`.
|
||||
|
||||
4. Connect the :ref:`display_interface`.
|
||||
|
||||
5. Connect the :ref:`indev_interface`.
|
||||
|
||||
6. Drive LVGL time-related tasks by calling :cpp:func:`lv_timer_handler` every few
|
||||
milliseconds to manage LVGL timers. See :ref:`timer_handler` for different ways
|
||||
to do this.
|
||||
|
||||
7. Optionally set a theme with :cpp:func:`lv_display_set_theme`.
|
||||
|
||||
8. Thereafter #include "lvgl/lvgl.h" in source files wherever you need to use LVGL
|
||||
functions.
|
||||
|
||||
|
||||
|
||||
.. _tick_interface:
|
||||
|
||||
Tick Interface
|
||||
**************
|
||||
|
||||
LVGL needs awareness of what time it is (i.e. elapsed time in milliseconds) for
|
||||
all of its tasks for which time is a factor: refreshing displays, reading user
|
||||
input, firing events, animations, etc.
|
||||
|
||||
.. image:: /misc/intro_data_flow.png
|
||||
:scale: 75 %
|
||||
:alt: LVGL Data Flow
|
||||
:align: center
|
||||
|
||||
There are two ways to provide this information to LVGL:
|
||||
|
||||
1. Supply LVGL with a callback function to retrieve elapsed system milliseconds by
|
||||
calling :cpp:expr:`lv_tick_set_cb(my_get_milliseconds_function)`.
|
||||
:cpp:expr:`my_get_milliseconds_function()` needs to return the number of
|
||||
milliseconds elapsed since system start up. Many platforms have built-in
|
||||
functions that can be used as they are. For example:
|
||||
|
||||
- SDL: ``lv_tick_set_cb(SDL_GetTicks);``
|
||||
- Arduino: ``lv_tick_set_cb(my_tick_get_cb);``, where ``my_tick_get_cb`` is:
|
||||
``static uint32_t my_tick_get_cb(void) { return millis(); }``
|
||||
- FreeRTOS: ``lv_tick_set_cb(xTaskGetTickCount);``
|
||||
- STM32: ``lv_tick_set_cb(HAL_GetTick);``
|
||||
- ESP32: ``lv_tick_set_cb(my_tick_get_cb);``, where ``my_tick_get_cb`` is a
|
||||
wrapper for ``esp_timer_get_time() / 1000;``
|
||||
|
||||
2. Call :cpp:expr:`lv_tick_inc(x)` periodically, where ``x`` is the elapsed
|
||||
milliseconds since the last call. If :cpp:func:`lv_tick_inc` is called from an
|
||||
ISR, it should be from either a high priority interrupt or an interrupt that
|
||||
cannot be missed when the system is under high load.
|
||||
|
||||
.. note:: :cpp:func:`lv_tick_inc` is only one of two LVGL functions that may be
|
||||
called from an interrupt. See the :ref:`threading` section to learn more.
|
||||
|
||||
The ticks (milliseconds) should be independent from any other activities of the MCU.
|
||||
|
||||
For example this works, but LVGL's timing will be incorrect as the execution time of
|
||||
:c:func:`lv_timer_handler` is not considered:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// Bad idea
|
||||
lv_timer_handler();
|
||||
lv_tick_inc(5);
|
||||
my_delay_ms(5);
|
||||
|
||||
|
||||
|
||||
.. _display_interface:
|
||||
|
||||
Display Interface
|
||||
*****************
|
||||
LVGL needs to be supplied with knowledge about each display panel you want it to use.
|
||||
Specificially:
|
||||
|
||||
- its pixel format and size (:ref:`creating_a_display`),
|
||||
- where to render pixels for it (:ref:`draw_buffers`), and
|
||||
- how to send those rendered pixels to it (:ref:`flush_callback`).
|
||||
|
||||
See the respective links for how to supply LVGL with this knowledge.
|
||||
|
||||
|
||||
|
||||
.. _indev_interface:
|
||||
|
||||
Input-Device Interface
|
||||
**********************
|
||||
LVGL needs to know how to get input from all user-input devices that will be used in
|
||||
your project. LVGL supports a wide variety of user-input devices:
|
||||
|
||||
- touch-screens,
|
||||
- touch-pads,
|
||||
- mice,
|
||||
- crowns,
|
||||
- encoders,
|
||||
- keypads,
|
||||
- keyboards,
|
||||
- etc.
|
||||
|
||||
See :ref:`indev_creation` to see how to do this.
|
||||
|
||||
|
||||
|
||||
API
|
||||
***
|
||||
:ref:`lv_tick_h`
|
||||
25
docs/intro/add-lvgl-to-your-project/getting_lvgl.rst
Normal file
25
docs/intro/add-lvgl-to-your-project/getting_lvgl.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
.. _getting_lvgl:
|
||||
|
||||
============
|
||||
Getting LVGL
|
||||
============
|
||||
|
||||
LVGL is available on GitHub: https://github.com/lvgl/lvgl.
|
||||
|
||||
You can clone it or
|
||||
`Download <https://github.com/lvgl/lvgl/archive/refs/heads/master.zip>`__
|
||||
the latest version of the library from GitHub.
|
||||
|
||||
The graphics library itself is the ``lvgl`` directory. It contains several
|
||||
directories but to use LVGL you only need the ``.c`` and ``.h`` files under
|
||||
the ``src`` directory, plus ``lvgl/lvgl.h``, and ``lvgl/lv_version.h``.
|
||||
|
||||
|
||||
Demos and Examples
|
||||
------------------
|
||||
|
||||
The ``lvgl`` directory also contains an ``examples`` and a ``demos``
|
||||
directory. If your project needs examples and/or demos, add the these
|
||||
directories to your project. If ``make`` or :ref:`build_cmake` handle the
|
||||
examples and demos directories, no extra action is required.
|
||||
|
||||
18
docs/intro/add-lvgl-to-your-project/index.rst
Normal file
18
docs/intro/add-lvgl-to-your-project/index.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
.. _add_lvgl_to_your_project:
|
||||
|
||||
========================
|
||||
Add LVGL to Your Project
|
||||
========================
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
getting_lvgl
|
||||
building_lvgl
|
||||
configuration
|
||||
connecting_lvgl
|
||||
timer_handler
|
||||
threading
|
||||
other_platforms
|
||||
|
||||
11
docs/intro/add-lvgl-to-your-project/other_platforms.rst
Normal file
11
docs/intro/add-lvgl-to-your-project/other_platforms.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. _other_platforms:
|
||||
|
||||
=========================
|
||||
Other Platforms and Tools
|
||||
=========================
|
||||
|
||||
See :ref:`Integration <integration_index>` to see how to use LVGL on different
|
||||
platforms. There, you will find many platform-specific descriptions e.g. for ESP32,
|
||||
Arduino, NXP, RT-Thread, NuttX, etc.
|
||||
|
||||
|
||||
277
docs/intro/add-lvgl-to-your-project/threading.rst
Normal file
277
docs/intro/add-lvgl-to-your-project/threading.rst
Normal file
@@ -0,0 +1,277 @@
|
||||
.. _threading:
|
||||
|
||||
========================
|
||||
Threading Considerations
|
||||
========================
|
||||
|
||||
.. _threading_definitions:
|
||||
|
||||
Definitions
|
||||
***********
|
||||
|
||||
.. _thread:
|
||||
|
||||
Thread
|
||||
In the context of this document, a thread is any sequence of CPU instructions.
|
||||
In "bare-metal" implementations (i.e. no OS), threads include:
|
||||
|
||||
- the main thread executing a while(1) loop that runs the system, and
|
||||
- interrupts.
|
||||
|
||||
When running under an OS, threads include:
|
||||
|
||||
- each task (or process),
|
||||
- interrupts, and
|
||||
- advanced OSes can have multiple "execution threads" within a processes.
|
||||
|
||||
.. _atomic operation:
|
||||
|
||||
Atomic Operation
|
||||
If operation X is atomic, that means that any thread observing the operation will
|
||||
see it either as not yet started, or as completed, and not in any state that is
|
||||
partially completed.
|
||||
|
||||
If other threads can see the operation in a partially performed state, or
|
||||
interfere with it, then operation X is not atomic.
|
||||
|
||||
If an atomic operation can fail, its implementation must return the the resource
|
||||
back to the state before the operation was started. To other threads it must
|
||||
appear as though the operation had not yet started.
|
||||
|
||||
.. _atomic data:
|
||||
.. _atomic:
|
||||
.. _non-atomic data:
|
||||
|
||||
Atomic Data
|
||||
A datum (i.e. contents of a variable or data structure) is atomic if any thread
|
||||
observing it will always see it in a consistent state, as if operations on it
|
||||
have either not yet started, or have been successfully completed, and not in a
|
||||
state that is partially changed or otherwise inconsistent.
|
||||
|
||||
When reading or writing a value is started and completed with 1 CPU instruction,
|
||||
it is automatically atomic, since it can never been seen in an inconsistent
|
||||
(partially-changed) state, even from a CPU interrupt or exception. With such
|
||||
values, no special protection is required by programmers to ensure all threads
|
||||
see it in a consistent state.
|
||||
|
||||
|
||||
|
||||
.. _lvgl_and_threads:
|
||||
|
||||
LVGL and Threads
|
||||
****************
|
||||
|
||||
LVGL is **not thread-safe**.
|
||||
|
||||
That means it is the programmer's responsibility to see that no LVGL function is
|
||||
called while another LVGL call is in progress in another thread. This includes calls
|
||||
to :cpp:func:`lv_timer_handler`.
|
||||
|
||||
.. note::
|
||||
Assuming the above is the case, it is safe to call LVGL functions in
|
||||
|
||||
- :ref:`event callbacks <events>`, and in
|
||||
- :ref:`timer callbacks <timer>`
|
||||
|
||||
because the thread that drives both of these is the thread that calls
|
||||
:cpp:func:`lv_timer_handler`.
|
||||
|
||||
Reason:
|
||||
|
||||
LVGL manages many complex data structures, and those structures are "system
|
||||
resources" that must be protected from being "seen" by other threads in an
|
||||
inconsistent state. A high percentage LVGL functions (functions that start with
|
||||
``lv_``) either read from or change those data structures. Those that change them
|
||||
place the data in an inconsistent state during execution (because such changes are
|
||||
multi-step sequences), but return them to a consistent state before those functions
|
||||
return. For this reason, execution of each LVGL function must be allowed to complete
|
||||
before any other LVGL function is started.
|
||||
|
||||
.. _os_exception:
|
||||
|
||||
.. admonition:: Exceptions to the Above:
|
||||
|
||||
These two LVGL functions may be called from any thread:
|
||||
|
||||
- :cpp:func:`lv_tick_inc` (see :ref:`tick_interface` for more information) and
|
||||
- :cpp:func:`lv_display_flush_ready` (see :ref:`flush_callback` for more information)
|
||||
|
||||
The reason this is okay is that the LVGL data changed by them is :ref:`atomic <atomic>`.
|
||||
|
||||
If an interrupt MUST convey information to part of your application that calls
|
||||
LVGL functions, set a flag or other atomic value that your LVGL-calling thread
|
||||
(or an :ref:`LVGL Timer <timer>` you create) can read from and take action.
|
||||
|
||||
If you are using an OS, there are a few other options. See below.
|
||||
|
||||
|
||||
.. _tasks:
|
||||
|
||||
Tasks
|
||||
*****
|
||||
Under an OS, it is common to have many threads of execution ("tasks" in some OSes)
|
||||
performing services for the application. In some cases, such threads can acquire
|
||||
data that should be shown (or otherwise reflected) in the user interface, and doing
|
||||
so requires making LVGL calls to get that data (or change) shown.
|
||||
|
||||
Yet it still remains the programmer's responsibility to see that no LVGL function is
|
||||
called while another LVGL call is in progress.
|
||||
|
||||
How do you do this?
|
||||
|
||||
|
||||
.. _gateway thread:
|
||||
|
||||
Method 1: Use a Gateway Thread
|
||||
-------------------------------
|
||||
A "Gateway Thread" (or "Gateway Task" in some OSes) is a thread (task) that the
|
||||
system designer designates to *exclusively* manage a system resource. An example is
|
||||
management of a remote chip, such as an EEPROM or other device that always needs to
|
||||
be brought into a consistent state before something new is started. Another example
|
||||
is management of multiple devices on an I2C bus (or any data bus). In this case the
|
||||
I2C bus is the "exclusively-managed resource", and having only one thread managing it
|
||||
guarantees that each action started is allowed to complete before another action with
|
||||
it is started.
|
||||
|
||||
LVGL's data structures are a system resource that requires such protection.
|
||||
|
||||
Using this method, creation, modification and deletion of all Widgets and other
|
||||
LVGL resources (i.e. all LVGL function calls excluding the :ref:`exceptions
|
||||
<os_exception>` mentioned above) are called by that thread. That means
|
||||
that thread is also the ONLY caller of :cpp:func:`lv_timer_handler`. (See
|
||||
:ref:`add_lvgl_to_your_project` for more information.)
|
||||
|
||||
This ensures LVGL's data structures "appear" atomic_ (all threads using this data
|
||||
"see" it in a consistent state) by the fact that no other threads are "viewing" those
|
||||
data structures. This is enforced by programmer discipline that ensures the `Gateway
|
||||
Thread`_ is the only thread making LVGL calls (excluding the :ref:`exceptions
|
||||
<os_exception>` mentioned above).
|
||||
|
||||
If `atomic data`_ relevant to the user interface is updated in another thread (i.e.
|
||||
by another task or in an interrupt), the thread calling LVGL functions can read that
|
||||
data directly without worry that it is in an inconsistent state. (To avoid
|
||||
unnecessary CPU overhead, a mechanism can be provided [such as a flag raised by the
|
||||
updating thread] so that the user interface is only updated when it will result in a
|
||||
change visible to the end user.)
|
||||
|
||||
If `non-atomic data`_ relevant to the user interface is updated in another thread
|
||||
(i.e. by another task or in an interrupt), an alternate (and safe) way of convey that
|
||||
data to the thread calling LVGL functions is to pass a private copy of that data to
|
||||
that thread via a QUEUE or other OS mechanism that protects that data from being seen
|
||||
in an inconsistent state.
|
||||
|
||||
Use of a `Gateway Thread`_ avoids the CPU-overhead (and coding overhead) of using a
|
||||
MUTEX to protect LVGL data structures.
|
||||
|
||||
|
||||
Method 2: Use a MUTEX
|
||||
----------------------
|
||||
A MUTEX stands for "MUTually EXclusive" and is a synchronization primative that
|
||||
protects the state of a system resource from being modified or accessed by multiple
|
||||
threads of execution at once. In other words, it makes data so protected "appear"
|
||||
atomic (all threads using this data "see" it in a consistent state). Most OSes
|
||||
provide MUTEXes.
|
||||
|
||||
The system designer assigns a single MUTEX to product a single system resource. Once
|
||||
assigned, that MUTEX performs such protection by programmers:
|
||||
|
||||
1. acquiring the MUTEX (a.k.a. locking it) before accessing or modifying that
|
||||
resource, and
|
||||
|
||||
2. releasing the MUTEX (a.k.a. unlocking it) after that access or modification
|
||||
is complete.
|
||||
|
||||
If a thread attempts to acquire (lock) the MUTEX while another thread "owns" it,
|
||||
that thread waits on the other thread to release (unlock) it before it is allowed
|
||||
to continue execution.
|
||||
|
||||
To be clear: this must be done *both* by threads that READ from that resource, and
|
||||
threads that MODIFY that resource.
|
||||
|
||||
If a MUTEX is used to protect LVGL data structures, that means *every* LVGL function
|
||||
call (or group of function calls) must be preceeded by #1, and followed by #2,
|
||||
including calls to :cpp:func:`lv_timer_handler`.
|
||||
|
||||
.. note::
|
||||
If your OS is integrated with LVGL (the macro :c:macro:`LV_USE_OS` has a value
|
||||
other than ``LV_OS_NONE`` in ``lv_conf.h``) you can use :cpp:func:`lv_lock()` and
|
||||
:cpp:func:`lv_unlock()` to perform #1 and #2.
|
||||
|
||||
When this is the case, :cpp:func:`lv_timer_handler` calls :cpp:func:`lv_lock()`
|
||||
and :cpp:func:`lv_unlock()` internally, so you do not have to bracket your
|
||||
calls to :cpp:func:`lv_timer_handler` with them.
|
||||
|
||||
If your OS is NOT integrated with LVGL, then these calls either return
|
||||
immediately with no effect, or are optimized away by the linker.
|
||||
|
||||
To enable :cpp:func:`lv_lock()` and :cpp:func:`lv_unlock()`, set ``LV_USE_OS``
|
||||
to a value other than ``LV_OS_NONE``.
|
||||
|
||||
This pseudocode illustrates the concept of using a MUTEX:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void lvgl_thread(void)
|
||||
{
|
||||
while(1) {
|
||||
uint32_t time_till_next;
|
||||
time_till_next = lv_timer_handler(); /* lv_lock/lv_unlock is called internally */
|
||||
thread_sleep(time_till_next); /* sleep for a while */
|
||||
}
|
||||
}
|
||||
|
||||
void other_thread(void)
|
||||
{
|
||||
/* You must always hold (lock) the MUTEX while calling LVGL functions. */
|
||||
lv_lock();
|
||||
lv_obj_t *img = lv_image_create(lv_screen_active());
|
||||
lv_unlock();
|
||||
|
||||
while(1) {
|
||||
lv_lock();
|
||||
/* Change to next image. */
|
||||
lv_image_set_src(img, next_image);
|
||||
lv_unlock();
|
||||
thread_sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.. _sleep_management:
|
||||
|
||||
Sleep Management
|
||||
****************
|
||||
|
||||
The MCU can go to sleep when no user input has been received for a certain period.
|
||||
In this case, the main ``while(1)`` could look like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
while(1) {
|
||||
/* Normal operation (no sleep) in < 1 sec inactivity */
|
||||
if(lv_display_get_inactive_time(NULL) < 1000) {
|
||||
lv_timer_handler();
|
||||
}
|
||||
/* Sleep after 1 sec inactivity */
|
||||
else {
|
||||
timer_stop(); /* Stop the timer where lv_tick_inc() is called */
|
||||
sleep(); /* Sleep the MCU */
|
||||
}
|
||||
my_delay_ms(5);
|
||||
}
|
||||
|
||||
You should also add the following lines to your input device read
|
||||
function to signal a wake-up (press, touch, click, etc.) has happened:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_tick_inc(LV_DEF_REFR_PERIOD); /* Force task execution on wake-up */
|
||||
timer_start(); /* Restart timer where lv_tick_inc() is called */
|
||||
lv_timer_handler(); /* Call `lv_timer_handler()` manually to process the wake-up event */
|
||||
|
||||
In addition to :cpp:func:`lv_display_get_inactive_time` you can check
|
||||
:cpp:func:`lv_anim_count_running` to see if all animations have finished.
|
||||
|
||||
|
||||
|
||||
63
docs/intro/add-lvgl-to-your-project/timer_handler.rst
Normal file
63
docs/intro/add-lvgl-to-your-project/timer_handler.rst
Normal file
@@ -0,0 +1,63 @@
|
||||
.. _timer_handler:
|
||||
|
||||
=============
|
||||
Timer Handler
|
||||
=============
|
||||
|
||||
To drive the timers of LVGL you need to call :cpp:func:`lv_timer_handler`
|
||||
periodically in one of the following:
|
||||
|
||||
- *while(1)* of *main()* function, or
|
||||
- an OS task periodically. (See :ref:`lvgl_and_threads`.)
|
||||
|
||||
.. image:: /misc/intro_data_flow.png
|
||||
:scale: 75 %
|
||||
:alt: LVGL Data Flow
|
||||
:align: center
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
while(1) {
|
||||
uint32_t time_till_next = lv_timer_handler();
|
||||
my_delay_ms(time_till_next);
|
||||
}
|
||||
|
||||
If you want to use :cpp:func:`lv_timer_handler` in a super-loop, a helper
|
||||
function :cpp:func:`lv_timer_handler_run_in_period` is provided to simplify
|
||||
supplying LVGL with time awareness:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
while(1) {
|
||||
...
|
||||
lv_timer_handler_run_in_period(5); /* run lv_timer_handler() every 5ms */
|
||||
...
|
||||
}
|
||||
|
||||
Or use the sleep time automatically calculated by LVGL:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
while(1) {
|
||||
...
|
||||
lv_timer_periodic_handler();
|
||||
...
|
||||
}
|
||||
|
||||
In an OS environment, you can use it together with the **delay** or
|
||||
**sleep** provided by OS to release CPU whenever possible:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
while (1) {
|
||||
uint32_t time_till_next = lv_timer_handler();
|
||||
os_delay_ms(time_till_next); /* delay to avoid unnecessary polling */
|
||||
}
|
||||
|
||||
See :ref:`timer` section to learn more about timers.
|
||||
|
||||
|
||||
API
|
||||
***
|
||||
468
docs/intro/basics.rst
Normal file
468
docs/intro/basics.rst
Normal file
@@ -0,0 +1,468 @@
|
||||
.. _lvgl_basics:
|
||||
|
||||
===========
|
||||
LVGL Basics
|
||||
===========
|
||||
|
||||
LVGL (Light and Versatile Graphics Library) is a free and open-source graphics
|
||||
library providing everything you need to create an embedded GUI with easy-to-use
|
||||
graphical elements, beautiful visual effects, and a low memory footprint.
|
||||
|
||||
How does it do this?
|
||||
|
||||
|
||||
|
||||
.. _basic_data_flow:
|
||||
|
||||
Overview of LVGL's Data Flow
|
||||
****************************
|
||||
|
||||
.. figure:: /misc/intro_data_flow.png
|
||||
:scale: 75 %
|
||||
:alt: LVGL Data Flow
|
||||
:align: center
|
||||
:figwidth: image
|
||||
|
||||
Overview of LVGL Data Flow
|
||||
|
||||
|
||||
You create one :ref:`display` for each physical display panel, create
|
||||
:ref:`basics_screen_widgets` on them, add :ref:`basics_widgets` onto those Screens.
|
||||
To handle touch, mouse, keypad, etc., you :ref:`create an Input Device <indev_creation>`
|
||||
for each. The :ref:`tick_interface` tells LVGL what time is it. :ref:`timer_handler`
|
||||
drives LVGL's timers which, in turn, perform all of LVGL's time-related tasks:
|
||||
|
||||
- periodically refreshes displays,
|
||||
- reads input devices,
|
||||
- fires events,
|
||||
- runs any animations, and
|
||||
- runs user-created timers.
|
||||
|
||||
|
||||
.. _applications_job:
|
||||
|
||||
Application's Job
|
||||
-----------------
|
||||
|
||||
After initialization, the application's job is merely to create Widget Trees when
|
||||
they are needed, manage events those Widgets generate (by way of user interaction
|
||||
and other things), and delete them when they are no longer needed. LVGL takes care
|
||||
of the rest.
|
||||
|
||||
|
||||
|
||||
.. _basics_major_concepts:
|
||||
|
||||
Major Concepts
|
||||
**************
|
||||
|
||||
|
||||
.. _display-vs-screen:
|
||||
|
||||
Display vs Screen
|
||||
-----------------
|
||||
Before we get into any details about Widgets, let us first clarify the difference
|
||||
between two terms that you will hereafter see frequently:
|
||||
|
||||
- A **Display** or **Display Panel** is the physical hardware displaying the pixels.
|
||||
- A :ref:`display` object is an object in RAM that represents a **Display** meant
|
||||
to be used by LVGL.
|
||||
- A **Screen** is the "root" Widget in the Widget Trees mentioned above, and are
|
||||
"attached to" a particular :ref:`display`.
|
||||
|
||||
|
||||
Default Display
|
||||
---------------
|
||||
When the first :ref:`display` object is created, it becomes the Default Display.
|
||||
Many functions related to Screen Widgets use the default display.
|
||||
See :ref:`default_display` for more information.
|
||||
|
||||
|
||||
.. _basics_screen_widgets:
|
||||
|
||||
Screen Widgets
|
||||
--------------
|
||||
In this documentation, the term "Screen Widget" is frequently shortened to just
|
||||
"Screen". But it is important to understand that a "Screen" is simply any
|
||||
:ref:`Widget <widgets>` created without a parent --- the "root" of each Widget Tree.
|
||||
|
||||
See :ref:`screens` for more details.
|
||||
|
||||
|
||||
Active Screen
|
||||
-------------
|
||||
|
||||
The Active Screen is the screen (and its child Widgets) currently being displayed.
|
||||
See :ref:`active_screen` for more information.
|
||||
|
||||
|
||||
.. _basics_widgets:
|
||||
|
||||
Widgets
|
||||
-------
|
||||
After LVGL is initialized (see :ref:`initializing_lvgl`), to create an interactive
|
||||
user interface, an application next creates a tree of Widgets that LVGL can render to
|
||||
the associated dislay, and with which the user can interact.
|
||||
|
||||
Widgets are "intelligent" LVGL graphical elements such as :ref:`Base Widgets
|
||||
<base_widget_overview>` (simple rectangles and :ref:`screens`), Buttons, Labels,
|
||||
Checkboxes, Switches, Sliders, Charts, etc. Go to :ref:`widgets` to see the full
|
||||
list.
|
||||
|
||||
To build this Widget Tree, the application first acquires a pointer to a Screen Widget.
|
||||
A system designer is free to use the default Screen created with the :ref:`display`
|
||||
and/or create his own. To create a new Screen Widget, simply create a Widget passing
|
||||
NULL as the parent argument. Technically, this can be any type of Widget, but in
|
||||
most cases it is a :ref:`base_widget_overview`. (An example of another type of
|
||||
Widget being used as a Screen is an :ref:`lv_image` Widget to supply an image for the
|
||||
background.)
|
||||
|
||||
The application then adds Widgets to this Screen as children in the tree. Widgets
|
||||
are automatically added as children to their parent Widgets at time of creation ---
|
||||
the Widget's parent is passed as the first argument to the function that creates
|
||||
the Widget. After being so added, we say that the parent Widget "contains" the
|
||||
child Widget.
|
||||
|
||||
Any Widget can contain other Widgets. For example, if you want a Button to have
|
||||
text, create a Label Widget and add it to the Button as a child.
|
||||
|
||||
Each child Widget becomes "part of" its parent Widget. Because of this relationship:
|
||||
|
||||
- when the parent Widget moves, its children move with it;
|
||||
- when the parent Widget is deleted, its children are deleted with it;
|
||||
- a child Widget is only visible within its parent's boundaries; any part of a child
|
||||
outside its parent's boundaries is clipped (i.e. not rendered).
|
||||
|
||||
Screens (and their child Widgets) can be created and deleted at any time *except*
|
||||
when the Screen is the :ref:`active_screen`. If you want to delete the current Screen
|
||||
as you load a new one, call :cpp:func:`lv_screen_load_anim` and pass ``true`` for the
|
||||
``auto_del`` argument. If you want to keep the current Screen in RAM when you load a
|
||||
new Screen, pass ``false`` for the ``auto_del`` argument, or call
|
||||
:cpp:func:`lv_screen_active` to load the new screen.
|
||||
|
||||
A system designer is free to keep any number of Screens (and their child Widgets) in
|
||||
RAM (e.g. for quick re-display again later). Doing so:
|
||||
|
||||
- requires more RAM, but
|
||||
- can save the time of repeatedly creating the Screen and its child Widgets;
|
||||
- can be handy when a Screen is complex and/or can be made the :ref:`active_screen` freqently.
|
||||
|
||||
If multiple Screens are maintained in RAM simultaneously, it is up to the system
|
||||
designer as to how they are managed.
|
||||
|
||||
|
||||
.. _basics_creating_widgets:
|
||||
|
||||
Creating Widgets
|
||||
~~~~~~~~~~~~~~~~
|
||||
Widgets are created by calling functions that look like this::
|
||||
|
||||
lv_<type>_create(parent)
|
||||
|
||||
The call will return an :cpp:type:`lv_obj_t` ``*`` pointer that can be used later to
|
||||
reference the Widget to set its attributes.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * slider1 = lv_slider_create(lv_screen_active());
|
||||
|
||||
|
||||
.. _basics_modifying_widgets:
|
||||
|
||||
Modifying Widgets
|
||||
~~~~~~~~~~~~~~~~~
|
||||
Attributes common to all Widgets are set by functions that look like this::
|
||||
|
||||
lv_obj_set_<attribute_name>(widget, <value>)
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_x(slider1, 30);
|
||||
lv_obj_set_y(slider1, 10);
|
||||
lv_obj_set_size(slider1, 200, 50);
|
||||
|
||||
Along with these attributes, widgets can have type-specific attributes which are
|
||||
set by functions that look like this::
|
||||
|
||||
lv_<type>_set_<attribute_name>(widget, <value>)
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_slider_set_value(slider1, 70, LV_ANIM_ON);
|
||||
|
||||
To see the full API visit the documentation of the Widget in question under
|
||||
:ref:`widgets` or study its related header file in the source code, e.g.
|
||||
|
||||
- lvgl/src/widgets/slider/lv_slider.h
|
||||
|
||||
or view it on GitHub, e.g.
|
||||
|
||||
- https://github.com/lvgl/lvgl/blob/master/src/widgets/slider/lv_slider.h .
|
||||
|
||||
|
||||
.. _basics_deleting_widgets:
|
||||
|
||||
Deleting Widgets
|
||||
~~~~~~~~~~~~~~~~
|
||||
To delete any widget and its children::
|
||||
|
||||
lv_obj_delete(lv_obj_t * widget)
|
||||
|
||||
|
||||
|
||||
.. _basics_events:
|
||||
|
||||
Events
|
||||
------
|
||||
|
||||
Events are used to inform the application that something has happened with a Widget.
|
||||
You can assign one or more callbacks to a Widget which will be called when the
|
||||
Widget is clicked, released, dragged, being deleted, etc.
|
||||
|
||||
A callback is assigned like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_event_cb(btn, my_btn_event_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
...
|
||||
|
||||
void my_btn_event_cb(lv_event_t * e)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
}
|
||||
|
||||
:cpp:enumerator:`LV_EVENT_ALL` can be used instead of :cpp:enumerator:`LV_EVENT_CLICKED`
|
||||
to invoke the callback for all events. (Beware: there are a LOT of events! This can
|
||||
be handy for debugging or learning what events occur for a given Widget, or indeed
|
||||
if the application needs to process all events for some reason.)
|
||||
|
||||
Event callbacks receive the argument :cpp:expr:`lv_event_t * e` containing the
|
||||
current event code and other event-related information. The current event code can
|
||||
be retrieved with:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
|
||||
The Widget that triggered the event can be retrieved with:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
|
||||
To learn all features of the events go to the :ref:`events` section.
|
||||
|
||||
|
||||
.. _basics_parts:
|
||||
|
||||
Parts
|
||||
-----
|
||||
|
||||
Widgets are built from one or more *parts*. For example, a button
|
||||
has only one part called :cpp:enumerator:`LV_PART_MAIN`. However, a
|
||||
:ref:`lv_slider` has :cpp:enumerator:`LV_PART_MAIN`, :cpp:enumerator:`LV_PART_INDICATOR`
|
||||
and :cpp:enumerator:`LV_PART_KNOB`.
|
||||
|
||||
By using parts you can apply different styles to sub-elements of a widget. (See below.)
|
||||
|
||||
Read the Widget's documentation to learn which parts it uses.
|
||||
|
||||
|
||||
.. _basics_states:
|
||||
|
||||
States
|
||||
------
|
||||
|
||||
Widgets can be in a combination of the following states:
|
||||
|
||||
- :cpp:enumerator:`LV_STATE_DEFAULT`: Normal, released state
|
||||
- :cpp:enumerator:`LV_STATE_CHECKED`: Toggled or checked state
|
||||
- :cpp:enumerator:`LV_STATE_FOCUSED`: Focused via keypad or encoder or clicked via touchpad/mouse
|
||||
- :cpp:enumerator:`LV_STATE_FOCUS_KEY`: Focused via keypad or encoder but not via touchpad/mouse
|
||||
- :cpp:enumerator:`LV_STATE_EDITED`: Edit by an encoder
|
||||
- :cpp:enumerator:`LV_STATE_HOVERED`: Hovered by mouse
|
||||
- :cpp:enumerator:`LV_STATE_PRESSED`: Being pressed
|
||||
- :cpp:enumerator:`LV_STATE_SCROLLED`: Being scrolled
|
||||
- :cpp:enumerator:`LV_STATE_DISABLED`: Disabled
|
||||
|
||||
For example, if you press a Widget it will automatically go to the
|
||||
:cpp:enumerator:`LV_STATE_FOCUSED` and :cpp:enumerator:`LV_STATE_PRESSED` states and when you
|
||||
release it the :cpp:enumerator:`LV_STATE_PRESSED` state will be removed while the
|
||||
:cpp:enumerator:`LV_STATE_FOCUSED` state remains active.
|
||||
|
||||
To check if a Widget is in a given state use
|
||||
:cpp:expr:`lv_obj_has_state(widget, LV_STATE_...)`. It will return ``true`` if the
|
||||
Widget is currently in that state.
|
||||
|
||||
To manually add or remove states use:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_state(widget, LV_STATE_...);
|
||||
lv_obj_remove_state(widget, LV_STATE_...);
|
||||
|
||||
|
||||
.. _basics_styles:
|
||||
|
||||
Styles
|
||||
------
|
||||
|
||||
A style instance contains properties such as background color, border
|
||||
width, font, etc. that describe the appearance of Widgets.
|
||||
|
||||
Styles are carried in :cpp:struct:`lv_style_t` objects. Only their pointer is saved
|
||||
in the Widgets so they need to be defined as static or global variables. Before
|
||||
using a style it needs to be initialized with :cpp:expr:`lv_style_init(&style1)`.
|
||||
After that, properties can be added to configure the style. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style1;
|
||||
lv_style_init(&style1);
|
||||
lv_style_set_bg_color(&style1, lv_color_hex(0xa03080))
|
||||
lv_style_set_border_width(&style1, 2))
|
||||
|
||||
See :ref:`style_properties_overview` for more details.
|
||||
|
||||
See :ref:`style_properties` to see the full list.
|
||||
|
||||
Styles are assigned using the OR-ed combination of a Widget's part and
|
||||
state. For example to use this style on the slider's indicator when the
|
||||
slider is pressed:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR | LV_STATE_PRESSED);
|
||||
|
||||
If the *part* is :cpp:enumerator:`LV_PART_MAIN` it can be omitted:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_style(btn1, &style1, LV_STATE_PRESSED); /* Equal to LV_PART_MAIN | LV_STATE_PRESSED */
|
||||
|
||||
Similarly, :cpp:enumerator:`LV_STATE_DEFAULT` can be omitted:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR); /* Equal to LV_PART_INDICATOR | LV_STATE_DEFAULT */
|
||||
|
||||
For :cpp:enumerator:`LV_STATE_DEFAULT` | :cpp:enumerator:`LV_PART_MAIN` simply pass ``0``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_style(btn1, &style1, 0); /* Equal to LV_PART_MAIN | LV_STATE_DEFAULT */
|
||||
|
||||
Styles can be cascaded (similarly to CSS). This means you can add more
|
||||
styles to a part of a Widget. For example ``style_btn`` can set a
|
||||
default button appearance, and ``style_btn_red`` can overwrite the
|
||||
background color to make the button red:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_style(btn1, &style_btn, 0);
|
||||
lv_obj_add_style(btn1, &style1_btn_red, 0);
|
||||
|
||||
If a property is not set for the current state, the style with
|
||||
:cpp:enumerator:`LV_STATE_DEFAULT` will be used. A default value is used if the
|
||||
property is not defined in the default state.
|
||||
|
||||
Some properties (particularly the text-related ones) can be inherited. This
|
||||
means if a property is not set in a Widget it will be searched for in
|
||||
its parents. For example, you can set the font once in the screen's
|
||||
style and all text on that screen will inherit it by default.
|
||||
|
||||
Local style properties also can be added to Widgets. This creates a
|
||||
style which resides inside the Widget and is used only by that Widget:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_style_bg_color(slider1, lv_color_hex(0x2080bb), LV_PART_INDICATOR | LV_STATE_PRESSED);
|
||||
|
||||
To learn all the features of styles see :ref:`styles`.
|
||||
|
||||
|
||||
.. _basics_themes:
|
||||
|
||||
Themes
|
||||
------
|
||||
|
||||
Themes are the default styles for Widgets. Styles from a theme are
|
||||
applied automatically when Widgets are created.
|
||||
|
||||
The theme for your application is a compile time configuration set in
|
||||
``lv_conf.h``.
|
||||
|
||||
|
||||
.. _basics_micropython:
|
||||
|
||||
MicroPython
|
||||
-----------
|
||||
|
||||
LVGL can even be used with :ref:`micropython`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Initialize
|
||||
import display_driver
|
||||
import lvgl as lv
|
||||
|
||||
# Create a button with a label
|
||||
scr = lv.obj()
|
||||
btn = lv.button(scr)
|
||||
btn.align(lv.ALIGN.CENTER, 0, 0)
|
||||
label = lv.label(btn)
|
||||
label.set_text('Hello World!')
|
||||
lv.screen_load(scr)
|
||||
|
||||
|
||||
|
||||
.. _going_deeper:
|
||||
|
||||
Going Deeper
|
||||
*************
|
||||
|
||||
There are several good ways ways to gain deeper knowledge of LVGL. Here is one
|
||||
recommended order of documents to read and things to play with while you are
|
||||
advancing your knowledge:
|
||||
|
||||
1. If not already read, start with :ref:`introduction` page of
|
||||
the documentation. (5 minutes)
|
||||
2. Check out the `Online Demos`_ to see LVGL in action. (3 minutes)
|
||||
3. If not already done, read the :ref:`lvgl_basics` (above). (15 minutes)
|
||||
4. Set up an LVGL :ref:`simulator`. (10 minutes)
|
||||
5. Have a look at some :ref:`examples` and their code.
|
||||
6. Add LVGL to your project. See :ref:`add_lvgl_to_your_project` or check out
|
||||
the `ready-to-use Projects`_.
|
||||
7. Read the :ref:`main_components` pages to get a better understanding of the library. (2-3 hours)
|
||||
8. Skim the documentation of :ref:`widgets` to see what is available.
|
||||
9. If you have questions go to the `Forum`_.
|
||||
10. Read the :ref:`contributing` guide to see how you can help to improve LVGL. (15 minutes)
|
||||
|
||||
|
||||
.. _online demos: https://lvgl.io/demos
|
||||
.. _ready-to-use projects: https://github.com/lvgl?q=lv_port_&type=&language=
|
||||
.. _forum: https://forum.lvgl.io/
|
||||
|
||||
|
||||
|
||||
.. _basics_examples:
|
||||
|
||||
Basic Examples
|
||||
**************
|
||||
|
||||
Below are several basic examples. They include the application code that produces
|
||||
the Widget Tree needed to make LVGL render the examples shown. Each example assumes
|
||||
a LVGL has undergone normal initialization, meaning that a ``lv_display_t`` object
|
||||
was created and therefore has an :ref:`active_screen`.
|
||||
|
||||
|
||||
.. include:: ../examples/get_started/index.rst
|
||||
|
||||
|
||||
@@ -1,290 +1,11 @@
|
||||
.. _introduction:
|
||||
.. _intro-page:
|
||||
|
||||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library providing everything you need to create an embedded GUI with easy-to-use graphical elements, beautiful visual effects and a low memory footprint.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
|
||||
Key features
|
||||
------------
|
||||
|
||||
- Powerful building blocks such as buttons, charts, lists, sliders, images, etc.
|
||||
- Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling
|
||||
- Various input devices such as touchpad, mouse, keyboard, encoder, etc.
|
||||
- Multi-language support with UTF-8 encoding
|
||||
- Multi-display support, i.e. use multiple TFT, monochrome displays simultaneously
|
||||
- Fully customizable graphic elements with CSS-like styles
|
||||
- Hardware independent: use with any microcontroller or display
|
||||
- Scalable: able to operate with little memory (64 kB Flash, 16 kB RAM)
|
||||
- OS, external memory and GPU are supported but not required
|
||||
- Single frame buffer operation even with advanced graphic effects
|
||||
- Written in C for maximal compatibility (C++ compatible)
|
||||
- Simulator to start embedded GUI design on a PC without embedded hardware
|
||||
- Binding to MicroPython
|
||||
- Tutorials, examples, themes for rapid GUI design
|
||||
- Documentation is available online and as PDF
|
||||
- Free and open-source under MIT license
|
||||
|
||||
.. _requirements:
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Basically, every modern controller which is able to drive a display is suitable to run LVGL. The minimal requirements are:
|
||||
|
||||
* 16, 32 or 64 bit microcontroller or processor
|
||||
* > 16 MHz clock speed is recommended
|
||||
* Flash/ROM: > 64 kB for the very essential components (> 180 kB is recommended)
|
||||
* RAM:
|
||||
* Static RAM usage: ~2 kB depending on the used features and object types
|
||||
* stack: > 2kB (> 8 kB is recommended)
|
||||
* Dynamic data (heap): > 2 KB (> 48 kB is recommended if using several objects).
|
||||
Set by :c:macro:`LV_MEM_SIZE` in ``lv_conf.h``.
|
||||
* Display buffer: > *"Horizontal resolution"* pixels (> 10 *"Horizontal resolution"* is recommended)
|
||||
* One frame buffer in the MCU or in an external display controller
|
||||
* C99 or newer compiler
|
||||
* Basic C (or C++) knowledge:
|
||||
* `pointers <https://www.tutorialspoint.com/cprogramming/c_pointers.htm>`_.
|
||||
* `structs <https://www.tutorialspoint.com/cprogramming/c_structures.htm>`_.
|
||||
* `callbacks <https://www.geeksforgeeks.org/callbacks-in-c/>`_.
|
||||
|
||||
|
||||
|
||||
:Note: *memory usage may vary depending on architecture, compiler and build options.*
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
The LVGL project (including all repositories) is licensed under `MIT license <https://github.com/lvgl/lvgl/blob/master/LICENCE.txt>`_.
|
||||
This means you can use it even in commercial projects.
|
||||
|
||||
It's not mandatory, but we highly appreciate it if you write a few words about your project in the `My projects <https://forum.lvgl.io/c/my-projects/10>`_ category of the forum or a private message to `lvgl.io <https://lvgl.io/#contact>`_.
|
||||
|
||||
Although you can get LVGL for free there is a massive amount of work behind it. It's created by a group of volunteers who made it available for you in their free time.
|
||||
|
||||
To make the LVGL project sustainable, please consider :ref:`contributing` to the project.
|
||||
You can choose from many different ways of contributing See :ref:`contributing` such as simply writing a tweet about you using LVGL, fixing bugs, translating the documentation, or even becoming a maintainer.
|
||||
|
||||
Repository layout
|
||||
-----------------
|
||||
|
||||
All repositories of the LVGL project are hosted on `GitHub <https://github.com/lvgl>`_
|
||||
|
||||
You will find these repositories there:
|
||||
|
||||
* `lvgl <https://github.com/lvgl/lvgl>`_: The library itself with many `examples <https://github.com/lvgl/lvgl/blob/master/examples/>`_ and `demos <https://github.com/lvgl/lvgl/blob/master/demos/>`_.
|
||||
* `lv_drivers <https://github.com/lvgl/lv_drivers>`_: Display and input device drivers
|
||||
* `blog <https://github.com/lvgl/blog>`_: Source of the `blog's site <https://blog.lvgl.io>`_
|
||||
* `sim <https://github.com/lvgl/sim>`_: Source of the `online simulator's site <https://sim.lvgl.io>`_
|
||||
* `lv_port_* <https://github.com/lvgl?q=lv_port&type=&language=>`_: LVGL ports to development boards or environments
|
||||
* `lv_binding_* <https://github.com/lvgl?q=lv_binding&type=&language=l>`_: Bindings to other languages
|
||||
|
||||
Release policy
|
||||
--------------
|
||||
|
||||
The core repositories follow the rules of `Semantic versioning <https://semver.org/>`_:
|
||||
|
||||
* Major version: incompatible API changes. E.g. v5.0.0, v6.0.0
|
||||
* Minor version: new but backward-compatible functionalities. E.g. v6.1.0, v6.2.0
|
||||
* Patch version: backward-compatible bug fixes. E.g. v6.1.1, v6.1.2
|
||||
|
||||
Tags like `vX.Y.Z` are created for every release.
|
||||
|
||||
|
||||
Release cycle
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
* Bug fixes: Released on demand even weekly
|
||||
* Minor releases: Every 3-4 months
|
||||
* Major releases: Approximately yearly
|
||||
|
||||
Branches
|
||||
^^^^^^^^
|
||||
|
||||
The core repositories have at least the following branches:
|
||||
|
||||
* `master`: latest version, patches are merged directly here.
|
||||
* `release/vX.Y`: stable versions of the minor releases
|
||||
* `fix/some-description`: temporary branches for bug fixes
|
||||
* `feat/some-description`: temporary branches for features
|
||||
|
||||
|
||||
Changelog
|
||||
^^^^^^^^^
|
||||
|
||||
The changes are recorded in :ref:`changelog`.
|
||||
|
||||
Version support
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Before v8 the last minor release of each major series was supported for 1 year.
|
||||
Starting from v8, every minor release is supported for 1 year.
|
||||
|
||||
|
||||
+---------+--------------+--------------+--------+
|
||||
| Version | Release date | Support end | Active |
|
||||
+=========+==============+==============+========+
|
||||
|v5.3 | 1 Feb, 2019 | 1 Feb, 2020 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v6.1 | 26 Nov, 2019 | 26 Nov, 2020 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v7.11 | 16 Mar, 2021 | 16 Mar, 2022 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.0 | 1 Jun, 2021 | 1 Jun, 2022 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.1 | 10 Nov, 2021 | 10 Nov, 2022 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.2 | 31 Jan, 2022 | 31 Jan, 2023 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.3 | 6 July, 2022 | 1 Jan, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.4 | Mar 19, 2024 | Mar 20, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v9.0 | Jan 22, 2024 | Jan 22, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v9.1 | Mar 20, 2024 | Mar 20, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v9.2 | Aug 26, 2024 | Aug 26, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|
||||
|
||||
FAQ
|
||||
---
|
||||
|
||||
Where can I ask questions?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can ask questions in the forum: `https://forum.lvgl.io/ <https://forum.lvgl.io/>`_.
|
||||
|
||||
We use `GitHub issues <https://github.com/lvgl/lvgl/issues>`_ for development related discussion.
|
||||
You should use them only if your question or issue is tightly related to the development of the library.
|
||||
|
||||
Before posting a question, please ready this FAQ section as you might find answer to your issue here too.
|
||||
|
||||
|
||||
Is my MCU/hardware supported?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Every MCU which is capable of driving a display via parallel port, SPI, RGB interface or anything else and fulfills the :ref:`requirements` is supported by LVGL.
|
||||
|
||||
This includes:
|
||||
|
||||
* "Common" MCUs like STM32F, STM32H, NXP Kinetis, LPC, iMX, dsPIC33, PIC32, SWM341 etc.
|
||||
* Bluetooth, GSM, Wi-Fi modules like Nordic NRF, Espressif ESP32 and Raspberry Pi Pico W
|
||||
* Linux with frame buffer device such as /dev/fb0. This includes Single-board computers like the Raspberry Pi
|
||||
* Anything else with a strong enough MCU and a peripheral to drive a display
|
||||
|
||||
|
||||
Is my display supported?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
LVGL needs just one simple driver function to copy an array of pixels into a given area of the display.
|
||||
If you can do this with your display then you can use it with LVGL.
|
||||
|
||||
Some examples of the supported display types:
|
||||
|
||||
* TFTs with 16 or 24 bit color depth
|
||||
* Monitors with an HDMI port
|
||||
* Small monochrome displays
|
||||
* Gray-scale displays
|
||||
* even LED matrices
|
||||
* or any other display where you can control the color/state of the pixels
|
||||
|
||||
See the :ref:`display_interface` section to learn more.
|
||||
|
||||
|
||||
LVGL doesn't start, randomly crashes or nothing is drawn on the display. What can be the problem?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Try increasing :c:macro:`LV_MEM_SIZE`.
|
||||
* Be sure your display works without LVGL. E.g. paint it to red on start up.
|
||||
* Enable :ref:`logging`
|
||||
* Enable asserts in ``lv_conf.h`` (`LV_USE_ASSERT_...`)
|
||||
* If you use an RTOS
|
||||
* increase the stack size of the task which calls :cpp:func:`lv_timer_handler`
|
||||
* Be sure you used a mutex as described here: :ref:`os_interrupt`
|
||||
|
||||
|
||||
My display driver is not called. What have I missed?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Be sure you are calling :cpp:expr:`lv_tick_inc(x)` in an interrupt and :cpp:func:`lv_timer_handler` in your main ``while(1)``.
|
||||
|
||||
Learn more in the :ref:`tick` and :ref:`timer_handler` sections.
|
||||
|
||||
|
||||
Why is the display driver called only once? Only the upper part of the display is refreshed.
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Be sure you are calling :cpp:expr:`lv_display_flush_ready(drv)` at the end of your "*display flush callback*".
|
||||
|
||||
|
||||
Why do I see only garbage on the screen?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Probably there a bug in your display driver. Try the following code without using LVGL. You should see a square with red-blue gradient.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define BUF_W 20
|
||||
#define BUF_H 10
|
||||
|
||||
lv_color_t buf[BUF_W * BUF_H];
|
||||
lv_color_t * buf_p = buf;
|
||||
uint16_t x, y;
|
||||
for(y = 0; y < BUF_H; y++) {
|
||||
lv_color_t c = lv_color_mix(LV_COLOR_BLUE, LV_COLOR_RED, (y * 255) / BUF_H);
|
||||
for(x = 0; x < BUF_W; x++){
|
||||
(*buf_p) = c;
|
||||
buf_p++;
|
||||
}
|
||||
}
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = 10;
|
||||
a.y1 = 40;
|
||||
a.x2 = a.x1 + BUF_W - 1;
|
||||
a.y2 = a.y1 + BUF_H - 1;
|
||||
my_flush_cb(NULL, &a, buf);
|
||||
|
||||
|
||||
Why do I see nonsense colors on the screen?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Probably LVGL's color format is not compatible with your display's color format. Check :c:macro:`LV_COLOR_DEPTH` in *lv_conf.h*.
|
||||
|
||||
|
||||
How to speed up my UI?
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Turn on compiler optimization and enable cache if your MCU has it
|
||||
- Increase the size of the display buffer
|
||||
- Use two display buffers and flush the buffer with DMA (or similar peripheral) in the background
|
||||
- Increase the clock speed of the SPI or parallel port if you use them to drive the display
|
||||
- If your display has an SPI port consider changing to a model with a parallel interface because it has much higher throughput
|
||||
- Keep the display buffer in internal RAM (not in external SRAM) because LVGL uses it a lot and it should have a fast access time
|
||||
|
||||
|
||||
How to reduce flash/ROM usage?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can disable all the unused features (such as animations, file system, GPU etc.) and object types in *lv_conf.h*.
|
||||
|
||||
If you are using GCC/CLANG you can add `-fdata-sections -ffunction-sections` compiler flags and `--gc-sections` linker flag to remove unused functions and variables from the final binary. If possible, add the `-flto` compiler flag to enable link-time-optimisation together with `-Os` for GCC or `-Oz` for CLANG.
|
||||
|
||||
|
||||
How to reduce the RAM usage
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Lower the size of the *Display buffer*
|
||||
* Reduce :c:macro:`LV_MEM_SIZE` in *lv_conf.h*. This memory is used when you create objects like buttons, labels, etc.
|
||||
* To work with lower :c:macro:`LV_MEM_SIZE` you can create objects only when required and delete them when they are not needed anymore
|
||||
|
||||
|
||||
How to work with an operating system?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To work with an operating system where tasks can interrupt each other (preemptively) you should protect LVGL related function calls with a mutex.
|
||||
See the :ref:`os_interrupt` section to learn more.
|
||||
introduction
|
||||
basics
|
||||
add-lvgl-to-your-project/index
|
||||
|
||||
304
docs/intro/introduction.rst
Normal file
304
docs/intro/introduction.rst
Normal file
@@ -0,0 +1,304 @@
|
||||
.. _introduction:
|
||||
|
||||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
LVGL (Light and Versatile Graphics Library) is a free and open-source graphics
|
||||
library providing everything you need to create an embedded GUI with easy-to-use
|
||||
graphical elements, beautiful visual effects, and a low memory footprint.
|
||||
|
||||
|
||||
Key features
|
||||
------------
|
||||
|
||||
- Powerful building blocks such as :ref:`buttons, charts, lists, sliders, images <widgets>`, etc.
|
||||
- Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling
|
||||
- Various input devices such as touchpad, mouse, keyboard, encoder, etc.
|
||||
- Multi-language support with UTF-8 encoding
|
||||
- Multi-display support, even with mixed color formats
|
||||
- Fully customizable graphic elements with CSS-like styles
|
||||
- Hardware independent: use with any microcontroller or display
|
||||
- Scalable: able to operate with little memory (64 kB Flash, 16 kB RAM)
|
||||
- :ref:`OS <threading>`, external memory and :ref:`GPU <draw>` are supported but not required
|
||||
- Single frame buffer operation even with advanced graphic effects
|
||||
- Written in C for maximal compatibility (C++ compatible)
|
||||
- :ref:`Simulator <simulator>` to start embedded GUI design on a PC without embedded hardware
|
||||
- User code developed under similator can be shared with firmware to make UI development more efficient.
|
||||
- Binding to :ref:`MicroPython`
|
||||
- Tutorials, examples, themes for rapid GUI design
|
||||
- Documentation is available online
|
||||
- Free and open-source under MIT license
|
||||
|
||||
|
||||
.. _requirements:
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Basically, every modern controller which is able to drive a display is suitable to run LVGL. The minimal requirements are:
|
||||
|
||||
* 16, 32 or 64 bit microcontroller or processor
|
||||
* > 16 MHz clock speed is recommended
|
||||
* Flash/ROM: > 64 kB for the very essential components (> 180 kB is recommended)
|
||||
* RAM:
|
||||
* Static RAM usage: ~2 kB depending on the used features and Widget types
|
||||
* stack: > 2kB (> 8 kB recommended)
|
||||
* Dynamic data (heap): > 2 KB (> 48 kB is recommended if using many GUI Widgets).
|
||||
Set by :c:macro:`LV_MEM_SIZE` in ``lv_conf.h``.
|
||||
* Display buffer: > *"Horizontal resolution"* pixels (> 10 X *"Horizontal resolution"* is recommended)
|
||||
* One frame buffer in the MCU or in an external display controller
|
||||
* C99 or newer compiler
|
||||
* Basic C (or C++) knowledge:
|
||||
* `pointers <https://www.tutorialspoint.com/cprogramming/c_pointers.htm>`__.
|
||||
* `structs <https://www.tutorialspoint.com/cprogramming/c_structures.htm>`__.
|
||||
* `callbacks <https://www.geeksforgeeks.org/callbacks-in-c/>`__.
|
||||
|
||||
.. note::
|
||||
*Memory usage may vary depending on architecture, compiler and build options.*
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
The LVGL project (including all repositories) is licensed under the `MIT license <https://github.com/lvgl/lvgl/blob/master/LICENCE.txt>`__.
|
||||
This means you can use it even in commercial projects.
|
||||
|
||||
It is not mandatory, but we highly appreciate it if you write a few words about your project in the `My projects <https://forum.lvgl.io/c/my-projects/10>`__ category of the forum or a private message to `lvgl.io <https://lvgl.io/#contact>`__.
|
||||
|
||||
Although you can get LVGL for free there is a massive amount of work behind it. It's created by a group of volunteers who made it available for you in their free time.
|
||||
|
||||
To make the LVGL project sustainable, please consider :ref:`contributing` to the project.
|
||||
You can choose from many different ways of contributing See :ref:`contributing` such as simply writing a tweet about you using LVGL, fixing bugs, translating the documentation, or even becoming a maintainer.
|
||||
|
||||
|
||||
Repository layout
|
||||
-----------------
|
||||
|
||||
All repositories of the LVGL project are hosted on `GitHub <https://github.com/lvgl>`_.
|
||||
|
||||
You will find these repositories there:
|
||||
|
||||
* `lvgl <https://github.com/lvgl/lvgl>`__: The library itself with many `examples <https://github.com/lvgl/lvgl/blob/master/examples/>`_ and `demos <https://github.com/lvgl/lvgl/blob/master/demos/>`__.
|
||||
* `lv_drivers <https://github.com/lvgl/lv_drivers>`__: Display and input device drivers
|
||||
* `blog <https://github.com/lvgl/blog>`__: Source of the `blog's site <https://blog.lvgl.io>`__
|
||||
* `sim <https://github.com/lvgl/sim>`__: Source of the `online simulator's site <https://sim.lvgl.io>`__
|
||||
* `lv_port_* <https://github.com/lvgl?q=lv_port&type=&language=>`__: LVGL ports to development boards or environments
|
||||
* `lv_binding_* <https://github.com/lvgl?q=lv_binding&type=&language=l>`__: Bindings to other languages
|
||||
|
||||
|
||||
Release policy
|
||||
--------------
|
||||
|
||||
The core repositories follow the rules of `Semantic Versioning <https://semver.org/>`__:
|
||||
|
||||
* Major version: incompatible API changes. E.g. v5.0.0, v6.0.0
|
||||
* Minor version: new but backward-compatible functionalities. E.g. v6.1.0, v6.2.0
|
||||
* Patch version: backward-compatible bug fixes. E.g. v6.1.1, v6.1.2
|
||||
|
||||
Tags like `vX.Y.Z` are created for every release.
|
||||
|
||||
|
||||
Release cycle
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
* Bug fixes: released on demand even weekly
|
||||
* Minor releases: every 3-4 months
|
||||
* Major releases: approximately yearly
|
||||
|
||||
|
||||
Branches
|
||||
^^^^^^^^
|
||||
|
||||
The core repositories have at least the following branches:
|
||||
|
||||
* `master`: latest version, patches are merged directly here
|
||||
* `release/vX.Y`: stable versions of the minor releases
|
||||
* `fix/some-description`: temporary branches for bug fixes
|
||||
* `feat/some-description`: temporary branches for features
|
||||
|
||||
|
||||
Change log
|
||||
^^^^^^^^^^
|
||||
|
||||
The changes are recorded in :ref:`changelog`.
|
||||
|
||||
|
||||
Version support
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Before v8 the last minor release of each major series was supported for 1 year.
|
||||
Starting from v8, every minor release is supported for 1 year.
|
||||
|
||||
|
||||
+---------+--------------+--------------+--------+
|
||||
| Version | Release date | Support end | Active |
|
||||
+=========+==============+==============+========+
|
||||
|v5.3 | 1 Feb, 2019 | 1 Feb, 2020 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v6.1 | 26 Nov, 2019 | 26 Nov, 2020 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v7.11 | 16 Mar, 2021 | 16 Mar, 2022 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.0 | 1 Jun, 2021 | 1 Jun, 2022 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.1 | 10 Nov, 2021 | 10 Nov, 2022 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.2 | 31 Jan, 2022 | 31 Jan, 2023 | No |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.3 | 6 July, 2022 | 1 Jan, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v8.4 | Mar 19, 2024 | Mar 20, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v9.0 | Jan 22, 2024 | Jan 22, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v9.1 | Mar 20, 2024 | Mar 20, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|v9.2 | Aug 26, 2024 | Aug 26, 2025 | Yes |
|
||||
+---------+--------------+--------------+--------+
|
||||
|
||||
|
||||
FAQ
|
||||
---
|
||||
|
||||
Where can I ask questions?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can ask questions in the forum: https://forum.lvgl.io/.
|
||||
|
||||
We use `GitHub issues <https://github.com/lvgl/lvgl/issues>`_ for development related discussion.
|
||||
You should use them only if your question or issue is tightly related to the development of the library.
|
||||
|
||||
Before posting a question, please read this FAQ section since you might find the answer to your issue here as well.
|
||||
|
||||
|
||||
Is my MCU/hardware supported?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Every MCU which is capable of driving a display via parallel port, SPI, RGB interface or anything else and fulfills the :ref:`requirements` is supported by LVGL.
|
||||
|
||||
This includes:
|
||||
|
||||
* "Common" MCUs like STM32F, STM32H, NXP Kinetis, LPC, iMX, dsPIC33, PIC32, SWM341 etc.
|
||||
* Bluetooth, GSM, Wi-Fi modules like Nordic NRF, Espressif ESP32 and Raspberry Pi Pico W
|
||||
* Linux with frame buffer device such as /dev/fb0. This includes Single-board computers like the Raspberry Pi
|
||||
* Anything else with a strong enough MCU and a peripheral to drive a display
|
||||
|
||||
|
||||
Is my display supported?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
LVGL needs just one simple driver function to copy an array of pixels into a given area of the display.
|
||||
If you can do this with your display then you can use it with LVGL.
|
||||
|
||||
Some examples of the supported display types:
|
||||
|
||||
* TFTs with 16 or 24 bit color depth
|
||||
* Monitors with an HDMI port
|
||||
* Small monochrome displays
|
||||
* Gray-scale displays
|
||||
* even LED matrices
|
||||
* or any other display where you can control the color/state of the pixels
|
||||
|
||||
See the :ref:`display` section to learn more.
|
||||
|
||||
|
||||
LVGL doesn't start, randomly crashes or nothing is drawn on the display. What can be the problem?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Try increasing :c:macro:`LV_MEM_SIZE`.
|
||||
* Be sure your display works without LVGL. E.g. paint it to red on start up.
|
||||
* Enable :ref:`logging`.
|
||||
* Enable assertions in ``lv_conf.h`` (``LV_USE_ASSERT_...``).
|
||||
* If you use an RTOS:
|
||||
* Increase the stack size of the task that calls :cpp:func:`lv_timer_handler`.
|
||||
* Be sure you are using one of the methods for thread management as described in :ref:`threading`.
|
||||
|
||||
|
||||
My display driver is not called. What have I missed?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Be sure you are calling :cpp:expr:`lv_tick_inc(x)` as prescribed in
|
||||
:ref:`tick_interface` and are calling :cpp:func:`lv_timer_handler` as prescribed in
|
||||
:ref:`timer_handler`.
|
||||
|
||||
Learn more in the :ref:`tick_interface` and :ref:`timer_handler` sections.
|
||||
|
||||
|
||||
Why is the display driver called only once? Only the upper part of the display is refreshed.
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Be sure you are calling :cpp:expr:`lv_display_flush_ready(drv)` at the end of your
|
||||
"*display flush callback*" as per :ref:`flush_callback` section.
|
||||
|
||||
|
||||
Why do I see only garbage on the screen?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There is probably a bug in your display driver. Try the following code without using LVGL. You should see a square with red-blue gradient.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define BUF_W 20
|
||||
#define BUF_H 10
|
||||
|
||||
lv_color_t buf[BUF_W * BUF_H];
|
||||
lv_color_t * buf_p = buf;
|
||||
uint16_t x, y;
|
||||
for(y = 0; y < BUF_H; y++) {
|
||||
lv_color_t c = lv_color_mix(LV_COLOR_BLUE, LV_COLOR_RED, (y * 255) / BUF_H);
|
||||
for(x = 0; x < BUF_W; x++){
|
||||
(*buf_p) = c;
|
||||
buf_p++;
|
||||
}
|
||||
}
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = 10;
|
||||
a.y1 = 40;
|
||||
a.x2 = a.x1 + BUF_W - 1;
|
||||
a.y2 = a.y1 + BUF_H - 1;
|
||||
my_flush_cb(NULL, &a, buf);
|
||||
|
||||
|
||||
Why do I see nonsense colors on the screen?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The configured LVGL color format is probably not compatible with your display's color format. Check :c:macro:`LV_COLOR_DEPTH` in *lv_conf.h*.
|
||||
|
||||
|
||||
How do I speed up my UI?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Turn on compiler optimization and enable instruction- and data-caching if your MCU has them.
|
||||
- Increase the size of the display buffer.
|
||||
- Use two display buffers and flush the buffer with DMA (or similar peripheral) in the background.
|
||||
- Increase the clock speed of the SPI or parallel port if you use them to drive the display.
|
||||
- If your display has an SPI port consider changing to a model with a parallel interface because it has much higher throughput.
|
||||
- Keep the display buffer in internal RAM (not in external SRAM) because LVGL uses it a lot and it should have fast access time.
|
||||
|
||||
|
||||
How do I reduce flash/ROM usage?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can disable unused features (such as animations, file system, GPU etc.) and widget types in *lv_conf.h*.
|
||||
|
||||
If you are using GCC/CLANG you can add `-fdata-sections -ffunction-sections` compiler flags and `--gc-sections` linker flag to remove unused functions and variables from the final binary. If possible, add the `-flto` compiler flag to enable link-time-optimisation together with `-Os` for GCC or `-Oz` for CLANG.
|
||||
|
||||
|
||||
How do I reduce RAM usage?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Lower the size of the *Display buffer*.
|
||||
* Reduce :c:macro:`LV_MEM_SIZE` in *lv_conf.h*. This memory is used when you create Widgets like buttons, labels, etc.
|
||||
* To work with lower :c:macro:`LV_MEM_SIZE` you can create Widgets only when required and delete them when they are not needed anymore.
|
||||
|
||||
|
||||
How do I use LVGL with an operating system?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To work with an operating system where tasks can interrupt each other (preemptively),
|
||||
you must ensure that no LVGL function call be called while another LVGL call is in
|
||||
progress. There are several ways to do this. See the :ref:`threading` section to
|
||||
learn more.
|
||||
|
||||
Reference in New Issue
Block a user