feat(docs): reorganize docs (#7136)
This commit is contained in:
578
docs/details/base-widget/coord.rst
Normal file
578
docs/details/base-widget/coord.rst
Normal file
@@ -0,0 +1,578 @@
|
||||
.. _coord:
|
||||
|
||||
============================
|
||||
Positions, Sizes and Layouts
|
||||
============================
|
||||
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
Similar to many other parts of LVGL, the concept of setting the
|
||||
coordinates was inspired by CSS. LVGL has by no means a complete
|
||||
implementation of CSS but a comparable subset is implemented (sometimes
|
||||
with minor adjustments).
|
||||
|
||||
In short this means:
|
||||
|
||||
- Explicitly set coordinates are stored in styles (position, size, layouts, etc.)
|
||||
- support min-width, max-width, min-height, max-height
|
||||
- have pixel, percentage, and "content" units
|
||||
- x=0; y=0 coordinate means the top-left corner of the parent plus the left/top padding plus border width
|
||||
- width/height means the full size, the "content area" is smaller with padding and border width
|
||||
- a subset of flexbox and grid layouts are supported
|
||||
|
||||
.. _coord_units:
|
||||
|
||||
Units
|
||||
*****
|
||||
|
||||
- pixel: Simply a position in pixels. An integer always means pixels.
|
||||
E.g. :cpp:expr:`lv_obj_set_x(btn, 10)`
|
||||
- percentage: The percentage of the size of the Widget or its parent
|
||||
(depending on the property). :cpp:expr:`lv_pct(value)` converts a value to
|
||||
percentage. E.g. :cpp:expr:`lv_obj_set_width(btn, lv_pct(50))`
|
||||
- :c:macro:`LV_SIZE_CONTENT`: Special value to set the width/height of an
|
||||
Widget to involve all the children. It's similar to ``auto`` in CSS.
|
||||
E.g. :cpp:expr:`lv_obj_set_width(btn, LV_SIZE_CONTENT)`.
|
||||
|
||||
|
||||
|
||||
.. _coord_boxing_model:
|
||||
|
||||
Boxing model
|
||||
************
|
||||
|
||||
LVGL follows CSS's `border-box <https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing>`__
|
||||
model. A Widget's "box" is built from the following parts:
|
||||
|
||||
- bounding box: the width/height of the elements.
|
||||
- border width: the width of the border.
|
||||
- padding: space between the sides of the Widget and its children.
|
||||
- margin: space outside of the Widget (considered only by some layouts)
|
||||
- content: the content area which is the size of the bounding box reduced by the border width and padding.
|
||||
|
||||
.. image:: /misc/boxmodel.png
|
||||
:alt: The box models of LVGL: The content area is smaller than the bounding box with the padding and border width
|
||||
|
||||
The border is drawn inside the bounding box. Inside the border LVGL
|
||||
keeps a "padding margin" when placing a Widget's children.
|
||||
|
||||
The outline is drawn outside the bounding box.
|
||||
|
||||
.. _coord_notes:
|
||||
|
||||
Important Notes
|
||||
***************
|
||||
|
||||
This section describes special cases in which LVGL's behavior might be
|
||||
unexpected.
|
||||
|
||||
.. _coord_postponed_coordinate_calculation:
|
||||
|
||||
Postponed coordinate calculation
|
||||
--------------------------------
|
||||
|
||||
LVGL doesn't recalculate all the coordinate changes immediately. This is
|
||||
done to improve performance. Instead, the Widgets are marked as "dirty"
|
||||
and before redrawing the screen LVGL checks if there are any "dirty"
|
||||
Widgets. If so it refreshes their position, size and layout.
|
||||
|
||||
In other words, if you need to get the coordinate of a Widget and the
|
||||
coordinates were just changed, LVGL needs to be forced to recalculate
|
||||
the coordinates. To do this call :cpp:func:`lv_obj_update_layout`.
|
||||
|
||||
The size and position might depend on the parent or layout. Therefore
|
||||
:cpp:func:`lv_obj_update_layout` recalculates the coordinates of all Widgets on
|
||||
the screen of ``obj``.
|
||||
|
||||
.. _coord_removing styles:
|
||||
|
||||
Removing styles
|
||||
---------------
|
||||
|
||||
As it's described in the :ref:`coord_using_styles` section,
|
||||
coordinates can also be set via style properties. To be more precise,
|
||||
under the hood every style coordinate related property is stored as a
|
||||
style property. If you use :cpp:expr:`lv_obj_set_x(widget, 20)` LVGL saves ``x=20``
|
||||
in the local style of the Widget.
|
||||
|
||||
This is an internal mechanism and doesn't matter much as you use LVGL.
|
||||
However, there is one case in which you need to be aware of the
|
||||
implementation. If the style(s) of a Widget are removed by
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_remove_style_all(widget)
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_remove_style(widget, NULL, LV_PART_MAIN);
|
||||
|
||||
the earlier set coordinates will be removed as well.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* The size of obj1 will be set back to the default in the end */
|
||||
lv_obj_set_size(widget1, 200, 100); /* Now obj1 has 200;100 size */
|
||||
lv_obj_remove_style_all(widget1); /* It removes the set sizes */
|
||||
|
||||
|
||||
/* widget2 will have 200;100 size in the end */
|
||||
lv_obj_remove_style_all(widget2);
|
||||
lv_obj_set_size(widget2, 200, 100);
|
||||
|
||||
|
||||
|
||||
.. _positioning_widgets:
|
||||
|
||||
Positioning Widgets
|
||||
*******************
|
||||
|
||||
|
||||
Direct
|
||||
------
|
||||
|
||||
To simply set the x and y coordinates of a Widget use:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_x(widget, 10); /* Separate... */
|
||||
lv_obj_set_y(widget, 20);
|
||||
lv_obj_set_pos(widget, 10, 20); /* Or in one function */
|
||||
|
||||
By default, the x and y coordinates are measured from the top left
|
||||
corner of the parent's content area. For example if the parent has five
|
||||
pixels of padding on every side the above code will place ``obj`` at
|
||||
(15, 25) because the content area starts after the padding.
|
||||
|
||||
Percentage values are calculated from the parent's content area size.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_x(btn, lv_pct(10)); //x = 10 % of parent content area width
|
||||
|
||||
|
||||
Alignment
|
||||
---------
|
||||
|
||||
|
||||
Inside parent widget
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
In many cases it is more convenient to tell LVGL to align your object relative to
|
||||
an "anchor point" in its parent *other* than its upper left corner. To establish
|
||||
that "anchor point", call :cpp:expr:`lv_obj_set_align(widget, LV_ALIGN_...)`. After
|
||||
that call, that "anchor point" will be remembered until another one is established.
|
||||
In other words, every futire x and y setting for that Widget will be relative to the
|
||||
that "anchor point".
|
||||
|
||||
Example: Position Widget (10,20) px relative to the center of its parent:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_align(widget, LV_ALIGN_CENTER);
|
||||
lv_obj_set_pos(widget, 10, 20);
|
||||
|
||||
/* Or combine the above in one function... */
|
||||
lv_obj_align(widget, LV_ALIGN_CENTER, 10, 20);
|
||||
|
||||
9 convenient "anchor points" can be used with these functions:
|
||||
|
||||
- :cpp:enumerator:`LV_ALIGN_TOP_LEFT`
|
||||
- :cpp:enumerator:`LV_ALIGN_TOP_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_TOP_RIGHT`
|
||||
- :cpp:enumerator:`LV_ALIGN_BOTTOM_LEFT`
|
||||
- :cpp:enumerator:`LV_ALIGN_BOTTOM_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_BOTTOM_RIGHT`
|
||||
- :cpp:enumerator:`LV_ALIGN_LEFT_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_RIGHT_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_CENTER`
|
||||
|
||||
See illustration below to visualize what these mean.
|
||||
|
||||
It's quite common to align a child to the center of its parent,
|
||||
therefore a dedicated function exists:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_center(widget);
|
||||
|
||||
//Has the same effect
|
||||
lv_obj_align(widget, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
If the parent's size changes, the set alignment and position of the
|
||||
children is updated automatically.
|
||||
|
||||
|
||||
Relative to another Widget
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Alternately, you can choose an "anchor point" on another Widget.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_align_to(widget, reference_widget, align, x, y);
|
||||
|
||||
where ``align`` can be done of the following:
|
||||
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_TOP_LEFT`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_TOP_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_TOP_RIGHT`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_BOTTOM_LEFT`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_BOTTOM_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_BOTTOM_RIGHT`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_LEFT_TOP`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_LEFT_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_LEFT_BOTTOM`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_RIGHT_TOP`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_RIGHT_MID`
|
||||
- :cpp:enumerator:`LV_ALIGN_OUT_RIGHT_BOTTOM`
|
||||
|
||||
Example: to horizontally center a label 10 pixels above a button:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_align_to(label, btn, LV_ALIGN_OUT_TOP_MID, 0, -10);
|
||||
|
||||
Note that, unlike with :cpp:func:`lv_obj_align`, :cpp:func:`lv_obj_align_to`
|
||||
does not remember the "anchor point" used, and so will not automatically reposition
|
||||
the aligned widget if the reference widget later moves.
|
||||
|
||||
The following illustration shows the meaning of each "anchor point" mentioned above.
|
||||
|
||||
.. image:: /misc/align.png
|
||||
|
||||
|
||||
|
||||
.. _coord_size:
|
||||
|
||||
Size
|
||||
****
|
||||
|
||||
Sizing the simple way
|
||||
---------------------
|
||||
|
||||
The width and the height of a Widget can be set easily as well:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_width(widget, 200); /* Separate... */
|
||||
lv_obj_set_height(widget, 100);
|
||||
lv_obj_set_size(widget, 200, 100); /* Or in one function */
|
||||
|
||||
Percentage values are calculated based on the parent's content area
|
||||
size. For example to set the Widget's height to the screen height:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_height(widget, lv_pct(100));
|
||||
|
||||
The size settings support a special value: :c:macro:`LV_SIZE_CONTENT`. It means
|
||||
the Widget's size in the respective direction will be set to the size of
|
||||
its children. Note that only children on the right and bottom sides will
|
||||
be considered and children on the top and left remain cropped. This
|
||||
limitation makes the behavior more predictable.
|
||||
|
||||
Widgets with :cpp:enumerator:`LV_OBJ_FLAG_HIDDEN` or :cpp:enumerator:`LV_OBJ_FLAG_FLOATING` will be
|
||||
ignored by the :c:macro:`LV_SIZE_CONTENT` calculation.
|
||||
|
||||
The above functions set the size of a Widget's bounding box but the
|
||||
size of the content area can be set as well. This means a Widget's
|
||||
bounding box will be enlarged with the addition of padding.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_content_width(widget, 50); /* The actual width: padding left + 50 + padding right */
|
||||
lv_obj_set_content_height(widget, 30); /* The actual width: padding top + 30 + padding bottom */
|
||||
|
||||
The size of the bounding box and the content area can be retrieved with
|
||||
the following functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int32_t w = lv_obj_get_width(widget);
|
||||
int32_t h = lv_obj_get_height(widget);
|
||||
int32_t content_w = lv_obj_get_content_width(widget);
|
||||
int32_t content_h = lv_obj_get_content_height(widget);
|
||||
|
||||
|
||||
.. _extending_click_area:
|
||||
|
||||
Extending the click area
|
||||
------------------------
|
||||
|
||||
By default, Widgets can be clicked only within their bounding area. However,
|
||||
especially with small Widgets, it can be helpful to make a Widget's "clickable" area
|
||||
larger. You can do this with :cpp:expr:`lv_obj_set_ext_click_area(widget, size)`.
|
||||
|
||||
|
||||
|
||||
.. _coord_using_styles:
|
||||
|
||||
Using styles
|
||||
************
|
||||
|
||||
Under the hood the position, size and alignment properties are style
|
||||
properties. The above described "simple functions" hide the style
|
||||
related code for the sake of simplicity and set the position, size, and
|
||||
alignment properties in the local styles of the Widget.
|
||||
|
||||
However, using styles to set the coordinates has some great advantages:
|
||||
|
||||
- It makes it easy to set the width/height/etc. for several Widgets
|
||||
together. E.g. make all the sliders 100x10 pixels sized.
|
||||
- It also makes possible to modify the values in one place.
|
||||
- The values can be partially overwritten by other styles. For example
|
||||
``style_btn`` makes the Widget ``100x50`` by default but adding
|
||||
``style_full_width`` overwrites only the width of the Widget.
|
||||
- The Widget can have different position or size depending on state.
|
||||
E.g. 100 px wide in :cpp:enumerator:`LV_STATE_DEFAULT` but 120 px
|
||||
in :cpp:enumerator:`LV_STATE_PRESSED`.
|
||||
- Style transitions can be used to make the coordinate changes smooth.
|
||||
|
||||
Here are some examples to set a Widget's size using a style:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
lv_style_set_width(&style, 100);
|
||||
|
||||
lv_obj_t * btn = lv_button_create(lv_screen_active());
|
||||
lv_obj_add_style(btn, &style, LV_PART_MAIN);
|
||||
|
||||
As you will see below there are some other great features of size and
|
||||
position setting. However, to keep the LVGL API lean, only the most
|
||||
common coordinate setting features have a "simple" version and the more
|
||||
complex features can be used via styles.
|
||||
|
||||
.. _coord_translation:
|
||||
|
||||
Translation
|
||||
***********
|
||||
|
||||
Let's say the there are 3 buttons next to each other. Their position is
|
||||
set as described above. Now you want to move a button up a little when
|
||||
it's pressed.
|
||||
|
||||
One way to achieve this is by setting a new Y coordinate for the pressed
|
||||
state:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_normal;
|
||||
lv_style_init(&style_normal);
|
||||
lv_style_set_y(&style_normal, 100);
|
||||
|
||||
static lv_style_t style_pressed;
|
||||
lv_style_init(&style_pressed);
|
||||
lv_style_set_y(&style_pressed, 80);
|
||||
|
||||
lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
|
||||
lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);
|
||||
|
||||
lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
|
||||
lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);
|
||||
|
||||
lv_obj_add_style(btn3, &style_normal, LV_STATE_DEFAULT);
|
||||
lv_obj_add_style(btn3, &style_pressed, LV_STATE_PRESSED);
|
||||
|
||||
This works, but it's not really flexible because the pressed coordinate
|
||||
is hard-coded. If the buttons are not at y=100, ``style_pressed`` won't
|
||||
work as expected. Translations can be used to solve this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_normal;
|
||||
lv_style_init(&style_normal);
|
||||
lv_style_set_y(&style_normal, 100);
|
||||
|
||||
static lv_style_t style_pressed;
|
||||
lv_style_init(&style_pressed);
|
||||
lv_style_set_translate_y(&style_pressed, -20);
|
||||
|
||||
lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
|
||||
lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);
|
||||
|
||||
lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
|
||||
lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);
|
||||
|
||||
lv_obj_add_style(btn3, &style_normal, LV_STATE_DEFAULT);
|
||||
lv_obj_add_style(btn3, &style_pressed, LV_STATE_PRESSED);
|
||||
|
||||
Translation is applied from the current position of the Widget.
|
||||
|
||||
Percentage values can be used in translations as well. The percentage is
|
||||
relative to the size of the Widget (and not to the size of the parent).
|
||||
For example :cpp:expr:`lv_pct(50)` will move the Widget with half of its
|
||||
width/height.
|
||||
|
||||
The translation is applied after the layouts are calculated. Therefore,
|
||||
even laid out Widgets' position can be translated.
|
||||
|
||||
The translation actually moves the Widget. That means it makes the
|
||||
scrollbars and :c:macro:`LV_SIZE_CONTENT` sized Widgets react to the position
|
||||
change.
|
||||
|
||||
.. _coord_transformation:
|
||||
|
||||
Transformation
|
||||
**************
|
||||
|
||||
Similarly to position, a Widget's size can be changed relative to the
|
||||
current size as well. The transformed width and height are added on both
|
||||
sides of the Widget. This means a 10 px transformed width makes the
|
||||
Widget 2x10 pixels wider.
|
||||
|
||||
Unlike position translation, the size transformation doesn't make the
|
||||
Widget "really" larger. In other words scrollbars, layouts, and
|
||||
:c:macro:`LV_SIZE_CONTENT` will not react to the transformed size. Hence, size
|
||||
transformation is "only" a visual effect.
|
||||
|
||||
This code enlarges a button when it's pressed:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_pressed;
|
||||
lv_style_init(&style_pressed);
|
||||
lv_style_set_transform_width(&style_pressed, 10);
|
||||
lv_style_set_transform_height(&style_pressed, 10);
|
||||
|
||||
lv_obj_add_style(btn, &style_pressed, LV_STATE_PRESSED);
|
||||
|
||||
.. _coord_min_max_size:
|
||||
|
||||
Min and Max size
|
||||
----------------
|
||||
|
||||
Similarly to CSS, LVGL also supports ``min-width``, ``max-width``,
|
||||
``min-height`` and ``max-height``. These are limits preventing a
|
||||
Widget's size from becoming smaller/larger than these values. They are
|
||||
especially useful if the size is set by percentage or
|
||||
:c:macro:`LV_SIZE_CONTENT`.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_max_height;
|
||||
lv_style_init(&style_max_height);
|
||||
lv_style_set_y(&style_max_height, 200);
|
||||
|
||||
lv_obj_set_height(widget, lv_pct(100));
|
||||
lv_obj_add_style(widget, &style_max_height, LV_STATE_DEFAULT); //Limit the height to 200 px
|
||||
|
||||
Percentage values can be used as well which are relative to the size of
|
||||
the parent's content area.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_max_height;
|
||||
lv_style_init(&style_max_height);
|
||||
lv_style_set_y(&style_max_height, lv_pct(50));
|
||||
|
||||
lv_obj_set_height(widget, lv_pct(100));
|
||||
lv_obj_add_style(widget, &style_max_height, LV_STATE_DEFAULT); //Limit the height to half parent height
|
||||
|
||||
|
||||
|
||||
.. _coord_layout:
|
||||
|
||||
Layout
|
||||
******
|
||||
|
||||
|
||||
Layout overview
|
||||
---------------
|
||||
|
||||
Layouts can update the position and size of a Widget's children. They
|
||||
can be used to automatically arrange the children into a line or column,
|
||||
or in much more complicated forms.
|
||||
|
||||
The position and size set by the layout overwrites the "normal" x, y,
|
||||
width, and height settings.
|
||||
|
||||
There is only one function that is the same for every layout:
|
||||
:cpp:func:`lv_obj_set_layout` ``(widget, <LAYOUT_NAME>)`` sets the layout on a Widget.
|
||||
For further settings of the parent and children see the documentation of
|
||||
the given layout.
|
||||
|
||||
|
||||
Built-in layouts
|
||||
----------------
|
||||
|
||||
LVGL comes with two very powerful layouts:
|
||||
|
||||
* Flexbox: arrange Widgets into rows or columns, with support for wrapping and expanding items.
|
||||
* Grid: arrange Widgets into fixed positions in 2D table.
|
||||
|
||||
Both are heavily inspired by the CSS layouts with the same name.
|
||||
Layouts are described in detail in their own section of documentation.
|
||||
|
||||
|
||||
Flags
|
||||
-----
|
||||
|
||||
There are some flags that can be used on Widgets to affect how they
|
||||
behave with layouts:
|
||||
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_HIDDEN` Hidden Widgets are ignored in layout calculations.
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_IGNORE_LAYOUT` The Widget is simply ignored by the layouts. Its coordinates can be set as usual.
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_FLOATING` Same as :cpp:enumerator:`LV_OBJ_FLAG_IGNORE_LAYOUT` but the Widget with :cpp:enumerator:`LV_OBJ_FLAG_FLOATING` will be ignored in :c:macro:`LV_SIZE_CONTENT` calculations.
|
||||
|
||||
These flags can be added/removed with :cpp:expr:`lv_obj_add_flag(widget, FLAG)` and :cpp:expr:`lv_obj_remove_flag(widget, FLAG)`
|
||||
|
||||
|
||||
Adding new layouts
|
||||
------------------
|
||||
|
||||
LVGL can be freely extended by a custom layout like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
uint32_t MY_LAYOUT;
|
||||
|
||||
...
|
||||
|
||||
MY_LAYOUT = lv_layout_register(my_layout_update, &user_data);
|
||||
|
||||
...
|
||||
|
||||
void my_layout_update(lv_obj_t * widget, void * user_data)
|
||||
{
|
||||
/* Will be called automatically if it's required to reposition/resize the children of "obj" */
|
||||
}
|
||||
|
||||
Custom style properties can be added which can be retrieved and used in
|
||||
the update callback. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
uint32_t MY_PROP;
|
||||
...
|
||||
|
||||
LV_STYLE_MY_PROP = lv_style_register_prop();
|
||||
|
||||
...
|
||||
static inline void lv_style_set_my_prop(lv_style_t * style, uint32_t value)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_style_set_prop(style, LV_STYLE_MY_PROP, v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.. _coord_example:
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
|
||||
|
||||
.. _coord_api:
|
||||
|
||||
API
|
||||
***
|
||||
281
docs/details/base-widget/event.rst
Normal file
281
docs/details/base-widget/event.rst
Normal file
@@ -0,0 +1,281 @@
|
||||
.. _events:
|
||||
|
||||
======
|
||||
Events
|
||||
======
|
||||
|
||||
Events are triggered in LVGL when something happens which might be
|
||||
interesting to the user, e.g. when a Widget:
|
||||
|
||||
- is clicked
|
||||
- is scrolled
|
||||
- has its value changed
|
||||
- is redrawn, etc.
|
||||
|
||||
Besides Widgets, events can registered from displays and input devices as well.
|
||||
It is not detailed below, but you can do this by changing the prefix of the functions
|
||||
from ``lv_obj_`` to ``lv_display_`` or ``lv_indev_``.
|
||||
|
||||
|
||||
.. _adding_events_to_a_widget:
|
||||
|
||||
Adding Events to a Widget
|
||||
*************************
|
||||
|
||||
The user can assign callback functions to a widget to process events.
|
||||
In practice, it looks like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * btn = lv_button_create(lv_screen_active());
|
||||
lv_obj_add_event_cb(btn, my_event_cb, LV_EVENT_CLICKED, user_data); /* Assign an event callback */
|
||||
|
||||
...
|
||||
|
||||
static void my_event_cb(lv_event_t * event)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
}
|
||||
|
||||
In the example :cpp:enumerator:`LV_EVENT_CLICKED` means that only the click event will
|
||||
call ``my_event_cb``. See the :ref:`list of event codes <events_codes>` for
|
||||
all the options. :cpp:enumerator:`LV_EVENT_ALL` can be used to receive all events.
|
||||
|
||||
The last parameter of :cpp:func:`lv_obj_add_event` is a pointer to any custom
|
||||
data that will be available in the event. NULL may be passed for this argument if
|
||||
there is no need to use that data when the event is processed. You can retrieve the
|
||||
pointer passed when setting the callback function like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
my_user_data_t * user_data;
|
||||
...
|
||||
user_data = lv_event_get_user_data(e);
|
||||
|
||||
More events can be added to a Widget, like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_event_cb(widget, my_event_cb_1, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_add_event_cb(widget, my_event_cb_2, LV_EVENT_PRESSED, NULL);
|
||||
lv_obj_add_event_cb(widget, my_event_cb_3, LV_EVENT_ALL, NULL); /* No filtering, receive all events */
|
||||
|
||||
Even the same event callback can be used on a Widget with different
|
||||
``user_data``. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_event_cb(widget, increment_on_click, LV_EVENT_CLICKED, &num1);
|
||||
lv_obj_add_event_cb(widget, increment_on_click, LV_EVENT_CLICKED, &num2);
|
||||
|
||||
The events will be called in the order as they were added.
|
||||
|
||||
Other Widgets can use the same *event callback*.
|
||||
|
||||
In the very same way, events can be attached to input devices and displays like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_display_add_event_cb(disp, event_cb, LV_EVENT_RESOLUTION_CHANGED, NULL);
|
||||
lv_indev_add_event_cb(indev, event_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
|
||||
Removing Event(s) from Widgets
|
||||
******************************
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
uint32_t i;
|
||||
uint32_t event_cnt = lv_obj_get_event_count(widget);
|
||||
for(i = 0; i < event_cnt; i++) {
|
||||
lv_event_dsc_t * event_dsc = lv_obj_get_event_dsc(widget, i);
|
||||
if(lv_event_dsc_get_cb(event_dsc) == some_event_cb) {
|
||||
lv_obj_remove_event(widget, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. _events_codes:
|
||||
|
||||
Event Codes
|
||||
***********
|
||||
|
||||
The event codes can be grouped into these categories: - Input device
|
||||
events - Drawing events - Other events - Special events - Custom events
|
||||
|
||||
All Widgets (such as Buttons/Labels/Sliders etc.) regardless their type
|
||||
receive the *Input device*, *Drawing* and *Other* events.
|
||||
|
||||
However, the *Special events* are specific to a particular widget type.
|
||||
See the :ref:`widgets' documentation <widgets>` to learn when they
|
||||
are sent,
|
||||
|
||||
*Custom events* are added by the user and are never sent by LVGL.
|
||||
|
||||
The following event codes exist:
|
||||
|
||||
Input Device Events
|
||||
-------------------
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_PRESSED`: Widget has been pressed
|
||||
- :cpp:enumerator:`LV_EVENT_PRESSING`: Widget is being pressed (called continuously while pressing)
|
||||
- :cpp:enumerator:`LV_EVENT_PRESS_LOST`: Widget is still being pressed but slid cursor/finger off Widget
|
||||
- :cpp:enumerator:`LV_EVENT_SHORT_CLICKED`: Widget was pressed for a short period of time, and then released without scrolling.
|
||||
- :cpp:enumerator:`LV_EVENT_SINGLE_CLICKED`: Widget was pressed for a short period of time, and then released without scrolling, for the first time in a click streak. A click streak refers to multiple short clicks within a short period of time and a small distance.
|
||||
- :cpp:enumerator:`LV_EVENT_DOUBLE_CLICKED`: Widget was pressed for a short period of time, and then released without scrolling, for the second time in a click streak.
|
||||
- :cpp:enumerator:`LV_EVENT_TRIPLE_CLICKED`: Widget was pressed for a short period of time, and then released without scrolling, for the third time in a click streak.
|
||||
- :cpp:enumerator:`LV_EVENT_LONG_PRESSED`: Widget has been pressed for at least `long_press_time`. Not called if scrolled.
|
||||
- :cpp:enumerator:`LV_EVENT_LONG_PRESSED_REPEAT`: Called after `long_press_time` in every `long_press_repeat_time` ms. Not called if scrolled.
|
||||
- :cpp:enumerator:`LV_EVENT_CLICKED`: Called on release if not scrolled (regardless of long press)
|
||||
- :cpp:enumerator:`LV_EVENT_RELEASED`: Called in every cases when Widget has been released
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_BEGIN`: Scrolling begins. The event parameter is a pointer to the animation of the scroll. Can be modified
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_THROW_BEGIN`:
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_END`: Scrolling ends
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL`: Scrolling
|
||||
- :cpp:enumerator:`LV_EVENT_GESTURE`: A gesture is detected. Get the gesture with :cpp:expr:`lv_indev_get_gesture_dir(lv_indev_active())`
|
||||
- :cpp:enumerator:`LV_EVENT_KEY`: A key is sent to Widget. Get the key with :cpp:expr:`lv_indev_get_key(lv_indev_active())`
|
||||
- :cpp:enumerator:`LV_EVENT_FOCUSED`: Widget received focus
|
||||
- :cpp:enumerator:`LV_EVENT_DEFOCUSED`: Widget is defocused
|
||||
- :cpp:enumerator:`LV_EVENT_LEAVE`: Widget is defocused but still selected
|
||||
- :cpp:enumerator:`LV_EVENT_HIT_TEST`: Perform advanced hit-testing
|
||||
- :cpp:enumerator:`LV_EVENT_INDEV_RESET`: Indev has been reset
|
||||
- :cpp:enumerator:`LV_EVENT_HOVER_OVER`: Indev hover over Widget
|
||||
- :cpp:enumerator:`LV_EVENT_HOVER_LEAVE`: Indev hover leave Widget
|
||||
|
||||
Drawing Events
|
||||
--------------
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_COVER_CHECK`: Check if Widget fully covers an area. The event parameter is :cpp:type:`lv_cover_check_info_t` ``*``.
|
||||
- :cpp:enumerator:`LV_EVENT_REFR_EXT_DRAW_SIZE`: Get the required extra draw area around Widget (e.g. for shadow). The event parameter is :cpp:type:`int32_t` ``*`` to store the size.
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_MAIN_BEGIN`: Starting the main drawing phase
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_MAIN`: Perform the main drawing
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_MAIN_END`: Finishing the main drawing phase
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_POST_BEGIN`: Starting the post draw phase (when all children are drawn)
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_POST`: Perform the post draw phase (when all children are drawn)
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_POST_END`: Finishing the post draw phase (when all children are drawn)
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_TASK_ADDED`: Adding a draw task
|
||||
|
||||
Special Events
|
||||
--------------
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_VALUE_CHANGED`: Widget's value has changed (i.e. slider moved)
|
||||
- :cpp:enumerator:`LV_EVENT_INSERT`: A text is inserted to Widget. The event data is ``char `*`` being inserted.
|
||||
- :cpp:enumerator:`LV_EVENT_REFRESH`: Notify Widget to refresh something on it (for the user)
|
||||
- :cpp:enumerator:`LV_EVENT_READY`: A process has finished
|
||||
- :cpp:enumerator:`LV_EVENT_CANCEL`: A process has been cancelled
|
||||
|
||||
Other Events
|
||||
------------
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_CREATE`: Widget is being created
|
||||
- :cpp:enumerator:`LV_EVENT_DELETE`: Widget is being deleted
|
||||
- :cpp:enumerator:`LV_EVENT_CHILD_CHANGED`: Child was removed, added, or its size, position were changed
|
||||
- :cpp:enumerator:`LV_EVENT_CHILD_CREATED`: Child was created, always bubbles up to all parents
|
||||
- :cpp:enumerator:`LV_EVENT_CHILD_DELETED`: Child was deleted, always bubbles up to all parents
|
||||
- :cpp:enumerator:`LV_EVENT_SCREEN_UNLOAD_START`: A screen unload started, fired immediately when scr_load is called
|
||||
- :cpp:enumerator:`LV_EVENT_SCREEN_LOAD_START`: A screen load started, fired when the screen change delay is expired
|
||||
- :cpp:enumerator:`LV_EVENT_SCREEN_LOADED`: A screen was loaded
|
||||
- :cpp:enumerator:`LV_EVENT_SCREEN_UNLOADED`: A screen was unloaded
|
||||
- :cpp:enumerator:`LV_EVENT_SIZE_CHANGED`: Widget coordinates/size have changed
|
||||
- :cpp:enumerator:`LV_EVENT_STYLE_CHANGED`: Widget's style has changed
|
||||
- :cpp:enumerator:`LV_EVENT_LAYOUT_CHANGED`: The children position has changed due to a layout recalculation
|
||||
- :cpp:enumerator:`LV_EVENT_GET_SELF_SIZE`: Get the internal size of a widget
|
||||
|
||||
Display Events
|
||||
--------------
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_INVALIDATE_AREA`
|
||||
- :cpp:enumerator:`LV_EVENT_RESOLUTION_CHANGED`
|
||||
- :cpp:enumerator:`LV_EVENT_COLOR_FORMAT_CHANGED`
|
||||
- :cpp:enumerator:`LV_EVENT_REFR_REQUEST`
|
||||
- :cpp:enumerator:`LV_EVENT_REFR_START`
|
||||
- :cpp:enumerator:`LV_EVENT_REFR_READY`
|
||||
- :cpp:enumerator:`LV_EVENT_RENDER_START`
|
||||
- :cpp:enumerator:`LV_EVENT_RENDER_READY`
|
||||
- :cpp:enumerator:`LV_EVENT_FLUSH_START`
|
||||
- :cpp:enumerator:`LV_EVENT_FLUSH_FINISH`
|
||||
|
||||
|
||||
Custom Events
|
||||
-------------
|
||||
|
||||
Any number of custom event codes can be registered by
|
||||
``uint32_t MY_EVENT_1 =`` :cpp:func:`lv_event_register_id`
|
||||
|
||||
They can be sent to any Widget with
|
||||
:cpp:expr:`lv_obj_send_event(widget, MY_EVENT_1, &some_data)`
|
||||
|
||||
|
||||
Refresh Event
|
||||
-------------
|
||||
|
||||
:cpp:enumerator:`LV_EVENT_REFRESH` is a special event because it's designed to let the
|
||||
user notify a Widget to refresh itself. Some examples:
|
||||
|
||||
- notify a label to refresh its text according to one or more variables (e.g. current time)
|
||||
- refresh a label when the language changes
|
||||
- enable a button if some conditions are met (e.g. the correct PIN is entered)
|
||||
- add/remove styles to/from a Widget if a limit is exceeded, etc
|
||||
|
||||
|
||||
Sending Events Manually
|
||||
***********************
|
||||
|
||||
To manually send events to a Widget, use
|
||||
``lv_obj_send_event(widget, <EVENT_CODE>, &some_data)``.
|
||||
|
||||
For example, this can be used to manually close a message box by
|
||||
simulating a button press (although there are simpler ways to do this):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Simulate the press of the first button (indexes start from zero) */
|
||||
uint32_t btn_id = 0;
|
||||
lv_obj_send_event(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);
|
||||
|
||||
The same works for display and input devices with
|
||||
``lv_display_send_event(widget, <EVENT_CODE>, &some_data)`` and
|
||||
``lv_indev_send_event(widget, <EVENT_CODE>, &some_data)``.
|
||||
|
||||
|
||||
Fields of lv_event_t
|
||||
********************
|
||||
|
||||
:cpp:type:`lv_event_t` is the only parameter passed to the event callback and it
|
||||
contains all data about the event. The following values can be gotten from it:
|
||||
|
||||
- :cpp:expr:`lv_event_get_code(e)`: get the event code
|
||||
- :cpp:expr:`lv_event_get_current_target(e)`: get Widget to which an event was sent. I.e. the Widget whose event handler is being called.
|
||||
- :cpp:expr:`lv_event_get_target(e)`: get Widget that originally triggered the event (different from :cpp:func:`lv_event_get_target` if :ref:`event bubbling <event_bubbling>` is enabled)
|
||||
- :cpp:expr:`lv_event_get_user_data(e)`: get the pointer passed as the last parameter of :cpp:func:`lv_obj_add_event`.
|
||||
- :cpp:expr:`lv_event_get_param(e)`: get the parameter passed as the last parameter of :cpp:func:`lv_obj_send_event`
|
||||
|
||||
.. _event_bubbling:
|
||||
|
||||
|
||||
Event Bubbling
|
||||
**************
|
||||
|
||||
If :cpp:expr:`lv_obj_add_flag(widget, LV_OBJ_FLAG_EVENT_BUBBLE)` is enabled all
|
||||
events will be sent to a Widget's parent as well. If the parent also has
|
||||
:cpp:enumerator:`LV_OBJ_FLAG_EVENT_BUBBLE` enabled the event will be sent to its
|
||||
parent, and so on.
|
||||
|
||||
The *target* parameter of the event is always the current target Widget,
|
||||
not the original Widget. To get the original target call
|
||||
:cpp:expr:`lv_event_get_target_obj(e)` in the event handler.
|
||||
|
||||
.. _events_examples:
|
||||
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
.. include:: ../../examples/event/index.rst
|
||||
|
||||
|
||||
.. _events_api:
|
||||
|
||||
API
|
||||
***
|
||||
18
docs/details/base-widget/index.rst
Normal file
18
docs/details/base-widget/index.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
.. _base_widget_overview:
|
||||
|
||||
===========
|
||||
Base Widget
|
||||
===========
|
||||
|
||||
The following details apply to all types of Widgets.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
obj
|
||||
coord
|
||||
layer
|
||||
styles/index
|
||||
event
|
||||
layouts/index
|
||||
scroll
|
||||
126
docs/details/base-widget/layer.rst
Normal file
126
docs/details/base-widget/layer.rst
Normal file
@@ -0,0 +1,126 @@
|
||||
.. _layers:
|
||||
|
||||
======
|
||||
Layers
|
||||
======
|
||||
|
||||
When the term "layer" is used in LVGL documentation, it may refer to one of several
|
||||
things:
|
||||
|
||||
1. for Widgets, the :ref:`layers_creation` creates a natural layering of Widgets;
|
||||
2. in the context of pixel rendering (drawing), there are :ref:`draw_layers`;
|
||||
3. permanent :ref:`screen_layers` are part of each :ref:`display` object, and
|
||||
are covered :ref:`here <screen_layers>`
|
||||
|
||||
#1 and #2 are covered below.
|
||||
|
||||
|
||||
|
||||
.. _layers_creation:
|
||||
|
||||
Order of Creation
|
||||
*****************
|
||||
|
||||
By default, LVGL draws new Widgets on top of old Widgets.
|
||||
|
||||
For example, assume we add a button to a parent Widget named button1 and
|
||||
then another button named button2. Then button1 (along with its child
|
||||
Widget(s)) will be in the background and can be covered by button2 and
|
||||
its children.
|
||||
|
||||
.. image:: /misc/layers.png
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Create a screen */
|
||||
lv_obj_t * scr = lv_obj_create(NULL, NULL);
|
||||
lv_screen_load(scr); /* Load the screen */
|
||||
|
||||
/* Create 2 buttons */
|
||||
lv_obj_t * btn1 = lv_button_create(scr, NULL); /* Create a button on the screen */
|
||||
lv_button_set_fit(btn1, true, true); /* Enable automatically setting the size according to content */
|
||||
lv_obj_set_pos(btn1, 60, 40); /* Set the position of the button */
|
||||
|
||||
lv_obj_t * btn2 = lv_button_create(scr, btn1); /* Copy the first button */
|
||||
lv_obj_set_pos(btn2, 180, 80); /* Set the position of the button */
|
||||
|
||||
/* Add labels to the buttons */
|
||||
lv_obj_t * label1 = lv_label_create(btn1, NULL); /* Create a label on the first button */
|
||||
lv_label_set_text(label1, "Button 1"); /* Set the text of the label */
|
||||
|
||||
lv_obj_t * label2 = lv_label_create(btn2, NULL); /* Create a label on the second button */
|
||||
lv_label_set_text(label2, "Button 2"); /* Set the text of the label */
|
||||
|
||||
/* Delete the second label */
|
||||
lv_obj_delete(label2);
|
||||
|
||||
.. _layers_order:
|
||||
|
||||
Changing Order
|
||||
--------------
|
||||
|
||||
There are four explicit ways to bring a Widget to the foreground:
|
||||
|
||||
- Use :cpp:expr:`lv_obj_move_foreground(widget)` to bring a Widget to the foreground.
|
||||
Similarly, use :cpp:expr:`lv_obj_move_background(widget)` to move it to the background.
|
||||
- Use :cpp:expr:`lv_obj_move_to_index(widget, idx)` to move a Widget to a given index in the order of children.
|
||||
|
||||
- ``0``: background
|
||||
- ``child_num - 1``: foreground
|
||||
- ``< 0``: count from the top, to move forward (up): :cpp:expr:`lv_obj_move_to_index(widget, lv_obj_get_index(widget) - 1)`
|
||||
|
||||
- Use :cpp:expr:`lv_obj_swap(widget1, widget2)` to swap the relative layer position of two Widgets.
|
||||
- When :cpp:expr:`lv_obj_set_parent(widget, new_parent)` is used, ``widget`` will be on the foreground of ``new_parent``.
|
||||
|
||||
|
||||
.. _draw_layers:
|
||||
|
||||
Draw Layers
|
||||
***********
|
||||
|
||||
Some style properties cause LVGL to allocate a buffer and render a Widget and its
|
||||
children there first. Later that layer will be merged to the screen or its parent
|
||||
layer after applying some transformations or other modifications.
|
||||
|
||||
Simple Layer
|
||||
------------
|
||||
|
||||
The following style properties trigger the creation of a "Simple Layer":
|
||||
|
||||
- ``opa_layered``
|
||||
- ``bitmap_mask_src``
|
||||
- ``blend_mode``
|
||||
|
||||
In this case the Widget will be sliced into ``LV_DRAW_SW_LAYER_SIMPLE_BUF_SIZE``
|
||||
sized chunks.
|
||||
|
||||
If there is no memory for a new chunk, LVGL will try allocating the layer after
|
||||
another chunk is rendered and freed.
|
||||
|
||||
Transformed Layer
|
||||
-----------------
|
||||
|
||||
When the widget is transformed a larger part of the Widget needs to rendered to
|
||||
provide enough data for transformation. LVGL tries to render as small area of the
|
||||
widget as possible, but due to the nature of transformations no slicing is possible
|
||||
in this case.
|
||||
|
||||
The following style properties trigger the creation of a "Transform Layer":
|
||||
|
||||
- ``transform_scale_x``
|
||||
- ``transform_scale_y``
|
||||
- ``transform_skew_x``
|
||||
- ``transform_skew_y``
|
||||
- ``transform_rotate``
|
||||
|
||||
Clip corner
|
||||
-----------
|
||||
|
||||
The ``clip_corner`` style property also causes LVGL to create a 2 layers with radius
|
||||
height for the top and bottom parts of the Widget.
|
||||
|
||||
|
||||
.. _layers_api:
|
||||
|
||||
API
|
||||
***
|
||||
178
docs/details/base-widget/layouts/flex.rst
Normal file
178
docs/details/base-widget/layouts/flex.rst
Normal file
@@ -0,0 +1,178 @@
|
||||
.. _flex:
|
||||
|
||||
====
|
||||
Flex
|
||||
====
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
The Flexbox (or Flex for short) is a subset of `CSS Flexbox <https://css-tricks.com/snippets/css/a-guide-to-flexbox/>`__.
|
||||
|
||||
It can arrange items into rows or columns (tracks), handle wrapping,
|
||||
adjust the spacing between the items and tracks, handle *grow* to make
|
||||
the item(s) fill the remaining space with respect to min/max width and
|
||||
height.
|
||||
|
||||
To make a Widget flex container call
|
||||
:cpp:expr:`lv_obj_set_layout(widget, LV_LAYOUT_FLEX)`.
|
||||
|
||||
Note that the flex layout feature of LVGL needs to be globally enabled
|
||||
with :c:macro:`LV_USE_FLEX` in ``lv_conf.h``.
|
||||
|
||||
Terms
|
||||
*****
|
||||
|
||||
- **tracks**: the rows or columns
|
||||
- **main direction**: row or column, the direction in which the items are
|
||||
placed
|
||||
- **cross direction**: perpendicular to the main direction
|
||||
- **wrap**: if there is no more space in the track a new track is started
|
||||
- **grow**: if set on an item it will grow to fill the remaining space on
|
||||
the track. The available space will be distributed among items
|
||||
respective to their grow value (larger value means more space)
|
||||
- **gap**: the space between the rows and columns or the items on a track
|
||||
|
||||
Simple interface
|
||||
****************
|
||||
|
||||
With the following functions you can set a Flex layout on any parent.
|
||||
|
||||
.. _flex_flow:
|
||||
|
||||
Flex flow
|
||||
---------
|
||||
|
||||
:cpp:expr:`lv_obj_set_flex_flow(widget, flex_flow)`
|
||||
|
||||
The possible values for ``flex_flow`` are:
|
||||
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_ROW`: Place the children in a row without wrapping
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_COLUMN`: Place the children in a column without wrapping
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_ROW_WRAP`: Place the children in a row with wrapping
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_COLUMN_WRAP`: Place the children in a column with wrapping
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_ROW_REVERSE`: Place the children in a row without wrapping but in reversed order
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_COLUMN_REVERSE`: Place the children in a column without wrapping but in reversed order
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_ROW_WRAP_REVERSE`: Place the children in a row with wrapping but in reversed order
|
||||
- :cpp:enumerator:`LV_FLEX_FLOW_COLUMN_WRAP_REVERSE`: Place the children in a column with wrapping but in reversed order
|
||||
|
||||
.. _flex_align:
|
||||
|
||||
Flex align
|
||||
----------
|
||||
|
||||
To manage the placement of the children use
|
||||
:cpp:expr:`lv_obj_set_flex_align(widget, main_place, cross_place, track_cross_place)`
|
||||
|
||||
- ``main_place`` determines how to distribute the items in their track
|
||||
on the main axis. E.g. flush the items to the right on :cpp:enumerator:`LV_FLEX_FLOW_ROW_WRAP`. (It's called
|
||||
``justify-content`` in CSS)
|
||||
- ``cross_place`` determines how to distribute the items in their track
|
||||
on the cross axis. E.g. if the items have different height place them
|
||||
to the bottom of the track. (It's called ``align-items`` in CSS)
|
||||
- ``track_cross_place`` determines how to distribute the tracks (It's
|
||||
called ``align-content`` in CSS)
|
||||
|
||||
The possible values are:
|
||||
|
||||
- :cpp:enumerator:`LV_FLEX_ALIGN_START`: means left on a horizontally and top vertically (default)
|
||||
- :cpp:enumerator:`LV_FLEX_ALIGN_END`: means right on a horizontally and bottom vertically
|
||||
- :cpp:enumerator:`LV_FLEX_ALIGN_CENTER`: simply center
|
||||
- :cpp:enumerator:`LV_FLEX_ALIGN_SPACE_EVENLY`: items are distributed so
|
||||
that the spacing between any two items (and the space to the edges) is
|
||||
equal. Does not apply to ``track_cross_place``.
|
||||
- :cpp:enumerator:`LV_FLEX_ALIGN_SPACE_AROUND`: items are evenly
|
||||
distributed in the track with equal space around them. Note that
|
||||
visually the spaces aren't equal, since all the items have equal space
|
||||
on both sides. The first item will have one unit of space against the
|
||||
container edge, but two units of space between the next item because
|
||||
that next item has its own spacing that applies. Not applies to
|
||||
``track_cross_place``.
|
||||
- :cpp:enumerator:`LV_FLEX_ALIGN_SPACE_BETWEEN`: items are evenly distributed in
|
||||
the track: first item is on the start line, last item on the end line. Not applies to ``track_cross_place``.
|
||||
|
||||
.. _flex_grow:
|
||||
|
||||
Flex grow
|
||||
---------
|
||||
|
||||
Flex grow can be used to make one or more children fill the available
|
||||
space on the track. When more children have grow parameters, the
|
||||
available space will be distributed proportionally to the grow values.
|
||||
For example, there is 400 px remaining space and 4 Widgets with grow:
|
||||
|
||||
- ``A`` with grow = 1
|
||||
- ``B`` with grow = 1
|
||||
- ``C`` with grow = 2
|
||||
|
||||
``A`` and ``B`` will have 100 px size, and ``C`` will have 200 px size.
|
||||
|
||||
Flex grow can be set on a child with
|
||||
:cpp:expr:`lv_obj_set_flex_grow(child, value)`. ``value`` needs to be >
|
||||
1 or 0 to disable grow on the child.
|
||||
|
||||
.. _flex_style:
|
||||
|
||||
Style interface
|
||||
***************
|
||||
|
||||
All the Flex-related values are style properties under the hood and you
|
||||
can use them similarly to any other style property.
|
||||
|
||||
The following flex related style properties exist:
|
||||
|
||||
- :cpp:enumerator:`FLEX_FLOW`
|
||||
- :cpp:enumerator:`FLEX_MAIN_PLACE`
|
||||
- :cpp:enumerator:`FLEX_CROSS_PLACE`
|
||||
- :cpp:enumerator:`FLEX_TRACK_PLACE`
|
||||
- :cpp:enumerator:`FLEX_GROW`
|
||||
|
||||
.. _flex_padding:
|
||||
|
||||
Internal padding
|
||||
----------------
|
||||
|
||||
To modify the minimum space flexbox inserts between Widgets, the
|
||||
following properties can be set on the flex container style:
|
||||
|
||||
- ``pad_row`` Sets the padding between the rows.
|
||||
|
||||
- ``pad_column`` Sets the padding between the columns.
|
||||
|
||||
These can for example be used if you don't want any padding between your
|
||||
Widgets: :cpp:expr:`lv_style_set_pad_column(&row_container_style,0)`
|
||||
|
||||
.. _flex_other:
|
||||
|
||||
Other features
|
||||
**************
|
||||
|
||||
RTL
|
||||
---
|
||||
|
||||
If the base direction of the container is set the
|
||||
:cpp:enumerator:`LV_BASE_DIR_RTL` the meaning of
|
||||
:cpp:enumerator:`LV_FLEX_ALIGN_START` and
|
||||
:cpp:enumerator:`LV_FLEX_ALIGN_END` is swapped on ``ROW`` layouts. I.e.
|
||||
``START`` will mean right.
|
||||
|
||||
The items on ``ROW`` layouts, and tracks of ``COLUMN`` layouts will be
|
||||
placed from right to left.
|
||||
|
||||
New track
|
||||
---------
|
||||
|
||||
You can force Flex to put an item into a new line with
|
||||
:cpp:expr:`lv_obj_add_flag(child, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK)`.
|
||||
|
||||
.. _flex_example:
|
||||
|
||||
Example
|
||||
*******
|
||||
|
||||
.. include:: ../../../examples/layouts/flex/index.rst
|
||||
|
||||
.. _flex_api:
|
||||
|
||||
API
|
||||
***
|
||||
184
docs/details/base-widget/layouts/grid.rst
Normal file
184
docs/details/base-widget/layouts/grid.rst
Normal file
@@ -0,0 +1,184 @@
|
||||
.. _grid:
|
||||
|
||||
====
|
||||
Grid
|
||||
====
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
The Grid layout is a subset of `CSS Grid <https://css-tricks.com/snippets/css/complete-guide-grid/>`__.
|
||||
|
||||
It can arrange items into a 2D "table" that has rows or columns
|
||||
(tracks). The item can span through multiple columns or rows. The
|
||||
track's size can be set in pixel, to the largest item
|
||||
(:c:macro:`LV_GRID_CONTENT`) or in "Free unit" (FR) to distribute the free
|
||||
space proportionally.
|
||||
|
||||
To make a Widget a grid container call :cpp:expr:`lv_obj_set_layout(widget, LV_LAYOUT_GRID)`.
|
||||
|
||||
Note that the grid layout feature of LVGL needs to be globally enabled
|
||||
with :c:macro:`LV_USE_GRID` in ``lv_conf.h``.
|
||||
|
||||
Terms
|
||||
*****
|
||||
|
||||
- **tracks**: the rows or columns
|
||||
- **free unit (FR)**: if set on track's size is set in ``FR`` it will grow
|
||||
to fill the remaining space on the parent.
|
||||
- **gap**: the space between the rows and columns or the items on a track
|
||||
|
||||
Simple interface
|
||||
****************
|
||||
|
||||
With the following functions you can easily set a Grid layout on any
|
||||
parent.
|
||||
|
||||
.. _grid_descriptors:
|
||||
|
||||
Grid descriptors
|
||||
----------------
|
||||
|
||||
First you need to describe the size of rows and columns. It can be done
|
||||
by declaring 2 arrays and the track sizes in them. The last element must
|
||||
be :c:macro:`LV_GRID_TEMPLATE_LAST`.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static int32_t column_dsc[] = {100, 400, LV_GRID_TEMPLATE_LAST}; /* 2 columns with 100 and 400 ps width */
|
||||
static int32_t row_dsc[] = {100, 100, 100, LV_GRID_TEMPLATE_LAST}; /* 3 100 px tall rows */
|
||||
|
||||
To set the descriptors on a parent use
|
||||
:cpp:expr:`lv_obj_set_grid_dsc_array(widget, col_dsc, row_dsc)`.
|
||||
|
||||
Besides simple settings the size in pixel you can use two special
|
||||
values:
|
||||
|
||||
- :c:macro:`LV_GRID_CONTENT` set the size to fit the largest child on this track
|
||||
- :cpp:expr:`LV_GRID_FR(X)` tell what portion of the remaining space
|
||||
should be used by this track. Larger value means larger space.
|
||||
|
||||
.. _grid_items:
|
||||
|
||||
Grid items
|
||||
----------
|
||||
|
||||
By default, the children are not added to the grid. They need to be
|
||||
added manually to a cell.
|
||||
|
||||
To do this call
|
||||
:cpp:expr:`lv_obj_set_grid_cell(child, column_align, column_pos, column_span, row_align, row_pos, row_span)`.
|
||||
|
||||
``column_align`` and ``row_align`` determine how to align the children
|
||||
in its cell. The possible values are:
|
||||
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_START`: means left on a horizontally and top vertically (default)
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_END`: means right on a horizontally and bottom vertically
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_CENTER`: simply center ``column_pos`` and ``row_pos``
|
||||
means the zero based index of the cell into the item should be placed.
|
||||
|
||||
``column_span`` and ``row_span`` means how many tracks should the item
|
||||
involve from the start cell. Must be ``>= 1``.
|
||||
|
||||
.. _grid_align:
|
||||
|
||||
Grid align
|
||||
----------
|
||||
|
||||
If there are some empty space the track can be aligned several ways:
|
||||
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_START`: means left on a horizontally and top vertically. (default)
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_END`: means right on a horizontally and bottom vertically
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_CENTER`: simply center
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_SPACE_EVENLY`: items are distributed so that the spacing
|
||||
between any two items (and the space to the edges) is equal. Not applies to ``track_cross_place``.
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_SPACE_AROUND`: items are
|
||||
evenly distributed in the track with equal space around them. Note that
|
||||
visually the spaces aren't equal, since all the items have equal space
|
||||
on both sides. The first item will have one unit of space against the
|
||||
container edge, but two units of space between the next item because
|
||||
that next item has its own spacing that applies. Not applies to ``track_cross_place``.
|
||||
- :cpp:enumerator:`LV_GRID_ALIGN_SPACE_BETWEEN`: items are
|
||||
evenly distributed in the track: first item is on the start line, last
|
||||
item on the end line. Not applies to ``track_cross_place``.
|
||||
|
||||
To set the track's alignment use
|
||||
:cpp:expr:`lv_obj_set_grid_align(widget, column_align, row_align)`.
|
||||
|
||||
.. _grid_subgrid:
|
||||
|
||||
Sub grid
|
||||
--------
|
||||
|
||||
If you set the column and/or row grid descriptors of a widget to ``NULL`` it will use the grid descriptor(s) from it's parent.
|
||||
For example if you create a grid item on 2..6 columns and 1..3 rows of the parent,
|
||||
the grid item will see 5 columns and 4 rows with the corresponding track size from the parent.
|
||||
|
||||
This way even if a wrapper item is used on the grid and can be made "transparent" from the grid's point of view.
|
||||
|
||||
Limitations:
|
||||
|
||||
- The sub grid is resolved only in one level depth. That is a grid can have a sub grid children, but a sub grid can't have another sub grid.
|
||||
- ``LV_GRID_CONTENT`` tracks on the are not handled in the sub grid, only in the its own grid.
|
||||
|
||||
The sub grid feature works the same as in CSS. For further reference see `this description <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid>`__.
|
||||
|
||||
.. _grid_style:
|
||||
|
||||
Style interface
|
||||
***************
|
||||
|
||||
All the Grid related values are style properties under the hood and you
|
||||
can use them similarly to any other style properties.
|
||||
|
||||
The following Grid related style properties exist:
|
||||
|
||||
- :cpp:enumerator:`GRID_COLUMN_DSC_ARRAY`
|
||||
- :cpp:enumerator:`GRID_ROW_DSC_ARRAY`
|
||||
- :cpp:enumerator:`GRID_COLUMN_ALIGN`
|
||||
- :cpp:enumerator:`GRID_ROW_ALIGN`
|
||||
- :cpp:enumerator:`GRID_CELL_X_ALIGN`
|
||||
- :cpp:enumerator:`GRID_CELL_COLUMN_POS`
|
||||
- :cpp:enumerator:`GRID_CELL_COLUMN_SPAN`
|
||||
- :cpp:enumerator:`GRID_CELL_Y_ALIGN`
|
||||
- :cpp:enumerator:`GRID_CELL_ROW_POS`
|
||||
- :cpp:enumerator:`GRID_CELL_ROW_SPAN`
|
||||
|
||||
.. _grid_padding:
|
||||
|
||||
Internal padding
|
||||
----------------
|
||||
|
||||
To modify the minimum space Grid inserts between Widgets, the following
|
||||
properties can be set on the Grid container style:
|
||||
|
||||
- ``pad_row`` Sets the padding between the rows.
|
||||
- ``pad_column`` Sets the padding between the columns.
|
||||
|
||||
.. _grid_other:
|
||||
|
||||
Other features
|
||||
**************
|
||||
|
||||
RTL
|
||||
---
|
||||
|
||||
If the base direction of the container is set to :cpp:enumerator:`LV_BASE_DIR_RTL`,
|
||||
the meaning of :cpp:enumerator:`LV_GRID_ALIGN_START` and :cpp:enumerator:`LV_GRID_ALIGN_END` is
|
||||
swapped. I.e. ``START`` will mean right-most.
|
||||
|
||||
The columns will be placed from right to left.
|
||||
|
||||
.. _grid_examples:
|
||||
|
||||
Example
|
||||
*******
|
||||
|
||||
.. include:: ../../../examples/layouts/grid/index.rst
|
||||
|
||||
.. _grid_api:
|
||||
|
||||
API
|
||||
***
|
||||
12
docs/details/base-widget/layouts/index.rst
Normal file
12
docs/details/base-widget/layouts/index.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
.. _layouts:
|
||||
|
||||
=======
|
||||
Layouts
|
||||
=======
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
flex
|
||||
grid
|
||||
633
docs/details/base-widget/obj.rst
Normal file
633
docs/details/base-widget/obj.rst
Normal file
@@ -0,0 +1,633 @@
|
||||
.. _widget_basics:
|
||||
|
||||
=============
|
||||
Widget Basics
|
||||
=============
|
||||
|
||||
|
||||
|
||||
What is a Widget?
|
||||
*****************
|
||||
A Widget is the **basic building block** of the LVGL user interface.
|
||||
|
||||
Examples of Widgets: :ref:`Base Widget (and Screen) <base_widget>`,
|
||||
:ref:`Button <lv_button>`, :ref:`Label <lv_label>`,
|
||||
:ref:`Image <lv_image>`, :ref:`List <lv_list>`,
|
||||
:ref:`Chart <lv_chart>` and :ref:`Text Area <lv_textarea>`.
|
||||
|
||||
See :ref:`widgets` to see all Widget types.
|
||||
|
||||
All Widgets are referenced using an :cpp:type:`lv_obj_t` pointer as a handle.
|
||||
This pointer can later be used to read or change the Widget's attributes.
|
||||
|
||||
|
||||
|
||||
.. _base_widget:
|
||||
|
||||
Base Widget
|
||||
***********
|
||||
The most fundamental of all Widgets is the Base Widget, on which all other widgets
|
||||
are based. From an Object-Oriented perspective, think of the Base Widget as the
|
||||
Widget class from which all other Widgets inherit.
|
||||
|
||||
The functions and functionalities of the Base Widget can be used with
|
||||
other widgets as well. For example :cpp:expr:`lv_obj_set_width(slider, 100)`.
|
||||
|
||||
The Base Widget can be used directly as a simple widget. While it is a simple
|
||||
rectangle, it has a large number of features shared with all Widgets, detailed
|
||||
below and in subsequent pages. In HTML terms, think of it as a ``<div>``.
|
||||
|
||||
|
||||
|
||||
.. _widget_attributes:
|
||||
|
||||
Attributes
|
||||
**********
|
||||
|
||||
|
||||
Basic attributes
|
||||
----------------
|
||||
|
||||
All Widget types share some basic attributes:
|
||||
|
||||
- Position
|
||||
- Size
|
||||
- Parent
|
||||
- Styles
|
||||
- Events it emits
|
||||
- Flags like *Clickable*, *Scollable*, etc.
|
||||
- Etc.
|
||||
|
||||
You can set/get these attributes with ``lv_obj_set_...`` and
|
||||
``lv_obj_get_...`` functions. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Set basic Widget attributes */
|
||||
lv_obj_set_size(btn1, 100, 50); /* Set a button's size */
|
||||
lv_obj_set_pos(btn1, 20,30); /* Set a button's position */
|
||||
|
||||
For complete details on position, size, coordinates and layouts, see :ref:`coord`.
|
||||
|
||||
|
||||
Widget-specific attributes
|
||||
--------------------------
|
||||
|
||||
The Widget types have special attributes as well. For example, a slider has
|
||||
|
||||
- Minimum and maximum values
|
||||
- Current value
|
||||
|
||||
For these special attributes, every Widget type may have unique API
|
||||
functions. For example for a slider:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Set slider specific attributes */
|
||||
lv_slider_set_range(slider1, 0, 100); /* Set the min. and max. values */
|
||||
lv_slider_set_value(slider1, 40, LV_ANIM_ON); /* Set the current value (position) */
|
||||
|
||||
The API of the widgets is described in their
|
||||
:ref:`Documentation <widgets>` but you can also check the respective
|
||||
header files (e.g. *widgets/lv_slider.h*)
|
||||
|
||||
|
||||
.. _lv_obj_parents_and_children:
|
||||
|
||||
Parents and children
|
||||
--------------------
|
||||
|
||||
A Widget's parent is set when the widget is created --- the parent is passed to the
|
||||
creation function.
|
||||
|
||||
To get a Widget's current parent, use :cpp:expr:`lv_obj_get_parent(widget)`.
|
||||
|
||||
You can move the Widget to a new parent with :cpp:expr:`lv_obj_set_parent(widget, new_parent)`.
|
||||
|
||||
To get a specific child of a parent use :cpp:expr:`lv_obj_get_child(parent, idx)`.
|
||||
Some examples for ``idx``:
|
||||
|
||||
- ``0`` get the child created first
|
||||
- ``1`` get the child created second
|
||||
- ``-1`` get the child created last
|
||||
|
||||
You can iterate through a parent Widget's children like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; i < lv_obj_get_child_count(parent); i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(parent, i);
|
||||
/* Do something with child. */
|
||||
}
|
||||
|
||||
:cpp:expr:`lv_obj_get_index(widget)` returns the index of the Widget in its parent.
|
||||
It is equivalent to the number of older children in the parent.
|
||||
|
||||
You can bring a Widget to the foreground or send it to the background with
|
||||
:cpp:expr:`lv_obj_move_foreground(widget)` and :cpp:expr:`lv_obj_move_background(widget)`.
|
||||
|
||||
You can change the index of a Widget in its parent using :cpp:expr:`lv_obj_move_to_index(widget, index)`.
|
||||
|
||||
You can swap the position of two Widgets with :cpp:expr:`lv_obj_swap(widget1, widget2)`.
|
||||
|
||||
To get a Widget's Screen (highest-level parent) use :cpp:expr:`lv_obj_get_screen(widget)`.
|
||||
|
||||
|
||||
|
||||
.. _widget_working_mechanisms:
|
||||
|
||||
Working Mechanisms
|
||||
******************
|
||||
|
||||
Parent-child structure
|
||||
----------------------
|
||||
|
||||
A parent Widget can be considered as the container of its children. Every Widget has
|
||||
exactly one parent Widget (except Screens), but a parent Widget can have any number
|
||||
of children. There is no limitation for the type of the parent but there are Widgets
|
||||
which are typically a parent (e.g. button) or a child (e.g. label).
|
||||
|
||||
|
||||
|
||||
Moving together
|
||||
---------------
|
||||
|
||||
If the position of a parent changes, the children will move along with
|
||||
it. Therefore, all positions are relative to the parent.
|
||||
|
||||
.. image:: /misc/par_child1.png
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * parent = lv_obj_create(lv_screen_active()); /* Create a parent Widget on current screen */
|
||||
lv_obj_set_size(parent, 100, 80); /* Set size of parent */
|
||||
|
||||
lv_obj_t * obj1 = lv_obj_create(parent); /* Create a Widget on previously created parent Widget */
|
||||
lv_obj_set_pos(widget1, 10, 10); /* Set position of new Widget */
|
||||
|
||||
Modify the position of the parent:
|
||||
|
||||
.. image:: /misc/par_child2.png
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_pos(parent, 50, 50); /* Move the parent. The child will move with it. */
|
||||
|
||||
(For simplicity the adjusting of colors of the Widgets is not shown in
|
||||
the example.)
|
||||
|
||||
Visibility only on the parent
|
||||
-----------------------------
|
||||
|
||||
If a child is partially or fully outside its parent then the parts
|
||||
outside will not be visible.
|
||||
|
||||
.. image:: /misc/par_child3.png
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_x(widget1, -30); /* Move the child a little bit off the parent */
|
||||
|
||||
This behavior can be overwritten with
|
||||
:cpp:expr:`lv_obj_add_flag(widget, LV_OBJ_FLAG_OVERFLOW_VISIBLE)` which allow the
|
||||
children to be drawn out of the parent.
|
||||
|
||||
Create and delete Widgets
|
||||
-------------------------
|
||||
|
||||
In LVGL, Widgets can be created and deleted dynamically at run time. It
|
||||
means only the currently created (existing) Widgets consume RAM.
|
||||
|
||||
This allows for the creation of a screen just when a button is clicked
|
||||
to open it, and for deletion of screens when a new screen is loaded.
|
||||
|
||||
UIs can be created based on the current environment of the device. For
|
||||
example one can create meters, charts, bars and sliders based on the
|
||||
currently attached sensors.
|
||||
|
||||
Every widget has its own **create** function with a prototype like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * lv_<widget>_create(lv_obj_t * parent, <other parameters if any>);
|
||||
|
||||
Typically, the create functions only have a ``parent`` parameter telling
|
||||
them on which Widget to create the new Widget.
|
||||
|
||||
The return value is a pointer to the created Widget with :cpp:type:`lv_obj_t` ``*``
|
||||
type.
|
||||
|
||||
There is a common **delete** function for all Widget types. It deletes
|
||||
the Widget and all of its children.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void lv_obj_delete(lv_obj_t * widget);
|
||||
|
||||
:cpp:func:`lv_obj_delete` will delete the Widget immediately. If for any reason you
|
||||
can't delete the Widget immediately you can use
|
||||
:cpp:expr:`lv_obj_delete_async(widget)` which will perform the deletion on the next
|
||||
call of :cpp:func:`lv_timer_handler`. This is useful e.g. if you want to
|
||||
delete the parent of a Widget in the child's :cpp:enumerator:`LV_EVENT_DELETE`
|
||||
handler.
|
||||
|
||||
You can remove all the children of a Widget (but not the Widget itself)
|
||||
using :cpp:expr:`lv_obj_clean(widget)`.
|
||||
|
||||
You can use :cpp:expr:`lv_obj_delete_delayed(widget, 1000)` to delete a Widget after
|
||||
some time. The delay is expressed in milliseconds.
|
||||
|
||||
Sometimes you're not sure whether a Widget was deleted and you need some way to
|
||||
check if it's still "alive". Anytime before the Widget is deleted, you can use
|
||||
cpp:expr:`lv_obj_null_on_delete(&widget)` to cause your Widget pointer to be set to ``NULL``
|
||||
when the Widget is deleted.
|
||||
|
||||
Make sure the pointer variable itself stays valid until the Widget is deleted. Here
|
||||
is an example:
|
||||
|
||||
.. code:: c
|
||||
|
||||
void some_timer_callback(lv_timer_t * t)
|
||||
{
|
||||
static lv_obj_t * my_label;
|
||||
if(my_label == NULL) {
|
||||
my_label = lv_label_create(lv_screen_active());
|
||||
lv_obj_delete_delayed(my_label, 1000);
|
||||
lv_obj_null_on_delete(&my_label);
|
||||
}
|
||||
else {
|
||||
lv_obj_set_x(my_label, lv_obj_get_x(my_label) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.. _screens:
|
||||
|
||||
Screens
|
||||
*******
|
||||
|
||||
What are Screens?
|
||||
-----------------
|
||||
|
||||
Not to be confused with a :ref:`display`, Screens are simply any Widget created
|
||||
without a parent (i.e. passing NULL for the ``parent`` argument during creation). As
|
||||
such, they form the "root" of a Widget Tree.
|
||||
|
||||
Normally the Base Widget is used for this purpose since it has all the features most
|
||||
Screens need. But an :ref:`lv_image` Widget can also be used to create a wallpaper
|
||||
background for the Widget Tree.
|
||||
|
||||
All Screens:
|
||||
|
||||
- are automatically attached to the :ref:`default_display` current when the Screen
|
||||
was created;
|
||||
- automatically occupy the full area of the associated display;
|
||||
- cannot be moved, i.e. functions such as :cpp:func:`lv_obj_set_pos` and
|
||||
:cpp:func:`lv_obj_set_size` cannot be used on screens.
|
||||
|
||||
Each :ref:`display` object can have multiple screens associated with it, but not vice
|
||||
versa. Thus the relationship::
|
||||
|
||||
Display
|
||||
|
|
||||
--- (one or more)
|
||||
/|\
|
||||
Screen Widgets (root of a Widget Tree)
|
||||
|
|
||||
O (zero or more)
|
||||
/|\
|
||||
Child Widgets
|
||||
|
||||
|
||||
Creating Screens
|
||||
----------------
|
||||
|
||||
Screens are created like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * scr1 = lv_obj_create(NULL);
|
||||
|
||||
Screens can be deleted with :cpp:expr:`lv_obj_delete(scr)`, but be sure you do not
|
||||
delete the :ref:`active_screen`.
|
||||
|
||||
|
||||
.. _active_screen:
|
||||
|
||||
Active Screen
|
||||
-------------
|
||||
While each :ref:`display` object can have any number of Screens Widgets associated
|
||||
with it, only one of those Screens is considered "Active" at any given time. That
|
||||
Screen is referred to as the Display's "Active Screen". For this reason, only one
|
||||
Screen and its child Widgets will ever be shown on a display at one time.
|
||||
|
||||
When each :ref:`display` object was created, a default screen was created with it and
|
||||
set as its "Active Screen".
|
||||
|
||||
To get a pointer to the "Active Screen", call :cpp:func:`lv_screen_active`.
|
||||
|
||||
To set a Screen to be the "Active Screen", call :cpp:func:`lv_screen_load` or
|
||||
:cpp:func:`lv_screen_load_anim`.
|
||||
|
||||
|
||||
.. _loading_screens:
|
||||
|
||||
Loading Screens
|
||||
---------------
|
||||
|
||||
To load a new screen, use :cpp:expr:`lv_screen_load(scr1)`. This sets ``scr1`` as
|
||||
the Active Screen.
|
||||
|
||||
Load Screen with Animation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A new screen can be loaded with animation by using
|
||||
:cpp:expr:`lv_screen_load_anim(scr, transition_type, time, delay, auto_del)`. The
|
||||
following transition types exist:
|
||||
|
||||
- :cpp:enumerator:`LV_SCR_LOAD_ANIM_NONE`: Switch immediately after ``delay`` milliseconds
|
||||
- :cpp:enumerator:`LV_SCR_LOAD_ANIM_OVER_LEFT`, :cpp:enumerator:`LV_SCR_LOAD_ANIM_OVER_RIGHT`, :cpp:enumerator:`LV_SCR_LOAD_ANIM_OVER_TOP` and :cpp:enumerator:`LV_SCR_LOAD_ANIM_OVER_BOTTOM`: Move the new screen over the current towards the given direction
|
||||
- :cpp:enumerator:`LV_SCR_LOAD_ANIM_OUT_LEFT`, :cpp:enumerator:`LV_SCR_LOAD_ANIM_OUT_RIGHT`, :cpp:enumerator:`LV_SCR_LOAD_ANIM_OUT_TOP` and :cpp:enumerator:`LV_SCR_LOAD_ANIM_OUT_BOTTOM`: Move out the old screen over the current towards the given direction
|
||||
- :cpp:enumerator:`LV_SCR_LOAD_ANIM_MOVE_LEFT`, :cpp:enumerator:`LV_SCR_LOAD_ANIM_MOVE_RIGHT`, :cpp:enumerator:`LV_SCR_LOAD_ANIM_MOVE_TOP` and :cpp:enumerator:`LV_SCR_LOAD_ANIM_MOVE_BOTTOM`: Move both the current and new screens towards the given direction
|
||||
- :cpp:enumerator:`LV_SCR_LOAD_ANIM_FADE_IN` and :cpp:enumerator:`LV_SCR_LOAD_ANIM_FADE_OUT`: Fade the new screen over the old screen, or vice versa
|
||||
|
||||
Setting ``auto_del`` to ``true`` will automatically delete the old
|
||||
screen when the animation is finished.
|
||||
|
||||
The new screen will become active (returned by :cpp:func:`lv_screen_active`) when
|
||||
the animation starts after ``delay`` time. All inputs are disabled
|
||||
during the screen animation.
|
||||
|
||||
|
||||
.. _layers_overview:
|
||||
|
||||
Layers
|
||||
------
|
||||
|
||||
When an ``lv_display_t`` object is created, 4 Screens (layers) are created and
|
||||
attached to it.
|
||||
|
||||
1. Bottom Layer
|
||||
2. Active Screen
|
||||
3. Top Layer
|
||||
4. System Layer
|
||||
|
||||
1, 3 and 4 are independent of the :ref:`active_screen` and they will be shown (if
|
||||
they contain anything that is visible) regardless of which screen is the Active
|
||||
Screen. See :ref:`screen_layers` for more information.
|
||||
|
||||
|
||||
.. _transparent_screens:
|
||||
|
||||
Transparent Screens
|
||||
-------------------
|
||||
|
||||
Usually, the opacity of the Screen is :cpp:enumerator:`LV_OPA_COVER` to provide a
|
||||
solid background for its children. If this is not the case (opacity <
|
||||
100%) the display's ``bottom_layer`` will be visible. If the bottom layer's
|
||||
opacity is also not :cpp:enumerator:`LV_OPA_COVER` LVGL will have no solid background
|
||||
to draw.
|
||||
|
||||
This configuration (transparent Screen) could be useful to create, for example,
|
||||
on-screen display (OSD) menus where a video is played on a different hardware layer
|
||||
of the display panel, and a menu is overlaid on a higher layer.
|
||||
|
||||
To properly render a UI on a transparent Screen the Display's color format needs to
|
||||
be set to one with an alpha channel (for example LV_COLOR_FORMAT_ARGB8888).
|
||||
|
||||
In summary, to enable transparent screens and displays for OSD menu-like UIs:
|
||||
|
||||
- Set the screen's ``bg_opa`` to transparent:
|
||||
:cpp:expr:`lv_obj_set_style_bg_opa(lv_screen_active(), LV_OPA_TRANSP, LV_PART_MAIN)`
|
||||
- Set the bottom layer's ``bg_opa`` to transparent:
|
||||
:cpp:expr:`lv_obj_set_style_bg_opa(lv_layer_bottom(), LV_OPA_TRANSP, LV_PART_MAIN)`
|
||||
- Set a color format with alpha channel. E.g.
|
||||
:cpp:expr:`lv_display_set_color_format(disp, LV_COLOR_FORMAT_ARGB8888)`
|
||||
|
||||
|
||||
|
||||
.. _widget_parts:
|
||||
|
||||
Parts
|
||||
*****
|
||||
|
||||
The widgets are built from multiple parts. For example a
|
||||
:ref:`Base Widget <base_widget>` uses the main and scrollbar parts but a
|
||||
:ref:`Slider <lv_slider>` uses the main, indicator and knob parts.
|
||||
Parts are similar to *pseudo-elements* in CSS.
|
||||
|
||||
The following predefined parts exist in LVGL:
|
||||
|
||||
- :cpp:enumerator:`LV_PART_MAIN`: A background like rectangle
|
||||
- :cpp:enumerator:`LV_PART_SCROLLBAR`: The scrollbar(s)
|
||||
- :cpp:enumerator:`LV_PART_INDICATOR`: Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox
|
||||
- :cpp:enumerator:`LV_PART_KNOB`: Like a handle to grab to adjust the value
|
||||
- :cpp:enumerator:`LV_PART_SELECTED`: Indicate the currently selected option or section
|
||||
- :cpp:enumerator:`LV_PART_ITEMS`: Used if the widget has multiple similar elements (e.g. table cells)
|
||||
- :cpp:enumerator:`LV_PART_CURSOR`: Mark a specific place e.g. text area's or chart's cursor
|
||||
- :cpp:enumerator:`LV_PART_CUSTOM_FIRST`: Custom parts can be added from here.
|
||||
|
||||
The main purpose of parts is to allow styling the "components" of the
|
||||
widgets. They are described in more detail in the
|
||||
:ref:`Style overview <styles>` section.
|
||||
|
||||
|
||||
|
||||
.. _widget_states:
|
||||
|
||||
States
|
||||
******
|
||||
|
||||
The Widget 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 (not supported now)
|
||||
- :cpp:enumerator:`LV_STATE_PRESSED`: Being pressed
|
||||
- :cpp:enumerator:`LV_STATE_SCROLLED`: Being scrolled
|
||||
- :cpp:enumerator:`LV_STATE_DISABLED`: Disabled state
|
||||
- :cpp:enumerator:`LV_STATE_USER_1`: Custom state
|
||||
- :cpp:enumerator:`LV_STATE_USER_2`: Custom state
|
||||
- :cpp:enumerator:`LV_STATE_USER_3`: Custom state
|
||||
- :cpp:enumerator:`LV_STATE_USER_4`: Custom state
|
||||
|
||||
The states are usually automatically changed by the library as the user
|
||||
interacts with a Widget (presses, releases, focuses, etc.). However,
|
||||
the states can be changed manually as well. To set or clear given state (but
|
||||
leave the other states untouched) use
|
||||
:cpp:expr:`lv_obj_add_state(widget, LV_STATE_...)` and
|
||||
:cpp:expr:`lv_obj_remove_state(widget, LV_STATE_...)`. In both cases OR-ed state
|
||||
values can be used as well. E.g.
|
||||
:cpp:expr:`lv_obj_add_state(widget, part, LV_STATE_PRESSED | LV_PRESSED_CHECKED)`.
|
||||
|
||||
To learn more about the states read the related section of the
|
||||
:ref:`Style overview <styles>`.
|
||||
|
||||
|
||||
|
||||
.. _lv_obj_flags:
|
||||
|
||||
Flags
|
||||
*****
|
||||
|
||||
There are some Widget attributes which can be enabled/disabled by
|
||||
:cpp:expr:`lv_obj_add_flag(widget, LV_OBJ_FLAG_...)` and
|
||||
:cpp:expr:`lv_obj_remove_flag(widget, LV_OBJ_FLAG_...)`.
|
||||
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_HIDDEN` Make the Widget hidden. (Like it wasn't there at all)
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_CLICKABLE` Make the Widget clickable by input devices
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_CLICK_FOCUSABLE` Add focused state to the Widget when clicked
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_CHECKABLE` Toggle checked state when the Widget is clicked
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLLABLE` Make the Widget scrollable
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_ELASTIC` Allow scrolling inside but with slower speed
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_MOMENTUM` Make the Widget scroll further when "thrown"
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_ONE` Allow scrolling only one snappable children
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_CHAIN_HOR` Allow propagating the horizontal scroll to a parent
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_CHAIN_VER` Allow propagating the vertical scroll to a parent
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_CHAIN` Simple packaging for (:cpp:expr:`LV_OBJ_FLAG_SCROLL_CHAIN_HOR | LV_OBJ_FLAG_SCROLL_CHAIN_VER`)
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_ON_FOCUS` Automatically scroll Widget to make it visible when focused
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_WITH_ARROW` Allow scrolling the focused Widget with arrow keys
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SNAPPABLE` If scroll snap is enabled on the parent it can snap to this Widget
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_PRESS_LOCK` Keep the Widget pressed even if the press slid from the Widget
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_EVENT_BUBBLE` Propagate the events to the parent as well
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_GESTURE_BUBBLE` Propagate the gestures to the parent
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_ADV_HITTEST` Allow performing more accurate hit (click) test. E.g. accounting for rounded corners
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_IGNORE_LAYOUT` Make the Widget not positioned by the layouts
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_FLOATING` Do not scroll the Widget when the parent scrolls and ignore layout
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS` Enable sending ``LV_EVENT_DRAW_TASK_ADDED`` events
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_OVERFLOW_VISIBLE` Do not clip the children's content to the parent's boundary
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_FLEX_IN_NEW_TRACK` Start a new flex track on this item
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_LAYOUT_1` Custom flag, free to use by layouts
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_LAYOUT_2` Custom flag, free to use by layouts
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_WIDGET_1` Custom flag, free to use by widget
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_WIDGET_2` Custom flag, free to use by widget
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_USER_1` Custom flag, free to use by user
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_USER_2` Custom flag, free to use by user
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_USER_3` Custom flag, free to use by user
|
||||
- :cpp:enumerator:`LV_OBJ_FLAG_USER_4` Custom flag, free to use by user
|
||||
|
||||
Some examples:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Hide on Widget */
|
||||
lv_obj_add_flag(widget, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
/* Make a Widget non-clickable */
|
||||
lv_obj_remove_flag(widget, LV_OBJ_FLAG_CLICKABLE);
|
||||
|
||||
|
||||
|
||||
.. _lv_obj_events:
|
||||
|
||||
Base-Widget Events
|
||||
******************
|
||||
|
||||
.. _widget_events:
|
||||
|
||||
Events from Input Devices
|
||||
-------------------------
|
||||
- :cpp:enumerator:`LV_EVENT_PRESSED` Widget has been pressed.
|
||||
- :cpp:enumerator:`LV_EVENT_PRESSING` Widget is being pressed (sent continuously while pressing).
|
||||
- :cpp:enumerator:`LV_EVENT_PRESS_LOST` Widget is still being pressed but slid cursor/finger off Widget.
|
||||
- :cpp:enumerator:`LV_EVENT_SHORT_CLICKED` Widget was pressed for a short period of time, then released. Not sent if scrolled.
|
||||
- :cpp:enumerator:`LV_EVENT_SINGLE_CLICKED` Sent for first short click within a small distance and short time.
|
||||
- :cpp:enumerator:`LV_EVENT_DOUBLE_CLICKED` Sent for second short click within small distance and short time.
|
||||
- :cpp:enumerator:`LV_EVENT_TRIPLE_CLICKED` Sent for third short click within small distance and short time.
|
||||
- :cpp:enumerator:`LV_EVENT_LONG_PRESSED` Object has been pressed for at least `long_press_time`. Not sent if scrolled.
|
||||
- :cpp:enumerator:`LV_EVENT_LONG_PRESSED_REPEAT` Sent after `long_press_time` in every `long_press_repeat_time` ms. Not sent if scrolled.
|
||||
- :cpp:enumerator:`LV_EVENT_CLICKED` Sent on release if not scrolled (regardless to long press).
|
||||
- :cpp:enumerator:`LV_EVENT_RELEASED` Sent in every cases when Widget has been released.
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_BEGIN` Scrolling begins. The event parameter is a pointer to the animation of the scroll. Can be modified.
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_THROW_BEGIN` Received when scrolling begins.
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_END` Scrolling ended.
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL` Scrolling
|
||||
- :cpp:enumerator:`LV_EVENT_GESTURE` A gesture is detected. Get gesture with `lv_indev_get_gesture_dir(lv_indev_active());`
|
||||
- :cpp:enumerator:`LV_EVENT_KEY` A key is sent to Widget. Get key with `lv_indev_get_key(lv_indev_active());`
|
||||
- :cpp:enumerator:`LV_EVENT_FOCUSED` Widget received focus,
|
||||
- :cpp:enumerator:`LV_EVENT_DEFOCUSED` Widget's focus has been lost.
|
||||
- :cpp:enumerator:`LV_EVENT_LEAVE` Widget's focus has been lost but is still selected.
|
||||
- :cpp:enumerator:`LV_EVENT_HIT_TEST` Perform advanced hit-testing.
|
||||
|
||||
Special Events
|
||||
--------------
|
||||
- :cpp:enumerator:`LV_EVENT_VALUE_CHANGED` when the :cpp:enumerator:`LV_OBJ_FLAG_CHECKABLE` flag is
|
||||
enabled and the Widget was clicked (on transition to/from the checked state)
|
||||
|
||||
Drawing Events
|
||||
--------------
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_MAIN` Performing drawing of main part
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_MAIN_BEGIN` Starting drawing of main part
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_MAIN_END` Finishing drawing of main part
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_POST` Perform the post draw phase (when all children are drawn)
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_POST_BEGIN` Starting the post draw phase (when all children are drawn)
|
||||
- :cpp:enumerator:`LV_EVENT_DRAW_POST_END` Finishing the post draw phase (when all children are drawn)
|
||||
|
||||
Other Events
|
||||
------------
|
||||
- :cpp:enumerator:`LV_EVENT_DELETE` Object is being deleted
|
||||
- :cpp:enumerator:`LV_EVENT_CHILD_CHANGED` Child was removed, added, or its size, position were changed
|
||||
- :cpp:enumerator:`LV_EVENT_CHILD_CREATED` Child was created, always bubbles up to all parents
|
||||
- :cpp:enumerator:`LV_EVENT_CHILD_DELETED` Child was deleted, always bubbles up to all parents
|
||||
- :cpp:enumerator:`LV_EVENT_SIZE_CHANGED` Object coordinates/size have changed
|
||||
- :cpp:enumerator:`LV_EVENT_STYLE_CHANGED` Object's style has changed
|
||||
- :cpp:enumerator:`LV_EVENT_LAYOUT_CHANGED` A child's position has changed due to a layout recalculation (when container has flex or grid layout style)
|
||||
- :cpp:enumerator:`LV_EVENT_GET_SELF_SIZE` Get internal size of a widget
|
||||
|
||||
.. admonition:: Further Reading
|
||||
|
||||
Learn more about :ref:`events`.
|
||||
|
||||
|
||||
|
||||
.. _lv_obj_keys:
|
||||
|
||||
Keys
|
||||
****
|
||||
|
||||
If :cpp:enumerator:`LV_OBJ_FLAG_CHECKABLE` is enabled, :cpp:enumerator:`LV_KEY_RIGHT` and
|
||||
:cpp:enumerator:`LV_KEY_UP` make the Widget checked, and :cpp:enumerator:`LV_KEY_LEFT` and
|
||||
:cpp:enumerator:`LV_KEY_DOWN` make it unchecked.
|
||||
|
||||
If :cpp:enumerator:`LV_OBJ_FLAG_SCROLLABLE` is enabled, but the Widget is not editable
|
||||
(as declared by the widget class), the arrow keys (:cpp:enumerator:`LV_KEY_UP`,
|
||||
:cpp:enumerator:`LV_KEY_DOWN`, :cpp:enumerator:`LV_KEY_LEFT`, :cpp:enumerator:`LV_KEY_RIGHT`) scroll the Widget.
|
||||
If the Widget can only scroll vertically, :cpp:enumerator:`LV_KEY_LEFT` and
|
||||
:cpp:enumerator:`LV_KEY_RIGHT` will scroll up/down instead, making it compatible with
|
||||
an encoder input device. See :ref:`Input devices overview <indev>` for
|
||||
more on encoder behaviors and the edit mode.
|
||||
|
||||
.. admonition:: Further Reading
|
||||
|
||||
Learn more about :ref:`indev_keys`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.. _widget_snapshot:
|
||||
|
||||
Snapshot
|
||||
********
|
||||
|
||||
A snapshot image can be generated for a Widget together with its
|
||||
children. Check details in :ref:`snapshot`.
|
||||
|
||||
|
||||
|
||||
Example
|
||||
*******
|
||||
|
||||
.. include:: ../../examples/widgets/obj/index.rst
|
||||
|
||||
|
||||
|
||||
.. _lv_obj_api:
|
||||
|
||||
API
|
||||
***
|
||||
294
docs/details/base-widget/scroll.rst
Normal file
294
docs/details/base-widget/scroll.rst
Normal file
@@ -0,0 +1,294 @@
|
||||
.. _scrolling:
|
||||
|
||||
=========
|
||||
Scrolling
|
||||
=========
|
||||
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
In LVGL scrolling works very intuitively: if a Widget is outside its
|
||||
parent content area (the size without padding), the parent becomes
|
||||
scrollable and scrollbar(s) will appear. That's it.
|
||||
|
||||
Any Widget can be scrollable including :ref:`base_widget`, ``lv_image``,
|
||||
``lv_button``, ``lv_meter``, etc
|
||||
|
||||
The Widget can either be scrolled horizontally or vertically in one
|
||||
stroke; diagonal scrolling is not possible.
|
||||
|
||||
|
||||
Scrollbar
|
||||
---------
|
||||
|
||||
Mode
|
||||
^^^^
|
||||
|
||||
Scrollbars are displayed according to a configured ``mode``. The
|
||||
following ``mode``\ (s) exist:
|
||||
|
||||
- :cpp:enumerator:`LV_SCROLLBAR_MODE_OFF`: Never show the scrollbars
|
||||
- :cpp:enumerator:`LV_SCROLLBAR_MODE_ON`: Always show the scrollbars
|
||||
- :cpp:enumerator:`LV_SCROLLBAR_MODE_ACTIVE`: Show scroll bars while a Widget is being scrolled
|
||||
- :cpp:enumerator:`LV_SCROLLBAR_MODE_AUTO`: Show scroll bars when the content is large enough to be scrolled
|
||||
|
||||
:cpp:expr:`lv_obj_set_scrollbar_mode(widget, LV_SCROLLBAR_MODE_...)` sets the scrollbar mode on a Widget.
|
||||
|
||||
Styling
|
||||
^^^^^^^
|
||||
|
||||
The scrollbars have their own dedicated part, called
|
||||
:cpp:enumerator:`LV_PART_SCROLLBAR`. For example a scrollbar can turn to red like
|
||||
this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_red;
|
||||
lv_style_init(&style_red);
|
||||
lv_style_set_bg_color(&style_red, lv_color_red());
|
||||
|
||||
...
|
||||
|
||||
lv_obj_add_style(widget, &style_red, LV_PART_SCROLLBAR);
|
||||
|
||||
A Widget goes to the :cpp:enumerator:`LV_STATE_SCROLLED` state while it's being
|
||||
scrolled. This allows adding different styles to the scrollbar or the
|
||||
Widget itself when scrolled. This code makes the scrollbar blue when the
|
||||
Widget is scrolled:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_blue;
|
||||
lv_style_init(&style_blue);
|
||||
lv_style_set_bg_color(&style_blue, lv_color_blue());
|
||||
|
||||
...
|
||||
|
||||
lv_obj_add_style(widget, &style_blue, LV_STATE_SCROLLED | LV_PART_SCROLLBAR);
|
||||
|
||||
If the base direction of the :cpp:enumerator:`LV_PART_SCROLLBAR` is RTL
|
||||
(:c:macro:`LV_BASE_DIR_RTL`) the vertical scrollbar will be placed on the left.
|
||||
Note that, the ``base_dir`` style property is inherited. Therefore, it
|
||||
can be set directly on the :cpp:enumerator:`LV_PART_SCROLLBAR` part of a Widget or on
|
||||
the Widget's or any parent's main part to make a scrollbar inherit the
|
||||
base direction.
|
||||
|
||||
``pad_left/right/top/bottom`` sets the spacing around the scrollbars and
|
||||
``width`` sets the scrollbar's width.
|
||||
|
||||
|
||||
.. _scroll_events:
|
||||
|
||||
Scrolling Events
|
||||
----------------
|
||||
|
||||
The following events are related to scrolling:
|
||||
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_BEGIN`: Scrolling begins. The event parameter is
|
||||
``NULL`` or an ``lv_anim_t *`` with a scroll animation descriptor that can be modified if required.
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL_END`: Scrolling ends.
|
||||
- :cpp:enumerator:`LV_EVENT_SCROLL`: Scroll happened. Triggered on every position change. Scroll events
|
||||
|
||||
|
||||
Features of scrolling
|
||||
*********************
|
||||
|
||||
Besides, managing "normal" scrolling there are many interesting and
|
||||
useful additional features.
|
||||
|
||||
Scrollable
|
||||
----------
|
||||
|
||||
It's possible to make a Widget non-scrollable with
|
||||
:cpp:expr:`lv_obj_remove_flag(widget, LV_OBJ_FLAG_SCROLLABLE)`.
|
||||
|
||||
Non-scrollable Widgets can still propagate the scrolling (chain) to
|
||||
their parents.
|
||||
|
||||
The direction in which scrolling happens can be controlled by
|
||||
:cpp:expr:`lv_obj_set_scroll_dir(widget, LV_DIR_...)`.
|
||||
|
||||
The following values are possible for the direction:
|
||||
|
||||
- :cpp:enumerator:`LV_DIR_TOP`: only scroll up
|
||||
- :cpp:enumerator:`LV_DIR_LEFT`: only scroll left
|
||||
- :cpp:enumerator:`LV_DIR_BOTTOM`: only scroll down
|
||||
- :cpp:enumerator:`LV_DIR_RIGHT`: only scroll right
|
||||
- :cpp:enumerator:`LV_DIR_HOR`: only scroll horizontally
|
||||
- :cpp:enumerator:`LV_DIR_VER`: only scroll vertically
|
||||
- :cpp:enumerator:`LV_DIR_ALL`: scroll any directions
|
||||
|
||||
OR-ed values are also possible. E.g. :cpp:expr:`LV_DIR_TOP | LV_DIR_LEFT`.
|
||||
|
||||
Scroll chain
|
||||
------------
|
||||
|
||||
If a Widget can't be scrolled further (e.g. its content has reached the
|
||||
bottom-most position) additional scrolling is propagated to its parent.
|
||||
If the parent can be scrolled in that direction than it will be scrolled
|
||||
instead. It continues propagating to the grandparent and
|
||||
grand-grandparents as well.
|
||||
|
||||
The propagation on scrolling is called "scroll chaining" and it can be
|
||||
enabled/disabled with ``LV_OBJ_FLAG_SCROLL_CHAIN_HOR/VER`` flag. If
|
||||
chaining is disabled the propagation stops on the Widget and the
|
||||
parent(s) won't be scrolled.
|
||||
|
||||
Scroll momentum
|
||||
---------------
|
||||
|
||||
When the user scrolls a Widget and releases it, LVGL can emulate
|
||||
inertial momentum for the scrolling. It's like the Widget was thrown and
|
||||
scrolling slows down smoothly.
|
||||
|
||||
The scroll momentum can be enabled/disabled with the
|
||||
:cpp:enumerator:`LV_OBJ_FLAG_SCROLL_MOMENTUM` flag.
|
||||
|
||||
Elastic scroll
|
||||
--------------
|
||||
|
||||
Normally a Widget can't be scrolled past the extremities of its
|
||||
content. That is the top side of the content can't be below the top side
|
||||
of the Widget.
|
||||
|
||||
However, with :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_ELASTIC` a fancy effect is added
|
||||
when the user "over-scrolls" the content. The scrolling slows down, and
|
||||
the content can be scrolled inside the Widget. When the Widget is
|
||||
released the content scrolled in it will be animated back to the valid
|
||||
position.
|
||||
|
||||
Snapping
|
||||
--------
|
||||
|
||||
The children of a Widget can be snapped according to specific rules
|
||||
when scrolling ends. Children can be made snappable individually with
|
||||
the :cpp:enumerator:`LV_OBJ_FLAG_SNAPPABLE` flag.
|
||||
|
||||
A Widget can align snapped children in four ways:
|
||||
|
||||
- :cpp:enumerator:`LV_SCROLL_SNAP_NONE`: Snapping is disabled. (default)
|
||||
- :cpp:enumerator:`LV_SCROLL_SNAP_START`: Align the children to the left/top side of a scrolled Widget
|
||||
- :cpp:enumerator:`LV_SCROLL_SNAP_END`: Align the children to the right/bottom side of a scrolled Widget
|
||||
- :cpp:enumerator:`LV_SCROLL_SNAP_CENTER`: Align the children to the center of a scrolled Widget
|
||||
|
||||
Snap alignment is set with
|
||||
:cpp:expr:`lv_obj_set_scroll_snap_x(widget, LV_SCROLL_SNAP_...)` and
|
||||
:cpp:expr:`lv_obj_set_scroll_snap_y(widget, LV_SCROLL_SNAP_...)`.
|
||||
|
||||
Under the hood the following happens:
|
||||
|
||||
1. User scrolls a Widget and releases the screen
|
||||
2. LVGL calculates where the scroll would end considering scroll momentum
|
||||
3. LVGL finds the nearest scroll point
|
||||
4. LVGL scrolls to the snap point with an animation
|
||||
|
||||
Scroll one
|
||||
----------
|
||||
|
||||
The "scroll one" feature tells LVGL to allow scrolling only one
|
||||
snappable child at a time. This requires making the children snappable
|
||||
and setting a scroll snap alignment different from
|
||||
:cpp:enumerator:`LV_SCROLL_SNAP_NONE`.
|
||||
|
||||
This feature can be enabled by the :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_ONE` flag.
|
||||
|
||||
Scroll on focus
|
||||
---------------
|
||||
|
||||
Imagine that there a lot of Widgets in a group that are on a scrollable
|
||||
Widget. Pressing the "Tab" button focuses the next Widget but it might
|
||||
be outside the visible area of the scrollable Widget. If the "scroll on
|
||||
focus" feature is enabled LVGL will automatically scroll Widgets to
|
||||
bring their children into view. The scrolling happens recursively
|
||||
therefore even nested scrollable Widgets are handled properly. The
|
||||
Widget will be scrolled into view even if it's on a different page of a
|
||||
tabview.
|
||||
|
||||
|
||||
Scroll manually
|
||||
***************
|
||||
|
||||
The following API functions allow manual scrolling of Widgets:
|
||||
|
||||
- ``lv_obj_scroll_by(widget, x, y, LV_ANIM_ON/OFF)`` scroll by ``x`` and ``y`` values
|
||||
- ``lv_obj_scroll_to(widget, x, y, LV_ANIM_ON/OFF)`` scroll to bring the given coordinate to the top left corner
|
||||
- ``lv_obj_scroll_to_x(widget, x, LV_ANIM_ON/OFF)`` scroll to bring the given coordinate to the left side
|
||||
- ``lv_obj_scroll_to_y(widget, y, LV_ANIM_ON/OFF)`` scroll to bring the given coordinate to the top side
|
||||
|
||||
From time to time you may need to retrieve the scroll position of an
|
||||
element, either to restore it later, or to display dynamically some
|
||||
elements according to the current scroll. Here is an example to see how
|
||||
to combine scroll event and store the scroll top position.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static int scroll_value = 0;
|
||||
|
||||
static void store_scroll_value_event_cb(lv_event_t* e) {
|
||||
lv_obj_t* screen = lv_event_get_target(e);
|
||||
scroll_value = lv_obj_get_scroll_top(screen);
|
||||
printf("%d pixels are scrolled out on the top\n", scroll_value);
|
||||
}
|
||||
|
||||
lv_obj_t* container = lv_obj_create(NULL);
|
||||
lv_obj_add_event_cb(container, store_scroll_value_event_cb, LV_EVENT_SCROLL, NULL);
|
||||
|
||||
Scroll coordinates can be retrieved from different axes with these
|
||||
functions:
|
||||
|
||||
- ``lv_obj_get_scroll_x(widget)`` Get the ``x`` coordinate of Widget
|
||||
- ``lv_obj_get_scroll_y(widget)`` Get the ``y`` coordinate of Widget
|
||||
- ``lv_obj_get_scroll_top(widget)`` Get the scroll coordinate from the top
|
||||
- ``lv_obj_get_scroll_bottom(widget)`` Get the scroll coordinate from the bottom
|
||||
- ``lv_obj_get_scroll_left(widget)`` Get the scroll coordinate from the left
|
||||
- ``lv_obj_get_scroll_right(widget)`` Get the scroll coordinate from the right
|
||||
|
||||
|
||||
Self size
|
||||
*********
|
||||
|
||||
Self size is a property of a Widget. Normally, the user shouldn't use
|
||||
this parameter but if a custom widget is created it might be useful.
|
||||
|
||||
In short, self size establishes the size of a Widget's content. To
|
||||
understand it better take the example of a table. Let's say it has 10
|
||||
rows each with 50 px height. So the total height of the content is 500
|
||||
px. In other words the "self height" is 500 px. If the user sets only
|
||||
200 px height for the table LVGL will see that the self size is larger
|
||||
and make the table scrollable.
|
||||
|
||||
This means not only the children can make a Widget scrollable but a
|
||||
larger self size will as well.
|
||||
|
||||
LVGL uses the :cpp:enumerator:`LV_EVENT_GET_SELF_SIZE` event to get the self size of
|
||||
a Widget. Here is an example to see how to handle the event:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if(event_code == LV_EVENT_GET_SELF_SIZE) {
|
||||
lv_point_t * p = lv_event_get_param(e);
|
||||
|
||||
//If x or y < 0 then it doesn't need to be calculated now
|
||||
if(p->x >= 0) {
|
||||
p->x = 200; //Set or calculate the self width
|
||||
}
|
||||
|
||||
if(p->y >= 0) {
|
||||
p->y = 50; //Set or calculate the self height
|
||||
}
|
||||
}
|
||||
|
||||
.. _scroll_example:
|
||||
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
.. include:: ../../examples/scroll/index.rst
|
||||
|
||||
.. _scroll_api:
|
||||
|
||||
|
||||
API
|
||||
***
|
||||
11
docs/details/base-widget/styles/index.rst
Normal file
11
docs/details/base-widget/styles/index.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. _styles:
|
||||
|
||||
======
|
||||
Styles
|
||||
======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
style
|
||||
style-properties
|
||||
1657
docs/details/base-widget/styles/style-properties.rst
Normal file
1657
docs/details/base-widget/styles/style-properties.rst
Normal file
File diff suppressed because it is too large
Load Diff
538
docs/details/base-widget/styles/style.rst
Normal file
538
docs/details/base-widget/styles/style.rst
Normal file
@@ -0,0 +1,538 @@
|
||||
.. _style_details:
|
||||
|
||||
=============
|
||||
Style Details
|
||||
=============
|
||||
|
||||
*Styles* are used to set the appearance of Widgets. Styles in lvgl are
|
||||
heavily inspired by CSS. The concept in a nutshell is that a
|
||||
style is an :cpp:type:`lv_style_t` variable which can hold properties like
|
||||
border width, font, text color and so on. It's similar to a ``class`` in CSS.
|
||||
|
||||
- Styles can be assigned to Widgets to change their appearance. Upon
|
||||
assignment, the target part (*pseudo-element* in CSS) and target state
|
||||
(*pseudo class*) can be specified. For example one can add
|
||||
``style_blue`` to the knob of a slider when it's in pressed state.
|
||||
- The same style can be used by any number of Widgets.
|
||||
- Styles can be cascaded which means multiple styles may be assigned to a Widget and
|
||||
each style can have different properties. Therefore, not all properties
|
||||
have to be specified in a style. LVGL will search for a property until a
|
||||
style defines it or use a default if it's not specified by any of the
|
||||
styles. For example ``style_btn`` can result in a default gray button
|
||||
and ``style_btn_red`` can add only a ``background-color=red`` to
|
||||
overwrite the background color.
|
||||
- The most recently added style has higher precedence. This means if a property
|
||||
is specified in two styles the newest style in the Widget will be used.
|
||||
- Some properties (e.g. text color) can be inherited from a parent(s) if it's not specified in a Widget.
|
||||
- Widgets can also have local styles with higher precedence than "normal" styles.
|
||||
- Unlike CSS (where pseudo-classes describe different states, e.g. ``:focus``),
|
||||
in LVGL a property is assigned to a given state.
|
||||
- Transitions can be applied when the Widget changes state.
|
||||
|
||||
.. _styles_states:
|
||||
|
||||
States
|
||||
******
|
||||
|
||||
The Widgets can be in the combination of the following states:
|
||||
|
||||
- :cpp:enumerator:`LV_STATE_DEFAULT`: (0x0000) Normal, released state
|
||||
- :cpp:enumerator:`LV_STATE_CHECKED`: (0x0001) Toggled or checked state
|
||||
- :cpp:enumerator:`LV_STATE_FOCUSED`: (0x0002) Focused via keypad or encoder or clicked via touchpad/mouse
|
||||
- :cpp:enumerator:`LV_STATE_FOCUS_KEY`: (0x0004) Focused via keypad or encoder but not via touchpad/mouse
|
||||
- :cpp:enumerator:`LV_STATE_EDITED`: (0x0008) Edit by an encoder
|
||||
- :cpp:enumerator:`LV_STATE_HOVERED`: (0x0010) Hovered by mouse
|
||||
- :cpp:enumerator:`LV_STATE_PRESSED`: (0x0020) Being pressed
|
||||
- :cpp:enumerator:`LV_STATE_SCROLLED`: (0x0040) Being scrolled
|
||||
- :cpp:enumerator:`LV_STATE_DISABLED`: (0x0080) Disabled state
|
||||
- :cpp:enumerator:`LV_STATE_USER_1`: (0x1000) Custom state
|
||||
- :cpp:enumerator:`LV_STATE_USER_2`: (0x2000) Custom state
|
||||
- :cpp:enumerator:`LV_STATE_USER_3`: (0x4000) Custom state
|
||||
- :cpp:enumerator:`LV_STATE_USER_4`: (0x8000) Custom state
|
||||
|
||||
A Widget can be in a combination of states such as being focused and
|
||||
pressed at the same time. This is represented as :cpp:expr:`LV_STATE_FOCUSED | LV_STATE_PRESSED`.
|
||||
|
||||
A style can be added to any state or state combination. For example,
|
||||
setting a different background color for the default and pressed states.
|
||||
If a property is not defined in a state the best matching state's
|
||||
property will be used. Typically this means the property with
|
||||
:cpp:enumerator:`LV_STATE_DEFAULT` is used.˛ If the property is not set even for the
|
||||
default state the default value will be used. (See later)
|
||||
|
||||
But what does the "best matching state's property" really mean? States
|
||||
have a precedence which is shown by their value (see in the above list).
|
||||
A higher value means higher precedence. To determine which state's
|
||||
property to use let's take an example. Imagine the background color is
|
||||
defined like this:
|
||||
|
||||
- :cpp:enumerator:`LV_STATE_DEFAULT`: white
|
||||
- :cpp:enumerator:`LV_STATE_PRESSED`: gray
|
||||
- :cpp:enumerator:`LV_STATE_FOCUSED`: red
|
||||
|
||||
1. Initially the Widget is in the default state, so it's a simple case:
|
||||
the property is perfectly defined in the Widget's current state as
|
||||
white.
|
||||
2. When the Widget is pressed there are 2 related properties: default
|
||||
with white (default is related to every state) and pressed with gray.
|
||||
The pressed state has 0x0020 precedence which is higher than the
|
||||
default state's 0x0000 precedence, so gray color will be used.
|
||||
3. When the Widget has focus the same thing happens as in pressed state
|
||||
and red color will be used. (Focused state has higher precedence than
|
||||
default state).
|
||||
4. When the Widget has focus and pressed both gray and red would work,
|
||||
but the pressed state has higher precedence than focused so gray
|
||||
color will be used.
|
||||
5. It's possible to set e.g. rose color for :cpp:expr:`LV_STATE_PRESSED | LV_STATE_FOCUSED`.
|
||||
In this case, this combined state has 0x0020 + 0x0002 = 0x0022 precedence, which is higher than
|
||||
the pressed state's precedence so rose color would be used.
|
||||
6. When the Widget is in the checked state there is no property to set
|
||||
the background color for this state. So for lack of a better option,
|
||||
the Widget remains white from the default state's property.
|
||||
|
||||
Some practical notes:
|
||||
|
||||
- The precedence (value) of states is quite intuitive, and it's something the
|
||||
user would expect naturally. E.g. if a Widget has focus the user will still
|
||||
want to see if it's pressed, therefore the pressed state has a higher
|
||||
precedence. If the focused state had a higher precedence it would overwrite
|
||||
the pressed color.
|
||||
- If you want to set a property for all states (e.g. red background color)
|
||||
just set it for the default state. If the Widget can't find a property
|
||||
for its current state it will fall back to the default state's property.
|
||||
- Use ORed states to describe the properties for complex cases. (E.g.
|
||||
pressed + checked + focused)
|
||||
- It might be a good idea to use different
|
||||
style elements for different states. For example, finding background
|
||||
colors for released, pressed, checked + pressed, focused, focused +
|
||||
pressed, focused + pressed + checked, etc. states is quite difficult.
|
||||
Instead, for example, use the background color for pressed and checked
|
||||
states and indicate the focused state with a different border color.
|
||||
|
||||
.. _styles_cascading:
|
||||
|
||||
Cascading styles
|
||||
****************
|
||||
|
||||
It's not required to set all the properties in one style. It's possible
|
||||
to add more styles to a Widget and have the latter added style modify
|
||||
or extend appearance. For example, create a general gray button style
|
||||
and create a new one for red buttons where only the new background color
|
||||
is set.
|
||||
|
||||
This is much like in CSS when used classes are listed like
|
||||
``<div class=".btn .btn-red">``.
|
||||
|
||||
Styles added later have precedence over ones set earlier. So in the
|
||||
gray/red button example above, the normal button style should be added
|
||||
first and the red style second. However, the precedence of the states
|
||||
are still taken into account. So let's examine the following case:
|
||||
|
||||
- the basic button style defines dark-gray color for the default state and
|
||||
light-gray color for the pressed state
|
||||
- the red button style defines the background color as red only in the default state
|
||||
|
||||
In this case, when the button is released (it's in default state) it
|
||||
will be red because a perfect match is found in the most recently added
|
||||
style (red). When the button is pressed the light-gray color is a better
|
||||
match because it describes the current state perfectly, so the button
|
||||
will be light-gray.
|
||||
|
||||
.. _styles_inheritance:
|
||||
|
||||
Inheritance
|
||||
***********
|
||||
|
||||
Some properties (typically those related to text) can be inherited from
|
||||
the parent Widget's styles. Inheritance is applied only if the given
|
||||
property is not set in the Widget's styles (even in default state). In
|
||||
this case, if the property is inheritable, the property's value will be
|
||||
searched in the parents until a Widget specifies a value for the
|
||||
property. The parents will use their own state to determine the value.
|
||||
So if a button is pressed, and the text color comes from here, the
|
||||
pressed text color will be used.
|
||||
|
||||
.. _styles_parts:
|
||||
|
||||
Parts
|
||||
*****
|
||||
|
||||
Widgets can be composed of *parts* which may each have their own styles.
|
||||
|
||||
The following predefined parts exist in LVGL:
|
||||
|
||||
- :cpp:enumerator:`LV_PART_MAIN`: A background like rectangle
|
||||
- :cpp:enumerator:`LV_PART_SCROLLBAR`: The scrollbar(s)
|
||||
- :cpp:enumerator:`LV_PART_INDICATOR`: Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox
|
||||
- :cpp:enumerator:`LV_PART_KNOB`: Like a handle to grab to adjust a value
|
||||
- :cpp:enumerator:`LV_PART_SELECTED`: Indicate the currently selected option or section
|
||||
- :cpp:enumerator:`LV_PART_ITEMS`: Used if the widget has multiple similar elements (e.g. table cells)
|
||||
- :cpp:enumerator:`LV_PART_CURSOR`: Mark a specific place e.g. text area's or chart's cursor
|
||||
- :cpp:enumerator:`LV_PART_CUSTOM_FIRST`: Custom part identifiers can be added starting from here.
|
||||
|
||||
For example a :ref:`Slider <lv_slider>` has three parts:
|
||||
|
||||
- Background
|
||||
- Indicator
|
||||
- Knob
|
||||
|
||||
This means all three parts of the slider can have their own styles. See
|
||||
later how to add styles to Widgets and parts.
|
||||
|
||||
.. _styles_initialize:
|
||||
|
||||
Initialize styles and set/get properties
|
||||
****************************************
|
||||
|
||||
Styles are stored in :cpp:type:`lv_style_t` variables. Style variables should be
|
||||
``static``, global or dynamically allocated. In other words they cannot
|
||||
be local variables in functions which are destroyed when the function
|
||||
exits. Before using a style it should be initialized with
|
||||
:cpp:expr:`lv_style_init(&my_style)`. After initializing a style, properties can
|
||||
be added or changed.
|
||||
|
||||
Property set functions looks like this:
|
||||
``lv_style_set_<property_name>(&style, <value>);`` For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_style_t style_btn;
|
||||
lv_style_init(&style_btn);
|
||||
lv_style_set_bg_color(&style_btn, lv_color_hex(0x115588));
|
||||
lv_style_set_bg_opa(&style_btn, LV_OPA_50);
|
||||
lv_style_set_border_width(&style_btn, 2);
|
||||
lv_style_set_border_color(&style_btn, lv_color_black());
|
||||
|
||||
static lv_style_t style_btn_red;
|
||||
lv_style_init(&style_btn_red);
|
||||
lv_style_set_bg_color(&style_btn_red, lv_palette_main(LV_PALETTE_RED));
|
||||
lv_style_set_bg_opa(&style_btn_red, LV_OPA_COVER);
|
||||
|
||||
To remove a property use:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_style_remove_prop(&style, LV_STYLE_BG_COLOR);
|
||||
|
||||
To get a property's value from a style:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_style_value_t v;
|
||||
lv_result_t res = lv_style_get_prop(&style, LV_STYLE_BG_COLOR, &v);
|
||||
if(res == LV_RESULT_OK) { /* Found */
|
||||
do_something(v.color);
|
||||
}
|
||||
|
||||
:cpp:union:`lv_style_value_t` has 3 fields:
|
||||
|
||||
- :cpp:member:`num`: for integer, boolean and opacity properties
|
||||
- :cpp:member:`color`: for color properties
|
||||
- :cpp:member:`ptr`: for pointer properties
|
||||
|
||||
To reset a style (free all its data) use:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_style_reset(&style);
|
||||
|
||||
Styles can be built as ``const`` as well to save RAM:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const lv_style_const_prop_t style1_props[] = {
|
||||
LV_STYLE_CONST_WIDTH(50),
|
||||
LV_STYLE_CONST_HEIGHT(50),
|
||||
LV_STYLE_CONST_PROPS_END
|
||||
};
|
||||
|
||||
LV_STYLE_CONST_INIT(style1, style1_props);
|
||||
|
||||
Later ``const`` style can be used like any other style but (obviously)
|
||||
new properties cannot be added.
|
||||
|
||||
.. _styles_add_remove:
|
||||
|
||||
Add and remove styles to a widget
|
||||
*********************************
|
||||
|
||||
A style on its own is not that useful. It must be assigned to a Widget
|
||||
to take effect.
|
||||
|
||||
Add styles
|
||||
----------
|
||||
|
||||
To add a style to a Widget use
|
||||
``lv_obj_add_style(widget, &style, <selector>)``. ``<selector>`` is an
|
||||
OR-ed value of parts and state to which the style should be added. Some
|
||||
examples:
|
||||
|
||||
- :cpp:expr:`LV_PART_MAIN | LV_STATE_DEFAULT`
|
||||
- :cpp:enumerator:`LV_STATE_PRESSED`: The main part in pressed state. :cpp:enumerator:`LV_PART_MAIN` can be omitted
|
||||
- :cpp:enumerator:`LV_PART_SCROLLBAR`: The scrollbar part in the default state. :cpp:enumerator:`LV_STATE_DEFAULT` can be omitted.
|
||||
- :cpp:expr:`LV_PART_SCROLLBAR | LV_STATE_SCROLLED`: The scrollbar part when the Widget is being scrolled
|
||||
- :cpp:expr:`LV_PART_INDICATOR | LV_STATE_PRESSED | LV_STATE_CHECKED` The indicator part when the Widget is pressed and checked at the same time.
|
||||
|
||||
Using :cpp:func:`lv_obj_add_style`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_style(btn, &style_btn, 0); /* Default button style */
|
||||
lv_obj_add_style(btn, &btn_red, LV_STATE_PRESSED); /* Overwrite only some colors to red when pressed */
|
||||
|
||||
Replace styles
|
||||
--------------
|
||||
|
||||
To replace a specific style of a Widget use
|
||||
:cpp:expr:`lv_obj_replace_style(widget, old_style, new_style, selector)`. This
|
||||
function will only replace ``old_style`` with ``new_style`` if the
|
||||
``selector`` matches the ``selector`` used in ``lv_obj_add_style``. Both
|
||||
styles, i.e. ``old_style`` and ``new_style``, must not be ``NULL`` (for
|
||||
adding and removing separate functions exist). If the combination of
|
||||
``old_style`` and ``selector`` exists multiple times in ``obj``\ 's
|
||||
styles, all occurrences will be replaced. The return value of the
|
||||
function indicates whether at least one successful replacement took
|
||||
place.
|
||||
|
||||
Using :cpp:func:`lv_obj_replace_style`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_add_style(btn, &style_btn, 0); /* Add a button style */
|
||||
lv_obj_replace_style(btn, &style_btn, &new_style_btn, 0); /* Replace the button style with a different one */
|
||||
|
||||
Remove styles
|
||||
-------------
|
||||
|
||||
To remove all styles from a Widget use :cpp:expr:`lv_obj_remove_style_all(widget)`.
|
||||
|
||||
To remove specific styles use
|
||||
:cpp:expr:`lv_obj_remove_style(widget, style, selector)`. This function will remove
|
||||
``style`` only if the ``selector`` matches with the ``selector`` used in
|
||||
:cpp:func:`lv_obj_add_style`. ``style`` can be ``NULL`` to check only the
|
||||
``selector`` and remove all matching styles. The ``selector`` can use
|
||||
the :cpp:enumerator:`LV_STATE_ANY` and :cpp:enumerator:`LV_PART_ANY` values to remove the style from
|
||||
any state or part.
|
||||
|
||||
Report style changes
|
||||
--------------------
|
||||
|
||||
If a style which is already assigned to a Widget changes (i.e. a
|
||||
property is added or changed), the Widgets using that style should be
|
||||
notified. There are 3 options to do this:
|
||||
|
||||
1. If you know that the changed properties can be applied by a simple redraw
|
||||
(e.g. color or opacity changes) just call :cpp:expr:`lv_obj_invalidate(widget)`
|
||||
or :cpp:expr:`lv_obj_invalidate(lv_screen_active())`.
|
||||
2. If more complex style properties were changed or added, and you know which
|
||||
Widget(s) are affected by that style call :cpp:expr:`lv_obj_refresh_style(widget, part, property)`.
|
||||
To refresh all parts and properties use :cpp:expr:`lv_obj_refresh_style(widget, LV_PART_ANY, LV_STYLE_PROP_ANY)`.
|
||||
3. To make LVGL check all Widgets to see if they use a style and refresh them
|
||||
when needed, call :cpp:expr:`lv_obj_report_style_change(&style)`. If ``style``
|
||||
is ``NULL`` all Widgets will be notified about a style change.
|
||||
|
||||
Get a property's value on a Widget
|
||||
-----------------------------------
|
||||
|
||||
To get a final value of property
|
||||
|
||||
- considering cascading, inheritance, local styles and transitions (see below)
|
||||
- property get functions like this can be used: ``lv_obj_get_style_<property_name>(widget, <part>)``.
|
||||
These functions use the Widget's current state and if no better candidate exists they return a default value.
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_color_t color = lv_obj_get_style_bg_color(btn, LV_PART_MAIN);
|
||||
|
||||
.. _styles_local:
|
||||
|
||||
Local styles
|
||||
************
|
||||
|
||||
In addition to "normal" styles, Widgets can also store local styles.
|
||||
This concept is similar to inline styles in CSS
|
||||
(e.g. ``<div style="color:red">``) with some modification.
|
||||
|
||||
Local styles are like normal styles, but they can't be shared among
|
||||
other Widgets. If used, local styles are allocated automatically, and
|
||||
freed when the Widget is deleted. They are useful to add local
|
||||
customization to a Widget.
|
||||
|
||||
Unlike in CSS, LVGL local styles can be assigned to states
|
||||
(*pseudo-classes*) and parts (*pseudo-elements*).
|
||||
|
||||
To set a local property use functions like
|
||||
``lv_obj_set_style_<property_name>(widget, <value>, <selector>);`` For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_set_style_bg_color(slider, lv_color_red(), LV_PART_INDICATOR | LV_STATE_FOCUSED);
|
||||
|
||||
|
||||
.. _style_properties_overview:
|
||||
|
||||
Style Properties Overview
|
||||
*************************
|
||||
|
||||
For the full list of style properties click :ref:`here <style_properties>`.
|
||||
|
||||
|
||||
Typical background properties
|
||||
-----------------------------
|
||||
|
||||
In the documentation of the widgets you will see sentences like "The
|
||||
widget uses the typical background properties". These "typical
|
||||
background properties" are the ones related to:
|
||||
|
||||
- Background
|
||||
- Border
|
||||
- Outline
|
||||
- Shadow
|
||||
- Padding
|
||||
- Width and height transformation
|
||||
- X and Y translation
|
||||
|
||||
.. _styles_transitions:
|
||||
|
||||
Transitions
|
||||
***********
|
||||
|
||||
By default, when a Widget changes state (e.g. it's pressed) the new
|
||||
properties from the new state are set immediately. However, with
|
||||
transitions it's possible to play an animation on state change. For
|
||||
example, on pressing a button its background color can be animated to
|
||||
the pressed color over 300 ms.
|
||||
|
||||
The parameters of the transitions are stored in the styles. It's
|
||||
possible to set
|
||||
|
||||
- the time of the transition
|
||||
- the delay before starting the transition
|
||||
- the animation path (also known as the timing or easing function)
|
||||
- the properties to animate
|
||||
|
||||
The transition properties can be defined for each state. For example,
|
||||
setting a 500 ms transition time in the default state means that when
|
||||
the Widget goes to the default state a 500 ms transition time is
|
||||
applied. Setting a 100 ms transition time in the pressed state causes a
|
||||
100 ms transition when going to the pressed state. This example
|
||||
configuration results in going to the pressed state quickly and then
|
||||
going back to default slowly.
|
||||
|
||||
To describe a transition an :cpp:struct:`lv_transition_dsc_t` variable needs to be
|
||||
initialized and added to a style:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Only its pointer is saved so must static, global or dynamically allocated */
|
||||
static const lv_style_prop_t trans_props[] = {
|
||||
LV_STYLE_BG_OPA, LV_STYLE_BG_COLOR,
|
||||
0, /* End marker */
|
||||
};
|
||||
|
||||
static lv_style_transition_dsc_t trans1;
|
||||
lv_style_transition_dsc_init(&trans1, trans_props, lv_anim_path_ease_out, duration_ms, delay_ms);
|
||||
|
||||
lv_style_set_transition(&style1, &trans1);
|
||||
|
||||
.. _styles_opacity_blend_modes_transformations:
|
||||
|
||||
Opacity, Blend modes and Transformations
|
||||
****************************************
|
||||
|
||||
If the ``opa``, ``blend_mode``, ``transform_angle``, or
|
||||
``transform_zoom`` properties are set to their non-default value LVGL
|
||||
creates a snapshot about the widget and all its children in order to
|
||||
blend the whole widget with the set opacity, blend mode and
|
||||
transformation properties.
|
||||
|
||||
These properties have this effect only on the ``MAIN`` part of the
|
||||
widget.
|
||||
|
||||
The created snapshot is called "intermediate layer" or simply "layer".
|
||||
If only ``opa`` and/or ``blend_mode`` is set to a non-default value LVGL
|
||||
can build the layer from smaller chunks. The size of these chunks can be
|
||||
configured by the following properties in ``lv_conf.h``:
|
||||
|
||||
- :cpp:enumerator:`LV_LAYER_SIMPLE_BUF_SIZE`: [bytes] the optimal target buffer size. LVGL will try to allocate this size of memory.
|
||||
- :cpp:enumerator:`LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE`: [bytes] used if :cpp:enumerator:`LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
|
||||
|
||||
If transformation properties were also used the layer cannot be
|
||||
rendered in chunks, but one larger memory needs to be allocated. The
|
||||
required memory depends on the angle, zoom and pivot parameters, and the
|
||||
size of the area to redraw, but it's never larger than the size of the
|
||||
widget (including the extra draw size used for shadow, outline, etc).
|
||||
|
||||
If the widget can fully cover the area to redraw, LVGL creates an RGB
|
||||
layer (which is faster to render and uses less memory). If the opposite
|
||||
case ARGB rendering needs to be used. A widget might not cover its area
|
||||
if it has radius, ``bg_opa != 255``, has shadow, outline, etc.
|
||||
|
||||
The click area of the widget is also transformed accordingly.
|
||||
|
||||
.. _styles_color_filter:
|
||||
|
||||
Color filter
|
||||
************
|
||||
|
||||
TODO
|
||||
|
||||
.. _styles_themes:
|
||||
|
||||
Themes
|
||||
******
|
||||
|
||||
Themes are a collection of styles. If there is an active theme LVGL
|
||||
applies it on every created widget. This will give a default appearance
|
||||
to the UI which can then be modified by adding further styles.
|
||||
|
||||
Every display can have a different theme. For example, you could have a
|
||||
colorful theme on a TFT and monochrome theme on a secondary monochrome
|
||||
display.
|
||||
|
||||
To set a theme for a display, two steps are required:
|
||||
|
||||
1. Initialize a theme
|
||||
2. Assign the initialized theme to a display.
|
||||
|
||||
Theme initialization functions can have different prototypes. This
|
||||
example shows how to set the "default" theme:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_theme_t * th = lv_theme_default_init(display, /* Use the DPI, size, etc from this display */
|
||||
LV_COLOR_PALETTE_BLUE, LV_COLOR_PALETTE_CYAN, /* Primary and secondary palette */
|
||||
false, /* Light or dark mode */
|
||||
&lv_font_montserrat_10, &lv_font_montserrat_14, &lv_font_montserrat_18); /* Small, normal, large fonts */
|
||||
|
||||
lv_display_set_theme(display, th); /* Assign the theme to the display */
|
||||
|
||||
The included themes are enabled in ``lv_conf.h``. If the default theme
|
||||
is enabled by :c:macro:`LV_USE_THEME_DEFAULT` LVGL automatically initializes
|
||||
and sets it when a display is created.
|
||||
|
||||
Extending themes
|
||||
----------------
|
||||
|
||||
Built-in themes can be extended. If a custom theme is created, a parent
|
||||
theme can be selected. The parent theme's styles will be added before
|
||||
the custom theme's styles. Any number of themes can be chained this way.
|
||||
E.g. default theme -> custom theme -> dark theme.
|
||||
|
||||
:cpp:expr:`lv_theme_set_parent(new_theme, base_theme)` extends the
|
||||
``base_theme`` with the ``new_theme``.
|
||||
|
||||
There is an example for it below.
|
||||
|
||||
.. _styles_example:
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
.. include:: ../../../examples/styles/index.rst
|
||||
|
||||
.. _styles_api:
|
||||
|
||||
API
|
||||
***
|
||||
75
docs/details/debugging/gdb_plugin.rst
Normal file
75
docs/details/debugging/gdb_plugin.rst
Normal file
@@ -0,0 +1,75 @@
|
||||
.. _gdb_plugin:
|
||||
|
||||
===========
|
||||
GDB Plug-In
|
||||
===========
|
||||
|
||||
Debugging LVGL with GDB
|
||||
-----------------------
|
||||
|
||||
To facilitate debugging LVGL with GDB, a GDB plugin is provided. This plugin
|
||||
can be found in the ``lvgl/scripts/gdb`` directory. The GDB plugin can be used
|
||||
with any target where GDB is available. For example, you can use it to debug a
|
||||
device connected to a PC via JLink, which provides a GDB server. Additionally,
|
||||
if your device crashes and you have a core dump, you can use GDB to analyze the
|
||||
core dump. To load the LVGL GDB plugin within GDB's command line, type the
|
||||
following command:
|
||||
|
||||
``source lvgl/scripts/gdb/gdbinit.py``
|
||||
|
||||
|
||||
Example of usage:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
(gdb) source lvgl/scripts/gdb/gdbinit.py
|
||||
|
||||
(gdb) dump obj -L 2
|
||||
obj@0x60700000dd10 (0,0,799,599)
|
||||
tabview@0x608000204ca0 (0,0,799,599)
|
||||
obj@0x607000025da0 (0,0,799,69)
|
||||
obj@0x607000025e80 (0,70,799,599)
|
||||
obj@0x60700002bd70 (743,543,791,591)
|
||||
btn@0x60700002c7f0 (747,547,787,587)
|
||||
keyboard@0x60d0000f7040 (0,300,799,599)
|
||||
dropdown-list@0x608000205420 (0,0,129,129)
|
||||
label@0x60d0000f7ba0 (22,22,56,39)
|
||||
(gdb)
|
||||
|
||||
The plugin provides the following commands.
|
||||
|
||||
- ``dump obj``: Dump the object tree.
|
||||
- ``info style``: Show the object's style.
|
||||
|
||||
|
||||
Dump obj tree
|
||||
-------------
|
||||
|
||||
``dump obj``: Dump the object tree.
|
||||
|
||||
``dump obj -L 2``: Dump the object tree with a depth of 2.
|
||||
|
||||
``dump obj -a 0x60700000dd10``: Dump the object tree starting from the specified address.
|
||||
|
||||
|
||||
Show obj's style
|
||||
----------------
|
||||
|
||||
This command can dump the object's local style, since style value is a union, it's displayed in all possible formats.
|
||||
|
||||
``info style address_of_obj``: Show the object's style.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
(gdb) info style 0x60700000dd10
|
||||
32 = {num = 90, ptr = 0x5a, color = {blue = 90 'Z', green = 0 '\000', red = 0 '\000'}}
|
||||
158 = {num = 32767, ptr = 0x7fff, color = {blue = 255 '\377', green = 127 '\177', red = 0 '\000'}}
|
||||
(gdb) p lv_global->disp_default->act_scr
|
||||
$4 = (lv_obj_t *) 0x60700000dd10
|
||||
(gdb) info style $4
|
||||
32 = {num = 90, ptr = 0x5a, color = {blue = 90 'Z', green = 0 '\000', red = 0 '\000'}}
|
||||
158 = {num = 32767, ptr = 0x7fff, color = {blue = 255 '\377', green = 127 '\177', red = 0 '\000'}}
|
||||
(gdb)
|
||||
13
docs/details/debugging/index.rst
Normal file
13
docs/details/debugging/index.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
.. _debugging:
|
||||
|
||||
=========
|
||||
Debugging
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
gdb_plugin
|
||||
log
|
||||
profiler
|
||||
vg_lite_tvg
|
||||
71
docs/details/debugging/log.rst
Normal file
71
docs/details/debugging/log.rst
Normal file
@@ -0,0 +1,71 @@
|
||||
.. _logging:
|
||||
|
||||
=======
|
||||
Logging
|
||||
=======
|
||||
|
||||
LVGL has a built-in *Log* module to inform the user about what is
|
||||
happening in the library.
|
||||
|
||||
Log level
|
||||
*********
|
||||
|
||||
To enable logging, set :c:macro:`LV_USE_LOG` in ``lv_conf.h`` and set
|
||||
:c:macro:`LV_LOG_LEVEL` to one of the following values:
|
||||
|
||||
- :c:macro:`LV_LOG_LEVEL_TRACE`: A lot of logs to give detailed information
|
||||
- :c:macro:`LV_LOG_LEVEL_INFO`: Log important events
|
||||
- :c:macro:`LV_LOG_LEVEL_WARN`: Log if something unwanted happened but didn't cause a problem
|
||||
- :c:macro:`LV_LOG_LEVEL_ERROR`: Only critical issues, where the system may fail
|
||||
- :c:macro:`LV_LOG_LEVEL_USER`: Only user messages
|
||||
- :c:macro:`LV_LOG_LEVEL_NONE`: Do not log anything
|
||||
|
||||
The events which have a higher level than the set log level will be logged
|
||||
as well. E.g. if you :c:macro:`LV_LOG_LEVEL_WARN`, errors will be also logged.
|
||||
|
||||
|
||||
Printing logs
|
||||
*************
|
||||
|
||||
Logging with printf
|
||||
-------------------
|
||||
|
||||
If your system supports ``printf``, you just need to enable
|
||||
:c:macro:`LV_LOG_PRINTF` in ``lv_conf.h`` to send the logs with ``printf``.
|
||||
|
||||
Custom log function
|
||||
-------------------
|
||||
|
||||
If you can't use ``printf`` or want to use a custom function to log, you
|
||||
can register a "logger" callback with :cpp:func:`lv_log_register_print_cb`.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void my_log_cb(lv_log_level_t level, const char * buf)
|
||||
{
|
||||
serial_send(buf, strlen(buf));
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
|
||||
lv_log_register_print_cb(my_log_cb);
|
||||
|
||||
Add logs
|
||||
********
|
||||
|
||||
You can also use the log module via the
|
||||
``LV_LOG_TRACE/INFO/WARN/ERROR/USER(text)`` or ``LV_LOG(text)``
|
||||
functions. Here:
|
||||
|
||||
- ``LV_LOG_TRACE/INFO/WARN/ERROR/USER(text)`` append following information to your ``text``
|
||||
- Log Level
|
||||
- \__FILE\_\_
|
||||
- \__LINE\_\_
|
||||
- \__func\_\_
|
||||
- ``LV_LOG(text)`` is similar to ``LV_LOG_USER`` but has no extra information attached.
|
||||
|
||||
API
|
||||
***
|
||||
243
docs/details/debugging/profiler.rst
Normal file
243
docs/details/debugging/profiler.rst
Normal file
@@ -0,0 +1,243 @@
|
||||
.. _profiler:
|
||||
|
||||
========
|
||||
Profiler
|
||||
========
|
||||
|
||||
As the complexity of the application increases, performance issues such as low FPS and frequent cache misses
|
||||
causing lag may arise. LVGL has internally set up some hooks for performance measurement to help developers
|
||||
analyze and locate performance issues.
|
||||
|
||||
.. _profiler_introduction:
|
||||
|
||||
Introduction
|
||||
************
|
||||
|
||||
LVGL has a built-in trace system to track and record the timestamps of important events that occur during runtime,
|
||||
such as rendering events and user input events. These event timestamps serve as important metrics for performance analysis.
|
||||
|
||||
The trace system has a configurable record buffer that stores the names of event functions and their timestamps.
|
||||
When the buffer is full, the trace system prints the log information through the provided user interface.
|
||||
|
||||
The output trace logs are formatted according to Android's `systrace <https://developer.android.com/topic/performance/tracing>`_
|
||||
format and can be visualized using `Perfetto <https://ui.perfetto.dev>`_.
|
||||
|
||||
.. _profiler_usage:
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
Configure profiler
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To enable the profiler, set :c:macro:`LV_USE_PROFILER` in ``lv_conf.h`` and configure the following options:
|
||||
|
||||
1. Enable the built-in profiler functionality by setting :c:macro:`LV_USE_PROFILER_BUILTIN`.
|
||||
|
||||
2. Buffer configuration: Set the value of :c:macro:`LV_PROFILER_BUILTIN_BUF_SIZE` to configure the buffer size. A larger buffer can store more trace event information, reducing interference with rendering. However, it also results in higher memory consumption.
|
||||
|
||||
3. Timestamp configuration: LVGL uses the :cpp:func:`lv_tick_get` function with a precision of 1ms by default to obtain timestamps when events occur. Therefore, it cannot accurately measure intervals below 1ms. If your system environment can provide higher precision (e.g., 1us), you can configure the profiler as follows:
|
||||
|
||||
- Recommended configuration in **UNIX** environments:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
static uint32_t my_get_tick_us_cb(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
static int my_get_tid_cb(void)
|
||||
{
|
||||
return (int)syscall(SYS_gettid);
|
||||
}
|
||||
|
||||
static int my_get_cpu_cb(void)
|
||||
{
|
||||
int cpu_id = 0;
|
||||
syscall(SYS_getcpu, &cpu_id, NULL);
|
||||
return cpu_id;
|
||||
}
|
||||
|
||||
void my_profiler_init(void)
|
||||
{
|
||||
lv_profiler_builtin_config_t config;
|
||||
lv_profiler_builtin_config_init(&config);
|
||||
config.tick_per_sec = 1000000; /* One second is equal to 1000000 microseconds */
|
||||
config.tick_get_cb = my_get_tick_us_cb;
|
||||
config.tid_get_cb = my_get_tid_cb;
|
||||
config.cpu_get_cb = my_get_cpu_cb;
|
||||
lv_profiler_builtin_init(&config);
|
||||
}
|
||||
|
||||
- Recommended configuration in **Arduino** environments:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void my_profiler_init(void)
|
||||
{
|
||||
lv_profiler_builtin_config_t config;
|
||||
lv_profiler_builtin_config_init(&config);
|
||||
config.tick_per_sec = 1000000; /* One second is equal to 1000000 microseconds */
|
||||
config.tick_get_cb = micros; /* Use the microsecond time stamp provided by Arduino */
|
||||
lv_profiler_builtin_init(&config);
|
||||
}
|
||||
|
||||
4. Log output configuration: LVGL uses the :cpp:func:`LV_LOG` interface by default to output trace information. If you want to use another interface to output log information (e.g., file stream), you can redirect the log output using the following code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void my_log_print_cb(const char * buf)
|
||||
{
|
||||
printf("%s", buf);
|
||||
}
|
||||
|
||||
void my_profiler_init(void)
|
||||
{
|
||||
lv_profiler_builtin_config_t config;
|
||||
lv_profiler_builtin_config_init(&config);
|
||||
... /* other configurations */
|
||||
config.flush_cb = my_log_print_cb;
|
||||
lv_profiler_builtin_init(&config);
|
||||
}
|
||||
|
||||
Run the test scenario
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Run the UI scenario that you want to measure, such as scrolling a scrollable page up and down or entering/exiting an application.
|
||||
|
||||
Process the logs
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Save the output log as `my_trace.txt`, use `trace_filter.py` for filtering and preprocessing:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./lvgl/scripts/trace_filter.py my_trace.txt
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python3 ./lvgl/scripts/trace_filter.py my_trace.txt
|
||||
|
||||
You will obtain a processed text file named `trace.systrace`, which roughly contains the following content:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
# tracer: nop
|
||||
#
|
||||
LVGL-1 [0] 2892.002993: tracing_mark_write: B|1|lv_timer_handler
|
||||
LVGL-1 [0] 2892.002993: tracing_mark_write: B|1|_lv_display_refr_timer
|
||||
LVGL-1 [0] 2892.003459: tracing_mark_write: B|1|refr_invalid_areas
|
||||
LVGL-1 [0] 2892.003461: tracing_mark_write: B|1|lv_draw_rect
|
||||
LVGL-1 [0] 2892.003550: tracing_mark_write: E|1|lv_draw_rect
|
||||
LVGL-1 [0] 2892.003552: tracing_mark_write: B|1|lv_draw_rect
|
||||
LVGL-1 [0] 2892.003556: tracing_mark_write: E|1|lv_draw_rect
|
||||
LVGL-1 [0] 2892.003560: tracing_mark_write: B|1|lv_draw_rect
|
||||
LVGL-1 [0] 2892.003573: tracing_mark_write: E|1|lv_draw_rect
|
||||
...
|
||||
|
||||
Import the processed `trace.systrace` file into `Perfetto <https://ui.perfetto.dev>`_ and wait for it to be parsed.
|
||||
|
||||
Performance analysis
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the log parsing is successful, you will see the following screen:
|
||||
|
||||
.. image:: /misc/perfetto_ui.png
|
||||
|
||||
In the Perfetto UI, use the :kbd:`A` or :kbd:`D` keys to pan the timeline horizontally
|
||||
and the :kbd:`W` or :kbd:`S` keys to zoom in or out on the timeline.
|
||||
Use the mouse to move the focus and click on functions on the timeline to observe their execution time.
|
||||
|
||||
Add Measurement Point
|
||||
*********************
|
||||
|
||||
Users can add their own measured functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void my_function_1(void)
|
||||
{
|
||||
LV_PROFILER_BEGIN;
|
||||
do_something();
|
||||
LV_PROFILER_END;
|
||||
}
|
||||
|
||||
void my_function_2(void)
|
||||
{
|
||||
LV_PROFILER_BEGIN_TAG("do_something_1");
|
||||
do_something_1();
|
||||
LV_PROFILER_END_TAG("do_something_1");
|
||||
|
||||
LV_PROFILER_BEGIN_TAG("do_something_2");
|
||||
do_something_2();
|
||||
LV_PROFILER_END_TAG("do_something_2");
|
||||
}
|
||||
|
||||
.. _profiler_custom_implementation:
|
||||
|
||||
Custom profiler implementation
|
||||
******************************
|
||||
|
||||
If you wish to use a profiler method provided by your operating system, you can modify the following configurations in ``lv_conf.h``:
|
||||
|
||||
- :c:macro:`LV_PROFILER_INCLUDE`: Provides a header file for the profiler function.
|
||||
- :c:macro:`LV_PROFILER_BEGIN`: Profiler start point function.
|
||||
- :c:macro:`LV_PROFILER_END`: Profiler end point function.
|
||||
- :c:macro:`LV_PROFILER_BEGIN_TAG`: Profiler start point function with custom tag.
|
||||
- :c:macro:`LV_PROFILER_END_TAG`: Profiler end point function with custom tag.
|
||||
|
||||
|
||||
Taking `NuttX <https://github.com/apache/nuttx>`_ RTOS as an example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_PROFILER_INCLUDE "nuttx/sched_note.h"
|
||||
#define LV_PROFILER_BEGIN sched_note_begin(NOTE_TAG_ALWAYS)
|
||||
#define LV_PROFILER_END sched_note_end(NOTE_TAG_ALWAYS)
|
||||
#define LV_PROFILER_BEGIN_TAG(str) sched_note_beginex(NOTE_TAG_ALWAYS, str)
|
||||
#define LV_PROFILER_END_TAG(str) sched_note_endex(NOTE_TAG_ALWAYS, str)
|
||||
|
||||
.. _profiler_faq:
|
||||
|
||||
FAQ
|
||||
***
|
||||
|
||||
Perfetto log parsing fails
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Please check the completeness of the logs. If the logs are incomplete, it may be due to the following reasons:
|
||||
|
||||
1. Serial port reception errors caused by a high baud rate. You need to reduce the baud rate.
|
||||
2. Data corruption caused by other thread logs inserted during the printing of trace logs. You need to disable the log output of other threads or refer to the configuration above to use a separate log output interface.
|
||||
3. Make sure that the string passed in by :c:macro:`LV_PROFILER_BEGIN_TAG` or :c:macro:`LV_PROFILER_END_TAG` is not a local variable on the stack or a string in shared memory, because currently only the string address is recorded and the content is not copied.
|
||||
|
||||
Function execution time displayed as 0s in Perfetto
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the function execution time is lower than the precision of the timestamps, this situation can occur. You can refer to the configuration instructions above to use a higher precision timestamp.
|
||||
|
||||
Significant stuttering occurs during profiling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When the buffer used to store trace events becomes full, the profiler will output all the data in the buffer, which can cause UI blocking and stuttering during the output. You can optimize this by taking the following measures:
|
||||
|
||||
1. Increase the value of :c:macro:`LV_PROFILER_BUILTIN_BUF_SIZE`. A larger buffer can reduce the frequency of log printing, but it also consumes more memory.
|
||||
2. Optimize the execution time of log printing functions, such as increasing the serial port baud rate or improving file writing speed.
|
||||
|
||||
Trace logs are not being output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the trace logs are not automatically printed when the buffer is not full, you can try the following methods to force the log output:
|
||||
|
||||
1. Reduce the value of :c:macro:`LV_PROFILER_BUILTIN_BUF_SIZE` to fill the buffer more quickly and trigger automatic printing.
|
||||
2. Manually call or use a timer to call the :cpp:func:`lv_profiler_builtin_flush` function to force the log output.
|
||||
|
||||
27
docs/details/debugging/vg_lite_tvg.rst
Normal file
27
docs/details/debugging/vg_lite_tvg.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
.. _vg_lite_tvg:
|
||||
|
||||
=================
|
||||
VG-Lite Simulator
|
||||
=================
|
||||
|
||||
LVGL integrates a VG-Lite simulator based on ThorVG.
|
||||
Its purpose is to simplify the debugging of VG-Lite adaptation and reduce the time of debugging and locating problems on hardware devices.
|
||||
|
||||
It has been integrated into the CI automated compilation and testing process to ensure that the VG-Lite rendering backend can be fully tested after each PR modification.
|
||||
|
||||
How It Works
|
||||
************
|
||||
|
||||
Sort out the APIs in the ``vg_lite.h`` header file provided by the vendor, re-implement the APIs using `ThorVG <https://github.com/thorvg/thorvg>`_,
|
||||
and simulate the same rendering images as the real hardware on the simulator.
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|
||||
1. Enable VG-Lite rendering backend, see :ref:`vglite`.
|
||||
|
||||
2. Enable ThorVG and turn on the configuration :c:macro:`LV_USE_THORVG_INTERNAL` or :c:macro:`LV_USE_THORVG_EXTERNAL`.
|
||||
It is recommended to use the internal ThorVG library to ensure uniform rendering results.
|
||||
|
||||
3. Enable :c:macro:`LV_USE_VG_LITE_THORVG` and set :c:macro:`LV_DRAW_BUF_ALIGN` to 64. The rest of the options can remain default.
|
||||
Make sure :c:macro:`LV_VG_LITE_USE_GPU_INIT` is enabled, because the thorvg drawing context needs to be initialized before it can be used.
|
||||
17
docs/details/index.rst
Normal file
17
docs/details/index.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
.. _reference:
|
||||
|
||||
=========
|
||||
Reference
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
base-widget/index
|
||||
widgets/index
|
||||
main-components/index
|
||||
other-components/index
|
||||
../examples
|
||||
debugging/index
|
||||
integration/index
|
||||
libs/index
|
||||
501
docs/details/integration/bindings/api_json.rst
Normal file
501
docs/details/integration/bindings/api_json.rst
Normal file
@@ -0,0 +1,501 @@
|
||||
Output API as JSON data
|
||||
=======================
|
||||
|
||||
We have written a script that will read the header files in LVGL and outputs a more friendly JSON format for the API.
|
||||
This is done so that bindings that generate code automatically will have an easy way to collect the needed information
|
||||
without having to reinvent the wheel. The JSON data format has already made libraries for reading the format for just
|
||||
about every programming language out there.
|
||||
|
||||
The script in order to run does have some requirements.
|
||||
|
||||
- Python >= 3.10
|
||||
- Pycparser >= 2.21: Python Library for reading the preprocessor ouotput from the C compiler
|
||||
- PyMSVC >= 0.4.0: Python library is using MSVC Compiler
|
||||
- C compiler, gcc for Linux, clang for OSX and MSVC for Windows
|
||||
- Doxygen: used to read the docstrings from the header files.
|
||||
|
||||
|
||||
There are several options when running the script. They are as follows
|
||||
|
||||
- `--output-path`: output directory for JSON file. If one is not supplied then it will be output stdout
|
||||
- `--lvgl-config`: path to lv_conf.h (including file name), if this is not set then a config file will be
|
||||
generated that has most common things turned on
|
||||
- `--develop`: leaves the temporary folder in place.
|
||||
|
||||
|
||||
to use the script
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python /scripts/gen_json/gen_json.py --output-path=json/output/directory --lvgl-config=path/to/lv_conf.h
|
||||
|
||||
|
||||
or if you want to run a subprocess from inside of a generation script and read the output from stdout
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python /scripts/gen_json/gen_json.py --lvgl-config=path/to/lv_conf.h
|
||||
|
||||
|
||||
The JSON data is broken apart into a couple of main categories.
|
||||
|
||||
- enums
|
||||
- functions
|
||||
- function_pointers
|
||||
- structures
|
||||
- unions
|
||||
- variables
|
||||
- typedefs
|
||||
- forward_decls
|
||||
- macros
|
||||
|
||||
Those categories are the element names undert the root of the JSON data.
|
||||
The value for each categry is an array of JSON elements. There is a bit of
|
||||
nesting with the elements in the arrays and I have created "json_types" that
|
||||
will allow you to identify exactly what you are dealing with.
|
||||
|
||||
The different "json_types" are as follows:
|
||||
|
||||
- ``"array"``: The array type is used to identify arrays.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"dim"``: number of items in the array
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
- ``"type"``: This may or may not be available.
|
||||
- ``"name"``: the name of the data type
|
||||
|
||||
|
||||
- ``"field"``: This type is used to describe fields in structures and unions.
|
||||
It is used in the ``"fields"`` array of the ``"struct"`` and ``"union"`` JSON types.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the field.
|
||||
- ``"type"``: This contains the type information for the field. Check the
|
||||
``"json_type"`` to know what type you are dealing with.
|
||||
- ``"bitsize"``: The number of bits the field has or ``null``
|
||||
if there is no bit size defined
|
||||
- ``"docstring"``: you should know what this is.
|
||||
|
||||
|
||||
- ``"arg"``: Used to describe an argument/parameter in a function or a function pointer.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the argument/parameter.
|
||||
- ``"type"``: This contains the type information for the field. Check the
|
||||
``"json_type"`` to know what type you are dealing with.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
|
||||
|
||||
- ``"forward_decl"``: Describes a forward declaration.There are structures in
|
||||
LVGL that are considered to be private and that is what these desccribe.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the formard declaration.
|
||||
- ``"type"``: This contains the type information for the field. Check the
|
||||
``"json_type"`` to know what type you are dealing with.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
|
||||
|
||||
- ``"function_pointer"``: Describes a function pointer. These are used when
|
||||
registering callback functions in LVGL.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the function pointer.
|
||||
- ``"type"``: This contains the return type information for the function pointer.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"args"``: array of ``"arg"`` Widgets. This describes the fuction arguments/parameters.
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
|
||||
|
||||
- ``"variable"``: Describes a global variable.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the variable.
|
||||
- ``"type"``: This contains the type information for the field. Check the
|
||||
``"json_type"`` to know what type you are dealing with.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
- ``"storage"``: array of storage classifiers, IE "extern"
|
||||
|
||||
|
||||
- ``"special_type"``: Currently only used to describe an ellipsis argument
|
||||
for a function.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: will always be "ellipsis".
|
||||
|
||||
|
||||
- ``"primitive_type"``: This is a base type. There or no other types beneith this.
|
||||
This tells you that the type is a basic or primitive C type.
|
||||
IE: struct, union, int, unsigned int, etc...
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the primitive type.
|
||||
|
||||
|
||||
- ``"enum"``: Describes a grouping of enumeration items/members.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the enumeration group/type.
|
||||
- ``"type"``: This contains the type information for the enumeration group.
|
||||
This is always going to be an "int" type. Make sure you do not use this
|
||||
type as the type for the members of this enumeration group. Check the
|
||||
enumeration members type to get the correct type.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"members"``: array of ``"enum_member"`` Widgets
|
||||
|
||||
|
||||
- ``"enum_member"``: Describes an enumeration item/member. Only found under
|
||||
the ``"members"`` field of an ``"enum"`` JSON type
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the enumeration.
|
||||
- ``"type"``: This contains the type information for the enum member.
|
||||
This gets a bit tricky because the type specified in here is not always
|
||||
going to be an "int". It will usually point to an lvgl type and the type
|
||||
of the lvgl type can be found in the ``"typedefs"`` section.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"value"``: the enumeration member/item's value
|
||||
|
||||
|
||||
- ``"lvgl_type"``: This is a base type. There or no other types beneith this.
|
||||
This tells you that the type is an LVGL data type.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the type.
|
||||
- ``"quals"``: array of qualifiers, IE "const
|
||||
|
||||
|
||||
- ``"struct"``: Describes a structure
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the structure.
|
||||
- ``"type"``: This contains the primitive type information for the structure.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"fields"``: array of ``"field"`` elements.
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
|
||||
|
||||
- ``"union"``: Describes a union
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the union.
|
||||
- ``"type"``: This contains the primitive type information for the union.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"fields"``: array of ``"field"`` elements.
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
|
||||
|
||||
- ``"macro"``: describes a macro. There is limited information that can be
|
||||
collected about macros and in most cases a binding will need to have these
|
||||
statically added to a binding. It is more for collecting the docstrings than
|
||||
anything else.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the macro.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
|
||||
|
||||
- ``"ret_type"``: return type from a function. This is only going to be seen in the ``"type"``
|
||||
element of a ``"function"`` type.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"type"``: This contains the type information for the field. Check the
|
||||
``"json_type"`` to know what type you are dealing with.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
|
||||
|
||||
- ``"function"``: Describes a function.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the function.
|
||||
- ``"type"``: This contains the type information for the return value.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"args"``: array of ``"arg"`` json types. This describes the fuction arguments/parameters.
|
||||
|
||||
|
||||
- ``"stdlib_type"``: This is a base type, meaning that there are no more
|
||||
type levels beneith this. This tells us that the type is from the C stdlib.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the type.
|
||||
- ``"quals"``: array of qualifiers, IE "const
|
||||
|
||||
|
||||
- ``"unknown_type"``: This should not be seen. If it is then there needs to be
|
||||
an adjustment made to the script. Please open an issue and let us know if you see this type.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the type.
|
||||
- ``"quals"``: array of qualifiers, IE "const
|
||||
|
||||
|
||||
- ``"pointer"``: This is a wrapper object to let you know that the type you
|
||||
are dealing with is a pointer
|
||||
|
||||
Available JSON fields:
|
||||
- ``"type"``: This contains the type information for the pointer. Check the
|
||||
``"json_type"`` to know what type you are dealing with.
|
||||
- ``"quals"``: array of qualifiers, IE "const", may or may not be available.
|
||||
|
||||
|
||||
- ``"typedef"``: type definitions. I will explain more on this below.
|
||||
|
||||
Available JSON fields:
|
||||
- ``"name"``: The name of the typedef.
|
||||
- ``"type"``: This contains the type information for the field. Check the
|
||||
``"json_type"`` to know what type you are dealing with.
|
||||
- ``"docstring"``: you should know what this is.
|
||||
- ``"quals"``: array of qualifiers, IE "const"
|
||||
|
||||
|
||||
|
||||
Here is an example of what the output will look like.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"enums":[
|
||||
{
|
||||
"name":"_lv_result_t",
|
||||
"type":{
|
||||
"name":"int",
|
||||
"json_type":"primitive_type"
|
||||
},
|
||||
"json_type":"enum",
|
||||
"docstring":"LVGL error codes. ",
|
||||
"members":[
|
||||
{
|
||||
"name":"LV_RESULT_INVALID",
|
||||
"type":{
|
||||
"name":"_lv_result_t",
|
||||
"json_type":"lvgl_type"
|
||||
},
|
||||
"json_type":"enum_member",
|
||||
"docstring":"",
|
||||
"value":"0x0"
|
||||
},
|
||||
{
|
||||
"name":"LV_RESULT_OK",
|
||||
"type":{
|
||||
"name":"_lv_result_t",
|
||||
"json_type":"lvgl_type"
|
||||
},
|
||||
"json_type":"enum_member",
|
||||
"docstring":"",
|
||||
"value":"0x1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"functions":[
|
||||
{
|
||||
"name":"lv_version_info",
|
||||
"type":{
|
||||
"type":{
|
||||
"type":{
|
||||
"name":"char",
|
||||
"json_type":"primitive_type",
|
||||
"quals":[
|
||||
"const"
|
||||
]
|
||||
},
|
||||
"json_type":"pointer",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"ret_type",
|
||||
"docstring":""
|
||||
},
|
||||
"json_type":"function",
|
||||
"docstring":"",
|
||||
"args":[
|
||||
{
|
||||
"name":null,
|
||||
"type":{
|
||||
"name":"void",
|
||||
"json_type":"primitive_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"arg",
|
||||
"docstring":"",
|
||||
"quals":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"function_pointers":[
|
||||
{
|
||||
"name":"lv_tlsf_walker",
|
||||
"type":{
|
||||
"type":{
|
||||
"name":"void",
|
||||
"json_type":"primitive_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"ret_type",
|
||||
"docstring":""
|
||||
},
|
||||
"json_type":"function_pointer",
|
||||
"docstring":"",
|
||||
"args":[
|
||||
{
|
||||
"name":"ptr",
|
||||
"type":{
|
||||
"type":{
|
||||
"name":"void",
|
||||
"json_type":"primitive_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"pointer",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"arg",
|
||||
"docstring":""
|
||||
},
|
||||
{
|
||||
"name":"size",
|
||||
"type":{
|
||||
"name":"size_t",
|
||||
"json_type":"stdlib_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"arg",
|
||||
"docstring":""
|
||||
},
|
||||
{
|
||||
"name":"used",
|
||||
"type":{
|
||||
"name":"int",
|
||||
"json_type":"primitive_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"arg",
|
||||
"docstring":""
|
||||
},
|
||||
{
|
||||
"name":"user",
|
||||
"type":{
|
||||
"type":{
|
||||
"name":"void",
|
||||
"json_type":"primitive_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"pointer",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"arg",
|
||||
"docstring":""
|
||||
}
|
||||
],
|
||||
"quals":[]
|
||||
}
|
||||
],
|
||||
"structures":[
|
||||
{
|
||||
"name":"_lv_gradient_cache_t",
|
||||
"type":{
|
||||
"name":"struct",
|
||||
"json_type":"primitive_type"
|
||||
},
|
||||
"json_type":"struct",
|
||||
"docstring":null,
|
||||
"fields":[
|
||||
{
|
||||
"name":"color_map",
|
||||
"type":{
|
||||
"type":{
|
||||
"name":"lv_color_t",
|
||||
"json_type":"lvgl_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"pointer",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"field",
|
||||
"bitsize":null,
|
||||
"docstring":""
|
||||
},
|
||||
{
|
||||
"name":"opa_map",
|
||||
"type":{
|
||||
"type":{
|
||||
"name":"lv_opa_t",
|
||||
"json_type":"lvgl_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"pointer",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"field",
|
||||
"bitsize":null,
|
||||
"docstring":""
|
||||
},
|
||||
{
|
||||
"name":"size",
|
||||
"type":{
|
||||
"name":"uint32_t",
|
||||
"json_type":"stdlib_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"field",
|
||||
"bitsize":null,
|
||||
"docstring":""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"unions":[],
|
||||
"variables":[
|
||||
{
|
||||
"name":"lv_global",
|
||||
"type":{
|
||||
"name":"lv_global_t",
|
||||
"json_type":"lvgl_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"variable",
|
||||
"docstring":"",
|
||||
"quals":[],
|
||||
"storage":[
|
||||
"extern"
|
||||
]
|
||||
}
|
||||
],
|
||||
"typedefs":[
|
||||
{
|
||||
"name":"lv_pool_t",
|
||||
"type":{
|
||||
"type":{
|
||||
"name":"void",
|
||||
"json_type":"primitive_type",
|
||||
"quals":[]
|
||||
},
|
||||
"json_type":"pointer"
|
||||
},
|
||||
"json_type":"typedef",
|
||||
"docstring":"",
|
||||
"quals":[]
|
||||
}
|
||||
],
|
||||
"forward_decls":[
|
||||
{
|
||||
"name":"lv_fragment_managed_states_t",
|
||||
"type":{
|
||||
"name":"struct",
|
||||
"json_type":"primitive_type"
|
||||
},
|
||||
"json_type":"forward_decl",
|
||||
"docstring":"",
|
||||
"quals":[]
|
||||
}
|
||||
],
|
||||
"macros":[
|
||||
{
|
||||
"name":"ZERO_MEM_SENTINEL",
|
||||
"json_type":"macro",
|
||||
"docstring":""
|
||||
}
|
||||
]
|
||||
}
|
||||
5
docs/details/integration/bindings/cpp.rst
Normal file
5
docs/details/integration/bindings/cpp.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
===
|
||||
Cpp
|
||||
===
|
||||
|
||||
In progress: https://github.com/lvgl/lv_binding_cpp
|
||||
13
docs/details/integration/bindings/index.rst
Normal file
13
docs/details/integration/bindings/index.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
========
|
||||
Bindings
|
||||
========
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api_json
|
||||
cpp
|
||||
javascript
|
||||
micropython
|
||||
pikascript
|
||||
136
docs/details/integration/bindings/javascript.rst
Normal file
136
docs/details/integration/bindings/javascript.rst
Normal file
@@ -0,0 +1,136 @@
|
||||
==========
|
||||
JavaScript
|
||||
==========
|
||||
|
||||
With `lv_binding_js <https://github.com/lvgl/lv_binding_js>`__ you can write lvgl with JavaScript.
|
||||
|
||||
It uses React's virtual DOM concept to manipulate lvgl UI components, providing a familiar React-like
|
||||
experience to users.
|
||||
|
||||
**Code**
|
||||
|
||||
**Code Running on Real Device**
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
|
||||
- `Features <#features>`__
|
||||
- `Demo <#demo>`__
|
||||
- `Building <#building>`__
|
||||
- `Components <#components>`__
|
||||
- `Font <#font>`__
|
||||
- `Animation <#animation>`__
|
||||
- `Style <#style>`__
|
||||
- `JSAPI <#jsapi>`__
|
||||
- `Thanks <#thanks>`__
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Support all lvgl built-in components
|
||||
- Fully support lvgl flex and grid style
|
||||
- support most lvgl style, just write like html5 css
|
||||
- support dynamic load image
|
||||
- Fully support lvgl animation
|
||||
|
||||
|
||||
Demo
|
||||
----
|
||||
|
||||
See the `demo <https://github.com/lvgl/lv_binding_js/tree/master/demo>`__ folder
|
||||
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
The following are developer notes on how to build lvgljs on your native platform. They are not complete guides,
|
||||
but include notes on the necessary libraries, compile flags, etc.
|
||||
|
||||
|
||||
lvgljs
|
||||
~~~~~~
|
||||
|
||||
- `ubuntu build Notes for sdl simulator <https://github.com/lvgl/lv_binding_js/blob/master/doc/build/build-ubuntu-arm.md>`__
|
||||
- `macos x86 build Notes for sdl simulator <https://github.com/lvgl/lv_binding_js/blob/master/doc/build/build-macos-x86-simulator.md>`__
|
||||
- `ubuntu build Notes for platform arm <https://github.com/lvgl/lv_binding_js/blob/master/doc/build/build-ubuntu-x86-simulator.md>`__
|
||||
|
||||
|
||||
JS Bundle
|
||||
~~~~~~~~~
|
||||
|
||||
- `JS Bundle build Notes <https://github.com/lvgl/lv_binding_js/blob/master/doc/build/js-bundle.md>`__
|
||||
|
||||
|
||||
Components
|
||||
----------
|
||||
|
||||
- `View <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/View.md>`__
|
||||
- `Image <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Image.md>`__
|
||||
- `Button <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Button.md>`__
|
||||
- `Text <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Text.md>`__
|
||||
- `Input <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Input.md>`__
|
||||
- `Textarea <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Textarea.md>`__
|
||||
- `Switch <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Switch.md>`__
|
||||
- `Checkbox <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Checkbox.md>`__
|
||||
- `Dropdownlist <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Dropdownlist.md>`__
|
||||
- `ProgressBar <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/ProgressBar.md>`__
|
||||
- `Line <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Line.md>`__
|
||||
- `Roller <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Roller.md>`__
|
||||
- `Keyboard <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Keyboard.md>`__
|
||||
- `Calendar <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Calendar.md>`__
|
||||
- `Chart <https://github.com/lvgl/lv_binding_js/blob/master/doc/component/Chart.md>`__
|
||||
|
||||
|
||||
Font
|
||||
----
|
||||
|
||||
- `Builtin-Symbol <https://github.com/lvgl/lv_binding_js/blob/master/doc/Symbol/symbol.md>`__
|
||||
|
||||
|
||||
Animation
|
||||
---------
|
||||
|
||||
- `Animation <https://github.com/lvgl/lv_binding_js/blob/master/doc/animate/animate.md>`__
|
||||
|
||||
|
||||
Style
|
||||
-----
|
||||
|
||||
.. include::https://github.com/lvgl/lv_binding_js/blob/master/doc/style/position-size-layout.md
|
||||
|
||||
- `position-size-layout <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/position-size-layout.md>`__
|
||||
- `boxing-model <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/boxing-model.md>`__
|
||||
- `color <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/color.md>`__
|
||||
- `flex <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/flex.md>`__
|
||||
- `grid <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/grid.md>`__
|
||||
- `font <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/font.md>`__
|
||||
- `opacity <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/opacity.md>`__
|
||||
- `display <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/display.md>`__
|
||||
- `background <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/background.md>`__
|
||||
- `scroll <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/scroll.md>`__
|
||||
- `shadow <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/shadow.md>`__
|
||||
- `recolor <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/recolor.md>`__
|
||||
- `line <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/line.md>`__
|
||||
- `transition <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/transition.md>`__
|
||||
- `transform <https://github.com/lvgl/lv_binding_js/blob/master/doc/style/transform.md>`__
|
||||
|
||||
|
||||
JSAPI
|
||||
-----
|
||||
|
||||
- `network <https://github.com/lvgl/lv_binding_js/blob/master/doc/jsapi/network.md>`__
|
||||
- `filesystem <https://github.com/lvgl/lv_binding_js/blob/master/doc/jsapi/fs.md>`__
|
||||
- `dimension <https://github.com/lvgl/lv_binding_js/blob/master/doc/jsapi/dimension.md>`__
|
||||
|
||||
|
||||
Thanks
|
||||
------
|
||||
|
||||
lvgljs depends on following excellent work
|
||||
|
||||
- `lvgl <https://github.com/lvgl/lvgl>`__: Create beautiful UIs for any MCU, MPU and display type
|
||||
- `QuickJS <https://bellard.org/quickjs/>`__: JavaScript engine
|
||||
- `libuv <https://github.com/libuv/libuv>`__: platform abstraction layer
|
||||
- `curl <https://github.com/curl/curl>`__: HTTP client
|
||||
- `txiki.js <https://github.com/saghul/txiki.js>`__: Tiny JavaScript runtime
|
||||
304
docs/details/integration/bindings/micropython.rst
Normal file
304
docs/details/integration/bindings/micropython.rst
Normal file
@@ -0,0 +1,304 @@
|
||||
.. _micropython:
|
||||
|
||||
===========
|
||||
MicroPython
|
||||
===========
|
||||
|
||||
|
||||
What is MicroPython?
|
||||
--------------------
|
||||
|
||||
`MicroPython <http://micropython.org/>`__ is Python for microcontrollers. Using MicroPython, you can write Python3
|
||||
code and run it even on a bare metal architecture with limited resources.
|
||||
|
||||
|
||||
Highlights of MicroPython
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **Compact**: Fits and runs within just 256k of code space and 16k of RAM. No OS is needed, although you
|
||||
can also run it with an OS, if you want.
|
||||
- **Compatible**: Strives to be as compatible as possible with normal Python (known as CPython).
|
||||
- **Versatile**: Supports many architectures (x86, x86-64, ARM, ARM Thumb, Xtensa).
|
||||
- **Interactive**: No need for the compile-flash-boot cycle. With the REPL (interactive prompt) you can type
|
||||
commands and execute them immediately, run scripts, etc.
|
||||
- **Popular**: Many platforms are supported. The user base is growing bigger. Notable forks:
|
||||
|
||||
- `MicroPython <https://github.com/micropython/micropython>`__
|
||||
- `CircuitPython <https://github.com/adafruit/circuitpython>`__
|
||||
- `MicroPython_ESP32_psRAM_LoBo <https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo>`__
|
||||
|
||||
- **Embedded Oriented**: Comes with modules specifically for embedded systems, such as the
|
||||
`machine module <https://docs.micropython.org/en/latest/library/machine.html#classes>`__
|
||||
for accessing low-level hardware (I/O pins, ADC, UART, SPI, I2C, RTC, Timers etc.)
|
||||
|
||||
|
||||
--------------
|
||||
|
||||
|
||||
Why MicroPython + LVGL?
|
||||
-----------------------
|
||||
|
||||
MicroPython `does not have a good native high-level GUI library <https://forum.micropython.org/viewtopic.php?f=18&t=5543>`__.
|
||||
LVGL is an `Object-Oriented Component Based <https://blog.lvgl.io/2018-12-13/extend-lvgl-objects>`__
|
||||
high-level GUI library, which seems to be a natural candidate to map into a higher level language, such as Python.
|
||||
LVGL is implemented in C and its APIs are in C.
|
||||
|
||||
|
||||
Here are some advantages of using LVGL in MicroPython:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Develop GUI in Python, a very popular high level language. Use paradigms such as Object-Oriented Programming.
|
||||
- Usually, GUI development requires multiple iterations to get things right. With C, each iteration consists of
|
||||
**``Change code`` > ``Build`` > ``Flash`` > ``Run``**. In MicroPython it's just
|
||||
**``Change code`` > ``Run``** ! You can even run commands interactively using the
|
||||
`REPL <https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop>`__ (the interactive prompt)
|
||||
|
||||
|
||||
MicroPython + LVGL could be used for:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Fast prototyping GUI.
|
||||
- Shortening the cycle of changing and fine-tuning the GUI.
|
||||
- Modelling the GUI in a more abstract way by defining reusable composite Widgets, taking advantage of Python's language features
|
||||
such as Inheritance, Closures, List Comprehension, Generators, Exception Handling, Arbitrary Precision Integers and others.
|
||||
- Make LVGL accessible to a larger audience. No need to know C to create a nice GUI on an embedded system. This goes well with
|
||||
`CircuitPython vision <https://learn.adafruit.com/welcome-to-circuitpython/what-is-circuitpython>`__.
|
||||
CircuitPython was designed with education in mind, to make it easier for new or inexperienced users to get started with
|
||||
embedded development.
|
||||
- Creating tools to work with LVGL at a higher level (e.g. drag-and-drop designer).
|
||||
|
||||
|
||||
--------------
|
||||
|
||||
|
||||
So what does it look like?
|
||||
--------------------------
|
||||
|
||||
It's very much like the C API, but Object-Oriented for LVGL components.
|
||||
|
||||
Let's dive right into an example!
|
||||
|
||||
|
||||
A simple example
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. 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)
|
||||
|
||||
|
||||
How can I use it?
|
||||
-----------------
|
||||
|
||||
|
||||
Online Simulator
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
If you want to experiment with LVGL + MicroPython without downloading anything, you can use our online
|
||||
simulator! It's a fully functional LVGL + MicroPython that runs entirely in the browser and allows you to
|
||||
edit a python script and run it.
|
||||
|
||||
`Click here to experiment on the online simulator <https://sim.lvgl.io/>`__
|
||||
|
||||
Many :ref:`LVGL examples <examples>` are available also for MicroPython. Just click the link!
|
||||
|
||||
|
||||
PC Simulator
|
||||
~~~~~~~~~~~~
|
||||
|
||||
MicroPython is ported to many platforms. One notable port is "unix", which allows you to build and run MicroPython
|
||||
(+LVGL) on a Linux machine. (On a Windows machine you might need Virtual Box or WSL or MinGW or Cygwin etc.)
|
||||
|
||||
`Click here to know more information about building and running the unix port <https://github.com/lvgl/lv_micropython>`__
|
||||
|
||||
|
||||
Embedded Platforms
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the end, the goal is to run it all on an embedded platform. Both MicroPython and LVGL can be used on many embedded
|
||||
architectures. `lv_micropython <https://github.com/lvgl/lv_micropython>`__ is a fork of MicroPython+LVGL and currently
|
||||
supports Linux, ESP32, STM32 and RP2. It can be ported to any other platform supported by MicroPython.
|
||||
|
||||
- You would also need display and input drivers. You can either use one of the existing drivers provided with lv_micropython,
|
||||
or you can create your own input/display drivers for your specific hardware.
|
||||
- Drivers can be implemented either in C as a MicroPython module, or in pure Python!
|
||||
|
||||
|
||||
lv_micropython already contains these drivers:
|
||||
|
||||
- Display drivers:
|
||||
|
||||
- SDL on Linux
|
||||
- X11 on Linux
|
||||
- ESP32 specific:
|
||||
|
||||
- ILI9341
|
||||
- ILI9488
|
||||
- GC9A01
|
||||
- ST7789
|
||||
- ST7735
|
||||
|
||||
- Generic (pure Python):
|
||||
|
||||
- ILI9341
|
||||
- ST7789
|
||||
- ST7735
|
||||
|
||||
- Input drivers:
|
||||
|
||||
- SDL
|
||||
- X11
|
||||
- XPT2046
|
||||
- FT6X36
|
||||
- ESP32 ADC with resistive touch
|
||||
|
||||
|
||||
Where can I find more information?
|
||||
----------------------------------
|
||||
|
||||
- ``lv_micropython`` `README <https://github.com/lvgl/lv_micropython>`__
|
||||
- ``lv_binding_micropython`` `README <https://github.com/lvgl/lv_binding_micropython>`__
|
||||
- The `LVGL micropython forum <https://forum.lvgl.io/c/micropython>`__ (Feel free to ask anything!)
|
||||
- At MicroPython: `docs <http://docs.micropython.org/en/latest/>`__ and `forum <https://forum.micropython.org/>`__
|
||||
- `Blog Post <https://blog.lvgl.io/2019-02-20/micropython-bindings>`__, a little outdated.
|
||||
|
||||
|
||||
The MicroPython Binding is auto generated!
|
||||
------------------------------------------
|
||||
|
||||
- LVGL is a git submodule inside `lv_micropython <https://github.com/lvgl/lv_micropython>`__
|
||||
(LVGL is a git submodule of `lv_binding_micropython <https://github.com/lvgl/lv_binding_micropython>`__
|
||||
which is itself a submodule of `lv_micropython <https://github.com/lvgl/lv_micropython>`__).
|
||||
- When building lv_micropython, the public LVGL C API is scanned and MicroPython API is auto-generated. That means that
|
||||
lv_micropython provides LVGL API for **any** LVGL version, and generally does not require code changes as LVGL evolves.
|
||||
|
||||
|
||||
LVGL C API Coding Conventions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For a summary of coding conventions to follow see the :ref:`coding-style`.
|
||||
|
||||
|
||||
.. _memory_management:
|
||||
|
||||
Memory Management
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
- When LVGL runs in MicroPython, all dynamic memory allocations (:cpp:func:`lv_malloc`) are handled by MicroPython's memory
|
||||
manager which is `garbage-collected <https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)>`__ (GC).
|
||||
- To prevent GC from collecting memory prematurely, all dynamic allocated RAM must be reachable by GC.
|
||||
- GC is aware of most allocations, except from pointers on the `Data Segment <https://en.wikipedia.org/wiki/Data_segment>`__:
|
||||
|
||||
- Pointers which are global variables
|
||||
- Pointers which are static global variables
|
||||
- Pointers which are static local variables
|
||||
|
||||
|
||||
Such pointers need to be defined in a special way to make them reachable by GC
|
||||
|
||||
|
||||
Identify The Problem
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Problem happens when an allocated memory's pointer (return value of :cpp:func:`lv_malloc`) is stored only in either **global**,
|
||||
**static global** or **static local** pointer variable and not as part of a previously allocated ``struct`` or other variable.
|
||||
|
||||
|
||||
Solve The Problem
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Replace the global/static local var with :cpp:expr:`(LV_GLOBAL_DEFAULT()->_var)`
|
||||
- Include ``lv_global.h`` on files that use ``LV_GLOBAL_DEFAULT``
|
||||
- Add ``_var`` to ``lv_global_t`` on ``lv_global.h``
|
||||
|
||||
|
||||
Example
|
||||
^^^^^^^
|
||||
|
||||
|
||||
More Information
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
- `In the README <https://github.com/lvgl/lv_binding_micropython#memory-management>`__
|
||||
- `In the Blog <https://blog.lvgl.io/2019-02-20/micropython-bindings#i-need-to-allocate-a-littlevgl-struct-such-as-style-color-etc-how-can-i-do-that-how-do-i-allocatedeallocate-memory-for-it>`__
|
||||
|
||||
|
||||
.. _callbacks:
|
||||
|
||||
Callbacks
|
||||
~~~~~~~~~
|
||||
|
||||
In C a callback is just a function pointer. But in MicroPython we need to register a *MicroPython callable object* for each
|
||||
callback. Therefore in the MicroPython binding we need to register both a function pointer and a MicroPython object for every callback.
|
||||
|
||||
Therefore we defined a **callback convention** for the LVGL C API that expects lvgl headers to be defined in a certain
|
||||
way. Callbacks that are declared according to the convention would allow the binding to register a MicroPython object
|
||||
next to the function pointer when registering a callback, and access that object when the callback is called.
|
||||
|
||||
- The basic idea is that we have ``void * user_data`` field that is used automatically by the MicroPython Binding
|
||||
to save the *MicroPython callable object* for a callback. This field must be provided when registering the function
|
||||
pointer, and provided to the callback function itself.
|
||||
- Although called "user_data", the user is not expected to read/write that field. Instead, the MicroPython glue code uses
|
||||
``user_data`` to automatically keep track of the MicroPython callable object. The glue code updates it when the callback
|
||||
is registered, and uses it when the callback is called in order to invoke a call to the original callable object.
|
||||
|
||||
|
||||
There are a few options for defining a callback in LVGL C API:
|
||||
|
||||
- Option 1: ``user_data`` in a struct
|
||||
|
||||
- There's a struct that contains a field called ``void * user_data``
|
||||
|
||||
- A pointer to that struct is provided as the **first** argument of a callback registration function
|
||||
- A pointer to that struct is provided as the **first** argument of the callback itself
|
||||
|
||||
- Option 2: ``user_data`` as a function argument
|
||||
|
||||
- A parameter called ``void * user_data`` is provided to the registration function as the **last** argument
|
||||
|
||||
- The callback itself receives ``void *`` as the **last** argument
|
||||
|
||||
- Option 3: both callback and ``user_data`` are struct fields
|
||||
|
||||
- The API exposes a struct with both function pointer member and ``user_data`` member
|
||||
|
||||
- The function pointer member receives the same struct as its **first** argument
|
||||
|
||||
|
||||
In practice it's also possible to mix these options, for example provide a struct pointer when registering a callback
|
||||
(option 1) and provide ``user_data`` argument when calling the callback (options 2),
|
||||
**as long as the same ``user_data`` that was registered is passed to the callback when it's called**.
|
||||
|
||||
|
||||
Examples
|
||||
^^^^^^^^
|
||||
|
||||
- :cpp:type:`lv_anim_t` contains ``user_data`` field. :cpp:func:`lv_anim_set_path_cb` registers `path_cb` callback.
|
||||
Both ``lv_anim_set_path_cb`` and :cpp:type:`lv_anim_path_cb_t` receive :cpp:type:`lv_anim_t` as their first argument
|
||||
- ``path_cb`` field can also be assigned directly in the Python code because it's a member of :cpp:type:`lv_anim_t`
|
||||
which contains ``user_data`` field, and :cpp:type:`lv_anim_path_cb_t` receive :cpp:type:`lv_anim_t` as its first argument.
|
||||
- :cpp:func:`lv_imgfont_create` registers ``path_cb`` and receives ``user_data`` as the last argument.
|
||||
The callback :cpp:type:`lv_imgfont_get_path_cb_t` also receives the ``user_data`` as the last argument.
|
||||
|
||||
|
||||
.. _more-information-1:
|
||||
|
||||
More Information
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
- In the `Blog <https://blog.lvgl.io/2019-08-05/micropython-pure-display-driver#using-callbacks>`__
|
||||
and in the `README <https://github.com/lvgl/lv_binding_micropython#callbacks>`__
|
||||
- `[v6.0] Callback conventions #1036 <https://github.com/lvgl/lvgl/issues/1036>`__
|
||||
- Various discussions: `here <https://github.com/lvgl/lvgl/pull/3294#issuecomment-1184895335>`__
|
||||
and `here <https://github.com/lvgl/lvgl/issues/1763#issuecomment-762247629>`__
|
||||
and`here <https://github.com/lvgl/lvgl/issues/316#issuecomment-467221587>`__
|
||||
198
docs/details/integration/bindings/pikascript.rst
Normal file
198
docs/details/integration/bindings/pikascript.rst
Normal file
@@ -0,0 +1,198 @@
|
||||
PikaScript
|
||||
==========
|
||||
|
||||
|
||||
What is PikaScript ?
|
||||
--------------------
|
||||
|
||||
`PikaScript <https://github.com/pikasTech/pikascript>`__ is a Python interpreter designed specifically for
|
||||
microcontrollers, and it supports a subset of the common Python3 syntax.
|
||||
|
||||
It's lighter, requiring only 32k of code space and 4k of RAM, which means it can run on stm32f103c8 (blue-pill)
|
||||
or even stm32g030c8, on the other hand, you can leave valuable space for more material or larger buffer areas.
|
||||
|
||||
It is simpler, out of the box, runs with no porting and configuration at all, does not depend on OS or file
|
||||
system, has good support for popular IDEs for Windows platforms like Keil, IAR, RT-Thread-Studio, and of course,
|
||||
supports linux-gcc development platforms.
|
||||
|
||||
It's smarter, with a unique C module mechanism that allows you to generate bindings automatically by simply
|
||||
writing the API for the C module in Python, and you don't need to deal with the headache of writing any macros
|
||||
or global tables manually. On the other hand, all C modules have sophisticated smart hints, even hinting at the types
|
||||
of your arguments .
|
||||
|
||||
|
||||
--------------
|
||||
|
||||
|
||||
Why PikaScript + LVGL ?
|
||||
-----------------------
|
||||
|
||||
- PikaScript now supports the main features of LVGL8, and these APIs are fully compatible with MicroPython!
|
||||
This means that you can continue to use already written code from MicroPython, and then use less code space and RAM.
|
||||
- Enjoy detailed code hints down to the parameter type for a better programming experience
|
||||
- Use a more convenient IDE, such as vs-based simulation projects
|
||||
|
||||
|
||||
So how does it look like?
|
||||
-------------------------
|
||||
|
||||
Here are some examples of lvgl that PikaScript can already run, they are mainly from the lvgl documentation examples
|
||||
|
||||
|
||||
LV_ARC
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pika_lvgl as lv
|
||||
import PikaStdLib
|
||||
mem = PikaStdLib.MemChecker()
|
||||
# Create an Arc
|
||||
arc = lv.arc(lv.screen_active())
|
||||
arc.set_end_angle(200)
|
||||
arc.set_size(150, 150)
|
||||
arc.center()
|
||||
print('mem used max: %0.2f kB' % (mem.getMax()))
|
||||
print('mem used now: %0.2f kB' % (mem.getNow()))
|
||||
|
||||
|
||||
LV_BAR
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pika_lvgl as lv
|
||||
import PikaStdLib
|
||||
mem = PikaStdLib.MemChecker()
|
||||
bar1 = lv.bar(lv.screen_active())
|
||||
bar1.set_size(200, 20)
|
||||
bar1.center()
|
||||
bar1.set_value(70, lv.ANIM.OFF)
|
||||
print('mem used max: %0.2f kB' % (mem.getMax()))
|
||||
print('mem used now: %0.2f kB' % (mem.getNow()))
|
||||
|
||||
|
||||
LV_BTN
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pika_lvgl as lv
|
||||
import PikaStdLib
|
||||
mem = PikaStdLib.MemChecker()
|
||||
|
||||
|
||||
def event_cb_1(evt):
|
||||
print('in evt1')
|
||||
print('mem used now: %0.2f kB' % (mem.getNow()))
|
||||
|
||||
|
||||
def event_cb_2(evt):
|
||||
print('in evt2')
|
||||
print('mem used now: %0.2f kB' % (mem.getNow()))
|
||||
|
||||
|
||||
btn1 = lv.btn(lv.screen_active())
|
||||
btn1.align(lv.ALIGN.TOP_MID, 0, 10)
|
||||
btn2 = lv.btn(lv.screen_active())
|
||||
btn2.align(lv.ALIGN.TOP_MID, 0, 50)
|
||||
btn1.add_event_cb(event_cb_1, lv.EVENT.CLICKED, 0)
|
||||
btn2.add_event_cb(event_cb_2, lv.EVENT.CLICKED, 0)
|
||||
print('mem used max: %0.2f kB' % (mem.getMax()))
|
||||
print('mem used now: %0.2f kB' % (mem.getNow()))
|
||||
|
||||
|
||||
LV_CHECKBOX
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pika_lvgl as lv
|
||||
import PikaStdLib
|
||||
mem = PikaStdLib.MemChecker()
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.set_text("Apple")
|
||||
cb.align(lv.ALIGN.TOP_LEFT, 0 ,0)
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.set_text("Banana")
|
||||
cb.add_state(lv.STATE.CHECKED)
|
||||
cb.align(lv.ALIGN.TOP_LEFT, 0 ,30)
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.set_text("Lemon")
|
||||
cb.add_state(lv.STATE.DISABLED)
|
||||
cb.align(lv.ALIGN.TOP_LEFT, 0 ,60)
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
|
||||
cb.set_text("Melon")
|
||||
cb.align(lv.ALIGN.TOP_LEFT, 0 ,90)
|
||||
print('mem used max: %0.2f kB' % (mem.getMax()))
|
||||
print('mem used now: %0.2f kB' % (mem.getNow()))
|
||||
|
||||
|
||||
--------------
|
||||
|
||||
|
||||
How does it work?
|
||||
-----------------
|
||||
|
||||
PikaScript has a unique C module smart binding tool
|
||||
|
||||
Just write the Python interface in pika_lvgl.pyi (.pyi is the python interface file)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# pika_lvgl.pyi
|
||||
class arc(lv_obj):
|
||||
def set_end_angle(self, angle: int): ...
|
||||
def set_bg_angles(self, start: int, end: int): ...
|
||||
def set_angles(self, start: int, end: int): ...
|
||||
|
||||
|
||||
Then PikaScript's pre-compiler can automatically bind the following C functions, simply by naming the functions
|
||||
in the module_class_method format, without any additional work, and all binding and registration is done automatically.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* pika_lvgl_arc.c */
|
||||
void pika_lvgl_arc_set_end_angle(PikaObj* self, int angle) {
|
||||
lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj");
|
||||
lv_arc_set_end_angle(lv_obj, angle);
|
||||
}
|
||||
void pika_lvgl_arc_set_bg_angles(PikaObj *self, int start, int end){
|
||||
lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj");
|
||||
lv_arc_set_bg_angles(lv_obj, start, end);
|
||||
}
|
||||
void pika_lvgl_arc_set_angles(PikaObj *self, int start, int end){
|
||||
lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj");
|
||||
lv_arc_set_angles(lv_obj, start, end);
|
||||
}
|
||||
|
||||
|
||||
To use the module, just ``import pika_lvgl`` and the precompiler will automatically scan main.py and bind the
|
||||
``pika_lvgl`` module
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ ./rust-msc-latest-win10.exe
|
||||
(pikascript) packages installed:
|
||||
pikascript-core==v1.10.0
|
||||
PikaStdLib==v1.10.0
|
||||
PikaStdDevice==v1.10.0
|
||||
(pikascript) pika compiler:
|
||||
scanning main.py...
|
||||
binding pika_lvgl.pyi...
|
||||
|
||||
|
||||
The precompiler is written in Rust, runs on windows and linux, and is completely open source.
|
||||
|
||||
In addition to binding C modules, the precompiler compiles Python scripts to bytecode in the PC, reducing the
|
||||
size of the script and increasing its speed.
|
||||
|
||||
|
||||
--------------
|
||||
|
||||
|
||||
How can I use it?
|
||||
-----------------
|
||||
|
||||
The simulation repo on vs is available on https://github.com/pikasTech/lv_pikascript
|
||||
80
docs/details/integration/building/cmake.rst
Normal file
80
docs/details/integration/building/cmake.rst
Normal file
@@ -0,0 +1,80 @@
|
||||
.. _build_cmake:
|
||||
|
||||
=====
|
||||
CMake
|
||||
=====
|
||||
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This project uses CMakePresets to ensure an easy build.
|
||||
Find out more on Cmake Presets here: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
You need to install
|
||||
|
||||
- CMake
|
||||
- Ninja (for Linux builds). Be sure to Add ninja to your PATH!
|
||||
|
||||
|
||||
How to build this project using cmake
|
||||
-------------------------------------
|
||||
|
||||
The recommended way to build this project is to use the provided CMakePresets.json. This file contains 2 configurations
|
||||
|
||||
- a windows (msvc) build using Visual Studio
|
||||
- a linux (gcc) build using Ninja
|
||||
|
||||
|
||||
More configurations will be added once available.
|
||||
|
||||
|
||||
Build with IDE
|
||||
--------------
|
||||
|
||||
The recommend way for consuming CMakePresets is a CMakePresets aware IDE such as
|
||||
|
||||
- VS 2022
|
||||
- VS Code
|
||||
- CLion
|
||||
|
||||
|
||||
Simply load this project into your IDE and select your desired preset and you are good to go.
|
||||
|
||||
|
||||
Build with CMake GUI
|
||||
--------------------
|
||||
|
||||
Open this project with CMake GUI and select your desired preset. When hitting the generate button,
|
||||
CMake will create solution files (for VS) or Ninja Files (for Linux Ninja Build)
|
||||
|
||||
The following targets are available.
|
||||
|
||||
- lvgl (the actual library, required)
|
||||
- lvgl_thorvg (an vector graphics extension, optional)
|
||||
- lvgl_examples (example usages, optional)
|
||||
- lvgl_demos (some demos, optional)
|
||||
|
||||
|
||||
All optional targets can be disabled by setting the proper cache variables.
|
||||
If you use cmake to install lvgl 3 folders will be created.
|
||||
|
||||
- include/lvgl (contains all public headers)
|
||||
- bin (contains all binaries (\*.dll))
|
||||
- lib (contains all precompiled source files (\*.lib))
|
||||
|
||||
|
||||
Build with Command line
|
||||
-----------------------
|
||||
|
||||
You can also build your project using the command line. Run the following commands
|
||||
|
||||
- ``cmake --preset windows-base``
|
||||
- ``cmake --build --preset windows-base_dbg``
|
||||
- ``ctest --preset windows-base_dbg``
|
||||
|
||||
|
||||
10
docs/details/integration/building/index.rst
Normal file
10
docs/details/integration/building/index.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
=============
|
||||
Build systems
|
||||
=============
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
make
|
||||
cmake
|
||||
7
docs/details/integration/building/make.rst
Normal file
7
docs/details/integration/building/make.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
.. _build_make:
|
||||
|
||||
====
|
||||
make
|
||||
====
|
||||
|
||||
LVGL can be easily integrated into any Makefile project by adding ``include lvgl/lvgl.mk`` to the main ``Makefile``.
|
||||
57
docs/details/integration/chip/arm.rst
Normal file
57
docs/details/integration/chip/arm.rst
Normal file
@@ -0,0 +1,57 @@
|
||||
.. _arm:
|
||||
|
||||
===
|
||||
Arm
|
||||
===
|
||||
|
||||
Arm is a leading semiconductor and software design company, renowned for creating the Cortex-M microcontroller (MCU) cores and Cortex-A/R (MPU) processor cores, which are integral to a wide range of devices. These cores are at the heart of many embedded systems, powering chips from industry giants such as STMicroelectronics, NXP, and Renesas. Arm's energy-efficient designs are used in billions of devices worldwide, from microcontrollers to smartphones and servers. By licensing their processor designs, Arm enables a broad ecosystem of partners to develop customized solutions optimized for performance, power, and size. Arm's architecture is highly compatible with various operating systems and software libraries, including LVGL, making it a versatile choice for developers creating efficient, high-performance graphical user interfaces.
|
||||
|
||||
Compile LVGL for Arm
|
||||
--------------------
|
||||
|
||||
No specific action is required. Any compiler that supports the target Arm architecture can be used to compile LVGL's source code, including GCC, LLVM, and AC6.
|
||||
|
||||
It is also possible to cross-compile LVGL for an MPU (instead of compiling it on the target hardware) or create a shared library. For more information, check out :ref:`build_cmake`.
|
||||
|
||||
Getting Started with AC6
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since AC6 is a proprietary toolchain, it contains many specific optimizations, so you can expect the best performance when using it.
|
||||
|
||||
AC6 is not free, but it offers a community license that can be activated as follows:
|
||||
|
||||
1. Download and install the AC6 compiler from `Arm's website <https://developer.arm.com/Tools%20and%20Software/Arm%20Compiler%20for%20Embedded>`__.
|
||||
2. To register a community license, go to the ``bin`` folder of the compiler and, in a terminal, run ``armlm.exe activate -server https://mdk-preview.keil.arm.com -product KEMDK-COM0`` (On Linux, use ``./armlm``).
|
||||
|
||||
IDE Support
|
||||
-----------
|
||||
|
||||
There are no limitations on the supported IDEs. LVGL works in various vendors' IDEs, including Arm's Keil MDK, IAR, Renesas's e2 studio, NXP's MCUXpresso, ST's CubeIDE, as well as custom make or CMake projects.
|
||||
|
||||
Arm2D and the Helium instruction set
|
||||
------------------------------------
|
||||
|
||||
Arm Cortex-M55 and Cortex-M85 have the `SIMD Helium <https://www.arm.com/technologies/helium>`__ instruction set.
|
||||
Among many others, this can effectively speed up UI rendering. :ref:`Arm2D <arm2d>` is a library maintained by Arm that leverages the Helium instruction set.
|
||||
|
||||
Note that GCC has some known issues with Helium intrinsics. It is recommended to use AC6 or LLVM when dealing with Helium code.
|
||||
|
||||
|
||||
To add Arm2D to your project, follow these steps:
|
||||
|
||||
1. To utilize its power, ensure that ``mcpu`` is set to ``cortex-m85``, ``cortex-m55``, or ``cortex-m52`` and add the ``-fvectorize`` flag. To test without SIMD, use e.g. ``cortex-m85+nomve``.
|
||||
2. Arm2D can be downloaded from `https://github.com/ARM-software/Arm-2D <https://github.com/ARM-software/Arm-2D>`__. Consider using the ``developing`` branch, which contains the latest updates.
|
||||
3. Add ``Arm-2D/Library/Include`` to the include paths.
|
||||
4. Copy ``Arm-2D/Library/Include/template/arm_2d_cfg.h`` to any location you prefer to provide the default configuration for Arm2D. Ensure that the folder containing ``arm_2d_cfg.h`` is added to the include path.
|
||||
5. The Arm2D repository contains several examples and templates; however, ensure that only ``Arm-2D/Library/Source`` is compiled.
|
||||
6. The CMSIS DSP library also needs to be added to the project. You can use CMSIS-PACKS or add it manually.
|
||||
7. For better performance, enable ``LTO`` (Link Time Optimization) and use ``-Omax`` or ``-Ofast``.
|
||||
8. Arm2D tries to read/write multiple data with a single instruction. Therefore, it's important to use the fastest memory (e.g., ``BSS`` or ``TCM``) for LVGL's buffer to avoid memory bandwidth bottlenecks.
|
||||
9. Enable ``LV_USE_DRAW_ARM2D_SYNC 1`` and ``LV_USE_DRAW_SW_ASM LV_DRAW_SW_ASM_HELIUM`` in ``lv_conf.h``.
|
||||
|
||||
Neon Acceleration
|
||||
-----------------
|
||||
|
||||
Several Cortex-A microprocessors support the `Neon SIMD <https://www.arm.com/technologies/neon>`__ instruction set. LVGL has built-in support to improve the performance of software rendering by utilizing Neon instructions. To enable Neon acceleration, set ``LV_USE_DRAW_SW_ASM`` to ``LV_DRAW_SW_ASM_NEON`` in ``lv_conf.h``.
|
||||
|
||||
|
||||
198
docs/details/integration/chip/espressif.rst
Normal file
198
docs/details/integration/chip/espressif.rst
Normal file
@@ -0,0 +1,198 @@
|
||||
=============================
|
||||
Espressif (ESP32 Chip Series)
|
||||
=============================
|
||||
|
||||
LVGL can be used and configured as standard `ESP-IDF <https://github.com/espressif/esp-idf>`__ component.
|
||||
|
||||
If you are new to ESP-IDF, follow the instructions in the `ESP-IDF Programming guide <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html>`__ to install and set up ESP-IDF on your machine.
|
||||
|
||||
|
||||
LVGL Demo Projects for ESP32
|
||||
----------------------------
|
||||
|
||||
For a quick start with LVGL and ESP32, the following pre-configured demo projects are available for specific development boards:
|
||||
|
||||
- `ESP-BOX-3 <https://github.com/lvgl/lv_port_espressif_esp-box-3>`__
|
||||
- `ESP32-S3-LCD-EV-BOARD <https://github.com/lvgl/lv_port_espressif_esp32-s3-lcd-ev-board>`__
|
||||
- `M5Stack-CoreS3 <https://github.com/lvgl/lv_port_espressif_M5Stack_CoreS3>`__
|
||||
|
||||
Refer to the README.md files in these repositories for build and flash instructions.
|
||||
|
||||
These demo projects use Espressif's Board Support Packages (BSPs). Additional BSPs and examples are available in the `esp-bsp <https://github.com/espressif/esp-bsp>`__ repository.
|
||||
|
||||
|
||||
Using LVGL in Your ESP-IDF Project
|
||||
----------------------------------
|
||||
|
||||
The simplest way to integrate LVGL into your ESP-IDF project is via the `esp_lvgl_port <https://components.espressif.com/components/espressif/esp_lvgl_port>`__ component. This component, used in the demo projects mentioned above, provides helper functions for easy installation of LVGL and display drivers. Moreover, it can add support for touch, rotary encoders, button or USB HID inputs. It simplifies power savings, screen rotation and other platform specific nuances.
|
||||
|
||||
The esp_lvgl_port supports LVGL versions 8 and 9 and is compatible with ESP-IDF v4.4 and above. To add it to your project, use the following command:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
idf.py add-dependency "espressif/esp_lvgl_port^2.3.0"
|
||||
|
||||
By default, esp_lvgl_port depends on the latest stable version of LVGL, so no additional steps are needed for new projects. If a specific LVGL version is required, specify this in your project to avoid automatic updates. LVGL can also be used without esp_lvgl_port, as described below.
|
||||
|
||||
Obtaining LVGL
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
LVGL is distributed through `ESP Registry <https://components.espressif.com/>`__, where all LVGL releases are uploaded.
|
||||
In case you do not want to use esp_lvgl_port, you can add `LVGL component <https://components.espressif.com/component/lvgl/lvgl>`__ into your project with following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
idf.py add-dependency lvgl/lvgl^9.*
|
||||
|
||||
Adjust the ``^9.*`` part to match your LVGL version requirement. More information on version specifications can be found in the `IDF Component Manager documentation <https://docs.espressif.com/projects/idf-component-manager/en/latest/reference/versioning.html#range-specifications>`__. During the next build, the LVGL component will be fetched from the component registry and added to the project.
|
||||
|
||||
**Advanced usage: Use LVGL as local component**
|
||||
|
||||
For LVGL development and testing, it may be useful to use LVGL as a local component instead of from the ESP Registry, which offers only released versions and does not allow local modifications. To do this, clone LVGL to your project with the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
git submodule add https://github.com/lvgl/lvgl.git components/lvgl
|
||||
|
||||
.. note::
|
||||
|
||||
All components from ``${project_dir}/components`` are automatically added to build.
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
To configure LVGL, launch the configuration menu with ``idf.py menuconfig`` in your project root directory. Navigate to ``Component config`` and then ``LVGL configuration``.
|
||||
|
||||
|
||||
Support for Display and Touch Drivers
|
||||
-------------------------------------
|
||||
|
||||
For successful LVGL project you will need a display driver and optionally a touch driver. Espressif provides these drivers that are built on its `esp_lcd <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/lcd/index.html>`__ component.
|
||||
|
||||
- esp_lcd natively supports for some `basic displays <https://github.com/espressif/esp-idf/tree/master/components/esp_lcd/src>`__
|
||||
- Other displays are maintained in `esp-bsp repository <https://github.com/espressif/esp-bsp/tree/master/components/lcd>`__ and are uploaded to ESP Registry
|
||||
- Touch drivers are maintained in `esp-bsp repository <https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch>`__ and are uploaded to ESP Registry
|
||||
|
||||
These components share a common public API, making it easy to migrate your projects across different display and touch drivers.
|
||||
|
||||
To add a display or touch driver to your project, use a command like:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
idf.py add-dependency "espressif/esp_lcd_gc9a01^2.0.0"
|
||||
|
||||
Using the File System under ESP-IDF
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
ESP-IDF uses the standard C functions (``fopen``, ``fread``) in all storage related APIs.
|
||||
This allows seamless interoperability with LVGL when enabling the :c:macro:`LV_USE_FS_STDIO` configuration.
|
||||
The process is described in details below, using ``SPIFFS`` as demonstration.
|
||||
|
||||
- **Decide what storage system you want to use**
|
||||
|
||||
ESP-IDF has many, ready-to-use examples like
|
||||
`SPIFFS <https://github.com/espressif/esp-idf/tree/master/examples/storage/spiffsgen>`__
|
||||
,
|
||||
`SD Card <https://github.com/espressif/esp-idf/tree/master/examples/storage/sd_card/sdspi>`__
|
||||
and
|
||||
`LittleFS <https://github.com/espressif/esp-idf/tree/master/examples/storage/littlefs>`__
|
||||
.
|
||||
|
||||
- **Re-configure your own project**
|
||||
|
||||
The example project should be examined for details, but in general the changes involve:
|
||||
|
||||
- Enabling LVGL's STDIO file system in the configuration
|
||||
|
||||
You can use ``menuconfig``:
|
||||
|
||||
- ``Component config → LVGL configuration → 3rd Party Libraries``: enable ``File system on top of stdio API``
|
||||
- Then select ``Set an upper cased letter on which the drive will accessible`` and set it to ``65`` (ASCII **A**)
|
||||
- You can also set ``Default driver letter`` to 65 to skip the prefix in file paths.
|
||||
|
||||
- Modifying the partition table
|
||||
|
||||
The exact configuration depends on your flash size and existing partitions,
|
||||
but the new final result should look something like this:
|
||||
|
||||
.. csv-table:: Partition Table
|
||||
|
||||
nvs, data, nvs, 0x9000, 0x6000
|
||||
phy_init, data, phy, 0xf000, 0x1000
|
||||
factory, app, factory, 0x10000, 1400k
|
||||
storage, data, spiffs, , 400k
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
If you are not using a custom ``partition.csv`` yet, it can be added
|
||||
via ``menuconfig`` (``Partition Table → Partition Table → Custom partition table CSV``).
|
||||
|
||||
- Apply changes to the build system
|
||||
|
||||
Some ESP file systems provide automatic generation from a host folder using CMake. The proper line(s) must be copied to ``main/CMakeLists.txt``
|
||||
|
||||
.. note::
|
||||
|
||||
``LittleFS`` has extra dependencies that should be added to ``main/idf_component.yml``
|
||||
|
||||
- **Prepare the image files**
|
||||
|
||||
LVGL's ``LVGLImage.py`` Python tool can be used to convert images to binary pixel map files.
|
||||
It supports various formats and compression.
|
||||
|
||||
Meanwhile 3rd party libraries
|
||||
(like :ref:`LodePNG<lodepng_rst>` and :ref:`Tiny JPEG<tjpgd>`)
|
||||
allow using image files without conversion.
|
||||
|
||||
After preparing the files, they should be moved to the target device:
|
||||
|
||||
- If properly activated a **SPIFFS** file system based on the ``spiffs_image`` folder should be automatically generated and later flashed to the target
|
||||
- Similar mechanism for **LittleFS** uses the ``flash_data`` folder, but it's only available for Linux hosts
|
||||
- For the **SD Card**, a traditional file browser can be used
|
||||
|
||||
- **Invoke proper API calls in the application code**
|
||||
|
||||
The core functionality requires only a few lines. The following example draws the image as well.
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include "esp_spiffs.h"
|
||||
|
||||
void lv_example_image_from_esp_fs(void) {
|
||||
|
||||
esp_vfs_spiffs_conf_t conf = {
|
||||
.base_path = "/spiffs",
|
||||
.partition_label = NULL,
|
||||
.max_files = 5,
|
||||
.format_if_mount_failed = false
|
||||
};
|
||||
|
||||
esp_err_t ret = esp_vfs_spiffs_register(&conf);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register SPIFF filesystem");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_t * obj = lv_image_create(lv_screen_active());
|
||||
lv_image_set_src(widget, "A:/spiffs/logo.bin");
|
||||
lv_obj_center(widget);
|
||||
}
|
||||
|
||||
- **Build and flash**
|
||||
|
||||
After calling ``idf.py build flash`` the picture should be displayed on the screen.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Changes made by ``menuconfig`` are not being tracked in the repository if the ``sdkconfig`` file is added to ``.gitignore``, which is the default for many ESP-IDF projects.
|
||||
To make your configuration permanent, add the following lines to ``sdkconfig.defaults``:
|
||||
|
||||
.. code:: c
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_LV_USE_FS_STDIO=y
|
||||
CONFIG_LV_FS_STDIO_LETTER=65
|
||||
CONFIG_LV_LV_FS_DEFAULT_DRIVE_LETTER=65
|
||||
12
docs/details/integration/chip/index.rst
Normal file
12
docs/details/integration/chip/index.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
============
|
||||
Chip vendors
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
arm
|
||||
espressif
|
||||
nxp
|
||||
renesas
|
||||
stm32
|
||||
410
docs/details/integration/chip/nxp.rst
Normal file
410
docs/details/integration/chip/nxp.rst
Normal file
@@ -0,0 +1,410 @@
|
||||
===
|
||||
NXP
|
||||
===
|
||||
|
||||
NXP has integrated LVGL into the MCUXpresso SDK packages for several of our
|
||||
microcontrollers as an optional software component, allowing easy evaluation and
|
||||
migration into your product design. LVGL is a free and open-source embedded
|
||||
graphic library with features that enable you to create embedded GUIs with
|
||||
intuitive graphical elements, beautiful visual effects and a low memory
|
||||
footprint. The complete graphic framework includes a variety of widgets for you
|
||||
to use in the creation of your GUI, and supports more advanced functions such as
|
||||
animations and anti-aliasing.
|
||||
|
||||
LVGL enables graphics in our free GUI Guider UI tool. It's available for use
|
||||
with NXP’s general purpose and crossover microcontrollers, providing developers
|
||||
with a tool for creating complete, high quality GUI applications with LVGL.
|
||||
|
||||
Creating new project with LVGL
|
||||
------------------------------
|
||||
|
||||
`Download an SDK for a supported board <https://www.nxp.com/design/software/embedded-software/littlevgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY?&tid=vanLITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY>`__
|
||||
today and get started with your next GUI application. It comes fully configured
|
||||
with LVGL (and with PXP/VGLite support if the modules are present), no
|
||||
additional integration work is required.
|
||||
|
||||
HW acceleration for NXP iMX RT platforms
|
||||
----------------------------------------
|
||||
|
||||
Depending on the RT platform used, the acceleration can be done by NXP PXP
|
||||
(PiXel Pipeline) and/or the Verisilicon GPU through an API named VGLite. Each
|
||||
accelerator has its own context that allows them to be used individually as well
|
||||
simultaneously (in LVGL multithreading mode).
|
||||
|
||||
PXP accelerator
|
||||
~~~~~~~~~~~~~~~
|
||||
Basic configuration:
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Select NXP PXP engine in "lv_conf.h": Set :c:macro:`LV_USE_PXP` to `1`.
|
||||
- In order to use PXP as a draw unit, select in "lv_conf.h": Set :c:macro:`LV_USE_DRAW_PXP` to `1`.
|
||||
- In order to use PXP to rotate the screen, select in "lv_conf.h": Set :c:macro:`LV_USE_ROTATE_PXP` to `1`.
|
||||
- Enable PXP asserts in "lv_conf.h": Set :c:macro: `LV_USE_PXP_ASSERT` to `1`.
|
||||
There are few PXP assertions that can stop the program execution in case the
|
||||
c:macro:`LV_ASSERT_HANDLER` is set to `while(1);` (Halt by default). Else,
|
||||
there will be logged just an error message via `LV_LOG_ERROR`.
|
||||
- If :c:macro:`SDK_OS_FREE_RTOS` symbol is defined, FreeRTOS implementation
|
||||
will be used, otherwise bare metal code will be included.
|
||||
|
||||
Basic initialization:
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
PXP draw initialization is done automatically in :cpp:func:`lv_init()` once the
|
||||
PXP is enabled as a draw unit or to rotate the screen, no user code is required:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
lv_draw_pxp_init();
|
||||
#endif
|
||||
|
||||
During PXP initialization, a new draw unit `lv_draw_pxp_unit_t` will be created
|
||||
with the additional callbacks, if :c:macro:`LV_USE_DRAW_PXP` is set to `1`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_draw_pxp_unit_t * draw_pxp_unit = lv_draw_create_unit(sizeof(lv_draw_pxp_unit_t));
|
||||
draw_pxp_unit->base_unit.evaluate_cb = _pxp_evaluate;
|
||||
draw_pxp_unit->base_unit.dispatch_cb = _pxp_dispatch;
|
||||
draw_pxp_unit->base_unit.delete_cb = _pxp_delete;
|
||||
|
||||
|
||||
and an addition thread `_pxp_render_thread_cb()` will be spawned in order to
|
||||
handle the supported draw tasks.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if LV_USE_PXP_DRAW_THREAD
|
||||
lv_thread_init(&draw_pxp_unit->thread, LV_THREAD_PRIO_HIGH, _pxp_render_thread_cb, 2 * 1024, draw_pxp_unit);
|
||||
#endif
|
||||
|
||||
If `LV_USE_PXP_DRAW_THREAD` is not defined, then no additional draw thread will be created
|
||||
and the PXP drawing task will get executed on the same LVGL main thread.
|
||||
|
||||
`_pxp_evaluate()` will get called after each task is being created and will
|
||||
analyze if the task is supported by PXP or not. If it is supported, then an
|
||||
preferred score and the draw unit id will be set to the task. An `score` equal
|
||||
to `100` is the default CPU score. Smaller score means that PXP is capable of
|
||||
drawing it faster.
|
||||
|
||||
`_pxp_dispatch()` is the PXP dispatcher callback, it will take a ready to draw
|
||||
task (having the `DRAW_UNIT_ID_PXP` set) and will pass the task to the PXP draw
|
||||
unit for processing.
|
||||
|
||||
`_pxp_delete()` will cleanup the PXP draw unit.
|
||||
|
||||
|
||||
Features supported:
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Several drawing features in LVGL can be offloaded to the PXP engine. The CPU is
|
||||
available for other operations while the PXP is running. RTOS is required to
|
||||
block the LVGL drawing thread and switch to another task or suspend the CPU for
|
||||
power savings.
|
||||
|
||||
Supported draw tasks are available in "src/draw/nxp/pxp/lv_draw_pxp.c":
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
lv_draw_pxp_fill(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
lv_draw_pxp_img(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
lv_draw_pxp_layer(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Additional, the screen rotation can be handled by the PXP:
|
||||
|
||||
.. code-block::c
|
||||
|
||||
void lv_draw_pxp_rotate(const void * src_buf, void * dest_buf, int32_t src_width, int32_t src_height,
|
||||
int32_t src_stride, int32_t dest_stride, lv_display_rotation_t rotation,
|
||||
lv_color_format_t cf);
|
||||
|
||||
- Fill area with color (w/o radius, w/o gradient) + optional opacity.
|
||||
- Blit source image RGB565/ARGB888/XRGB8888 over destination.
|
||||
RGB565/RGB888/ARGB888/XRGB8888 + optional opacity.
|
||||
- Recolor source image RGB565.
|
||||
- Scale and rotate (90, 180, 270 degree) source image RGB565.
|
||||
- Blending layers (w/ same supported formats as blitting).
|
||||
- Rotate screen (90, 180, 270 degree).
|
||||
|
||||
|
||||
Known limitations:
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- PXP can only rotate at 90x angles.
|
||||
- Rotation is not supported for images unaligned to blocks of 16x16 pixels. PXP
|
||||
is set to process 16x16 blocks to optimize the system for memory bandwidth and
|
||||
image processing time. The output engine essentially truncates any output
|
||||
pixels after the desired number of pixels has been written. When rotating a
|
||||
source image and the output is not divisible by the block size, the incorrect
|
||||
pixels could be truncated and the final output image can look shifted.
|
||||
- Recolor or transformation for images w/ opacity or alpha channel can't be
|
||||
obtained in a single PXP pipeline configuration. Two or multiple steps would
|
||||
be required.
|
||||
- Buffer address must be aligned to 64 bytes: set :c:macro:`LV_DRAW_BUF_ALIGN`
|
||||
to `64` in "lv_conf.h".
|
||||
No stride alignment is required: set :c:macro:`LV_DRAW_BUF_STRIDE_ALIGN` to
|
||||
`1` in "lv_conf.h".
|
||||
|
||||
Project setup:
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- Add PXP related source files (and corresponding headers if available) to
|
||||
project:
|
||||
|
||||
- "src/draw/nxp/pxp/lv_draw_buf_pxp.c": draw buffer callbacks
|
||||
- "src/draw/nxp/pxp/lv_draw_pxp_fill.c": fill area
|
||||
- "src/draw/nxp/pxp/lv_draw_pxp_img.c": blit image (w/ optional recolor or
|
||||
transformation)
|
||||
- "src/draw/nxp/pxp/lv_draw_pxp_layer.c": layer blending
|
||||
- "src/draw/nxp/pxp/lv_draw_pxp.c": draw unit initialization
|
||||
- "src/draw/nxp/pxp/lv_pxp_cfg.c": init, deinit, run/wait PXP device
|
||||
- "src/draw/nxp/pxp/lv_pxp_osa.c": OS abstraction (FreeRTOS or bare metal)
|
||||
- "src/draw/nxp/pxp/lv_pxp_utils.c": function helpers
|
||||
|
||||
- PXP related code depends on two drivers provided by MCU SDK. These drivers
|
||||
need to be added to project:
|
||||
|
||||
- fsl_pxp.c: PXP driver
|
||||
- fsl_cache.c: CPU cache handling functions
|
||||
|
||||
|
||||
PXP default configuration:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Implementation depends on multiple OS-specific functions. The struct
|
||||
:cpp:struct:`pxp_cfg_t` with callback pointers is used as a parameter for the
|
||||
:cpp:func:`lv_pxp_init()` function. Default implementation for FreeRTOS and
|
||||
bare metal is provided in lv_pxp_osa.c.
|
||||
|
||||
- :cpp:func:`pxp_interrupt_init()`: Initialize PXP interrupt (HW setup,
|
||||
OS setup)
|
||||
- :cpp:func:`pxp_interrupt_deinit()`: Deinitialize PXP interrupt (HW setup,
|
||||
OS setup)
|
||||
- :cpp:func:`pxp_run()`: Start PXP job. Use OS-specific mechanism to block
|
||||
drawing thread.
|
||||
- :cpp:func:`pxp_wait()`: Wait for PXP completion.
|
||||
|
||||
|
||||
VGLite accelerator
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Extra drawing features in LVGL can be handled by the VGLite engine. The
|
||||
CPU is available for other operations while the VGLite is running. An
|
||||
RTOS is required to block the LVGL drawing thread and switch to another
|
||||
task or suspend the CPU for power savings.
|
||||
|
||||
|
||||
Basic configuration:
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Select NXP VGLite engine in "lv_conf.h": Set :c:macro:`LV_USE_DRAW_VGLITE` to
|
||||
`1`. :c:macro:`SDK_OS_FREE_RTOS` symbol needs to be defined so that FreeRTOS
|
||||
driver osal implementation will be enabled.
|
||||
- Enable VGLite asserts in "lv_conf.h": Set :c:macro: `LV_USE_VGLITE_ASSERT` to
|
||||
`1`.
|
||||
VGLite assertions will verify the driver API status code and in any error, it
|
||||
can stop the program execution in case the c:macro: `LV_ASSERT_HANDLER` is set
|
||||
to `while(1);` (Halt by default). Else, there will be logged just an error
|
||||
message via `LV_LOG_ERROR`.
|
||||
|
||||
Basic initialization:
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Initialize VGLite GPU before calling :cpp:func:`lv_init()` by specifying the
|
||||
width/height of tessellation window. The default values for tesselation width
|
||||
and height, and command buffer size are in the SDK file "vglite_support.h".
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "vg_lite.h"
|
||||
#include "vglite_support.h"
|
||||
#endif
|
||||
...
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
if(vg_lite_init(DEFAULT_VG_LITE_TW_WIDTH, DEFAULT_VG_LITE_TW_HEIGHT) != VG_LITE_SUCCESS)
|
||||
{
|
||||
PRINTF("VGLite init error. STOP.");
|
||||
vg_lite_close();
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
if (vg_lite_set_command_buffer_size(VG_LITE_COMMAND_BUFFER_SIZE) != VG_LITE_SUCCESS)
|
||||
{
|
||||
PRINTF("VGLite set command buffer. STOP.");
|
||||
vg_lite_close();
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
VGLite draw initialization is done automatically in :cpp:func:`lv_init()` once
|
||||
the VGLite is enabled, no user code is required:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
lv_draw_vglite_init();
|
||||
#endif
|
||||
|
||||
During VGLite initialization, a new draw unit `lv_draw_vglite_unit_t` will be
|
||||
created with the additional callbacks:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_draw_vglite_unit_t * draw_vglite_unit = lv_draw_create_unit(sizeof(lv_draw_vglite_unit_t));
|
||||
draw_vglite_unit->base_unit.evaluate_cb = _vglite_evaluate;
|
||||
draw_vglite_unit->base_unit.dispatch_cb = _vglite_dispatch;
|
||||
draw_vglite_unit->base_unit.delete_cb = _vglite_delete;
|
||||
|
||||
and an addition thread `_vglite_render_thread_cb()` will be spawned in order to
|
||||
handle the supported draw tasks.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_THREAD
|
||||
lv_thread_init(&draw_vglite_unit->thread, LV_THREAD_PRIO_HIGH, _vglite_render_thread_cb, 2 * 1024, draw_vglite_unit);
|
||||
#endif
|
||||
|
||||
If `LV_USE_VGLITE_DRAW_THREAD` is not defined, then no additional draw thread will be created
|
||||
and the VGLite drawing task will get executed on the same LVGL main thread.
|
||||
|
||||
`_vglite_evaluate()` will get called after each task is being created and will
|
||||
analyze if the task is supported by VGLite or not. If it is supported, then an
|
||||
preferred score and the draw unit id will be set to the task. An `score` equal
|
||||
to `100` is the default CPU score. Smaller score means that VGLite is capable of
|
||||
drawing it faster.
|
||||
|
||||
`_vglite_dispatch()` is the VGLite dispatcher callback, it will take a ready to
|
||||
draw task (having the `DRAW_UNIT_ID_VGLITE` set) and will pass the task to the
|
||||
VGLite draw unit for processing.
|
||||
|
||||
`_vglite_delete()` will cleanup the VGLite draw unit.
|
||||
|
||||
|
||||
Advanced configuration:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Enable VGLite blit split in "lv_conf.h":
|
||||
Set :c:macro: `LV_USE_VGLITE_BLIT_SPLIT` to `1`.
|
||||
Enabling the blit split workaround will mitigate any quality degradation issue
|
||||
on screen's dimension > 352 pixels.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define VGLITE_BLIT_SPLIT_THR 352
|
||||
|
||||
- By default, the blit split threshold is set to 352. Blits with width or height
|
||||
higher than this value will be done in multiple steps. Value must be multiple
|
||||
of stride alignment in px. For most color formats, the alignment is 16px
|
||||
(except the index formats). Transformation will not be supported once with
|
||||
the blit split.
|
||||
|
||||
- Enable VGLite draw task synchronously in "lv_conf.h":
|
||||
Set :c:macro: `LV_USE_VGLITE_DRAW_ASYNC` to `1`.
|
||||
Multiple draw tasks can be queued and flushed them once to the GPU based on
|
||||
the GPU idle status. If GPU is busy, the task will be queued, and the VGLite
|
||||
dispatcher will ask for a new available task. If GPU is idle, the queue with
|
||||
any pending tasks will be flushed to the GPU. The completion status of draw
|
||||
task will be sent to the main LVGL thread asynchronously.
|
||||
|
||||
Features supported:
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Several drawing features in LVGL can be offloaded to the VGLite engine. The CPU
|
||||
is available for other operations while the GPU is running. RTOS is required to
|
||||
block the LVGL drawing thread and switch to another task or suspend the CPU for
|
||||
power savings.
|
||||
|
||||
Supported draw tasks are available in "src/draw/nxp/pxp/lv_draw_vglite.c":
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_LABEL:
|
||||
lv_draw_vglite_label(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
lv_draw_vglite_fill(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_BORDER:
|
||||
lv_draw_vglite_border(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
lv_draw_vglite_img(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
lv_draw_vglite_arc(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LINE:
|
||||
lv_draw_vglite_line(draw_unit, t->draw_dsc);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
lv_draw_vglite_layer(draw_unit, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
lv_draw_vglite_triangle(draw_unit, t->draw_dsc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
All the below operation can be done in addition with optional opacity.
|
||||
|
||||
- Fill area with color (w/ radius or gradient).
|
||||
- Blit source image (any format from ``_vglite_src_cf_supported()``) over
|
||||
destination (any format from ``_vglite_dest_cf_supported()``).
|
||||
- Recolor source image.
|
||||
- Scale and rotate (any decimal degree) source image.
|
||||
- Blending layers (w/ same supported formats as blitting).
|
||||
- Draw letters (blit bitmap letters / raster font).
|
||||
- Draw full borders (LV_BORDER_SIDE_FULL).
|
||||
- Draw arcs (w/ rounded edges).
|
||||
- Draw lines (w/ dash or rounded edges).
|
||||
- Draw triangles with color (w/ gradient).
|
||||
|
||||
|
||||
Known limitations:
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Source image alignment: The byte alignment requirement for a pixel depends on
|
||||
the specific pixel format. Both buffer address and buffer stride must be
|
||||
aligned. As general rule, the alignment is set to 16 pixels. This makes the
|
||||
buffer address alignment to be 32 bytes for RGB565 and 64 bytes for ARGB8888.
|
||||
- For pixel engine (PE) destination, the alignment should be 64 bytes for all
|
||||
tiled (4x4) buffer layouts. The pixel engine has no additional alignment
|
||||
requirement for linear buffer layouts (:c:macro:`VG_LITE_LINEAR`).
|
||||
|
||||
|
||||
Project setup:
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- Add VGLite related source files (and corresponding headers if available) to
|
||||
project:
|
||||
|
||||
- "src/draw/nxp/vglite/lv_draw_buf_vglite.c": draw buffer callbacks
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_arc.c": draw arc
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_border.c": draw border
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_fill.c": fill area
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_img.c": blit image (w/ optional recolor or transformation)
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_label.c": draw label
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_layer.c": layer blending
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_line.c": draw line
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite_triangle.c": draw triangle
|
||||
- "src/draw/nxp/vglite/lv_draw_vglite.c": draw unit initialization
|
||||
- "src/draw/nxp/vglite/lv_vglite_buf.c": init/get vglite buffer
|
||||
- "src/draw/nxp/vglite/lv_vglite_matrix.c": set vglite matrix
|
||||
- "src/draw/nxp/vglite/lv_vglite_path.c": create vglite path data
|
||||
- "src/draw/nxp/vglite/lv_vglite_utils.c": function helpers
|
||||
224
docs/details/integration/chip/renesas.rst
Normal file
224
docs/details/integration/chip/renesas.rst
Normal file
@@ -0,0 +1,224 @@
|
||||
.. _renesas:
|
||||
|
||||
=======
|
||||
Renesas
|
||||
=======
|
||||
|
||||
`Renesas <https://renesas.com/>`__ is an official partner of LVGL. Therefore, LVGL contains built-in support for
|
||||
`Dave2D <https://www.renesas.com/document/mas/tes-dave2d-driver-documentation>`__ (the GPU of Renesas) and we also maintain
|
||||
ready-to-use Renesas projects.
|
||||
|
||||
|
||||
Dave2D
|
||||
------
|
||||
|
||||
Dave2D is capable of accelerating most of the drawing operations of LVGL:
|
||||
|
||||
- Rectangle drawing, even with gradients
|
||||
- Image drawing, scaling, and rotation
|
||||
- Letter drawing
|
||||
- Triangle drawing
|
||||
- Line drawing
|
||||
|
||||
|
||||
As Dave2D works in the background, the CPU is free for other tasks. In practice, during rendering, Dave2D can reduce the CPU usage by
|
||||
half or to one-third, depending on the application.
|
||||
|
||||
|
||||
GLCDC
|
||||
-----
|
||||
|
||||
GLCDC is a multi-stage graphics output peripheral available in several Renesas MCUs. It is able to drive LCD panels via a highly
|
||||
configurable RGB interface.
|
||||
|
||||
More info can be found at the :ref:`driver's page<renesas_glcdc>`.
|
||||
|
||||
|
||||
Supported boards
|
||||
----------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 30 30 30
|
||||
|
||||
* -
|
||||
- **EK-RA8D1**
|
||||
- **EK-RA6M3G**
|
||||
- **RX72N Envision Kit**
|
||||
* - CPU
|
||||
- 480MHz, Arm Cortex-M85 core
|
||||
- 120MHz, Arm Cortex-M4 core
|
||||
- 240MHz, Renesas RXv3 core
|
||||
* - Memory
|
||||
-
|
||||
| 1MB internal, 64MB external SDRAM
|
||||
| 2MB internal, 64MB External Octo-SPI Flash
|
||||
-
|
||||
| 640kB internal SRAM
|
||||
| 2MB internal, 32MB external QSPI Flash
|
||||
-
|
||||
| 1MB internal SRAM
|
||||
| 4MB internal, 32MB external QSPI Flash
|
||||
* - Display
|
||||
-
|
||||
| 4.5”
|
||||
| 480x854
|
||||
| 2-lane MIPI
|
||||
-
|
||||
| 4.3”
|
||||
| 480x272
|
||||
| Parallel RGB565
|
||||
-
|
||||
| 4.3”
|
||||
| 480x272
|
||||
| Parallel RGB565
|
||||
* - `Board <https://lvgl.io/boards>`__ video
|
||||
- .. raw:: html
|
||||
|
||||
<iframe width="320" height="180" src="https://www.youtube.com/embed/WkJPB8wto_U" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||
|
||||
- .. raw:: html
|
||||
|
||||
<iframe width="320" height="180" src="https://www.youtube.com/embed/0kar4Ee3Qic" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||
|
||||
- .. raw:: html
|
||||
|
||||
<iframe width="320" height="180" src="https://www.youtube.com/embed/__56v8DsfH0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||
|
||||
* - Links
|
||||
- `Demo repository for EK-RA8D1 <https://github.com/lvgl/lv_port_renesas_ek-ra8d1>`__
|
||||
- `Demo repository for EK-RA6M3G <https://github.com/lvgl/lv_port_renesas_ek-ra6m3g>`__
|
||||
- `Demo repository for RX72N Envision Kit <https://github.com/lvgl/lv_port_renesas_rx72n-envision-kit>`__
|
||||
|
||||
|
||||
Get started with the Renesas ecosystem
|
||||
--------------------------------------
|
||||
|
||||
.. |img_debug_btn| image:: /misc/renesas/debug_btn.png
|
||||
:alt: Debug button
|
||||
|
||||
.. dropdown:: RA Family
|
||||
|
||||
- The official IDE of Renesas is called e² studio. As it's Eclipse-based, it runs on Windows, Linux, and Mac as well.
|
||||
The RA family requires the latest version with FSP 5.3. It can be downloaded `here <https://www.renesas.com/us/en/software-tool/flexible-software-package-fsp>`__.
|
||||
- JLink is used for debugging, it can be downloaded `here <https://www.segger.com/downloads/jlink/>`__.
|
||||
- Clone the ready-to-use repository for your selected board:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://github.com/lvgl/lv_port_renesas_ek-ra8d1.git --recurse-submodules
|
||||
|
||||
|
||||
Downloading the `.zip` from GitHub doesn't work as it doesn't download the submodules.
|
||||
- Open e² studio, go to ``File`` -> ``Import project`` and select ``General`` / ``Existing projects into workspace``
|
||||
- Browse the cloned folder and press ``Finish``.
|
||||
- Double click on ``configuration.xml``. This will activate the `Configuration Window`.
|
||||
|
||||
Renesas' Flexible Software Package (FSP) incudes BSP and HAL layer support extended with multiple RTOS variants and other middleware stacks.
|
||||
The components will be available via code generation, including the entry point of *"main.c"*.
|
||||
|
||||
Press ``Generate Project Content`` in the top right corner.
|
||||
|
||||
.. image:: /misc/renesas/generate.png
|
||||
:alt: Code generation with FSP
|
||||
|
||||
- Build the project by pressing ``Ctrl`` + ``Alt`` + ``B``
|
||||
- Click the Debug button (|img_debug_btn|). If prompted with `Debug Configurations`, on the `Debugger` tab select the ``J-Link ARM`` as `Debug hardware` and the proper IC as `Target Device`:
|
||||
|
||||
- ``R7FA8D1BH`` for EK-RA8D1
|
||||
|
||||
.. image:: /misc/renesas/debug_ra8.png
|
||||
:alt: Debugger parameters for RA8
|
||||
|
||||
- ``R7FA6M3AH`` for EK-RA6M3G
|
||||
|
||||
.. image:: /misc/renesas/debug_ra6.png
|
||||
:alt: Debugger parameters for RA6
|
||||
|
||||
.. note::
|
||||
On EK-RA8D1 boards, the ``SW1`` DIP switch (middle of the board) 7 should be ON, all others are OFF.
|
||||
|
||||
.. dropdown:: RX Family
|
||||
|
||||
- The official IDE of Renesas is called e² studio. As it's Eclipse-based, it runs on Windows, Linux, and Mac as well.
|
||||
It can be downloaded `here <https://www.renesas.com/us/en/software-tool/e-studio>`__.
|
||||
- Download and install the required driver for the debugger
|
||||
|
||||
- for Windows: `64 bit here <https://www.renesas.com/us/en/document/uid/usb-driver-renesas-mcu-tools-v27700-64-bit-version-windows-os?r=488806>`__
|
||||
and `32 bit here <https://www.renesas.com/us/en/document/uid/usb-driver-renesas-mcu-toolse2e2-liteie850ie850apg-fp5-v27700for-32-bit-version-windows-os?r=488806>`__
|
||||
- for Linux: `here <https://www.renesas.com/us/en/document/swo/e2-emulator-e2-emulator-lite-linux-driver?r=488806>`__
|
||||
|
||||
- RX72 requires an external compiler for the RXv3 core. A free and open-source version is available
|
||||
`here <https://llvm-gcc-renesas.com/rx-download-toolchains/>`__ after a registration.
|
||||
|
||||
The compiler must be activated in e² studio:
|
||||
|
||||
- Go to go to ``Help`` -> ``Add Renesas Toolchains``
|
||||
- Press the ``Add...`` button
|
||||
- Browse the installation folder of the toolchain
|
||||
|
||||
<br/>
|
||||
|
||||
.. image:: /misc/renesas/toolchains.png
|
||||
:alt: Toolchains
|
||||
|
||||
- Clone the ready-to-use `lv_port_renesas_rx72n-envision-kit <https://github.com/lvgl/lv_port_renesas_rx72n-envision-kit.git>`__ repository:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://github.com/lvgl/lv_port_renesas_rx72n-envision-kit.git --recurse-submodules
|
||||
|
||||
|
||||
Downloading the `.zip` from GitHub doesn't work as it doesn't download the submodules.
|
||||
|
||||
- Open e² studio, go to ``File`` -> ``Import project`` and select ``General`` / ``Existing projects into workspace``
|
||||
- Select the cloned folder and press ``Finish``.
|
||||
- Double click on ``RX72N_EnVision_LVGL.scfg``. This will activate the `Configuration Window`.
|
||||
|
||||
Renesas' Smart Configurator (SMC) incudes BSP and HAL layer support extended with multiple RTOS variants and other middleware stacks.
|
||||
The components will be available via code generation, including the entry point of the application.
|
||||
|
||||
Press ``Generate Code`` in the top right corner.
|
||||
|
||||
.. image:: /misc/renesas/generate_smc.png
|
||||
:alt: Code generation with SMC
|
||||
|
||||
- Build the project by pressing ``Ctrl`` + ``Alt`` + ``B``
|
||||
- Click the Debug button (|img_debug_btn|). If prompted with `Debug Configurations`, on the `Debugger` tab select the ``E2 Lite``
|
||||
as `Debug hardware` and ``R5F572NN`` as `Target Device`:
|
||||
|
||||
.. image:: /misc/renesas/debug_rx72.png
|
||||
:alt: Debugger parameters for RX72
|
||||
|
||||
.. note::
|
||||
Make sure that both channels of ``SW1`` DIP switch (next to ``ECN1``) are OFF.
|
||||
|
||||
|
||||
Modify the project
|
||||
------------------
|
||||
|
||||
|
||||
Open a demo
|
||||
~~~~~~~~~~~
|
||||
|
||||
The entry point of the main task is contained in ``src/LVGL_thread_entry.c`` in all 3 projects.
|
||||
|
||||
You can disable the LVGL demos (or just comment them out) and call some ``lv_example_...()`` functions, or add your custom code.
|
||||
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
``src/lv_conf.h`` contains the most important settings for LVGL. Namely:
|
||||
|
||||
- :c:macro:`LV_COLOR_DEPTH` to set LVGL's default color depth
|
||||
- :c:macro:`LV_MEM_SIZE` to set the maximum RAM available for LVGL
|
||||
- :c:macro:`LV_USE_DAVE2D` to enable the GPU
|
||||
|
||||
|
||||
Hardware and software components can be modified in a visual way using the `Configuration Window`.
|
||||
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
In case of any problems or questions open an issue in the corresponding repository.
|
||||
295
docs/details/integration/chip/stm32.rst
Normal file
295
docs/details/integration/chip/stm32.rst
Normal file
@@ -0,0 +1,295 @@
|
||||
=====
|
||||
STM32
|
||||
=====
|
||||
|
||||
LVGL Can be added to `STM32CubeIDE <https://www.st.com/en/development-tools/stm32cubeide.html>`__
|
||||
in a similar fashion to any other Eclipse-based IDE.
|
||||
|
||||
|
||||
Including LVGL in a Project
|
||||
---------------------------
|
||||
|
||||
- Create or open a project in STM32CubeIDE.
|
||||
- Copy the entire LVGL folder to *[project_folder]/Drivers/lvgl*.
|
||||
- In the STM32CubeIDE **Project Explorer** pane: right click on the
|
||||
LVGL folder that you copied (you may need to refresh the view first
|
||||
before it will appear), and select **Add/remove include path…**. If
|
||||
this doesn't appear, or doesn't work, you can review your project
|
||||
include paths under the **Project** -> **Properties** menu, and then
|
||||
navigating to **C/C++ Build** -> **Settings** -> **Include paths**, and
|
||||
ensuring that the LVGL directory is listed.
|
||||
|
||||
Now that the source files are included in your project, follow the instructions to
|
||||
:ref:`add_lvgl_to_your_project` and to create the ``lv_conf.h`` file, and
|
||||
initialise the display.
|
||||
|
||||
|
||||
Bare Metal Example
|
||||
------------------
|
||||
|
||||
A minimal example using STM32CubeIDE, and HAL. \* When setting up
|
||||
**Pinout and Configuration** using the **Device Configuration Tool**,
|
||||
select **System Core** -> **SYS** and ensure that **Timebase Source** is
|
||||
set to **SysTick**. \* Configure any other peripherals (including the
|
||||
LCD panel), and initialise them in *main.c*. \* ``#include "lvgl.h"`` in
|
||||
the *main.c* file. \* Create some frame buffer(s) as global variables:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Frame buffers
|
||||
* Static or global buffer(s). The second buffer is optional
|
||||
* TODO: Adjust color format and choose buffer size. DISPLAY_WIDTH * 10 is one suggestion. */
|
||||
#define BYTES_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565)) /* will be 2 for RGB565 */
|
||||
#define BUFF_SIZE (DISPLAY_WIDTH * 10 * BYTES_PER_PIXEL)
|
||||
static uint8_t buf_1[BUFF_SIZE];
|
||||
static uint8_t buf_2[BUFF_SIZE];
|
||||
|
||||
- In your ``main()`` function, after initialising your CPU,
|
||||
peripherals, and LCD panel, call :cpp:func:`lv_init` to initialise LVGL.
|
||||
You can then create the display driver using
|
||||
:cpp:func:`lv_display_create`, and register the frame buffers using
|
||||
:cpp:func:`lv_display_set_buffers`.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
//Initialise LVGL UI library
|
||||
lv_init();
|
||||
|
||||
lv_display_t * disp = lv_display_create(WIDTH, HEIGHT); /* Basic initialization with horizontal and vertical resolution in pixels */
|
||||
lv_display_set_flush_cb(disp, my_flush_cb); /* Set a flush callback to draw to the display */
|
||||
lv_display_set_buffers(disp, buf_1, buf_2, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL); /* Set an initialized buffer */
|
||||
|
||||
- Create some dummy Widgets to test the output:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Change Active Screen's background color */
|
||||
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
|
||||
|
||||
/* Create a spinner */
|
||||
lv_obj_t * spinner = lv_spinner_create(lv_screen_active(), 1000, 60);
|
||||
lv_obj_set_size(spinner, 64, 64);
|
||||
lv_obj_align(spinner, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
|
||||
|
||||
- Add a call to :cpp:func:`lv_timer_handler` inside your ``while(1)`` loop:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Infinite loop */
|
||||
while (1)
|
||||
{
|
||||
lv_timer_handler();
|
||||
HAL_Delay(5);
|
||||
}
|
||||
|
||||
|
||||
- Add a call to :cpp:func:`lv_tick_inc` inside the :cpp:func:`SysTick_Handler` function. Open the *stm32xxxx_it.c*
|
||||
file (the name will depend on your specific MCU), and update the :cpp:func:`SysTick_Handler` function:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||
|
||||
HAL_SYSTICK_IRQHandler();
|
||||
lv_tick_inc(1);
|
||||
#ifdef USE_RTOS_SYSTICK
|
||||
osSystickHandler();
|
||||
#endif
|
||||
|
||||
/* USER CODE END SysTick_IRQn 0 */
|
||||
HAL_IncTick();
|
||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 1 */
|
||||
}
|
||||
|
||||
|
||||
- Finally, write the callback function, ``my_flush_cb``, which will send the display buffer to your LCD panel. Below is
|
||||
one example, but it will vary depending on your setup.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void my_flush_cb(lv_display_t * disp, const lv_area_t * area, lv_color_t * color_p)
|
||||
{
|
||||
//Set the drawing region
|
||||
set_draw_window(area->x1, area->y1, area->x2, area->y2);
|
||||
|
||||
int height = area->y2 - area->y1 + 1;
|
||||
int width = area->x2 - area->x1 + 1;
|
||||
|
||||
//We will do the SPI write manually here for speed
|
||||
HAL_GPIO_WritePin(DC_PORT, DC_PIN, GPIO_PIN_SET);
|
||||
//CS low to begin data
|
||||
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
|
||||
|
||||
//Write colour to each pixel
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
uint16_t color_full = (color_p->red << 11) | (color_p->green << 5) | (color_p->blue);
|
||||
parallel_write(color_full);
|
||||
|
||||
color_p++;
|
||||
}
|
||||
|
||||
//Return CS to high
|
||||
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
|
||||
|
||||
/* IMPORTANT!!!
|
||||
* Inform the graphics library that you are ready with the flushing */
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
|
||||
FreeRTOS Example
|
||||
----------------
|
||||
|
||||
A minimal example using STM32CubeIDE, HAL, and CMSISv1 (FreeRTOS).
|
||||
*Note that we have not used Mutexes in this example, however LVGL is* **NOT**
|
||||
*thread safe and so Mutexes should be used*. See: :ref:`threading`
|
||||
\* ``#include "lvgl.h"`` \* Create your frame buffer(s) as global variables:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Frame buffers
|
||||
* Static or global buffer(s). The second buffer is optional */
|
||||
#define BYTES_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565)) /* will be 2 for RGB565 */
|
||||
/* TODO: Declare your own BUFF_SIZE appropriate to your system. */
|
||||
static lv_color_t buf_1[BUFF_SIZE];
|
||||
#define BUFF_SIZE (DISPLAY_WIDTH * 10 * BYTES_PER_PIXEL)
|
||||
static uint8_t buf_1[BUFF_SIZE];
|
||||
static lv_color_t buf_2[BUFF_SIZE];
|
||||
|
||||
- In your ``main`` function, after your peripherals (SPI, GPIOs, LCD
|
||||
etc) have been initialised, initialise LVGL using :cpp:func:`lv_init`,
|
||||
create a new display driver using :cpp:func:`lv_display_create`, and
|
||||
register the frame buffers using :cpp:func:`lv_display_set_buffers`.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Initialise LVGL UI library */
|
||||
lv_init();
|
||||
lv_display_t *display = lv_display_create(WIDTH, HEIGHT); /* Create the display */
|
||||
lv_display_set_flush_cb(display, my_flush_cb); /* Set a flush callback to draw to the display */
|
||||
lv_display_set_buffers(disp, buf_1, buf_2, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL); /* Set an initialized buffer */
|
||||
|
||||
/* Register the touch controller with LVGL - Not included here for brevity. */
|
||||
|
||||
|
||||
- Create some dummy Widgets to test the output:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Change Active Screen's background color */
|
||||
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
|
||||
|
||||
/* Create a spinner */
|
||||
lv_obj_t * spinner = lv_spinner_create(lv_screen_active(), 1000, 60);
|
||||
lv_obj_set_size(spinner, 64, 64);
|
||||
lv_obj_align(spinner, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
|
||||
- Create two threads to call :cpp:func:`lv_timer_handler`, and
|
||||
:cpp:func:`lv_tick_inc`.You will need two ``osThreadId`` handles for
|
||||
CMSISv1. These don't strictly have to be globally accessible in this
|
||||
case, however STM32Cube code generation does by default. If you are
|
||||
using CMSIS and STM32Cube code generation it should look something
|
||||
like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
//Thread Handles
|
||||
osThreadId lvgl_tickHandle;
|
||||
osThreadId lvgl_timerHandle;
|
||||
|
||||
/* definition and creation of lvgl_tick */
|
||||
osThreadDef(lvgl_tick, LVGLTick, osPriorityNormal, 0, 1024);
|
||||
lvgl_tickHandle = osThreadCreate(osThread(lvgl_tick), NULL);
|
||||
|
||||
//LVGL update timer
|
||||
osThreadDef(lvgl_timer, LVGLTimer, osPriorityNormal, 0, 1024);
|
||||
lvgl_timerHandle = osThreadCreate(osThread(lvgl_timer), NULL);
|
||||
|
||||
- And create the thread functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* LVGL timer for tasks. */
|
||||
void LVGLTimer(void const * argument)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
lv_timer_handler();
|
||||
osDelay(20);
|
||||
}
|
||||
}
|
||||
/* LVGL tick source */
|
||||
void LVGLTick(void const * argument)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
lv_tick_inc(10);
|
||||
osDelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
- Finally, create the ``my_flush_cb`` function to output the frame
|
||||
buffer to your LCD. The specifics of this function will vary
|
||||
depending on which MCU features you are using. Below is an example
|
||||
for a typical MCU interface.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void my_flush_cb(lv_display_t * display, const lv_area_t * area, uint8_t * px_map);
|
||||
{
|
||||
uint16_t * color_p = (uint16_t *)px_map;
|
||||
|
||||
//Set the drawing region
|
||||
set_draw_window(area->x1, area->y1, area->x2, area->y2);
|
||||
|
||||
int height = area->y2 - area->y1 + 1;
|
||||
int width = area->x2 - area->x1 + 1;
|
||||
|
||||
//Begin SPI Write for DATA
|
||||
HAL_GPIO_WritePin(DC_PORT, DC_PIN, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
|
||||
|
||||
//Write colour to each pixel
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
parallel_write(color_p);
|
||||
color_p++;
|
||||
}
|
||||
|
||||
//Return CS to high
|
||||
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
|
||||
|
||||
/* IMPORTANT!!!
|
||||
* Inform the graphics library that you are ready with the flushing */
|
||||
lv_display_flush_ready(display);
|
||||
}
|
||||
|
||||
.. _dma2d:
|
||||
|
||||
DMA2D Support
|
||||
-------------
|
||||
|
||||
LVGL supports DMA2D - a feature of some STM32 MCUs which can improve performance
|
||||
when blending fills and images. Some STM32 product lines such as STM32F4 STM32F7, STM32L4,
|
||||
STM32U5, and STM32H7 include models with DMA2D support.
|
||||
|
||||
LVGL's integration with DMA2D can be enabled by setting ``LV_USE_DRAW_DMA2D``
|
||||
to ``1`` in ``lv_conf.h``
|
||||
|
||||
With ``LV_USE_DRAW_DMA2D_INTERRUPT`` set to ``0`` and ``LV_USE_OS`` set to ``LV_OS_NONE``,
|
||||
DMA2D will draw some fills and images concurrently with the software render where
|
||||
possible. If ``LV_USE_DRAW_DMA2D_INTERRUPT`` is set to ``1`` and ``LV_USE_OS`` set to
|
||||
``LV_OS_FREERTOS`` (or another OS) the main difference will be that the core will idle
|
||||
instead of "busywait" while waiting for a DMA2D transfer to complete.
|
||||
|
||||
If ``LV_USE_DRAW_DMA2D_INTERRUPT`` is enabled then you are required to call
|
||||
:cpp:expr:`lv_draw_dma2d_transfer_complete_interrupt_handler` whenever the DMA2D
|
||||
"transfer complete" global interrupt is received.
|
||||
|
||||
If your STM device has a Nema GPU, you can use the :ref:`Nema GFX renderer <stm32_nema_gfx>` instead.
|
||||
127
docs/details/integration/driver/X11.rst
Normal file
127
docs/details/integration/driver/X11.rst
Normal file
@@ -0,0 +1,127 @@
|
||||
=========================
|
||||
X11 Display/Inputs driver
|
||||
=========================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
| The **X11** display/input `driver <https://github.com/lvgl/lvgl/src/drivers/x11>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in an X11 desktop window.
|
||||
| It is an alternative to **Wayland**, **XCB**, **SDL** or **Qt**.
|
||||
|
||||
The main purpose for this driver is for testing/debugging the LVGL application in a **Linux** simulation window.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The X11 driver uses XLib to access the linux window manager.
|
||||
|
||||
1. Install XLib: ``sudo apt-get install libx11-6`` (should be installed already)
|
||||
2. Install XLib development package: ``sudo apt-get install libx11-dev``
|
||||
|
||||
|
||||
Configure X11 driver
|
||||
--------------------
|
||||
|
||||
1. Enable the X11 driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_X11 1
|
||||
|
||||
2. Optional configuration options:
|
||||
- Direct Exit
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_X11_DIRECT_EXIT 1 /* preferred default - ends the application automatically if last window has been closed */
|
||||
// or
|
||||
#define LV_X11_DIRECT_EXIT 0 /* application is responsible for ending the application (e.g. by own LV_EVENT_DELETE handler */
|
||||
|
||||
|
||||
- Double buffering
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_X11_DOUBLE_BUFFER 1 /* preferred default */
|
||||
// or
|
||||
#define LV_X11_DOUBLE_BUFFER 0 /* not recommended */
|
||||
|
||||
- Render mode
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_X11_RENDER_MODE_PARTIAL 1 /* LV_DISPLAY_RENDER_MODE_PARTIAL, preferred default */
|
||||
// or
|
||||
#define LV_X11_RENDER_MODE_DIRECT 1 /* LV_DISPLAY_RENDER_MODE_DIRECT, not recommended for X11 driver */
|
||||
// or
|
||||
#define LV_X11_RENDER_MODE_DULL 1 /* LV_DISPLAY_RENDER_MODE_FULL, not recommended for X11 driver */
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
| The minimal initialisation opening a window and enabling keyboard/mouse support
|
||||
| (e.g. in main.c, LV_X11_DIRECT_EXIT must be 1):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
...
|
||||
|
||||
/* initialize X11 display driver */
|
||||
lv_display_t * disp = lv_x11_window_create("LVGL X11 Simulation", monitor_hor_res, monitor_ver_res);
|
||||
|
||||
/* initialize X11 input drivers (for keyboard, mouse & mousewheel) */
|
||||
lv_x11_inputs_create(disp, NULL);
|
||||
|
||||
...
|
||||
|
||||
while(true)
|
||||
{
|
||||
...
|
||||
|
||||
/* Periodically call the lv_timer handler */
|
||||
lv_timer_handler();
|
||||
}
|
||||
}
|
||||
|
||||
| Full initialisation with mouse pointer symbol and own application exit handling
|
||||
| (dependent on LV_X11_DIRECT_EXIT (can be 1 or 0))
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
bool terminated = false;
|
||||
|
||||
#if !LV_X11_DIRECT_EXIT
|
||||
static void on_close_cb(lv_event_t * e)
|
||||
{
|
||||
...
|
||||
|
||||
terminate = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
...
|
||||
|
||||
/* initialize X11 display driver */
|
||||
lv_display_t * disp = lv_x11_window_create("LVGL X11 Simulation", monitor_hor_res, monitor_ver_res);
|
||||
lv_display_add_event_cb(disp, on_close_cb, LV_EVENT_DELETE, disp);
|
||||
|
||||
/* initialize X11 input drivers (for keyboard, mouse & mousewheel) */
|
||||
LV_IMAGE_DECLARE(my_mouse_cursor_icon);
|
||||
lv_x11_inputs_create(disp, &my_mouse_cursor_icon);
|
||||
|
||||
#if !LV_X11_DIRECT_EXIT
|
||||
/* set optional window close callback to enable application cleanup and exit */
|
||||
lv_x11_window_set_close_cb(disp, on_close_cb, disp);
|
||||
#endif
|
||||
|
||||
...
|
||||
|
||||
while(!terminated)
|
||||
{
|
||||
...
|
||||
|
||||
/* Periodically call the lv_timer handler */
|
||||
lv_timer_handler();
|
||||
}
|
||||
}
|
||||
41
docs/details/integration/driver/display/fbdev.rst
Normal file
41
docs/details/integration/driver/display/fbdev.rst
Normal file
@@ -0,0 +1,41 @@
|
||||
========================
|
||||
Linux Framebuffer Driver
|
||||
========================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The Linux framebuffer (fbdev) is a linux subsystem used to display graphics. It is a hardware-independent API that gives user space software
|
||||
access to the framebuffer (the part of a computer's video memory containing a current video frame) using only the Linux kernel's own basic
|
||||
facilities and its device file system interface, avoiding the need for libraries that implement video drivers in user space.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
Your system has a framebuffer device configured (usually under ``/dev/fb0``).
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the framebuffer driver support in lv_conf.h, by cmake compiler define or by KConfig. Additionally you may configure the rendering
|
||||
mode.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_LINUX_FBDEV 1
|
||||
#define LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To set up a framebuffer-based display, first create a display with ``lv_linux_fbdev_create``. Afterwards set the framebuffer device
|
||||
node on the display (usually this is ``/dev/fb0``).
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_display_t *disp = lv_linux_fbdev_create();
|
||||
lv_linux_fbdev_set_file(disp, "/dev/fb0");
|
||||
|
||||
If your screen stays black or only draws partially, you can try enabling direct rendering via ``LV_DISPLAY_RENDER_MODE_DIRECT``. Additionally,
|
||||
you can activate a force refresh mode with ``lv_linux_fbdev_set_force_refresh(true)``. This usually has a performance impact though and shouldn't
|
||||
be enabled unless really needed.
|
||||
210
docs/details/integration/driver/display/gen_mipi.rst
Normal file
210
docs/details/integration/driver/display/gen_mipi.rst
Normal file
@@ -0,0 +1,210 @@
|
||||
=================================================
|
||||
Generic MIPI DCS compatible LCD Controller driver
|
||||
=================================================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
From the `Wikipedia <https://en.wikipedia.org/wiki/MIPI_Alliance>`__:
|
||||
|
||||
`MIPI Alliance <https://www.mipi.org/>`__ is a global business alliance that develops technical specifications
|
||||
for the mobile ecosystem, particularly smart phones but including mobile-influenced industries. MIPI was founded in 2003 by Arm, Intel, Nokia, Samsung,
|
||||
STMicroelectronics and Texas Instruments.
|
||||
|
||||
MIPI Alliance published a series of specifications related to display devices, including DBI (Display Bus Interface), DSI (Display Serial Interface) and DCS
|
||||
(Display Command Set). Usually when one talks about a MIPI-compatible display, one thinks of a device with a DSI serial interface. However, the Display Bus Interface specification
|
||||
includes a number of other, legacy interfaces, like SPI serial, or i8080-compatible parallel interface, which are often used to interface LCD displays to lower-end microcontrollers.
|
||||
Furthermore, the DCS specification contains a standard command set, which is supported by a large number of legacy TFT LCD controllers, including the popular Sitronix
|
||||
(ST7735, ST7789, ST7796) and Ilitek (ILI9341) SOCs. These commands provide a common interface to configure display orientation, color resolution, various power modes, and provide generic video memory access. On top
|
||||
of that standard command set each LCD controller chip has a number of vendor-specific commands to configure voltage generator levels, timings, or gamma curves.
|
||||
|
||||
.. note::
|
||||
|
||||
It is important to understand that this generic MIPI LCD driver is not a hardware driver for displays with the DSI ("MIPI") serial interface. Instead, it implements the MIPI DCS command set used in many LCD controllers with an SPI or i8080 bus, and provides a common framework for chip-specific display controllers.
|
||||
|
||||
.. tip::
|
||||
Although this is a generic driver, it can be used to support compatible chips which do not have a specific driver.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
There are no prerequisites.
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the generic MIPI LCD driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_GENERIC_MIPI 1
|
||||
|
||||
.. note::
|
||||
:c:macro:`LV_USE_GENERIC_MIPI` is automatically enabled when a compatible driver is enabled.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
You need to implement two platform-dependent functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
|
||||
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
|
||||
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
The only difference between the :cpp:func:`my_lcd_send_cmd()` and :cpp:func:`my_lcd_send_color()` functions is that :cpp:func:`my_lcd_send_cmd()` is used to send short commands and it is expected
|
||||
complete the transaction when it returns (in other words, it should be blocking), while :cpp:func:`my_lcd_send_color()` is only used to send pixel data, and it is recommended to use
|
||||
DMA to transmit data in the background. More sophisticated methods can be also implemented, like queuing transfers and scheduling them in the background.
|
||||
|
||||
Please note that while display flushing is handled by the driver, it is the user's responsibility to call :cpp:func:`lv_display_flush_ready()`
|
||||
when the color transfer completes. In case of a DMA transfer this is usually done in a transfer ready callback.
|
||||
|
||||
.. note::
|
||||
While it is acceptable to use a blocking implementation for the pixel transfer as well, performance will suffer.
|
||||
|
||||
.. tip::
|
||||
Care must be taken to avoid sending a command while there is an active transfer going on in the background. It is the user's responsibility to implement this either
|
||||
by polling the hardware, polling a global variable (which is reset at the end of the transfer), or by using a semaphore or other locking mechanism.
|
||||
|
||||
Please also note that the driver does not handle the draw buffer allocation, because this may be platform-dependent, too. Thus you need to allocate the buffers and assign them
|
||||
to the display object as usual by calling :cpp:func:`lv_display_set_buffers()`.
|
||||
|
||||
The driver can be used to create multiple displays. In such a configuration the callbacks must be able to distinguish between the displays. Usually one would
|
||||
implement a separate set of callbacks for each display. Also note that the user must take care of arbitrating the bus when multiple devices are connected to it.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. note::
|
||||
You can find a step-by-step guide and the actual implementation of the callbacks on an STM32F746 using STM32CubeIDE and the ST HAL libraries here: :ref:`lcd_stm32_guide`
|
||||
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "src/drivers/display/st7789/lv_st7789.h"
|
||||
|
||||
#define LCD_H_RES 240
|
||||
#define LCD_V_RES 320
|
||||
#define LCD_BUF_LINES 60
|
||||
|
||||
lv_display_t *my_disp;
|
||||
|
||||
...
|
||||
|
||||
/* Initialize LCD I/O bus, reset LCD */
|
||||
static int32_t my_lcd_io_init(void)
|
||||
{
|
||||
...
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/* Send command to the LCD controller */
|
||||
static void my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
/* Send pixel data to the LCD controller */
|
||||
static void my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
...
|
||||
|
||||
/* Initialize LVGL */
|
||||
lv_init();
|
||||
|
||||
/* Initialize LCD bus I/O */
|
||||
if (my_lcd_io_init() != 0)
|
||||
return;
|
||||
|
||||
/* Create the LVGL display object and the LCD display driver */
|
||||
my_disp = lv_lcd_generic_mipi_create(LCD_H_RES, LCD_V_RES, LV_LCD_FLAG_NONE, my_lcd_send_cmd, my_lcd_send_color);
|
||||
|
||||
/* Set display orientation to landscape */
|
||||
lv_display_set_rotation(my_disp, LV_DISPLAY_ROTATION_90);
|
||||
|
||||
/* Configure draw buffers, etc. */
|
||||
uint8_t * buf1 = NULL;
|
||||
uint8_t * buf2 = NULL;
|
||||
|
||||
uint32_t buf_size = LCD_H_RES * LCD_BUF_LINES * lv_color_format_get_size(lv_display_get_color_format(my_disp));
|
||||
|
||||
buf1 = lv_malloc(buf_size);
|
||||
if(buf1 == NULL) {
|
||||
LV_LOG_ERROR("display draw buffer malloc failed");
|
||||
return;
|
||||
}
|
||||
/* Allocate secondary buffer if needed */
|
||||
...
|
||||
|
||||
lv_display_set_buffers(my_disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
ui_init(my_disp);
|
||||
|
||||
while(true) {
|
||||
...
|
||||
|
||||
/* Periodically call the lv_timer handler */
|
||||
lv_timer_handler();
|
||||
}
|
||||
}
|
||||
|
||||
Advanced topics
|
||||
---------------
|
||||
|
||||
Create flags
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The third argument of the :cpp:func:`lv_lcd_generic_mipi_create()` function is a flag array. This can be used to configure the orientation and RGB ordering of the panel if the
|
||||
default settings do not work for you. In particular, the generic MIPI driver accepts the following flags:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
LV_LCD_FLAG_NONE
|
||||
LV_LCD_FLAG_MIRROR_X
|
||||
LV_LCD_FLAG_MIRROR_Y
|
||||
LV_LCD_FLAG_BGR
|
||||
|
||||
You can pass multiple flags by ORing them together, e.g., :c:macro:`LV_LCD_FLAG_MIRROR_X` ``|`` :c:macro:`LV_LCD_FLAG_BGR`.
|
||||
|
||||
Custom command lists
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While the chip-specific drivers do their best to initialize the LCD controller correctly, it is possible, that different TFT panels need different configurations.
|
||||
In particular a correct gamma setup is crucial for good color reproduction. Unfortunately, finding a good set of parameters is not easy. Usually the manufacturer
|
||||
of the panel provides some example code with recommended register settings.
|
||||
|
||||
You can use the ``my_lcd_send_cmd()`` function to send an arbitrary command to the LCD controller. However, to make it easier to send a large number of parameters
|
||||
the generic MIPI driver supports sending a custom command list to the controller. The commands must be put into a 'uint8_t' array:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const uint8_t init_cmd_list[] = {
|
||||
<command 1>, <number of parameters>, <parameter 1>, ... <parameter N>,
|
||||
<command 2>, <number of parameters>, <parameter 1>, ... <parameter N>,
|
||||
...
|
||||
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF /* terminate list: this is required! */
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
lv_lcd_generic_mipi_send_cmd_list(my_disp, init_cmd_list);
|
||||
|
||||
You can add a delay between the commands by using the pseudo-command ``LV_LCD_CMD_DELAY_MS``, which must be followed by the delay given in 10ms units.
|
||||
To terminate the command list you must use a delay with a value of ``LV_LCD_CMD_EOF``, as shown above.
|
||||
|
||||
See an actual example of sending a command list `here <https://github.com/lvgl/lvgl/src/drivers/display/st7789/lv_st7789.c>`__.
|
||||
73
docs/details/integration/driver/display/ili9341.rst
Normal file
73
docs/details/integration/driver/display/ili9341.rst
Normal file
@@ -0,0 +1,73 @@
|
||||
=============================
|
||||
ILI9341 LCD Controller driver
|
||||
=============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The `ILI9341 <https://www.buydisplay.com/download/ic/ILI9341.pdf>`__ is a 262,144-color single-chip SOC driver for a-TFT liquid crystal display with resolution of 240RGBx320
|
||||
dots, comprising a 720-channel source driver, a 320-channel gate driver, 172,800 bytes GRAM for graphic
|
||||
display data of 240RGBx320 dots, and power supply circuit.
|
||||
ILI9341 supports parallel 8-/9-/16-/18-bit data bus MCU interface, 6-/16-/18-bit data bus RGB interface and
|
||||
3-/4-line serial peripheral interface (SPI).
|
||||
|
||||
The ILI9341 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/ili9341>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
|
||||
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
There are no prerequisites.
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the ILI9341 driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_ILI9341 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
You need to implement two platform-dependent functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
|
||||
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
|
||||
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
To create an ILI9341-based display use the function
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/**
|
||||
* Create an LCD display with ILI9341 driver
|
||||
* @param hor_res horizontal resolution
|
||||
* @param ver_res vertical resolution
|
||||
* @param flags default configuration settings (mirror, RGB ordering, etc.)
|
||||
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
|
||||
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
|
||||
* @return pointer to the created display
|
||||
*/
|
||||
lv_display_t * lv_ili9341_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
|
||||
lv_ili9341_send_cmd_cb_t send_cmd_cb, lv_ili9341_send_color_cb_t send_color_cb);
|
||||
|
||||
|
||||
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
|
||||
.. note::
|
||||
|
||||
You can find a step-by-step guide and the actual implementation of the callbacks on an STM32F746 using STM32CubeIDE and the ST HAL libraries here: :ref:`lcd_stm32_guide`
|
||||
|
||||
16
docs/details/integration/driver/display/index.rst
Normal file
16
docs/details/integration/driver/display/index.rst
Normal file
@@ -0,0 +1,16 @@
|
||||
=======
|
||||
Display
|
||||
=======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
fbdev
|
||||
gen_mipi
|
||||
ili9341
|
||||
lcd_stm32_guide
|
||||
renesas_glcdc
|
||||
st_ltdc
|
||||
st7735
|
||||
st7789
|
||||
st7796
|
||||
320
docs/details/integration/driver/display/lcd_stm32_guide.rst
Normal file
320
docs/details/integration/driver/display/lcd_stm32_guide.rst
Normal file
@@ -0,0 +1,320 @@
|
||||
.. _lcd_stm32_guide:
|
||||
|
||||
=========================================================================
|
||||
Step-by-step Guide: How to use the LVGL v9 LCD drivers with STM32 devices
|
||||
=========================================================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This guide is intended to be a step-by-step instruction of how to configure the STM32Cube HAL with the new TFT-LCD display drivers introduced in LVGL v9.0. The example code has been tested on the STM32F746-based Nucleo-F746ZG board with an ST7789-based LCD panel connected via SPI. The application itself and the hardware configuration code were generated with the STM32CubeIDE 1.14.0 tool.
|
||||
|
||||
.. tip::
|
||||
ST Micro provide their own TFT-LCD drivers in their X-CUBE-DISPLAY Software Extension Package. While these drivers can be used with LVGL as well, the LVGL LCD drivers do not depend on this package.
|
||||
|
||||
The LVGL LCD drivers are meant as an alternative, simple to use API to implement LCD support for your LVGL-based project on any platform. Moreover, even in the initial release we support more LCD controllers than X-CUBE-DISPLAY currently provides, and we plan to add support for even more LCD controllers in the future.
|
||||
|
||||
Please note however, that – unlike X-CUBE-DISPLAY – the LVGL LCD drivers do not implement the communication part, whether SPI, parallel i8080 bus or other. It is the user's responsibility to implement – and optimize – these on their chosen platform. LVGL will only provide examples for the most popular platforms.
|
||||
|
||||
By following the steps you will have a fully functional program, which can be used as the foundation of your own LVGL-based project. If you are in a hurry and not interested in the details, you can find the final project `here <https://github.com/lvgl/lv_port_lcd_stm32>`__. You will only need to configure LVGL to use the driver corresponding to your hardware (if it is other than the ST7789), and implement the function ``ui_init()`` to create your widgets.
|
||||
|
||||
.. note::
|
||||
|
||||
This example is not meant as the best possible implementation, or the recommended solution. It relies solely on the HAL drivers provided by ST Micro, which favor portability over performance. Despite of this the performance is very good, thanks to the efficient, DMA-based implementation of the drivers.
|
||||
|
||||
.. note::
|
||||
|
||||
Although the example uses FreeRTOS, this is not a strict requirement with the LVGL LCD display drivers.
|
||||
|
||||
You can find the source code snippets of this guide in the `lv_port_lcd_stm32_template.c <https://github.com/lvgl/lvgl/examples/porting/lv_port_lcd_stm32_template.c>`__ example.
|
||||
|
||||
Hardware configuration
|
||||
----------------------
|
||||
|
||||
In this example we'll use the SPI1 peripheral to connect the microcontroller to the LCD panel. Besides the hardware-controlled SPI pins SCK and MOSI we need some additional output pins for the chip select, command/data select, and LCD reset:
|
||||
|
||||
==== ============= ======= ==========
|
||||
pin configuration LCD user label
|
||||
==== ============= ======= ==========
|
||||
PA4 GPIO_Output CS LCD_CS
|
||||
PA5 SPI1_SCK SCK --
|
||||
PA7 SPI1_MOSI SDI --
|
||||
PA15 GPIO_Output RESET LCD_RESET
|
||||
PB10 GPIO_Output DC LCD_DCX
|
||||
==== ============= ======= ==========
|
||||
|
||||
Step-by-step instructions
|
||||
-------------------------
|
||||
|
||||
#. Create new project in File/New/STM32 Project.
|
||||
#. Select target processor/board.
|
||||
#. Set project name and location.
|
||||
#. Set Targeted Project Type to STM32Cube and press Finish.
|
||||
#. Say "Yes" to Initialize peripherals with their default Mode? After the project is created, the configuration file (.ioc) is opened automatically.
|
||||
#. Switch to the Pinout & Configuration tab.
|
||||
#. In the System Core category switch to RCC.
|
||||
#. Set High Speed Clock to "BYPASS Clock Source", and Low Speed Clock to "Crystal/Ceramic Resonator".
|
||||
#. In the System Core category select SYS, and set Timebase Source to other than SysTick (in our example, TIM2).
|
||||
#. Switch to the Clock Configuration tab.
|
||||
#. Set the HCLK clock frequency to the maximum value (216 MHz for the STM32F746).
|
||||
#. Switch back to the Pinout & Configuration tab, and in the Middleware and Software Packs category select FREERTOS.
|
||||
#. Select Interface: CMSIS_V1.
|
||||
#. In the Advanced Settings tab enable USE_NEWLIB_REENTRANT. We are finished here.
|
||||
#. In the Pinout view configure PA5 as SPI1_SCK, PA7 as SPI1_MOSI (right click the pin and select the function).
|
||||
#. In the Pinout & Configuration/Connectivity category select SPI1.
|
||||
#. Set Mode to Transmit Only Master, and Hardware NSS Signal to Disable.
|
||||
#. In the Configuration subwindow switch to Parameter Settings.
|
||||
#. Set Frame Format to Motorola, Data Size to 8 Bits, First Bit to MSB First.
|
||||
#. Set the Prescaler to the maximum value according to the LCD controller’s datasheet (e.g., 15 MBits/s). Set CPOL/CPHA as required (leave as default).
|
||||
#. Set NSSP Mode to Disabled and NSS Signal Type to Software.
|
||||
#. In DMA Settings add a new Request for SPI1_TX (when using SPI1).
|
||||
#. Set Priority to Medium, Data Width to Half Word.
|
||||
#. In NVIC Settings enable SPI1 global interrupt.
|
||||
#. In GPIO Settings set SPI1_SCK to Pull-down and Very High output speed and set the User Label to ``LCD_SCK``.
|
||||
#. Set SPI1_MOSI to Pull-up and Very High, and name it ``LCD_SDI``.
|
||||
#. Select System Core/GPIO category. In the Pinout view configure additional pins for chip select, reset and command/data select. Name them ``LCD_CS``, ``LCD_RESET`` and ``LCD_DCX``, respectively. Configure them as GPIO Output. (In this example we will use PA4 for ``LCD_CS``, PA15 for ``LCD_RESET`` and PB10 for ``LCD_DCX``.)
|
||||
#. Set ``LCD_CS`` to No pull-up and no pull-down, Low level and Very High speed.
|
||||
#. Set ``LCD_RESET`` to Pull-up and High level.
|
||||
#. Set ``LCD_DCX`` to No pull-up and no pull-down, High level and Very High speed.
|
||||
#. Open the Project Manager tab, and select Advanced Settings. On the right hand side there is a Register Callback window. Select SPI and set it to ENABLE.
|
||||
#. We are ready with the hardware configuration. Save the configuration and let STM32Cube generate the source.
|
||||
#. In the project tree clone the LVGL repository into the Middlewares/Third_Party folder (this tutorial uses the release/v9.0 branch of LVGL):
|
||||
|
||||
.. code-block:: dosbatch
|
||||
|
||||
git clone https://github.com/lvgl/lvgl.git -b release/v9.0
|
||||
|
||||
#. Cloning should create an 'lvgl' subfolder inside the 'Third_Party' folder. From the 'lvgl' folder copy 'lv_conf_template.h' into the 'Middlewares' folder, and rename it to 'lv_conf.h'. Refresh the project tree.
|
||||
#. Open 'lv_conf.h', and in line 15 change ``#if 0`` to ``#if 1``.
|
||||
#. Search for the string ``LV_USE_ST7735``, and enable the appropriate LCD driver by setting its value to 1. This example uses the ST7789 driver:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_ST7789 1
|
||||
|
||||
#. Right click the folder 'Middlewares/Third_Party/lvgl/tests', select Resource Configurations/Exclude from Build..., check both Debug and Release, then press OK.
|
||||
#. Right click the project name and select "Properties". In the C/C++ Build/Settings panel select MCU GCC Compiler/Include paths. In the Configuration dropdown select [ All configurations ]. Add the following Include path:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
../Middlewares/Third_Party/lvgl
|
||||
|
||||
#. Open Core/Src/stm32xxx_it.c (the file name depends on the processor variation). Add 'lv_tick.h' to the Private includes section:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "./src/tick/lv_tick.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
#. Find the function ``TIM2_IRQHandler``. Add a call to ``lv_tick_inc()``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void TIM2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN TIM2_IRQn 0 */
|
||||
|
||||
/* USER CODE END TIM2_IRQn 0 */
|
||||
HAL_TIM_IRQHandler(&htim2);
|
||||
/* USER CODE BEGIN TIM2_IRQn 1 */
|
||||
lv_tick_inc(1);
|
||||
/* USER CODE END TIM2_IRQn 1 */
|
||||
}
|
||||
|
||||
|
||||
#. Save the file, then open Core/Src/main.c. Add the following lines to the Private includes (if your LCD uses other than the ST7789, replace the driver path and header with the appropriate one):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "lvgl.h"
|
||||
#include "./src/drivers/display/st7789/lv_st7789.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
#. Add the following lines to Private defines (change them according to your LCD specs):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LCD_H_RES 240
|
||||
#define LCD_V_RES 320
|
||||
#define BUS_SPI1_POLL_TIMEOUT 0x1000U
|
||||
|
||||
|
||||
#. Add the following lines to the Private variables:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
osThreadId LvglTaskHandle;
|
||||
lv_display_t *lcd_disp;
|
||||
volatile int lcd_bus_busy = 0;
|
||||
|
||||
#. Add the following line to the Private function prototypes:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void ui_init(lv_display_t *disp);
|
||||
void LVGL_Task(void const *argument);
|
||||
|
||||
#. Add the following lines after USER CODE BEGIN RTOS_THREADS:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
osThreadDef(LvglTask, LVGL_Task, osPriorityIdle, 0, 1024);
|
||||
LvglTaskHandle = osThreadCreate(osThread(LvglTask), NULL);
|
||||
|
||||
#. Copy and paste the hardware initialization and the transfer callback functions from the example code after USER CODE BEGIN 4:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
|
||||
void lcd_color_transfer_ready_cb(SPI_HandleTypeDef *hspi)
|
||||
{
|
||||
/* CS high */
|
||||
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
|
||||
lcd_bus_busy = 0;
|
||||
lv_display_flush_ready(lcd_disp);
|
||||
}
|
||||
|
||||
/* Initialize LCD I/O bus, reset LCD */
|
||||
static int32_t lcd_io_init(void)
|
||||
{
|
||||
/* Register SPI Tx Complete Callback */
|
||||
HAL_SPI_RegisterCallback(&hspi1, HAL_SPI_TX_COMPLETE_CB_ID, lcd_color_transfer_ready_cb);
|
||||
|
||||
/* reset LCD */
|
||||
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_RESET);
|
||||
HAL_Delay(100);
|
||||
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(100);
|
||||
|
||||
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET);
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/* Platform-specific implementation of the LCD send command function. In general this should use polling transfer. */
|
||||
static void lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
|
||||
{
|
||||
LV_UNUSED(disp);
|
||||
while (lcd_bus_busy); /* wait until previous transfer is finished */
|
||||
/* Set the SPI in 8-bit mode */
|
||||
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
HAL_SPI_Init(&hspi1);
|
||||
/* DCX low (command) */
|
||||
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET);
|
||||
/* CS low */
|
||||
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
|
||||
/* send command */
|
||||
if (HAL_SPI_Transmit(&hspi1, cmd, cmd_size, BUS_SPI1_POLL_TIMEOUT) == HAL_OK) {
|
||||
/* DCX high (data) */
|
||||
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET);
|
||||
/* for short data blocks we use polling transfer */
|
||||
HAL_SPI_Transmit(&hspi1, (uint8_t *)param, (uint16_t)param_size, BUS_SPI1_POLL_TIMEOUT);
|
||||
/* CS high */
|
||||
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
}
|
||||
|
||||
/* Platform-specific implementation of the LCD send color function. For better performance this should use DMA transfer.
|
||||
* In case of a DMA transfer a callback must be installed to notify LVGL about the end of the transfer.
|
||||
*/
|
||||
static void lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
|
||||
{
|
||||
LV_UNUSED(disp);
|
||||
while (lcd_bus_busy); /* wait until previous transfer is finished */
|
||||
/* Set the SPI in 8-bit mode */
|
||||
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
HAL_SPI_Init(&hspi1);
|
||||
/* DCX low (command) */
|
||||
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET);
|
||||
/* CS low */
|
||||
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
|
||||
/* send command */
|
||||
if (HAL_SPI_Transmit(&hspi1, cmd, cmd_size, BUS_SPI1_POLL_TIMEOUT) == HAL_OK) {
|
||||
/* DCX high (data) */
|
||||
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET);
|
||||
/* for color data use DMA transfer */
|
||||
/* Set the SPI in 16-bit mode to match endianness */
|
||||
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
|
||||
HAL_SPI_Init(&hspi1);
|
||||
lcd_bus_busy = 1;
|
||||
HAL_SPI_Transmit_DMA(&hspi1, param, (uint16_t)param_size / 2);
|
||||
/* NOTE: CS will be reset in the transfer ready callback */
|
||||
}
|
||||
}
|
||||
|
||||
#. Add the LVGL_Task() function. Replace the ``lv_st7789_create()`` call with the appropriate driver. You can change the default orientation by adjusting the parameter of ``lv_display_set_rotation()``. You will also need to create the display buffers here. This example uses a double buffering scheme with 1/10th size partial buffers. In most cases this is a good compromise between the required memory size and performance, but you are free to experiment with other settings.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void LVGL_Task(void const *argument)
|
||||
{
|
||||
/* Initialize LVGL */
|
||||
lv_init();
|
||||
|
||||
/* Initialize LCD I/O */
|
||||
if (lcd_io_init() != 0)
|
||||
return;
|
||||
|
||||
/* Create the LVGL display object and the LCD display driver */
|
||||
lcd_disp = lv_st7789_create(LCD_H_RES, LCD_V_RES, LV_LCD_FLAG_NONE, lcd_send_cmd, lcd_send_color);
|
||||
lv_display_set_rotation(lcd_disp, LV_DISPLAY_ROTATION_270);
|
||||
|
||||
/* Allocate draw buffers on the heap. In this example we use two partial buffers of 1/10th size of the screen */
|
||||
lv_color_t * buf1 = NULL;
|
||||
lv_color_t * buf2 = NULL;
|
||||
|
||||
uint32_t buf_size = LCD_H_RES * LCD_V_RES / 10 * lv_color_format_get_size(lv_display_get_color_format(lcd_disp));
|
||||
|
||||
buf1 = lv_malloc(buf_size);
|
||||
if(buf1 == NULL) {
|
||||
LV_LOG_ERROR("display draw buffer malloc failed");
|
||||
return;
|
||||
}
|
||||
|
||||
buf2 = lv_malloc(buf_size);
|
||||
if(buf2 == NULL) {
|
||||
LV_LOG_ERROR("display buffer malloc failed");
|
||||
lv_free(buf1);
|
||||
return;
|
||||
}
|
||||
lv_display_set_buffers(lcd_disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
ui_init(lcd_disp);
|
||||
|
||||
for(;;) {
|
||||
/* The task running lv_timer_handler should have lower priority than that running `lv_tick_inc` */
|
||||
lv_timer_handler();
|
||||
/* raise the task priority of LVGL and/or reduce the handler period can improve the performance */
|
||||
osDelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
#. All that's left is to implement ``ui_init()`` to create the screen. Here's a simple "Hello World" example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void ui_init(lv_display_t *disp)
|
||||
{
|
||||
lv_obj_t *obj;
|
||||
|
||||
/* set screen background to white */
|
||||
lv_obj_t *scr = lv_screen_active();
|
||||
lv_obj_set_style_bg_color(scr, lv_color_white(), 0);
|
||||
lv_obj_set_style_bg_opa(scr, LV_OPA_100, 0);
|
||||
|
||||
/* create label */
|
||||
obj = lv_label_create(scr);
|
||||
lv_obj_set_align(widget, LV_ALIGN_CENTER);
|
||||
lv_obj_set_height(widget, LV_SIZE_CONTENT);
|
||||
lv_obj_set_width(widget, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_text_font(widget, &lv_font_montserrat_14, 0);
|
||||
lv_obj_set_style_text_color(widget, lv_color_black(), 0);
|
||||
lv_label_set_text(widget, "Hello World!");
|
||||
}
|
||||
|
||||
85
docs/details/integration/driver/display/renesas_glcdc.rst
Normal file
85
docs/details/integration/driver/display/renesas_glcdc.rst
Normal file
@@ -0,0 +1,85 @@
|
||||
.. _renesas_glcdc:
|
||||
|
||||
=============
|
||||
Renesas GLCDC
|
||||
=============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
.. image:: /misc/renesas/glcdc.png
|
||||
:alt: Architectural overview of Renesas GLCDC
|
||||
:align: center
|
||||
|
||||
<br/>
|
||||
|
||||
GLCDC is a multi-stage graphics output peripheral used in Renesas MCUs.
|
||||
It is designed to automatically generate timing and data signals for different LCD panels.
|
||||
|
||||
- Supports LCD panels with RGB interface (up to 24 bits) and sync signals (HSYNC, VSYNC and Data Enable optional)
|
||||
- Supports various color formats for input graphics planes (RGB888, ARGB8888, RGB565, ARGB1555, ARGB4444, CLUT8, CLUT4, CLUT1)
|
||||
- Supports the Color Look-Up Table (CLUT) usage for input graphics planes (ARGB8888) with 512 words (32 bits/word)
|
||||
- Supports various color formats for output (RGB888, RGB666, RGB565, Serial RGB888)
|
||||
- Can input two graphics planes on top of the background plane and blend them on the screen
|
||||
- Generates a dot clock to the panel. The clock source is selectable from internal or external (LCD_EXTCLK)
|
||||
- Supports brightness adjustment, contrast adjustment, and gamma correction
|
||||
- Supports GLCDC interrupts to handle frame-buffer switching or underflow detection
|
||||
|
||||
|
||||
Setting up a project and further integration with Renesas' ecosystem is described in detail on :ref:`page Renesas <renesas>`.
|
||||
Check out the following repositories for ready-to-use examples:
|
||||
|
||||
- `EK-RA8D1 <https://github.com/lvgl/lv_port_renesas_ek-ra8d1>`__
|
||||
- `EK-RA6M3G <https://github.com/lvgl/lv_port_renesas_ek-ra6m3g>`__
|
||||
- `RX72N Envision Kit <https://github.com/lvgl/lv_port_renesas_rx72n-envision-kit>`__
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
- This diver relies on code generated by e² studio. Missing the step while setting up the project will cause a compilation error.
|
||||
- Activate the diver by setting :c:macro:`LV_USE_RENESAS_GLCDC` to ``1`` in your *"lv_conf.h"*.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
There is no need to implement any platform-specific functions.
|
||||
|
||||
The following code demonstrates using the diver in :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_DIRECT` mode.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_display_t * disp = lv_renesas_glcdc_direct_create();
|
||||
lv_display_set_default(disp);
|
||||
|
||||
To use the driver in :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL` mode, an extra buffer must be allocated,
|
||||
preferably in the fastest available memory region.
|
||||
|
||||
Buffer swapping can be activated by passing a second buffer of same size instead of the :cpp:expr:`NULL` argument.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static lv_color_t partial_draw_buf[DISPLAY_HSIZE_INPUT0 * DISPLAY_VSIZE_INPUT0 / 10] BSP_PLACE_IN_SECTION(".sdram") BSP_ALIGN_VARIABLE(1024);
|
||||
|
||||
lv_display_t * disp = lv_renesas_glcdc_partial_create(partial_draw_buf, NULL, sizeof(partial_draw_buf));
|
||||
lv_display_set_default(disp);
|
||||
|
||||
.. note::
|
||||
|
||||
Partial mode can be activated via the macro in ``src/board_init.c`` file of the demo projects.
|
||||
|
||||
|
||||
Screen rotation
|
||||
"""""""""""""""
|
||||
|
||||
Software based screen rotation is supported in partial mode. It uses the common API, no extra configuration is required:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_display_set_rotation(lv_display_get_default(), LV_DISP_ROTATION_90);
|
||||
/* OR */
|
||||
lv_display_set_rotation(lv_display_get_default(), LV_DISP_ROTATION_180);
|
||||
/* OR */
|
||||
lv_display_set_rotation(lv_display_get_default(), LV_DISP_ROTATION_270);
|
||||
|
||||
Make sure the heap is large enough, as a buffer with the same size as the partial buffer will be allocated.
|
||||
75
docs/details/integration/driver/display/st7735.rst
Normal file
75
docs/details/integration/driver/display/st7735.rst
Normal file
@@ -0,0 +1,75 @@
|
||||
============================
|
||||
ST7735 LCD Controller driver
|
||||
============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The `ST7735S <https://www.buydisplay.com/download/ic/ST7735S.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 396
|
||||
source line and 162 gate line driving circuits. This chip is capable of connecting directly to an external
|
||||
microprocessor, and accepts Serial Peripheral Interface (SPI), 8-bit/9-bit/16-bit/18-bit parallel interface.
|
||||
Display data can be stored in the on-chip display data RAM of 132 x 162 x 18 bits. It can perform display data
|
||||
RAM read/write operation with no external operation clock to minimize power consumption. In addition,
|
||||
because of the integrated power supply circuits necessary to drive liquid crystal, it is possible to make a
|
||||
display system with fewer components.
|
||||
|
||||
The ST7735 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/st7735>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
|
||||
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
There are no prerequisites.
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the ST7735 driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_ST7735 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
You need to implement two platform-dependent functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
|
||||
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
|
||||
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
To create an ST7735-based display use the function
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/**
|
||||
* Create an LCD display with ST7735 driver
|
||||
* @param hor_res horizontal resolution
|
||||
* @param ver_res vertical resolution
|
||||
* @param flags default configuration settings (mirror, RGB ordering, etc.)
|
||||
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
|
||||
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
|
||||
* @return pointer to the created display
|
||||
*/
|
||||
lv_display_t * lv_st7735_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
|
||||
lv_st7735_send_cmd_cb_t send_cmd_cb, lv_st7735_send_color_cb_t send_color_cb);
|
||||
|
||||
|
||||
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
|
||||
.. note::
|
||||
|
||||
You can find a step-by-step guide and the actual implementation of the callbacks on an STM32F746 using STM32CubeIDE and the ST HAL libraries here: :ref:`lcd_stm32_guide`
|
||||
|
||||
74
docs/details/integration/driver/display/st7789.rst
Normal file
74
docs/details/integration/driver/display/st7789.rst
Normal file
@@ -0,0 +1,74 @@
|
||||
============================
|
||||
ST7789 LCD Controller driver
|
||||
============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The `ST7789 <https://www.buydisplay.com/download/ic/ST7789.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 720
|
||||
source line and 320 gate line driving circuits. This chip is capable of connecting directly to an external
|
||||
microprocessor, and accepts, 8-bits/9-bits/16-bits/18-bits parallel interface. Display data can be stored in the
|
||||
on-chip display data RAM of 240x320x18 bits. It can perform display data RAM read/write operation with no
|
||||
external operation clock to minimize power consumption. In addition, because of the integrated power supply
|
||||
circuit necessary to drive liquid crystal; it is possible to make a display system with the fewest components.
|
||||
|
||||
The ST7789 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/st7789>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
|
||||
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
There are no prerequisites.
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the ST7789 driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_ST7789 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
You need to implement two platform-dependent functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
|
||||
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
|
||||
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
To create an ST7789-based display use the function
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/**
|
||||
* Create an LCD display with ST7789 driver
|
||||
* @param hor_res horizontal resolution
|
||||
* @param ver_res vertical resolution
|
||||
* @param flags default configuration settings (mirror, RGB ordering, etc.)
|
||||
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
|
||||
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
|
||||
* @return pointer to the created display
|
||||
*/
|
||||
lv_display_t * lv_st7789_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
|
||||
lv_st7789_send_cmd_cb_t send_cmd_cb, lv_st7789_send_color_cb_t send_color_cb);
|
||||
|
||||
|
||||
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
|
||||
.. note::
|
||||
|
||||
You can find a step-by-step guide and the actual implementation of the callbacks on an STM32F746 using STM32CubeIDE and the ST HAL libraries here: :ref:`lcd_stm32_guide`
|
||||
|
||||
75
docs/details/integration/driver/display/st7796.rst
Normal file
75
docs/details/integration/driver/display/st7796.rst
Normal file
@@ -0,0 +1,75 @@
|
||||
============================
|
||||
ST7796 LCD Controller driver
|
||||
============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The `ST7796S <https://www.buydisplay.com/download/ic/ST7796S.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 960
|
||||
source lines and 480 gate lines driving circuits. The ST7796S is capable of connecting directly to an external
|
||||
microprocessor, and accepts 8-bit/9-bit/16-bit/18-bit parallel interface, SPI, and the ST7796S also provides
|
||||
MIPI interface. Display data can be stored in the on-chip display data RAM of 320x480x18 bits. It can perform
|
||||
display data RAM read-/write-operation with no external clock to minimize power consumption. In addition,
|
||||
because of the integrated power supply circuit necessary to drive liquid crystal; it is possible to make a display
|
||||
system with fewest components.
|
||||
|
||||
The ST7796 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/st7796>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
|
||||
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
There are no prerequisites.
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the ST7796 driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_ST7796 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
You need to implement two platform-dependent functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
|
||||
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
|
||||
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
To create an ST7796-based display use the function
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/**
|
||||
* Create an LCD display with ST7796 driver
|
||||
* @param hor_res horizontal resolution
|
||||
* @param ver_res vertical resolution
|
||||
* @param flags default configuration settings (mirror, RGB ordering, etc.)
|
||||
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
|
||||
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
|
||||
* @return pointer to the created display
|
||||
*/
|
||||
lv_display_t * lv_st7796_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
|
||||
lv_st7796_send_cmd_cb_t send_cmd_cb, lv_st7796_send_color_cb_t send_color_cb);
|
||||
|
||||
|
||||
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
|
||||
|
||||
.. note::
|
||||
|
||||
You can find a step-by-step guide and the actual implementation of the callbacks on an STM32F746 using STM32CubeIDE and the ST HAL libraries here: :ref:`lcd_stm32_guide`
|
||||
|
||||
102
docs/details/integration/driver/display/st_ltdc.rst
Normal file
102
docs/details/integration/driver/display/st_ltdc.rst
Normal file
@@ -0,0 +1,102 @@
|
||||
=================
|
||||
STM32 LTDC Driver
|
||||
=================
|
||||
|
||||
Some STM32s have a specialized peripheral for driving
|
||||
displays called LTDC (LCD-TFT display controller).
|
||||
|
||||
Usage Modes With LVGL
|
||||
*********************
|
||||
|
||||
The driver within LVGL is designed to work with an
|
||||
already-configured LTDC peripheral. It relies on the
|
||||
HAL to detect information about the configuration.
|
||||
The color format of the created LVGL display will
|
||||
match the LTDC layer's color format. Use STM32CubeIDE
|
||||
or STM32CubeMX to generate LTDC initialization code.
|
||||
|
||||
There are some different use cases for LVGL's driver.
|
||||
All permutations of the below options are well supported.
|
||||
|
||||
- single or double buffered
|
||||
- direct or partial render mode
|
||||
- OS and no OS
|
||||
- paralellized flushing with DMA2D (only for partial render mode)
|
||||
|
||||
If OS is enabled, a synchronization primitive will be used to
|
||||
give the thread a chance to yield to other threads while blocked,
|
||||
improving CPU utilization. See :c:macro:`LV_USE_OS` in your lv_conf.h
|
||||
|
||||
LTDC Layers
|
||||
***********
|
||||
|
||||
This driver creates an LVGL display
|
||||
which is only concerned with a specific layer of the LTDC peripheral, meaning
|
||||
two LVGL LTDC displays can be created and operate independently on the separate
|
||||
layers.
|
||||
|
||||
Direct Render Mode
|
||||
******************
|
||||
|
||||
For direct render mode, invoke :cpp:func:`lv_st_ltdc_create_direct` like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void * my_ltdc_framebuffer_address = (void *)0x20000000u;
|
||||
uint32_t my_ltdc_layer_index = 0; /* typically 0 or 1 */
|
||||
lv_display_t * disp = lv_st_ltdc_create_direct(my_ltdc_framebuffer_address,
|
||||
optional_other_full_size_buffer,
|
||||
my_ltdc_layer_index);
|
||||
|
||||
``my_ltdc_framebuffer_address`` is the framebuffer configured for use by
|
||||
LTDC. ``optional_other_full_size_buffer`` can be another buffer which is the same
|
||||
size as the default framebuffer for double-buffered
|
||||
mode, or ``NULL`` otherwise. ``my_ltdc_layer_index`` is the layer index of the
|
||||
LTDC layer to create the display for.
|
||||
|
||||
For the best visial results, ``optional_other_full_size_buffer`` should be used
|
||||
if enough memory is available. Single-buffered mode is what you should use
|
||||
if memory is very scarce. If there is almost enough memory for double-buffered
|
||||
direct mode, but not quite, then use partial render mode.
|
||||
|
||||
Partial Render Mode
|
||||
*******************
|
||||
|
||||
For partial render mode, invoke :cpp:func:`lv_st_ltdc_create_partial` like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static uint8_t partial_buf1[65536];
|
||||
static uint8_t optional_partial_buf2[65536];
|
||||
uint32_t my_ltdc_layer_index = 0; /* typically 0 or 1 */
|
||||
lv_display_t * disp = lv_st_ltdc_create_partial(partial_buf1,
|
||||
optional_partial_buf2,
|
||||
65536,
|
||||
my_ltdc_layer_index);
|
||||
|
||||
The driver will use the information in the LTDC layer configuration to find the
|
||||
layer's framebuffer and flush to it.
|
||||
|
||||
Providing a second partial buffer can improve CPU utilization and increase
|
||||
performance compared to
|
||||
a single buffer if :c:macro:`LV_ST_LTDC_USE_DMA2D_FLUSH` is enabled.
|
||||
|
||||
DMA2D
|
||||
*****
|
||||
|
||||
:c:macro:`LV_ST_LTDC_USE_DMA2D_FLUSH` can be enabled to use DMA2D to flush
|
||||
partial buffers in parallel with other LVGL tasks, whether or not OS is
|
||||
enabled. If the display is not partial, then there is no need to enable this
|
||||
option.
|
||||
|
||||
It must not be enabled at the same time as :c:macro:`LV_USE_DRAW_DMA2D`.
|
||||
See the :ref:`DMA2D support <dma2d>`.
|
||||
|
||||
|
||||
.. admonition:: Further Reading
|
||||
|
||||
You may be interested in enabling the :ref:`Nema GFX renderer <stm32_nema_gfx>`
|
||||
if your STM32 has a GPU which is supported by Nema GFX.
|
||||
|
||||
`lv_port_riverdi_stm32u5 <https://github.com/lvgl/lv_port_riverdi_stm32u5>`__
|
||||
is a way to quick way to get started with LTDC on LVGL.
|
||||
16
docs/details/integration/driver/index.rst
Normal file
16
docs/details/integration/driver/index.rst
Normal file
@@ -0,0 +1,16 @@
|
||||
.. _drivers:
|
||||
|
||||
=======
|
||||
Drivers
|
||||
=======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
display/index
|
||||
libinput
|
||||
opengles
|
||||
touchpad/index
|
||||
wayland
|
||||
windows
|
||||
X11
|
||||
87
docs/details/integration/driver/libinput.rst
Normal file
87
docs/details/integration/driver/libinput.rst
Normal file
@@ -0,0 +1,87 @@
|
||||
===============
|
||||
Libinput Driver
|
||||
===============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Libinput is an input stack for processes that need to provide events from commonly used input devices. That includes mice, keyboards, touchpads,
|
||||
touchscreens and graphics tablets. Libinput handles device-specific quirks and provides an easy-to-use API to receive events from devices.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
You have the development version of libinput installed (usually ``libinput-dev``). If your input device requires quirks, make sure they are
|
||||
installed as well (usually in ``/usr/share/libinput/*.quirks``). To test if your device is set up correctly for use with libinput, you can
|
||||
run ``libinput list-devices``.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ sudo libinput list-devices
|
||||
...
|
||||
Device: ETPS/2 Elantech Touchpad
|
||||
Kernel: /dev/input/event5
|
||||
Group: 10
|
||||
Seat: seat0, default
|
||||
Size: 102x74mm
|
||||
Capabilities: pointer gesture
|
||||
Tap-to-click: disabled
|
||||
Tap-and-drag: enabled
|
||||
...
|
||||
|
||||
If your device doesn't show up, you may have to configure udev and the appropriate udev rules to connect it.
|
||||
|
||||
Additionally, if you want full keyboard support, including letters and modifiers, you'll need the development version of libxkbcommon
|
||||
installed (usually ``libxkbcommon-dev``).
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the libinput driver support in lv_conf.h, by cmake compiler define or by KConfig.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_LIBINPUT 1
|
||||
|
||||
Full keyboard support needs to be enabled separately.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_LIBINPUT_XKB 1
|
||||
#define LV_LIBINPUT_XKB_KEY_MAP { .rules = NULL, .model = "pc101", .layout = "us", .variant = NULL, .options = NULL }
|
||||
|
||||
To find the right key map values, you may use the ``setxkbmap -query`` command.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To set up an input device via the libinput driver, all you need to do is call ``lv_libinput_create`` with the respective device type
|
||||
(``LV_INDEV_TYPE_POINTER`` or ``LV_INDEV_TYPE_KEYPAD``) and device node path (e.g. ``/dev/input/event5``).
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_indev_t *indev = lv_libinput_create(LV_INDEV_TYPE_POINTER, "/dev/input/event5");
|
||||
|
||||
Note that touchscreens are treated as (absolute) pointer devices by the libinput driver and require ``LV_INDEV_TYPE_POINTER``.
|
||||
|
||||
Depending on your system, the device node paths might not be stable across reboots. If this is the case, you can use ``lv_libinput_find_dev``
|
||||
to find the first device that has a specific capability.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *path = lv_libinput_find_dev(LV_LIBINPUT_CAPABILITY_TOUCH, true);
|
||||
|
||||
The second argument controls whether or not all devices are rescanned. If you have many devices connected this can get quite slow.
|
||||
Therefore, you should only specify ``true`` on the first call when calling this method multiple times in a row. If you want to find
|
||||
all devices that have a specific capability, use ``lv_libinput_find_devs``.
|
||||
|
||||
If you want to connect a keyboard device to a textarea, create a dedicated input group and set it on both the indev and textarea.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t *textarea = lv_textarea_create(...);
|
||||
...
|
||||
lv_group_t *keyboard_input_group = lv_group_create();
|
||||
lv_indev_set_group(indev, keyboard_input_group);
|
||||
lv_group_add_obj(keyboard_input_group, textarea);
|
||||
|
||||
224
docs/details/integration/driver/opengles.rst
Normal file
224
docs/details/integration/driver/opengles.rst
Normal file
@@ -0,0 +1,224 @@
|
||||
.. _opengl_es_driver:
|
||||
|
||||
===============================
|
||||
OpenGL ES Display/Inputs Driver
|
||||
===============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
| The **OpenGL ES** display/input `driver <https://github.com/lvgl/lvgl/src/drivers/opengles>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in an desktop window created via GLFW.
|
||||
| It is an alternative to **Wayland**, **XCB**, **SDL** or **Qt**.
|
||||
|
||||
The main purpose for this driver is for testing/debugging the LVGL application in an **OpenGL** simulation window.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The OpenGL driver uses GLEW GLFW to access the OpenGL window manager.
|
||||
|
||||
1. Install GLEW and GLFW: ``sudo apt-get install libglew-dev libglfw3-dev``
|
||||
|
||||
Configure OpenGL Driver
|
||||
-----------------------
|
||||
|
||||
1. Required linked libraries: -lGL -lGLEW -lglfw
|
||||
2. Enable the OpenGL driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_OPENGLES 1
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lvgl/examples/lv_examples.h"
|
||||
#include "lvgl/demos/lv_demos.h"
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
|
||||
int main()
|
||||
{
|
||||
/* initialize lvgl */
|
||||
lv_init();
|
||||
|
||||
/* create a window and initialize OpenGL */
|
||||
lv_glfw_window_t * window = lv_glfw_window_create(WIDTH, HEIGHT, true);
|
||||
|
||||
/* create a display that flushes to a texture */
|
||||
lv_display_t * texture = lv_opengles_texture_create(WIDTH, HEIGHT);
|
||||
lv_display_set_default(texture);
|
||||
|
||||
/* add the texture to the window */
|
||||
unsigned int texture_id = lv_opengles_texture_get_texture_id(texture);
|
||||
lv_glfw_texture_t * window_texture = lv_glfw_window_add_texture(window, texture_id, WIDTH, HEIGHT);
|
||||
|
||||
/* get the mouse indev of the window texture */
|
||||
lv_indev_t * mouse = lv_glfw_texture_get_mouse_indev(window_texture);
|
||||
|
||||
/* add a cursor to the mouse indev */
|
||||
LV_IMAGE_DECLARE(mouse_cursor_icon);
|
||||
lv_obj_t * cursor_obj = lv_image_create(lv_screen_active());
|
||||
lv_image_set_src(cursor_obj, &mouse_cursor_icon);
|
||||
lv_indev_set_cursor(mouse, cursor_obj);
|
||||
|
||||
/* create Widgets on the screen */
|
||||
lv_demo_widgets();
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint32_t time_until_next = lv_timer_handler();
|
||||
lv_delay_ms(time_until_next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Advanced Usage
|
||||
--------------
|
||||
|
||||
The OpenGL driver can draw textures from the user. A third-party library could be
|
||||
used to add content to a texture and the driver will draw the texture in the window.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
|
||||
void custom_texture_example(void)
|
||||
{
|
||||
/*****************
|
||||
* MAIN WINDOW
|
||||
*****************/
|
||||
|
||||
/* create a window and initialize OpenGL */
|
||||
/* multiple windows can be created */
|
||||
lv_glfw_window_t * window = lv_glfw_window_create(WIDTH, HEIGHT, true);
|
||||
|
||||
/****************************
|
||||
* OPTIONAL MAIN TEXTURE
|
||||
****************************/
|
||||
|
||||
/* create a main display that flushes to a texture */
|
||||
lv_display_t * main_texture = lv_opengles_texture_create(WIDTH, HEIGHT);
|
||||
lv_display_set_default(main_texture);
|
||||
|
||||
/* add the main texture to the window */
|
||||
unsigned int main_texture_id = lv_opengles_texture_get_texture_id(main_texture);
|
||||
lv_glfw_texture_t * window_main_texture = lv_glfw_window_add_texture(window, main_texture_id, WIDTH, HEIGHT);
|
||||
|
||||
/* get the mouse indev of this main texture */
|
||||
lv_indev_t * main_texture_mouse = lv_glfw_texture_get_mouse_indev(window_main_texture);
|
||||
|
||||
/* add a cursor to the mouse indev */
|
||||
LV_IMAGE_DECLARE(mouse_cursor_icon);
|
||||
lv_obj_t * cursor_obj = lv_image_create(lv_screen_active());
|
||||
lv_image_set_src(cursor_obj, &mouse_cursor_icon);
|
||||
lv_indev_set_cursor(main_texture_mouse, cursor_obj);
|
||||
|
||||
/* create Widgets on the screen of the main texture */
|
||||
lv_demo_widgets();
|
||||
|
||||
/**********************
|
||||
* ANOTHER TEXTURE
|
||||
**********************/
|
||||
|
||||
/* create a sub display that flushes to a texture */
|
||||
const int32_t sub_texture_w = 300;
|
||||
const int32_t sub_texture_h = 300;
|
||||
lv_display_t * sub_texture = lv_opengles_texture_create(sub_texture_w, sub_texture_h);
|
||||
|
||||
/* add the sub texture to the window */
|
||||
unsigned int sub_texture_id = lv_opengles_texture_get_texture_id(sub_texture);
|
||||
lv_glfw_texture_t * window_sub_texture = lv_glfw_window_add_texture(window, sub_texture_id, sub_texture_w, sub_texture_h);
|
||||
|
||||
/* create Widgets on the screen of the sub texture */
|
||||
lv_display_set_default(sub_texture);
|
||||
lv_example_keyboard_2();
|
||||
lv_display_set_default(main_texture);
|
||||
|
||||
/* position the sub texture within the window */
|
||||
lv_glfw_texture_set_x(window_sub_texture, 250);
|
||||
lv_glfw_texture_set_y(window_sub_texture, 150);
|
||||
|
||||
/* optionally change the opacity of the sub texture */
|
||||
lv_glfw_texture_set_opa(window_sub_texture, LV_OPA_80);
|
||||
|
||||
/*********************************************
|
||||
* USE AN EXTERNAL OPENGL TEXTURE IN LVGL
|
||||
*********************************************/
|
||||
|
||||
unsigned int external_texture_id;
|
||||
glGenTextures(1, &external_texture_id);
|
||||
glBindTexture(GL_TEXTURE_2D, external_texture_id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
LV_IMAGE_DECLARE(img_cogwheel_argb);
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
const int texture_format = GL_R8;
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
const int texture_format = GL_RGB565;
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
const int texture_format = GL_RGB;
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
const int texture_format = GL_RGBA;
|
||||
#else
|
||||
#error("Unsupported color format")
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, texture_format, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h, 0, GL_BGRA, GL_UNSIGNED_BYTE, img_cogwheel_argb.data);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
/* add the external texture to the window */
|
||||
lv_glfw_texture_t * window_external_texture = lv_glfw_window_add_texture(window, external_texture_id, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h);
|
||||
|
||||
/* set the position and opacity of the external texture within the window */
|
||||
lv_glfw_texture_set_x(window_external_texture, 20);
|
||||
lv_glfw_texture_set_y(window_external_texture, 20);
|
||||
lv_glfw_texture_set_opa(window_external_texture, LV_OPA_70);
|
||||
|
||||
/*********************************************
|
||||
* USE AN LVGL TEXTURE IN ANOTHER LIBRARY
|
||||
*********************************************/
|
||||
|
||||
lv_refr_now(sub_texture);
|
||||
|
||||
/* the texture is drawn on by LVGL and can be used by anything that uses OpenGL textures */
|
||||
third_party_lib_use_texture(sub_texture_id);
|
||||
}
|
||||
|
||||
OpenGL Texture Caching Renderer
|
||||
-------------------------------
|
||||
|
||||
There is a renderer in LVGL which caches software-rendered areas as OpenGL textures.
|
||||
The textures are retrieved from the cache and reused when there is a match.
|
||||
The performance will be drastically improved in most cases.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_DRAW_OPENGLES 1
|
||||
|
||||
Known Limitations
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Performance will be the same or slightly worse if the drawn areas are never found in the cache
|
||||
due to Widgets with continuously varying colors or shapes. One example is a label whose color
|
||||
is set to a random value every frame, as in the "Multiple labels" scene of the benchmark demo.
|
||||
- Layers with transparent pixels and an overall layer transparency will not blend correctly.
|
||||
The effect can be observed in the "Containers with opa_layer" scene of the benchmark demo
|
||||
in the border corners.
|
||||
- Layers with rotation are not currently supported. Images with rotation are fine.
|
||||
|
||||
|
||||
.. Comment: The above blank line is necessary for Sphinx to not complain,
|
||||
since it looks for the blank line after a bullet list.
|
||||
57
docs/details/integration/driver/touchpad/evdev.rst
Normal file
57
docs/details/integration/driver/touchpad/evdev.rst
Normal file
@@ -0,0 +1,57 @@
|
||||
==================
|
||||
Linux Evdev Driver
|
||||
==================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The Linux event device (evdev) is a hardware-independent API that gives access to input events from,
|
||||
for example, a mouse or touchscreen. It is exposed via the Linux device file system interface.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
Your system has an input device configured (usually under ``/dev/input/`` such as ``/dev/input/event0``).
|
||||
|
||||
Configuring the driver
|
||||
----------------------
|
||||
|
||||
Enable the Linux LVGL evdev driver support in ``lv_conf.h``.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_EVDEV 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To set up an event input, first create an input device with ``lv_edev_create`` setting it to the correct Linux event device.
|
||||
Then link this to the LVGL display with ``lv_indev_set_display``.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_indev_t *touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0");
|
||||
lv_indev_set_display(touch, disp);
|
||||
|
||||
Ensure that an ``lv_display_t`` object is already created for ``disp``. An example for this is shown below, using the Linux framebuffer driver.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_display_t * disp = lv_linux_fbdev
|
||||
lv_linux_fbdev_set_file(disp, "/dev/fb0");_create();
|
||||
|
||||
|
||||
Locating your input device
|
||||
--------------------------
|
||||
|
||||
If you can't determine your input device, first run
|
||||
|
||||
```$cat /proc/bus/input/devices```
|
||||
|
||||
This should show input devices and there will be entries with the word ``event`` which give a clue as to the device to use eg. ``event1`` would be ``/dev/input/event1``.
|
||||
|
||||
You can use ``evtest`` to show data from that event source to see if it is actually the one you want.
|
||||
|
||||
Try:
|
||||
|
||||
``$evtest /dev/input/event1`` replacing ``eventX`` with your event device from above.
|
||||
5
docs/details/integration/driver/touchpad/ft6x36.rst
Normal file
5
docs/details/integration/driver/touchpad/ft6x36.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
======
|
||||
FT6X36
|
||||
======
|
||||
|
||||
TODO
|
||||
9
docs/details/integration/driver/touchpad/index.rst
Normal file
9
docs/details/integration/driver/touchpad/index.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
========
|
||||
Touchpad
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
evdev
|
||||
ft6x36
|
||||
182
docs/details/integration/driver/wayland.rst
Normal file
182
docs/details/integration/driver/wayland.rst
Normal file
@@ -0,0 +1,182 @@
|
||||
.. _wayland_driver:
|
||||
|
||||
=============================
|
||||
Wayland Display/Inputs driver
|
||||
=============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
| The **Wayland** `driver <https://github.com/lvgl/lvgl/tree/master/src/drivers/wayland>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in a desktop window.
|
||||
| It is an alternative to **X11** or **SDL2**
|
||||
|
||||
The main purpose for this driver is for testing/debugging the LVGL application, it can also be used to run applications in 'kiosk mode'
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
The wayland driver requires some dependencies.
|
||||
|
||||
On Ubuntu
|
||||
|
||||
.. code:: bash
|
||||
|
||||
sudo apt-get install libwayland-dev libxkbcommon-dev libwayland-bin wayland-protocols
|
||||
|
||||
On Fedora
|
||||
|
||||
.. code:: bash
|
||||
|
||||
sudo dnf install wayland-devel libxkbcommon-devel wayland-utils wayland-protocols-devel
|
||||
|
||||
|
||||
Configuring the wayland driver
|
||||
------------------------------
|
||||
|
||||
1. Enable the wayland driver in ``lv_conf.h``
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define LV_USE_WAYLAND 1
|
||||
|
||||
2. Optional configuration options:
|
||||
|
||||
- Enable window decorations, only required on GNOME because out of all the available wayland compositors
|
||||
**only** Mutter/GNOME enforces the use of client side decorations
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define LV_WAYLAND_WINDOW_DECORATIONS 1
|
||||
|
||||
- Enable support for the deprecated 'wl_shell', Only useful when the BSP on the target has weston ``9.x``
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define LV_WAYLAND_WL_SHELL 1
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
#. In ``main.c`` ``#incude "lv_drivers/wayland/wayland.h"``
|
||||
#. Enable the Wayland driver in ``lv_conf.h`` with ``LV_USE_WAYLAND 1``
|
||||
|
||||
#. ``LV_COLOR_DEPTH`` should be set either to ``32`` or ``16`` in ``lv_conf.h``
|
||||
|
||||
#. Add a display using ``lv_wayland_window_create()``,
|
||||
possibly with a close callback to track the status of each display:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define H_RES (800)
|
||||
#define V_RES (480)
|
||||
|
||||
/* Create a display */
|
||||
lv_disp_t * disp = lv_wayland_create_window(H_RES, V_RES, "Window Title", close_cb);
|
||||
|
||||
|
||||
As part of the above call, the Wayland driver will register four input devices
|
||||
for each display:
|
||||
|
||||
* a KEYPAD connected to Wayland keyboard events
|
||||
* a POINTER connected to Wayland touch events
|
||||
* a POINTER connected to Wayland pointer events
|
||||
* an ENCODER connected to Wayland pointer axis events
|
||||
|
||||
Handles for input devices of each display can be obtained using
|
||||
``lv_wayland_get_indev_keyboard()``, ``lv_wayland_get_indev_touchscreen()``,
|
||||
``lv_wayland_get_indev_pointer()`` and ``lv_wayland_get_indev_pointeraxis()`` respectively.
|
||||
|
||||
Fullscreen mode
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
To programmatically fullscreen the window,
|
||||
use the ``lv_wayland_window_set_fullscreen()`` function respectively with ``true``
|
||||
or ``false`` for the ``fullscreen`` argument.
|
||||
|
||||
Maximized mode
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
To programmatically maximize the window,
|
||||
use the ``lv_wayland_window_set_maximized()`` function respectively with ``true``
|
||||
or ``false`` for the ``maximized`` argument.
|
||||
|
||||
|
||||
Custom timer handler
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Always call ``lv_wayland_timer_handler()`` in your timer loop instead of the regular ``lv_timer_handler()``.
|
||||
|
||||
**Note:** ``lv_wayland_timer_handler()`` internally calls ``lv_timer_handler()``
|
||||
|
||||
This allows the wayland client to work on well on weston, resizing shared memory buffers during
|
||||
a commit does not work well on weston.
|
||||
|
||||
Wrapping the call to ``lv_timer_hander()`` is a necessity to have more control over
|
||||
when the LVGL flush callback is called.
|
||||
|
||||
The custom timer handler returns ``false`` if the frame from previous cycle is not rendered.
|
||||
When this happens, it usually means that the application is minimized or hidden behind another window.
|
||||
Causing the driver to wait until the arrival of any message on the wayland socket, the process is in interruptible sleep.
|
||||
|
||||
Building the wayland driver
|
||||
---------------------------
|
||||
|
||||
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
|
||||
|
||||
If there is a need to use driver with another build system. The source and header files for the XDG shell
|
||||
must be generated from the definitions for the XDG shell protocol.
|
||||
|
||||
In the example Cmake is used to perform the operation by invoking the ``wayland-scanner`` utility
|
||||
|
||||
To achieve this manually,
|
||||
|
||||
Make sure the dependencies listed at the start of the article are installed.
|
||||
|
||||
The wayland protocol is defined using XML files which are present in ``/usr/share/wayland-protocols``
|
||||
|
||||
To generate the required files run the following commands:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
wayland-scanner client-header </usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml > wayland_xdg_shell.h
|
||||
wayland-scanner private-code </usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml > wayland_xdg_shell.c
|
||||
|
||||
The resulting files can then be integrated into the project, it's better to re-run ``wayland-scanner`` on
|
||||
each build to ensure that the correct versions are generated, they must match the version of the ``wayland-client``
|
||||
dynamically linked library installed on the system.
|
||||
|
||||
|
||||
Current state and objectives
|
||||
----------------------------
|
||||
|
||||
* Add direct rendering mode
|
||||
* Refactor the shell integrations to avoid excessive conditional compilation
|
||||
* Technically, the wayland driver allows to create multiple windows - but this feature is experimental.
|
||||
* Eventually add enhanced support for XDG shell to allow the creation of desktop apps on Unix-like platforms,
|
||||
similar to what the win32 driver does.
|
||||
* Add a support for Mesa, currently wl_shm is used and it's not the most effective technique.
|
||||
|
||||
|
||||
Bug reports
|
||||
-----------
|
||||
|
||||
The wayland driver is currently under construction, bug reports, contributions and feedback is always welcome.
|
||||
|
||||
It is however important to create detailed issues when a problem is encountered, logs and screenshots of the problem are of great help.
|
||||
|
||||
Please enable ``LV_USE_LOG`` and launch the simulator executable like so
|
||||
|
||||
.. code::
|
||||
|
||||
WAYLAND_DEBUG=1 ./path/to/simulator_executable > /tmp/debug 2>&1
|
||||
|
||||
This will create a log file called ``debug`` in the ``/tmp`` directory, copy-paste the content of the file in the github issue.
|
||||
The log file contains LVGL logs and the wayland messages.
|
||||
|
||||
Be sure to replicate the problem quickly otherwise the logs become too big
|
||||
|
||||
113
docs/details/integration/driver/windows.rst
Normal file
113
docs/details/integration/driver/windows.rst
Normal file
@@ -0,0 +1,113 @@
|
||||
=============================
|
||||
Windows Display/Inputs driver
|
||||
=============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The **Windows** display/input `driver <https://github.com/lvgl/lvgl/src/drivers/windows>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in a Windows Win32 window.
|
||||
|
||||
The main purpose for this driver is for testing/debugging the LVGL application in a **Windows** simulation window via **simulator mode**, or developing a standard **Windows** desktop application with LVGL via **application mode**.
|
||||
|
||||
Here are the **similarity** for simulator mode and application mode.
|
||||
|
||||
- Support LVGL pointer, keypad and encoder devices integration.
|
||||
- Support Windows touch input.
|
||||
- Support Windows input method integration input.
|
||||
- Support Per-monitor DPI Aware (both V1 and V2).
|
||||
|
||||
Here are the **differences** for simulator mode and application mode.
|
||||
|
||||
Simulator Mode
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- Designed for LVGL simulation scenario.
|
||||
- Keep the LVGL display resolution all time for trying best to simulate UI layout which will see in their production devices.
|
||||
- When Windows DPI scaling setting is changed, Windows backend will stretch the display content.
|
||||
|
||||
Application Mode
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
- Designed for Windows desktop application development scenario.
|
||||
- Have the Window resizing support and LVGL display resolution will be changed.
|
||||
- When Windows DPI scaling setting is changed, the LVGL display DPI value will also be changed.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The minimum Windows OS requirement for this driver is Windows Vista RTM.
|
||||
|
||||
If you use Windows API shim libraries like `YY-Thunks <https://github.com/Chuyu-Team/YY-Thunks>`__, the tested minimum Windows OS requirement for this driver is Windows XP RTM.
|
||||
|
||||
According to the Windows GDI API this driver used. Maybe the minimum Windows OS requirement limitation for this driver is Windows 2000 RTM.
|
||||
|
||||
Configure Windows driver
|
||||
------------------------
|
||||
|
||||
Enable the Windows driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_WINDOWS 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <Windows.h>
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lvgl/examples/lv_examples.h"
|
||||
#include "lvgl/demos/lv_demos.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
lv_init();
|
||||
|
||||
int32_t zoom_level = 100;
|
||||
bool allow_dpi_override = false;
|
||||
bool simulator_mode = false;
|
||||
lv_display_t* display = lv_windows_create_display(
|
||||
L"LVGL Display Window",
|
||||
800,
|
||||
480,
|
||||
zoom_level,
|
||||
allow_dpi_override,
|
||||
simulator_mode);
|
||||
if (!display)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_lock();
|
||||
|
||||
lv_indev_t* pointer_device = lv_windows_acquire_pointer_indev(display);
|
||||
if (!pointer_device)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_indev_t* keypad_device = lv_windows_acquire_keypad_indev(display);
|
||||
if (!keypad_device)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_indev_t* encoder_device = lv_windows_acquire_encoder_indev(display);
|
||||
if (!encoder_device)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_demo_widgets();
|
||||
|
||||
lv_unlock();
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint32_t time_till_next = lv_timer_handler();
|
||||
lv_delay_ms(time_till_next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
103
docs/details/integration/framework/arduino.rst
Normal file
103
docs/details/integration/framework/arduino.rst
Normal file
@@ -0,0 +1,103 @@
|
||||
=======
|
||||
Arduino
|
||||
=======
|
||||
|
||||
The `LVGL library <https://github.com/lvgl/lvgl>`__ is directly available as Arduino libraries.
|
||||
|
||||
Note that you need to choose a board powerful enough to run LVGL and
|
||||
your GUI. See the :ref:`requirements of LVGL <requirements>`.
|
||||
|
||||
For example ESP32 is a good candidate to create UI's with LVGL.
|
||||
|
||||
Get the LVGL Arduino library
|
||||
----------------------------
|
||||
|
||||
LVGL can be installed via the Arduino IDE Library Manager or as a .ZIP library.
|
||||
|
||||
You can `Download <https://github.com/lvgl/lvgl/archive/refs/heads/master.zip>`__
|
||||
the latest version of LVGL from GitHub and simply copy it to Arduino's
|
||||
library folder.
|
||||
|
||||
Set up drivers
|
||||
--------------
|
||||
|
||||
To get started it's recommended to use `TFT_eSPI <https://github.com/Bodmer/TFT_eSPI>`__ library as a TFT
|
||||
driver to simplify testing. To make it work, setup ``TFT_eSPI``
|
||||
according to your TFT display type via editing either:
|
||||
|
||||
- ``User_Setup.h``
|
||||
- or by selecting a configuration in the ``User_Setup_Select.h``
|
||||
|
||||
Both files are located in ``TFT_eSPI`` library's folder.
|
||||
|
||||
|
||||
Configure LVGL
|
||||
--------------
|
||||
|
||||
LVGL has its own configuration file called ``lv_conf.h``. When LVGL is
|
||||
installed, follow these configuration steps:
|
||||
|
||||
1. Go to the directory of the installed Arduino libraries
|
||||
2. Go to ``lvgl`` and copy ``lv_conf_template.h`` as ``lv_conf.h`` into the Arduino Libraries directory next to the ``lvgl`` library folder.
|
||||
3. Open ``lv_conf.h`` and change the first ``#if 0`` to ``#if 1`` to enable the content of the file
|
||||
4. Set the color depth of you display in :c:macro:`LV_COLOR_DEPTH`
|
||||
|
||||
Finally the layout with ``lv_conf.h`` should look like this:
|
||||
|
||||
::
|
||||
|
||||
arduino
|
||||
|-libraries
|
||||
|-lvgl
|
||||
|-other_lib_1
|
||||
|-other_lib_2
|
||||
|-lv_conf.h
|
||||
|
||||
|
||||
Initialize and run LVGL
|
||||
-----------------------
|
||||
|
||||
Take a look at `LVGL_Arduino.ino <https://github.com/lvgl/lvgl/blob/master/examples/arduino/LVGL_Arduino/LVGL_Arduino.ino>`__
|
||||
to see how to initialize LVGL. ``TFT_eSPI`` is used as the display driver.
|
||||
|
||||
In the INO file you can see how to register a display and a touchpad for
|
||||
LVGL and call an example.
|
||||
|
||||
|
||||
Use the examples and demos
|
||||
--------------------------
|
||||
|
||||
Note that, there is no dedicated INO file for every example. Instead,
|
||||
you can load an example by calling an ``lv_example_...`` function. For
|
||||
example :cpp:func:`lv_example_btn_1`.
|
||||
|
||||
:important: Due to some the limitations of Arduino's build system you
|
||||
need to copy ``lvgl/examples`` to ``lvgl/src/examples``. Similarly for
|
||||
the demos ``lvgl/demos`` to ``lvgl/src/demos``.
|
||||
|
||||
|
||||
Debugging and logging
|
||||
---------------------
|
||||
|
||||
LVGL can display debug information in case of trouble. In the
|
||||
``LVGL_Arduino.ino`` example there is a ``my_print`` method, which sends
|
||||
this debug information to the serial interface. To enable this feature
|
||||
you have to edit the ``lv_conf.h`` file and enable logging in the
|
||||
section ``log settings``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Log settings */
|
||||
#define USE_LV_LOG 1 /* Enable/disable the log module */
|
||||
#if LV_USE_LOG
|
||||
/* How important log should be added:
|
||||
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
|
||||
* LV_LOG_LEVEL_INFO Log important events
|
||||
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
|
||||
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
* LV_LOG_LEVEL_NONE Do not log anything
|
||||
*/
|
||||
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
|
||||
|
||||
After enabling the log module and setting :c:macro:`LV_LOG_LEVEL` accordingly, the
|
||||
output log is sent to the ``Serial`` port @ 115200 bps.
|
||||
11
docs/details/integration/framework/index.rst
Normal file
11
docs/details/integration/framework/index.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
==========
|
||||
Frameworks
|
||||
==========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
arduino
|
||||
platformio
|
||||
tasmota-berry
|
||||
|
||||
5
docs/details/integration/framework/platformio.rst
Normal file
5
docs/details/integration/framework/platformio.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
==========
|
||||
PlatformIO
|
||||
==========
|
||||
|
||||
TODO
|
||||
105
docs/details/integration/framework/tasmota-berry.rst
Normal file
105
docs/details/integration/framework/tasmota-berry.rst
Normal file
@@ -0,0 +1,105 @@
|
||||
=================
|
||||
Tasmota and berry
|
||||
=================
|
||||
|
||||
What is Tasmota?
|
||||
----------------
|
||||
|
||||
`Tasmota <https://github.com/arendst/Tasmota>`__ is a widely used
|
||||
open-source firmware for ESP8266 and EPS32 based devices. It supports a
|
||||
wide variety of devices, sensors and integrations to Home Automation and
|
||||
Cloud services. Tasmota firmware is downloaded more than 200,000 times
|
||||
each month, and has an active and growing community.
|
||||
|
||||
Tasmota provides access to hundreds of supported devices, full support
|
||||
of MQTT, HTTP(S), integration with major Home Automation systems, myriad
|
||||
of sensors, IR, RF, Zigbee, Bluetooth, AWS IoT, Azure IoT, Alexa and
|
||||
many more.
|
||||
|
||||
What is Berry?
|
||||
--------------
|
||||
|
||||
`Berry <https://github.com/berry-lang/berry>`__ is a ultra-lightweight
|
||||
dynamically typed embedded scripting language. It is designed for
|
||||
lower-performance embedded devices. The interpreter of Berry include a
|
||||
one-pass compiler and register-based VM, all the code is written in ANSI
|
||||
C99. Berry offers a syntax very similar to Python, and is inspired from
|
||||
LUA VM. It is fully integrated in Tasmota
|
||||
|
||||
Highlights of Berry
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Berry has the following advantages:
|
||||
|
||||
- Lightweight: A well-optimized interpreter with very little resources. Ideal for use in microprocessors.
|
||||
- Fast: optimized one-pass bytecode compiler and register-based virtual machine.
|
||||
- Powerful: supports imperative programming, object-oriented programming, functional programming.
|
||||
- Flexible: Berry is a dynamic type script, and it's intended for embedding in applications.
|
||||
It can provide good dynamic scalability for the host system.
|
||||
- Simple: simple and natural syntax, support garbage collection, and easy to use FFI (foreign function interface).
|
||||
- RAM saving: With compile-time object construction, most of the constant objects are stored
|
||||
in read-only code data segments, so the RAM usage of the interpreter is very low when it starts.
|
||||
|
||||
All features are detailed in the `Berry Reference Manual <https://github.com/berry-lang/berry/wiki/Reference>`__
|
||||
|
||||
--------------
|
||||
|
||||
Why LVGL + Tasmota + Berry?
|
||||
---------------------------
|
||||
|
||||
In 2021, Tasmota added full support of LVGL for ESP32 based devices. It
|
||||
also introduced the Berry scripting language, a small-footprint language
|
||||
similar to Python and fully integrated in Tasmota.
|
||||
|
||||
A comprehensive mapping of LVGL in Berry language is now available,
|
||||
similar to the mapping of MicroPython. It allows to use +98% of all LVGL
|
||||
features. It is also possible to write custom widgets in Berry.
|
||||
|
||||
Versions supported: LVGL v8.0.2, LodePNG v20201017, Freetype 2.10.4
|
||||
|
||||
Tasmota + Berry + LVGL could be used for:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Fast prototyping GUI.
|
||||
- Shortening the cycle of changing and fine-tuning the GUI.
|
||||
- Modelling the GUI in a more abstract way by defining reusable composite Widgets, taking
|
||||
advantage of Berry's language features such as Inheritance, Closures, Exception Handling…
|
||||
- Make LVGL accessible to a larger audience. No need to know C to create a nice GUI on an embedded system.
|
||||
|
||||
A higher level interface compatible with
|
||||
`OpenHASP <https://github.com/HASwitchPlate/openHASP>`__
|
||||
is also under development.
|
||||
|
||||
--------------
|
||||
|
||||
So what does it look like?
|
||||
--------------------------
|
||||
|
||||
TL;DR: Similar to MicroPython, it's very much like the C API, but Object-Oriented for LVGL components.
|
||||
|
||||
Let's dive right into an example!
|
||||
|
||||
A simple example
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
lv.start() # start LVGL
|
||||
scr = lv.screen_active() # get default screen
|
||||
btn = lv.btn(scr) # create button
|
||||
btn.center()
|
||||
label = lv.label(btn) # create a label in the button
|
||||
label.set_text("Button") # set a label to the button
|
||||
|
||||
How can I use it?
|
||||
-----------------
|
||||
|
||||
You can start in less than 10 minutes on a M5Stack or equivalent device
|
||||
in less than 10 minutes in this `short tutorial <https://tasmota.github.io/docs/LVGL_in_10_minutes/>`__
|
||||
|
||||
Where can I find more information?
|
||||
----------------------------------
|
||||
|
||||
- `Tasmota Documentation <https://tasmota.github.io/docs/>`__
|
||||
- `Berry Documentation <https://github.com/berry-lang/berry/wiki/Reference>`__
|
||||
- `Tasmota LVGL Berry documentation <https://tasmota.github.io/docs/LVGL/>`__
|
||||
9
docs/details/integration/ide/index.rst
Normal file
9
docs/details/integration/ide/index.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
====
|
||||
IDEs
|
||||
====
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
mdk
|
||||
pc-simulator
|
||||
5
docs/details/integration/ide/mdk.rst
Normal file
5
docs/details/integration/ide/mdk.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
===
|
||||
MDK
|
||||
===
|
||||
|
||||
TODO
|
||||
54
docs/details/integration/ide/pc-simulator.rst
Normal file
54
docs/details/integration/ide/pc-simulator.rst
Normal file
@@ -0,0 +1,54 @@
|
||||
.. _simulator:
|
||||
|
||||
===============
|
||||
Simulator on PC
|
||||
===============
|
||||
|
||||
You can try out LVGL **using only your PC** (i.e. without any
|
||||
development boards). LVGL will run on a simulator environment on the PC
|
||||
where anyone can write and experiment with real LVGL applications.
|
||||
|
||||
Using the simulator on a PC has the following advantages:
|
||||
|
||||
- Hardware independent: Write code, run it on the PC and see the result on a monitor.
|
||||
- Cross-platform: Any Windows, Linux or macOS system can run the PC simulator.
|
||||
- Portability: The written code is portable, which means you can simply copy it when migrating to embedded hardware.
|
||||
- Easy Validation: The simulator is also very useful to report bugs because it
|
||||
provides a common platform for every user.
|
||||
- Better developer experience: On PC Debuggers are usually faster and better, you can log to files,
|
||||
add a lot of ``printf`` s, do profiling, and so on.
|
||||
|
||||
|
||||
Select an IDE
|
||||
-------------
|
||||
|
||||
The simulator is ported to various IDEs (Integrated Development Environments).
|
||||
Choose your favorite IDE, read its README on GitHub, download the project, and load it to the IDE.
|
||||
|
||||
- `Eclipse with SDL driver <https://github.com/lvgl/lv_sim_eclipse_sdl>`__: Recommended on Linux and Mac, supports CMake as well
|
||||
- `VisualStudio <https://github.com/lvgl/lv_port_pc_visual_studio>`__: Recommended on Windows
|
||||
- `VSCode with SDL driver <https://github.com/lvgl/lv_port_pc_vscode>`__: Recommended on Linux (SDL) and Mac (SDL)
|
||||
- `CodeBlocks <https://github.com/lvgl/lv_sim_codeblocks_win>`__: Recommended on Windows
|
||||
- `PlatformIO with SDL driver <https://github.com/lvgl/lv_platformio>`__: Recommended on Linux and Mac but has an STM32 environment as well
|
||||
- `Generic Linux <https://github.com/lvgl/lv_port_linux>`__: CMake based project where you can easily switch between fbdev, DRM, and SDL.
|
||||
- `MDK with FastModel <https://github.com/lvgl/lv_port_an547_cm55_sim>`__: For Windows
|
||||
|
||||
External project not maintained by the LVGL organization:
|
||||
|
||||
- `QT Creator <https://github.com/Varanda-Labs/lvgl-qt-sim>`__: Cross platform
|
||||
|
||||
Built-in drivers
|
||||
----------------
|
||||
|
||||
LVGL comes with several :ref:`built-in drivers <drivers>`.
|
||||
|
||||
Even if a simulator project comes with e.g. SDL, you can easily replace it by enabling
|
||||
another driver in ``lv_conf.h`` and calling its ``create`` function.
|
||||
|
||||
For example to use the Linux frame buffer device instead of SDL just enable ``LV_USE_LINUX_FBDEV``
|
||||
and call
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_display_t *display = lv_linux_fbdev_create();
|
||||
lv_linux_fbdev_set_file(display, "/dev/fb0")
|
||||
17
docs/details/integration/index.rst
Normal file
17
docs/details/integration/index.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
.. _integration_index:
|
||||
|
||||
=======================
|
||||
Integration and Drivers
|
||||
=======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
bindings/index
|
||||
building/index
|
||||
chip/index
|
||||
driver/index
|
||||
renderers/index
|
||||
framework/index
|
||||
ide/index
|
||||
os/index
|
||||
5
docs/details/integration/os/freertos.rst
Normal file
5
docs/details/integration/os/freertos.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
========
|
||||
FreeRTOS
|
||||
========
|
||||
|
||||
TODO
|
||||
14
docs/details/integration/os/index.rst
Normal file
14
docs/details/integration/os/index.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
======
|
||||
(RT)OS
|
||||
======
|
||||
|
||||
.. toctree:: :maxdepth: 2
|
||||
|
||||
freertos
|
||||
mqx
|
||||
nuttx
|
||||
px5
|
||||
qnx
|
||||
rt-thread
|
||||
yocto/index
|
||||
zephyr
|
||||
10
docs/details/integration/os/mqx.rst
Normal file
10
docs/details/integration/os/mqx.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
.. _mqx:
|
||||
|
||||
========
|
||||
MQX RTOS
|
||||
========
|
||||
|
||||
See `MQX RTOS's homepage <https://www.nxp.com/design/design-center/software/embedded-software/mqx-software-solutions/mqx-real-time-operating-system-rtos:MQXRTOS>`__
|
||||
|
||||
|
||||
TODO
|
||||
158
docs/details/integration/os/nuttx.rst
Normal file
158
docs/details/integration/os/nuttx.rst
Normal file
@@ -0,0 +1,158 @@
|
||||
==========
|
||||
NuttX RTOS
|
||||
==========
|
||||
|
||||
What is NuttX?
|
||||
--------------
|
||||
|
||||
`NuttX <https://nuttx.apache.org/>`__ is a mature and secure real-time
|
||||
operating system (RTOS) with an emphasis on technical standards
|
||||
compliance and small size. It is scalable from 8-bit to 64-bit
|
||||
microcontrollers and microprocessors and compliant with the Portable
|
||||
Operating System Interface (POSIX) and the American National Standards
|
||||
Institute (ANSI) standards and with many Linux-like subsystems. The best
|
||||
way to think about NuttX is to think of it as a small Unix/Linux for
|
||||
microcontrollers.
|
||||
|
||||
Highlights of NuttX
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **Small** - Fits and runs in microcontrollers as small as 32 kB Flash
|
||||
and 8 kB of RAM.
|
||||
- **Compliant** - Strives to be as compatible as possible with POSIX
|
||||
and Linux.
|
||||
- **Versatile** - Supports many architectures (ARM, ARM Thumb, AVR,
|
||||
MIPS, OpenRISC, RISC-V 32-bit and 64-bit, RX65N, x86-64, Xtensa,
|
||||
Z80/Z180, etc.).
|
||||
- **Modular** - Its modular design allows developers to select only
|
||||
what really matters and use modules to include new features.
|
||||
- **Popular** - NuttX is used by many companies around the world.
|
||||
Probably you already used a product with NuttX without knowing it was
|
||||
running NuttX.
|
||||
- **Predictable** - NuttX is a preemptible Realtime kernel, so you can
|
||||
use it to create predictable applications for realtime control.
|
||||
|
||||
--------------
|
||||
|
||||
Why NuttX + LVGL?
|
||||
-----------------
|
||||
|
||||
Although NuttX has its own graphic library called
|
||||
`NX <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=139629474>`__,
|
||||
LVGL is a good alternative because users could find more eye-candy demos
|
||||
and they can reuse code from previous projects. LVGL is an
|
||||
`Object-Oriented Component
|
||||
Based <https://blog.lvgl.io/2018-12-13/extend-lvgl-objects>`__
|
||||
high-level GUI library, that could fit very well for a RTOS with
|
||||
advanced features like NuttX. LVGL is implemented in C and its APIs are
|
||||
in C.
|
||||
|
||||
Here are some advantages of using LVGL in NuttX
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Develop GUI in Linux first and when it is done just compile it for
|
||||
NuttX. Nothing more, no wasting of time.
|
||||
- Usually, GUI development for low level RTOS requires multiple
|
||||
iterations to get things right, where each iteration consists of
|
||||
**``Change code`` > ``Build`` > ``Flash`` > ``Run``**. Using LVGL,
|
||||
Linux and NuttX you can reduce this process and just test everything
|
||||
on your computer and when it is done, compile it on NuttX and that is
|
||||
it.
|
||||
|
||||
NuttX + LVGL could be used for
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- GUI demos to demonstrate your board graphics capacities.
|
||||
- Fast prototyping GUI for MVP (Minimum Viable Product) presentation.
|
||||
- visualize sensor data directly and easily on the board without using
|
||||
a computer.
|
||||
- Final products with a GUI without a touchscreen (i.e. 3D Printer
|
||||
Interface using Rotary Encoder to Input data).
|
||||
- Final products with a touchscreen (and all sorts of bells and
|
||||
whistles).
|
||||
|
||||
--------------
|
||||
|
||||
How to get started with NuttX and LVGL?
|
||||
---------------------------------------
|
||||
|
||||
There are many boards in the `NuttX
|
||||
mainline <https://github.com/apache/incubator-nuttx>`__ with support for
|
||||
LVGL. Let's use the
|
||||
`STM32F429IDISCOVERY <https://www.st.com/en/evaluation-tools/32f429idiscovery.html>`__
|
||||
as an example because it is a very popular board.
|
||||
|
||||
First you need to install the pre-requisites on your system
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's use the `Windows Subsystem for
|
||||
Linux <https://acassis.wordpress.com/2018/01/10/how-to-build-nuttx-on-windows-10/>`__
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ sudo apt-get install automake bison build-essential flex gcc-arm-none-eabi gperf git libncurses5-dev libtool libusb-dev libusb-1.0.0-dev pkg-config kconfig-frontends openocd
|
||||
|
||||
Now let's create a workspace to save our files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ mkdir ~/nuttxspace
|
||||
$ cd ~/nuttxspace
|
||||
|
||||
Clone the NuttX and Apps repositories:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ git clone https://github.com/apache/incubator-nuttx nuttx
|
||||
$ git clone https://github.com/apache/incubator-nuttx-apps apps
|
||||
|
||||
Configure NuttX to use the stm32f429i-disco board and the LVGL Demo
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ ./tools/configure.sh stm32f429i-disco:lvgl
|
||||
$ make
|
||||
|
||||
If everything went fine you should have now the file ``nuttx.bin`` to
|
||||
flash on your board:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ ls -l nuttx.bin
|
||||
-rwxrwxr-x 1 alan alan 287144 Jun 27 09:26 nuttx.bin
|
||||
|
||||
Flashing the firmware in the board using OpenOCD:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ sudo openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000"
|
||||
|
||||
Reset the board and using the 'NSH>' terminal start the LVGL demo:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
nsh> lvgldemo
|
||||
|
||||
Configurations
|
||||
--------------
|
||||
Here are some configurations that you can use to customize your NuttX and LVGL setup:
|
||||
|
||||
- **LV_USE_NUTTX_INDEPENDENT_IMAGE_HEAP** - You can enable or disable the
|
||||
LVGL image heap in NuttX. By default, it is disabled. If you enable
|
||||
it, LVGL will use the NuttX heap instead.
|
||||
|
||||
Where can I find more information?
|
||||
----------------------------------
|
||||
|
||||
- This blog post: `LVGL on
|
||||
LPCXpresso54628 <https://acassis.wordpress.com/2018/07/19/running-nuttx-on-lpcxpresso54628-om13098/>`__
|
||||
- NuttX mailing list: `Apache NuttX Mailing
|
||||
List <http://nuttx.incubator.apache.org/community/>`__
|
||||
|
||||
|
||||
.. Comment: The above blank line is necessary for Sphinx to not complain,
|
||||
since it looks for the blank line after a bullet list.
|
||||
8
docs/details/integration/os/px5.rst
Normal file
8
docs/details/integration/os/px5.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
========
|
||||
PX5 RTOS
|
||||
========
|
||||
|
||||
See `PX5 RTOS's homepage <https://px5rtos.com/>`__
|
||||
|
||||
|
||||
TODO
|
||||
158
docs/details/integration/os/qnx.rst
Normal file
158
docs/details/integration/os/qnx.rst
Normal file
@@ -0,0 +1,158 @@
|
||||
.. _qnx:
|
||||
|
||||
===
|
||||
QNX
|
||||
===
|
||||
|
||||
What is QNX?
|
||||
************
|
||||
|
||||
QNX is a commercial operating system first released in 1980. The operating
|
||||
system is based on a micro-kernel design, with the file system(s), network
|
||||
stack, and various other drivers each running in its own process with a separate
|
||||
address space.
|
||||
|
||||
See www.qnx.com for more details.
|
||||
|
||||
Highlight of QNX
|
||||
----------------
|
||||
|
||||
- 64-bit only, runs on x86_64 and ARMv8
|
||||
- Requires an MMU as the design mandates separation among processes
|
||||
- Support for thousands of processes and millions of threads
|
||||
- Up to 64 cores, up to 16TB of RAM
|
||||
- Virtualization support (as host and guest)
|
||||
- Full POSIX compatibility
|
||||
- Safety certification to various automotive, industrial and medical standards
|
||||
|
||||
How to run LVGL on QNX?
|
||||
***********************
|
||||
|
||||
There are two ways to use LVGL in your QNX project. The first is similar to how
|
||||
LVGL is used on other systems. The second is to build LVGL as either a shared or
|
||||
a static library.
|
||||
|
||||
Include LVGL in Your Project
|
||||
----------------------------
|
||||
|
||||
Follow the generic instructions for getting started with LVGL. After copying
|
||||
`lv_conf_template.h` to `lv_conf.h` make the following changes to the latter:
|
||||
|
||||
1. Enable QNX support:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_USE_QNX 1
|
||||
|
||||
2. Set colour depth to 32:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_COLOR_DEPTH 32
|
||||
|
||||
3. (Optional) Enable double-buffering:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define LV_QNX_BUF_COUNT 2
|
||||
|
||||
Build LVGL as a Library
|
||||
-----------------------
|
||||
|
||||
**Note that this method is an alternative to including LVGL in your project. If
|
||||
you choose to build a library then you do not need to follow the instructions in
|
||||
the previous section.**
|
||||
|
||||
The top-level `qnx` directory includes a recursive make file for building LVGL,
|
||||
both as a shared library and as a static library for the supported
|
||||
architectures. To build all libraries, simply invoke `make` in this directory:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
# cd $(LVGL_ROOT)/env_support/qnx
|
||||
# make
|
||||
|
||||
If you prefer to build for a specific architecture and variant, go to the
|
||||
appropriate directory and run `make` there. For example, to build a shared
|
||||
library for ARMv8:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
# cd $(LVGL_ROOT)/env_support/qnx/aarch64/so.le
|
||||
# make
|
||||
|
||||
As a general rule, if you only want to have one LVGL application in your system
|
||||
then it is better to use a static library. If you have more than one, and
|
||||
especially if they run concurrently, it is better to use the shared library.
|
||||
|
||||
Before building the library, you may wish to edit
|
||||
`$(LVGL_ROOT)/env_support/qnx/lv_conf.h`, e.g. to add fonts or disable
|
||||
double-buffering.
|
||||
|
||||
Writing a LVGL Application
|
||||
--------------------------
|
||||
|
||||
To create a LVGL application for QNX, follow these steps in your code:
|
||||
|
||||
1. Initialize the library.
|
||||
2. Create a window.
|
||||
3. Add the input devices.
|
||||
4. Create the UI.
|
||||
5. Run the event loop.
|
||||
|
||||
Steps 2, 3 and 5 use QNX-specific calls, but the rest of the code should be
|
||||
identical to that of a LVGL application written for any other platform.
|
||||
|
||||
The following code shows how to create a "Hello World" application:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/* Initialize the library. */
|
||||
lv_init();
|
||||
|
||||
/* Create a 800x480 window. */
|
||||
lv_display_t *disp = lv_qnx_window_create(800, 480);
|
||||
lv_qnx_window_set_title(disp, "LVGL Example");
|
||||
|
||||
/* Add keyboard and mouse devices. */
|
||||
lv_qnx_add_keyboard_device(disp);
|
||||
lv_qnx_add_pointer_device(disp);
|
||||
|
||||
/* Generate the UI. */
|
||||
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "Hello world");
|
||||
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
/* Run the event loop until it exits. */
|
||||
return lv_qnx_event_loop(disp);
|
||||
}
|
||||
|
||||
Build the Application
|
||||
---------------------
|
||||
|
||||
Building the application consists of compiling the source with the LVGL headers,
|
||||
and then linking against the library. This can be done in many ways, using
|
||||
different build systems. The following is a simple make file for the example
|
||||
above, which builds for ARMv8 with the shared library:
|
||||
|
||||
.. code-block:: makefile
|
||||
|
||||
CC=qcc -Vgcc_ntoaarch64le
|
||||
|
||||
LVGL_ROOT=$(HOME)/src/lvgl
|
||||
CCFLAGS=-I$(LVGL_ROOT)/env_support/qnx -I$(LVGL_ROOT)
|
||||
LDFLAGS=-lscreen -llvgl -L$(LVGL_ROOT)/env_support/qnx/aarch64/so.le
|
||||
|
||||
lvgl_example: lvgl_example.c
|
||||
$(CC) $(CCFLAGS) -Wall -o $@ $< $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ lvgl_example
|
||||
88
docs/details/integration/os/rt-thread.rst
Normal file
88
docs/details/integration/os/rt-thread.rst
Normal file
@@ -0,0 +1,88 @@
|
||||
==============
|
||||
RT-Thread RTOS
|
||||
==============
|
||||
|
||||
What is RT-Thread?
|
||||
------------------
|
||||
|
||||
`RT-Thread <https://www.rt-thread.io/>`__ is an `open
|
||||
source <https://github.com/RT-Thread/rt-thread>`__, neutral, and
|
||||
community-based real-time operating system (RTOS). RT-Thread has
|
||||
**Standard version** and **Nano version**. For resource-constrained
|
||||
microcontroller (MCU) systems, the Nano version that requires only 3 KB
|
||||
Flash and 1.2 KB RAM memory resources can be tailored with easy-to-use
|
||||
tools. For resource-rich IoT devices, RT-Thread can use the **online
|
||||
software package** management tool, together with system configuration
|
||||
tools, to achieve intuitive and rapid modular cutting, seamlessly import
|
||||
rich software packages; thus, achieving complex functions like Android's
|
||||
graphical interface and touch sliding effects, smart voice interaction
|
||||
effects, and so on.
|
||||
|
||||
Key features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Designed for resource-constrained devices, the minimum kernel
|
||||
requires only 1.2KB of RAM and 3 KB of Flash.
|
||||
- A variety of standard interfaces, such as POSIX, CMSIS, C++
|
||||
application environment.
|
||||
- Has rich components and a prosperous and fast growing `package ecosystem <https://packages.rt-thread.org/en/>`__
|
||||
- Elegant code style, easy to use, read and master.
|
||||
- High Scalability. RT-Thread has high-quality scalable software
|
||||
architecture, loose coupling, modularity, is easy to tailor and
|
||||
expand.
|
||||
- Supports high-performance applications.
|
||||
- Supports all mainstream compiling tools such as GCC, Keil and IAR.
|
||||
- Supports a wide range of `architectures and chips <https://www.rt-thread.io/board.html>`__
|
||||
|
||||
How to run LVGL on RT-Thread?
|
||||
-----------------------------
|
||||
|
||||
`中文文档 <https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/packages-manual/lvgl-docs/introduction>`__
|
||||
|
||||
LVGL has registered as a
|
||||
`softwarepackage <https://packages.rt-thread.org/en/detail.html?package=LVGL>`__
|
||||
of RT-Thread. By using
|
||||
`Env tool <https://www.rt-thread.io/download.html?download=Env>`__ or
|
||||
`RT-Thread Studio IDE <https://www.rt-thread.io/download.html?download=Studio>`__,
|
||||
RT-Thread users can easily download LVGL source code and combine with
|
||||
RT-Thread project.
|
||||
|
||||
RT-Thread community has port LVGL to several BSPs:
|
||||
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| BSP | BSP |
|
||||
+======================================================================================================================================+======================================================================================================================================================+
|
||||
| `QEMU simulator <https://github.com/RT-Thread/rt-thread/tree/master/bsp/qemu-vexpress-a9/applications/lvgl>`__ | `Infineon psoc6-evaluationkit-062S2 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/Infineon/psoc6-evaluationkit-062S2/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Visual Studio simulator <https://github.com/RT-Thread/rt-thread/tree/master/bsp/simulator/applications/lvgl>`__ | `Renesas ra6m3-ek <https://github.com/RT-Thread/rt-thread/tree/master/bsp/renesas/ra6m3-ek/board/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton numaker-iot-m487 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/numaker-iot-m487/applications/lvgl>`__ | `Renesas ra6m4-cpk <https://github.com/RT-Thread/rt-thread/tree/master/bsp/renesas/ra6m4-cpk/board/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton numaker-pfm-m487 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/numaker-pfm-m487/applications/lvgl>`__ | `Renesas ra6m3-hmi <https://github.com/RT-Thread/rt-thread/tree/master/bsp/renesas/ra6m3-hmi-board/board/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton nk-980iot <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/nk-980iot/applications/lvgl>`__ | `STM32H750 ART-Pi <https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32h750-artpi/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton numaker-m2354 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/numaker-m2354/applications/lvgl>`__ | `STM32F469 Discovery <https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32f469-st-disco/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton nk-n9h30 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/nk-n9h30/applications/lvgl>`__ | `STM32F407 explorer <https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32f407-atk-explorer/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton numaker-m032ki <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/numaker-m032ki/applications/lvgl>`__ | `STM32L475 pandora <https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32l475-atk-pandora/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton numaker-hmi-ma35d1 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/numaker-hmi-ma35d1/applications/lvgl>`__ | `NXP imxrt1060-evk <https://github.com/RT-Thread/rt-thread/tree/master/bsp/imxrt/imxrt1060-nxp-evk/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton numaker-iot-m467 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/numaker-iot-m467/applications/lvgl>`__ | `Raspberry PICO <https://github.com/RT-Thread/rt-thread/tree/master/bsp/raspberry-pico/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `Nuvoton numaker-m467hj <https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/numaker-m467hj/applications/lvgl>`__ | `NXP LPC55S69 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/lpc55sxx/lpc55s69_nxp_evk/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| `synwit swm341 <https://github.com/RT-Thread/rt-thread/tree/master/bsp/synwit/swm341/applications/lvgl>`__ |
|
||||
+--------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
Tutorials
|
||||
~~~~~~~~~
|
||||
|
||||
- `Introduce about RT-Thread and how to run LVGL on RT-Thread in simulators <https://www.youtube.com/watch?v=k7QYk6hSwnc>`__
|
||||
- `How to import a BSP project with latest code into RT-Thread Studio <https://www.youtube.com/watch?v=fREPLuh-h8k>`__
|
||||
- `How to Use LVGL with RT-Thread Studio in STM32F469 Discovery Board <https://www.youtube.com/watch?v=O_QA99BxnOE>`__
|
||||
- `RT-Thread Youtube Channel <https://www.youtube.com/channel/UCdDHtIfSYPq4002r27ffqPw>`__
|
||||
- `RT-Thread documentation center <https://www.rt-thread.io/document/site/>`__
|
||||
149
docs/details/integration/os/yocto/core_components.rst
Normal file
149
docs/details/integration/os/yocto/core_components.rst
Normal file
@@ -0,0 +1,149 @@
|
||||
.. _yocto_project_core_components:
|
||||
|
||||
=============================
|
||||
Yocto Project Core Components
|
||||
=============================
|
||||
|
||||
The BitBake task executor together with various types of configuration files
|
||||
form the OpenEmbedded-Core (OE-Core). This section overviews these components
|
||||
by describing their use and how they interact.
|
||||
|
||||
BitBake handles the parsing and execution of the data files. The data
|
||||
itself is of various types:
|
||||
|
||||
- *Recipes:* Provides details about particular pieces of software.
|
||||
|
||||
- *Class Data:* Abstracts common build information (e.g. how to build a
|
||||
Linux kernel).
|
||||
|
||||
- *Configuration Data:* Defines machine-specific settings, policy
|
||||
decisions, and so forth. Configuration data acts as the glue to bind
|
||||
everything together.
|
||||
|
||||
BitBake knows how to combine multiple data sources together and refers
|
||||
to each data source as a layer.
|
||||
|
||||
Here are some brief details on these core components.
|
||||
|
||||
.. _bitbake_section:
|
||||
|
||||
BitBake
|
||||
*******
|
||||
|
||||
BitBake is the tool at the heart of the OpenEmbedded Build System and is
|
||||
responsible for parsing the Metadata, generating a list of tasks from it, and
|
||||
then executing those tasks.
|
||||
|
||||
This section briefly introduces BitBake. If you want more information on
|
||||
BitBake, see the `BitBake User Manual <https://docs.yoctoproject.org/bitbake/2.
|
||||
8/index.html>`_.
|
||||
|
||||
To see a list of the options BitBake supports, use either of the
|
||||
following commands::
|
||||
|
||||
$ bitbake -h
|
||||
$ bitbake --help
|
||||
|
||||
The most common usage for BitBake is ``bitbake recipename``, where
|
||||
``recipename`` is the name of the recipe you want to build (referred
|
||||
to as the "target"). The target often equates to the first part of a
|
||||
recipe's filename (e.g. "foo" for a recipe named ``foo_1.3.0-r0.bb``).
|
||||
So, to process the ``matchbox-desktop_1.2.3.bb`` recipe file, you might
|
||||
type the following::
|
||||
|
||||
$ bitbake matchbox-desktop
|
||||
|
||||
Several different versions of ``matchbox-desktop`` might exist. BitBake chooses
|
||||
the one selected by the distribution configuration. You can get more details
|
||||
about how BitBake chooses between different target versions and providers in the
|
||||
"`Preferences <https://docs.yoctoproject.org/bitbake/2.8/bitbake-user-manual/
|
||||
bitbake-user-manual-execution.html#preferences>`_" section of the BitBake User
|
||||
Manual.
|
||||
|
||||
BitBake also tries to execute any dependent tasks first. So for example,
|
||||
before building ``matchbox-desktop``, BitBake would build a cross
|
||||
compiler and ``glibc`` if they had not already been built.
|
||||
|
||||
A useful BitBake option to consider is the ``-k`` or ``--continue``
|
||||
option. This option instructs BitBake to try and continue processing the
|
||||
job as long as possible even after encountering an error. When an error
|
||||
occurs, the target that failed and those that depend on it cannot be
|
||||
remade. However, when you use this option other dependencies can still
|
||||
be processed.
|
||||
|
||||
.. _recipes_section:
|
||||
|
||||
Recipes
|
||||
*******
|
||||
|
||||
Files that have the ``.bb`` suffix are "recipes" files. In general, a
|
||||
recipe contains information about a single piece of software. This
|
||||
information includes the location from which to download the unaltered
|
||||
source, any source patches to be applied to that source (if needed),
|
||||
which special configuration options to apply, how to compile the source
|
||||
files, and how to package the compiled output.
|
||||
|
||||
The term "package" is sometimes used to refer to recipes. However, since
|
||||
the word "package" is used for the packaged output from the OpenEmbedded
|
||||
build system (i.e. ``.ipk`` or ``.deb`` files), this document avoids
|
||||
using the term "package" when referring to recipes.
|
||||
|
||||
|
||||
.. _classes_section:
|
||||
|
||||
Classes
|
||||
*******
|
||||
|
||||
Class files (``.bbclass``) contain information that is useful to share
|
||||
between recipes files. An example is the autotools* class,
|
||||
which contains common settings for any application that is built with
|
||||
the `GNU Autotools <https://en.wikipedia.org/wiki/GNU_Autotools>`.
|
||||
The "`Classes <https://docs.yoctoproject.org/ref-manual/classes.
|
||||
html#classes>`_" chapter in the Yocto Project
|
||||
Reference Manual provides details about classes and how to use them.
|
||||
|
||||
|
||||
.. _configurations_section:
|
||||
|
||||
Configurations
|
||||
**************
|
||||
|
||||
The configuration files (``.conf``) define various configuration
|
||||
variables that govern the OpenEmbedded build process. These files fall
|
||||
into several areas that define machine configuration options,
|
||||
distribution configuration options, compiler tuning options, general
|
||||
common configuration options, and user configuration options in
|
||||
``conf/local.conf``, which is found in the `Build Directory <https://docs.
|
||||
yoctoproject.org/ref-manual/terms.html#term-Build-Directory>`_.
|
||||
|
||||
.. _layers_section:
|
||||
|
||||
Layers
|
||||
******
|
||||
|
||||
Layers are repositories that contain related metadata (i.e. sets of
|
||||
instructions) that tell the OpenEmbedded build system how to build a
|
||||
target. `The yocto project layer model <https://docs.yoctoproject.org/
|
||||
overview-manual/yp-intro.html#the-yocto-project-layer-model>`_
|
||||
facilitates collaboration, sharing, customization, and reuse within the
|
||||
Yocto Project development environment. Layers logically separate
|
||||
information for your project. For example, you can use a layer to hold
|
||||
all the configurations for a particular piece of hardware. Isolating
|
||||
hardware-specific configurations allows you to share other metadata by
|
||||
using a different layer where that metadata might be common across
|
||||
several pieces of hardware.
|
||||
|
||||
There are many layers working in the Yocto Project development environment. The
|
||||
`Yocto Project Compatible Layer Index <https://www.yoctoproject.org/development/
|
||||
yocto-project-compatible-layers/>`_ and `OpenEmbedded Layer Index <https://
|
||||
layers.openembedded.org/layerindex/branch/master/layers/>`_ both contain layers
|
||||
from
|
||||
which you can use or leverage.
|
||||
|
||||
By convention, layers in the Yocto Project follow a specific form. Conforming
|
||||
to a known structure allows BitBake to make assumptions during builds on where
|
||||
to find types of metadata. You can find procedures and learn about tools (i.e.
|
||||
``bitbake-layers``) for creating layers suitable for the Yocto Project in the
|
||||
"`understanding and creating layers <https://docs.yoctoproject.org/dev-manual/
|
||||
layers.html#understanding-and-creating-layers>`_" section of the
|
||||
Yocto Project Development Tasks Manual.
|
||||
28
docs/details/integration/os/yocto/index.rst
Normal file
28
docs/details/integration/os/yocto/index.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
.. _yocto:
|
||||
|
||||
=====
|
||||
Yocto
|
||||
=====
|
||||
|
||||
The Yocto Project (YP) is an open source collaboration project that helps
|
||||
developers create custom Linux-based systems regardless of the hardware
|
||||
architecture.
|
||||
|
||||
The project provides a flexible set of tools and a space where embedded
|
||||
developers worldwide can share technologies, software stacks, configurations,
|
||||
and best practices that can be used to create tailored Linux images for
|
||||
embedded and IOT devices, or anywhere a customized Linux OS is needed.
|
||||
|
||||
This section objective is to ease to process of understanding the basic
|
||||
concepts of Yocto and to help beginners to start with Yocto.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:maxdepth: 1
|
||||
|
||||
core_components
|
||||
lvgl_recipe
|
||||
terms_and_variables
|
||||
|
||||
|
||||
916
docs/details/integration/os/yocto/lvgl_recipe.rst
Normal file
916
docs/details/integration/os/yocto/lvgl_recipe.rst
Normal file
@@ -0,0 +1,916 @@
|
||||
.. _yocto_lvgl_recipe:
|
||||
|
||||
=============
|
||||
LVGL in Yocto
|
||||
=============
|
||||
|
||||
This chapter serves as a guide to help you create a recipe for an application
|
||||
using LVGL. While the process will be demonstrated for the Raspberry Pi 3
|
||||
(64-bit), it can be applied to any board in a similar way.
|
||||
|
||||
Build Host Packages
|
||||
*******************
|
||||
You must install essential host packages on your build host. The following
|
||||
command installs the host packages based on an Ubuntu distribution
|
||||
|
||||
.. code-block::
|
||||
|
||||
sudo apt install gawk wget git diffstat unzip texinfo gcc build-essential \
|
||||
chrpath socat cpio python3 python3-pip python3-pexpect xz-utils \
|
||||
debianutils iputils-ping python3-git python3-jinja2 python3-subunit zstd \
|
||||
liblz4-tool file locales libacl1
|
||||
|
||||
.. note::
|
||||
|
||||
For host package requirements on all supported Linux distributions, see the
|
||||
`Required Packages for the Build Host <https://docs.yoctoproject.org/
|
||||
ref-manual/system-requirements.html#required-packages-for-the-build-host>`_
|
||||
section in the Yocto Project Reference Manual.
|
||||
|
||||
|
||||
|
||||
Use Git to clone the required repositories
|
||||
******************************************
|
||||
After this section the folder tree will be like this
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
lvgl_yocto_guide/
|
||||
├── build/
|
||||
│ ├── cache/
|
||||
│ ├── conf/
|
||||
│ ├── downloads/
|
||||
│ └── ...
|
||||
└── sources/
|
||||
├── meta-openembedded
|
||||
├── meta-raspberrypi
|
||||
└── poky
|
||||
|
||||
Start creating the folder architecture
|
||||
|
||||
.. code-block::
|
||||
|
||||
mkdir -p lvgl_yocto_guide/sources
|
||||
|
||||
Clone Poky, meta-openembedded and meta-raspberrypi in the sources
|
||||
|
||||
.. code-block::
|
||||
|
||||
cd lvgl_yocto_guide/sources
|
||||
git clone --branch scarthgap https://git.yoctoproject.org/poky.git
|
||||
git clone --branch scarthgap https://git.openembedded.org/meta-openembedded
|
||||
git clone --branch scarthgap git://git.yoctoproject.org/meta-raspberrypi
|
||||
|
||||
|
||||
Build a base image
|
||||
******************
|
||||
To understand better what is going on, let's build the image like it is
|
||||
prepared for us
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
cd ../ # go back to the root folder
|
||||
source sources/poky/oe-init-build-env
|
||||
|
||||
Now you should have a folder named ``build`` next to ``sources``. The last
|
||||
command
|
||||
also sets the current directory to the build directory.
|
||||
|
||||
In the build directory, there is a ``conf`` folder with some files in it
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
└── build/
|
||||
└── conf/
|
||||
├── bblayers.conf
|
||||
├── conf-notes.txt
|
||||
├── conf-summary.txt
|
||||
├── local.conf
|
||||
└── templateconf.cfg
|
||||
|
||||
The important files for us are ``local.conf`` and ``bblayers.conf``
|
||||
|
||||
To add layers to the project there are 2 options:
|
||||
|
||||
**Bitbake commands (Option 1)**
|
||||
|
||||
You need to be in the same terminal you did the ``source`` command. Add the
|
||||
layers with the Bitbake command like this
|
||||
|
||||
.. code-block::
|
||||
|
||||
bitbake-layers add-layer ../sources/meta-openembedded
|
||||
bitbake-layers add-layer ../sources/meta-raspberrypi
|
||||
|
||||
**Modify conf file (Option 2)**
|
||||
|
||||
Open ``conf/bblayers.conf`` file and add manually the paths:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
|
||||
# changes incompatibly
|
||||
POKY_BBLAYERS_CONF_VERSION = "2"
|
||||
|
||||
BBPATH = "${TOPDIR}"
|
||||
BBFILES ?= ""
|
||||
|
||||
BBLAYERS ?= " \
|
||||
${TOPDIR}/../sources/poky/meta \
|
||||
${TOPDIR}/../sources/poky/meta-poky \
|
||||
${TOPDIR}/../sources/poky/meta-yocto-bsp \
|
||||
${TOPDIR}/../sources/meta-raspberrypi \
|
||||
${TOPDIR}/../sources/meta-openembedded/meta-oe \
|
||||
${TOPDIR}/../sources/meta-openembedded/meta-multimedia \
|
||||
${TOPDIR}/../sources/meta-openembedded/meta-networking \
|
||||
${TOPDIR}/../sources/meta-openembedded/meta-python \
|
||||
"
|
||||
|
||||
To ensure the layers were added as expected, run the Bitbake command to show
|
||||
all the layers::
|
||||
|
||||
bitbake-layers show-layers
|
||||
|
||||
The following layers should be listed:
|
||||
- core
|
||||
- yocto
|
||||
- yoctobsp
|
||||
- raspberrypi
|
||||
- openembedded-layer
|
||||
- multimedia-layer
|
||||
- networking-layer
|
||||
- meta-python
|
||||
|
||||
Build for RaspberryPi3 64
|
||||
=========================
|
||||
|
||||
The available machine configurations for Raspberrypi can be listed like this
|
||||
|
||||
.. code-block::
|
||||
|
||||
ls ../sources/meta-raspberrypi/conf/machine/*.conf
|
||||
|
||||
To build an image for Raspberrypi3 64 bits, modify the file ``local.conf`` file
|
||||
replacing the ``MACHINE ??=`` default value like this
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
MACHINE ??= "raspberrypi3-64"
|
||||
|
||||
To build the image we will target, it is also needed to add this to the file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch"
|
||||
|
||||
.. note::
|
||||
|
||||
You can find more information about this variable `here <https://meta-raspberrypi.readthedocs.io/en/latest/ipcompliance.html#linux-firmware-rpidistro>`_.
|
||||
|
||||
Everything is setup, time to build the image::
|
||||
|
||||
bitbake core-image-base
|
||||
|
||||
|
||||
Overview of the build
|
||||
=====================
|
||||
|
||||
Let's go through the build folders to understand what happened.
|
||||
|
||||
Downloads
|
||||
---------
|
||||
|
||||
The folder location can be changed with the ``DL_DIR`` variable.
|
||||
|
||||
The Downloads folder is a fundamental part of the Yocto build environment,
|
||||
serving as a local cache for all external sources and dependencies. This
|
||||
caching mechanism is essential for efficient builds, ensuring that repeated
|
||||
builds do not waste time downloading the same files again.
|
||||
|
||||
|
||||
tmp/deploy
|
||||
----------
|
||||
|
||||
This folder contains the final output artifacts that are ready for deployment.
|
||||
These artifacts include kernel images, root filesystems, packages, SDKs,
|
||||
bootloader files, and other components that are generated during the Yocto
|
||||
build process.
|
||||
|
||||
There are some key folders:
|
||||
- **images**: it contains the images that can be flashed or deployed to
|
||||
the target device. Files like the Linux kernel, root filesystem (e.g., .
|
||||
ext4, .tar.gz, .squashfs), bootloaders (e.g., U-Boot), and other
|
||||
bootable images for the device are found here. t’s organized by the
|
||||
machine (or target board) for which the image was built.
|
||||
- **rmp/deb/ipk**: These folders contain the individual software packages
|
||||
generated during the build, in the specified package format (RPM, DEB,
|
||||
or IPK). These packages are typically created when you’re building your
|
||||
Yocto project with package management support enabled. These can later
|
||||
be installed on the target device using package management tools
|
||||
- **sdk**: This subdirectory contains Software Development Kits (SDKs)
|
||||
that you can use to cross-compile applications for your target system.
|
||||
The SDKs are generated when you use the ``bitbake -c populate_sdk``
|
||||
command.
|
||||
|
||||
|
||||
tmp/sysroots-components
|
||||
-----------------------
|
||||
This folder is a modular approach introduced in Yocto to handle sysroots. It
|
||||
divides the sysroot into individual components, which can be thought of as the
|
||||
building blocks or packages that make up the entire sysroot environment.
|
||||
|
||||
Each component corresponds to a specific package or dependency that is staged
|
||||
into the sysroot. This approach allows for more efficient reuse of sysroots
|
||||
across multiple packages or builds, and it helps with dependency tracking and
|
||||
management during the build process.
|
||||
|
||||
The sysroot-components directory helps optimize the build process because if
|
||||
one package changes, Yocto only needs to update the corresponding component
|
||||
rather than rebuilding or copying the entire sysroot.
|
||||
|
||||
If you followed the previous steps, here are the folders you will find:
|
||||
- ``all``: Architecture-independent files.
|
||||
- ``cortexa53``: Files for the Cortex-A53 (ARMv8-A) architecture.
|
||||
- ``manifests``: Track files installed in the sysroot by package.
|
||||
- ``raspberrypi3_64``: Files specific to the Raspberry Pi 3 (64-bit).
|
||||
- ``x86_64``: Files for the x86_64 (PC) architecture, typically for
|
||||
cross-compilation tools.
|
||||
- ``x86_64-nativesdk``: Files related to the SDK for cross-compilation on
|
||||
an x86_64 host.
|
||||
|
||||
Each folder corresponds to components relevant to the specific architecture,
|
||||
and they collectively form the complete environment needed to compile and run
|
||||
software for the target and host systems.
|
||||
|
||||
tmp/sysroots-uninative
|
||||
----------------------
|
||||
|
||||
The sysroots-uninative directory in Yocto is used to support the "uninative"
|
||||
feature, which allows for more reproducible builds by ensuring that the build
|
||||
environment remains consistent across different host systems. It essentially
|
||||
provides a way to use the same native build tools across different Linux
|
||||
distributions.
|
||||
|
||||
tmp/work
|
||||
--------
|
||||
|
||||
The ``work`` folder in Yocto is a key directory in the ``tmp`` folder that
|
||||
holds all the temporary build artifacts for each package during the build
|
||||
process. It is where the actual building and compiling of individual packages
|
||||
or recipes takes place. Each package (or "recipe") that BitBake processes
|
||||
generates temporary files and directories inside this ``work`` folder.
|
||||
|
||||
The ``work`` folder is typically structured by machine architecture and
|
||||
package. Here's how it generally works:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
work/
|
||||
└── <architecture>/
|
||||
└── <package>/
|
||||
└── <version>/
|
||||
├── temp/
|
||||
├── work/
|
||||
├── sysroot-destdir/
|
||||
└── image/
|
||||
|
||||
This folder is very important and helps a lot during debug phases. The ``temp``
|
||||
subfolder contains important logs that can help you diagnose build issues. This
|
||||
is where you'll look when a build fails to figure out what went wrong.
|
||||
|
||||
|
||||
LVGL recipe
|
||||
***********
|
||||
|
||||
Find more information about recipes in :ref:`recipes_section` section.
|
||||
|
||||
There is a recipe in ``meta-openembedded`` since ``honister``.
|
||||
|
||||
.. list-table:: lvgl recipe version
|
||||
:widths: 200 100
|
||||
:header-rows: 1
|
||||
|
||||
* - Branch
|
||||
- Recipe
|
||||
* - scarthgap (Yocto Project 5.0)
|
||||
- lvgl 9.1.0
|
||||
* - nanbield (Yocto Project 4.3)
|
||||
- lvgl 8.3.10
|
||||
* - mickledore (Yocto Project 4.2)
|
||||
- lvgl 8.1.0
|
||||
* - langdale (Yocto Project 4.1)
|
||||
- lvgl 8.1.0
|
||||
* - langdale (Yocto Project 4.1)
|
||||
- lvgl 8.1.0
|
||||
* - kirkstone (Yocto Project 4.0)
|
||||
- lvgl 8.0.3
|
||||
|
||||
In this guide, we are on the ``scarthgap`` branch, so we are using lvgl 9.1.0.
|
||||
|
||||
Let's dive into this recipe to understand what is done. The objective is to add
|
||||
this library as a shared object in the target rootfs, and also to generate a
|
||||
SDK with lvgl.
|
||||
|
||||
This is the path of lvgl recipes: ``lvgl_yocto_guide/sources/meta-openembedded/
|
||||
meta-oe/recipes-graphics/lvgl``
|
||||
|
||||
Here is the architecture of lvgl recipes folder:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
lvgl
|
||||
├── files
|
||||
│ ├── 0002-fix-sdl-handle-both-LV_IMAGE_SRC_FILE-and-LV_IMAGE_S.patch
|
||||
│ ├── 0003-Make-fbdev-device-node-runtime-configurable-via-envi.patch
|
||||
│ ├── 0004-Factor-out-fbdev-initialization-code.patch
|
||||
│ ├── 0005-Add-DRM-KMS-example-support.patch
|
||||
│ ├── 0006-Add-SDL2-example-support.patch
|
||||
│ ├── 0007-fix-cmake-generate-versioned-shared-libraries.patch
|
||||
│ └── 0008-fix-fbdev-set-resolution-prior-to-buffer.patch
|
||||
├── lv-conf.inc
|
||||
├── lvgl_9.1.0.bb
|
||||
└── lvgl-demo-fb_9.1.0.bb
|
||||
|
||||
- ``file`` folder contains all the patches that can be applied when
|
||||
building the recipe.
|
||||
- ``lv_conf.inc`` is an include file, usually containing common configuration
|
||||
settings for LVGL that can be shared between multiple recipes.
|
||||
- ``lvgl_9.1.0.bb`` is the recipe to build lvgl library.
|
||||
- ``lvgl-demo-fb_9.1.0.bb`` is a recipe to build an application using lvgl.
|
||||
|
||||
For now let's understand the recipe of lvgl library.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# SPDX-FileCopyrightText: Huawei Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
HOMEPAGE = "https://lvgl.io/"
|
||||
DESCRIPTION = "LVGL is an OSS graphics library to create embedded GUI"
|
||||
SUMMARY = "Light and Versatile Graphics Library"
|
||||
LICENSE = "MIT"
|
||||
LIC_FILES_CHKSUM = "file://LICENCE.txt;md5=bf1198c89ae87f043108cea62460b03a"
|
||||
|
||||
SRC_URI = "\
|
||||
git://github.com/lvgl/lvgl;protocol=https;branch=master \
|
||||
file://0002-fix-sdl-handle-both-LV_IMAGE_SRC_FILE-and-LV_IMAGE_S.patch \
|
||||
file://0007-fix-cmake-generate-versioned-shared-libraries.patch \
|
||||
file://0008-fix-fbdev-set-resolution-prior-to-buffer.patch \
|
||||
"
|
||||
SRCREV = "e1c0b21b2723d391b885de4b2ee5cc997eccca91"
|
||||
|
||||
inherit cmake
|
||||
|
||||
EXTRA_OECMAKE = "-DLIB_INSTALL_DIR=${baselib} -DBUILD_SHARED_LIBS=ON"
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
require lv-conf.inc
|
||||
|
||||
do_install:append() {
|
||||
install -d "${D}${includedir}/${PN}"
|
||||
install -m 0644 "${S}/lv_conf.h" "${D}${includedir}/${PN}/lv_conf.h"
|
||||
}
|
||||
|
||||
FILES:${PN}-dev += "\
|
||||
${includedir}/${PN}/ \
|
||||
"
|
||||
|
||||
**LICENSE**: Indicates the licensing of the software, stating that it is
|
||||
distributed under the MIT License.
|
||||
|
||||
**LIC_FILES_CHKSUM**: This variable contains a checksum (in this case, an MD5 hash)
|
||||
for the license file (here assumed to be LICENCE.txt). This helps to ensure the
|
||||
integrity of the license file included in the package. In LVGL repository,
|
||||
there is a LICENSE.txt. To get the value of the hash of the file, you can do
|
||||
this command: ``md5sum LICENSE.txt``
|
||||
|
||||
SRC_URI: Specifies the locations of the source code and patches for the recipe:
|
||||
- The main source repository for LVGL specifying the master branch.
|
||||
- The following arguments are the local patch files that will be applied to
|
||||
the source code during the build process.
|
||||
|
||||
**SRCREV**: Defines the specific commit (in this case, a Git SHA hash) from
|
||||
which the source code will be fetched. This ensures that the build uses a
|
||||
consistent version of the code.
|
||||
|
||||
**inherit**: This line indicates that the recipe uses the ``cmake`` class,
|
||||
which provides functionality for building projects that use CMake as
|
||||
their build system.
|
||||
|
||||
**EXTRA_OECMAKE**: Additional options passed to CMake during the
|
||||
configuration step.
|
||||
|
||||
**S**: This variable defines the source directory where the unpacked source
|
||||
code will be located after fetching. ``${WORKDIR}`` is a standard
|
||||
variable in BitBake that points to the working directory for the recipe.
|
||||
require: This line includes another configuration file, ``lv-conf.inc``,
|
||||
which likely contains additional configuration options or variables
|
||||
specific to the LVGL library.
|
||||
|
||||
**FILES**: This is a BitBake variable used to specify the files that should
|
||||
be included in a particular package. In this case, the variable is
|
||||
specifying files for a package related to development (i.e., header
|
||||
files).
|
||||
|
||||
Recipe Tasks
|
||||
************
|
||||
|
||||
When a recipe is compiled, it will run multiple tasks. You can run each task
|
||||
manually to understand what is generated each step, or you can run ``bitbake
|
||||
lvgl`` to run all the tasks.
|
||||
|
||||
Fetch (do_fetch)
|
||||
.. code-block:: bash
|
||||
|
||||
bitbake lvgl -c fetch
|
||||
|
||||
Fetch task fetches the package source from the local or remote repository.
|
||||
|
||||
The fetch Repo address has to be stored in **SRC_URI** variable. In
|
||||
**SRCREV** Variable the commit hash of github repo is defined.
|
||||
|
||||
When the fetch task has been completed, you can find the fetched sources in
|
||||
``build/downloads``.
|
||||
|
||||
For this recipe, you will find a new folder here: ``lvgl_yocto_guide
|
||||
build/downloads/git2/github.com.lvgl.lvgl``.
|
||||
|
||||
You can also find the folder architecture created in ``lvgl_yocto_guide/
|
||||
build/tmp/work/cortexa53-poky-linux/lvgl`` but these folders are empty since
|
||||
only the fetch was done.
|
||||
|
||||
|
||||
|
||||
|
||||
Unpack (do_upack)
|
||||
.. code-block:: bash
|
||||
|
||||
bitbake lvgl -c unpack
|
||||
|
||||
Unpack task unpacks the package that has been downloaded with Fetch task.
|
||||
|
||||
In the ``lvgl_yocto_guide/build/tmp/work/cortexa53-poky-linux/lvgl/9.1.0``
|
||||
folder, you can now find the source code in ``git`` (as it was defined in
|
||||
the recipe). You will also see the patches that will be applied on the next
|
||||
step. So for now, the sources are unmodified and the same than the commit
|
||||
that was specified.
|
||||
|
||||
|
||||
|
||||
Patch (do_patch)
|
||||
.. code-block:: bash
|
||||
|
||||
bitbake lvgl -c patch
|
||||
|
||||
Patch task locates the patch files and applies the patches to the sources
|
||||
if any patch is available. This is optional task, executes if patch is
|
||||
available.
|
||||
|
||||
Patch file is also defined in **SRC_URI** variable. By default it runs in
|
||||
current source directory **${S}**.
|
||||
|
||||
Configure (do_configure)
|
||||
.. code-block:: bash
|
||||
|
||||
bitbake lvgl -c configure
|
||||
|
||||
The Configuration task configures the source by enabling and disabling any
|
||||
build-time and configuration options for the software being built before
|
||||
compilation if any configuration is available.
|
||||
|
||||
This is a optional steps, executes if configuration is available.
|
||||
|
||||
In this case, it creates a build directory, It invokes CMake to configure
|
||||
the project, specifying build options and paths based on variables in your
|
||||
recipe. It generates Makefiles or project files needed for the build. Also,
|
||||
there are operations added in the task in ``lv-conf.inc``.
|
||||
|
||||
So at the end of the task, in the ``lvgl_yocto_guide/build/tmp/work/
|
||||
cortexa53-poky-linux/lvgl/9.1.0``, you will find a ``build`` folder that was
|
||||
generated running the CMake command, but nothing is built yet. Also, the
|
||||
sysroots have everything required to build lvgl library.
|
||||
|
||||
|
||||
Compile (do_compile)
|
||||
.. code-block:: bash
|
||||
|
||||
bitbake lvgl -c compile
|
||||
|
||||
The Compilation task compiles the source code if any compilation steps are
|
||||
available and generates a binary file.
|
||||
|
||||
This is a optional steps, executes if compilation is available.
|
||||
|
||||
If there are any compilation steps, then these steps are define in
|
||||
do_compile() funtion of bitbake.
|
||||
|
||||
Like in the previous task, this is handle by ``inherit cmake``.
|
||||
|
||||
In the build folder, you can now see the built library. The ``.so`` files
|
||||
are available in ``lvgl_yocto_guide/build/tmp/work/ cortexa53-poky-linux/lvgl/9.1.0/build/lib``.
|
||||
|
||||
After this task has been completed, everything is ready to be installed.
|
||||
|
||||
Install (do_install)
|
||||
.. code-block:: bash
|
||||
|
||||
bitbake lvgl -c install
|
||||
|
||||
The Install task copies files that are to be packaged into the holding area
|
||||
**${D}**. This task runs with the current working directory **${S}** which
|
||||
is the compilation directory.
|
||||
|
||||
It creates the necessary directory for the header files in the destination
|
||||
installation directory.
|
||||
It installs the ``lv_conf.h`` header file from the source directory into the
|
||||
appropriate include directory in the destination path, ensuring it has the
|
||||
correct permissions.
|
||||
|
||||
The lvgl library (``.so`` files) are also ready to be installed in the final
|
||||
image. A new folder ``image`` was created.
|
||||
|
||||
.. important::
|
||||
|
||||
In the file ``build/conf/local.conf``, add these 2 lines at the end of the
|
||||
file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
IMAGE_INSTALL:append = " lvgl"
|
||||
TOOLCHAIN_HOST_TASK:append = " lvgl"
|
||||
|
||||
This will add the lvgl library in the generated image, and it will also add
|
||||
the library to the host SDK we will generate later on.
|
||||
|
||||
With these modifications, you can now run the image recipe again::
|
||||
|
||||
bitbake core-image-base
|
||||
|
||||
This will execute all the previous described tasks.
|
||||
|
||||
If everything went well, you should now found this file ``build/tmp/deploy/
|
||||
rpm/cortexa53/lvgl-9.1.0-r0.cortexa53.rpm`` and other rpm files related to
|
||||
lvgl.
|
||||
|
||||
SDK generation
|
||||
**************
|
||||
|
||||
Generating a Software Development Kit (SDK) in Yocto serves several important
|
||||
purposes, particularly in embedded development:
|
||||
|
||||
- **Development Environment**: The SDK provides developers with a
|
||||
ready-to-use development environment tailored for a specific target
|
||||
hardware platform.
|
||||
This includes the necessary tools, libraries, and headers to build
|
||||
applications that run on the target device.
|
||||
- **Cross-Compilation**: The SDK allows developers to cross-compile
|
||||
applications from a host machine (typically x86 or x86_64 architecture)
|
||||
for a different architecture (e.g., ARM). This is essential for embedded
|
||||
systems, where development often occurs on more powerful machines.
|
||||
- **Simplified Development**: By packaging all required components, the SDK
|
||||
simplifies the process of setting up a development environment.
|
||||
Developers don't need to manually install and configure tools and
|
||||
libraries; everything needed is included in the SDK.
|
||||
- **Consistent Build Environment**: The SDK ensures that developers are
|
||||
working with the same versions of and tools used in the Yocto
|
||||
build, which helps to avoid compatibility issues and ensures that
|
||||
applications will behave as expected on the target device.
|
||||
|
||||
To generate an SDK of the environment, run the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
bitbake core-image-base -c populate_sdk
|
||||
|
||||
This will create a sript ``build/tmp/deploy/sdk/
|
||||
poky-glibc-x86_64-core-image-base-cortexa53-raspberrypi3-64-toolchain-5.0.4.
|
||||
sh``. This script allows you to install the SDK where you prefer. Here is the
|
||||
execution output of the scrips
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ./sdk/poky-glibc-x86_64-core-image-base-cortexa53-raspberrypi3-64-toolchain-5.0.4.sh
|
||||
Poky (Yocto Project Reference Distro) SDK installer version 5.0.4
|
||||
=================================================================
|
||||
Enter target directory for SDK (default: /opt/poky/5.0.4): /opt/poky/sdk-with-lvgl
|
||||
You are about to install the SDK to "/opt/poky/sdk-with-lvgl". Proceed [Y/n]? y
|
||||
|
||||
If you want to ensure the SDK was generated with lvgl being installed, go to
|
||||
the path you extracted the SDK and find all lvgl files:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd /opt/poky/5.0.4/sysroots/cortexa53-poky-linux
|
||||
find . -name "*lvgl*"
|
||||
|
||||
The ``.so`` files you will find will depend on the LVGL configuration you used.
|
||||
|
||||
Now to use the SDK environment and cross-compile an application:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
source /opt/poke/5.0.4/environment-setup-cortexa53-poky-linux
|
||||
|
||||
.. note::
|
||||
|
||||
The tools available in LVGL library will depend on the build configuration
|
||||
the recipe was done with.
|
||||
|
||||
|
||||
Custom recipe
|
||||
*************
|
||||
|
||||
Until this section, everything was already done for you. We used existing
|
||||
recipes. The objective here is to create a recipe from scratch and to add the
|
||||
generated binary in the image.
|
||||
|
||||
Create a layer
|
||||
==============
|
||||
|
||||
First, create a layer and add it to the configuration file
|
||||
|
||||
.. code-block::
|
||||
|
||||
bitbake-layers create-layer ../sources/meta-mylvgl
|
||||
bitbake-layers add-layer ../sources/meta-mylvgl
|
||||
|
||||
In the ``sources`` folder, a new folder was created: ``meta-mylvgl`` and the
|
||||
directory tree should look like the following
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
├── conf
|
||||
│ └── layer.conf
|
||||
├── COPYING.MIT
|
||||
├── README
|
||||
└── recipes-example
|
||||
└── example
|
||||
└── example_0.1.bb
|
||||
|
||||
|
||||
Create a recipe
|
||||
===============
|
||||
|
||||
Following this structure, create a folder containing the recipies to build 1
|
||||
or multiple applications using lvgl
|
||||
|
||||
.. code-block::
|
||||
|
||||
cd ../sources/meta-mylvgl
|
||||
mkdir -p recipes-lvglapp/lvgl-fbdev-benchmark/files
|
||||
touch recipes-lvglapp/lvgl-fbdev-benchmark/lvglbenchmarkfbdev_2.4.bb
|
||||
|
||||
We will focus on 1 application that will clone an lvgl git repository and patch
|
||||
it for our needs.
|
||||
|
||||
The content of ``recipes-lvglapp/lvgl-fbdev-benchmark/lvglbenchmarkfbdev_2.4.
|
||||
bb``
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
DESCRIPTION = "My C++ lvgl app with CMake"
|
||||
|
||||
LICENSE = "MIT"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
|
||||
|
||||
# Update SRC_URI to point to the GitHub repository
|
||||
SRC_URI = "gitsm://github.com/lvgl/lv_port_linux.git;branch=master;protocol=https \
|
||||
file://0001-change-config-file-to-run-fbdev-with-2-threads.patch \
|
||||
file://0002-adapt-CMakeLists-file-to-compile-and-link-fbdev.patch \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
inherit cmake
|
||||
|
||||
CMAKE_PROJECT_NAME = "lvgl_app"
|
||||
CMAKE_PROJECT_VERSION = "2.0"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 ${S}/bin/lvglbenchmark ${D}${bindir}
|
||||
}
|
||||
|
||||
The sources come from ``lv_port_linux`` repository. We apply 2 patches to modify the ``CMakeLists.txt`` and ``lv_conf.h``.
|
||||
|
||||
Patch 1
|
||||
-------
|
||||
|
||||
Create the first patch file
|
||||
|
||||
.. code-block::
|
||||
|
||||
touch 0001-change-config-file-to-run-fbdev-with-2-threads.patch
|
||||
|
||||
Content of ``0001-change-config-file-to-run-fbdev-with-2-threads.patch``
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
From d49d475d57f69d6172a6b38095ebf3b887f0e731 Mon Sep 17 00:00:00 2001
|
||||
From: Gabriel Catel Torres <gabriel.catel@edgemtech.ch>
|
||||
Date: Tue, 1 Oct 2024 10:28:55 +0200
|
||||
Subject: [PATCH] change config file to run fbdev with 2 threads
|
||||
|
||||
---
|
||||
lv_conf.h | 34 +++++++++++++++++-----------------
|
||||
1 file changed, 17 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/lv_conf.h b/lv_conf.h
|
||||
index 62a834f..58fbe7a 100644
|
||||
--- a/lv_conf.h
|
||||
+++ b/lv_conf.h
|
||||
@@ -39,9 +39,9 @@
|
||||
* - LV_STDLIB_RTTHREAD: RT-Thread implementation
|
||||
* - LV_STDLIB_CUSTOM: Implement the functions externally
|
||||
*/
|
||||
-#define LV_USE_STDLIB_MALLOC LV_STDLIB_BUILTIN
|
||||
-#define LV_USE_STDLIB_STRING LV_STDLIB_BUILTIN
|
||||
-#define LV_USE_STDLIB_SPRINTF LV_STDLIB_BUILTIN
|
||||
+#define LV_USE_STDLIB_MALLOC LV_STDLIB_CLIB
|
||||
+#define LV_USE_STDLIB_STRING LV_STDLIB_CLIB
|
||||
+#define LV_USE_STDLIB_SPRINTF LV_STDLIB_CLIB
|
||||
|
||||
#define LV_STDINT_INCLUDE <stdint.h>
|
||||
#define LV_STDDEF_INCLUDE <stddef.h>
|
||||
@@ -89,7 +89,7 @@
|
||||
* - LV_OS_WINDOWS
|
||||
* - LV_OS_MQX
|
||||
* - LV_OS_CUSTOM */
|
||||
-#define LV_USE_OS LV_OS_NONE
|
||||
+#define LV_USE_OS LV_OS_PTHREAD
|
||||
|
||||
#if LV_USE_OS == LV_OS_CUSTOM
|
||||
#define LV_OS_CUSTOM_INCLUDE <stdint.h>
|
||||
@@ -117,12 +117,12 @@
|
||||
* and can't be drawn in chunks. */
|
||||
|
||||
/* The target buffer size for simple layer chunks. */
|
||||
-#define LV_DRAW_LAYER_SIMPLE_BUF_SIZE (24 * 1024) /* [bytes] */
|
||||
+#define LV_DRAW_LAYER_SIMPLE_BUF_SIZE (512 * 1024) /* [bytes] */
|
||||
|
||||
/* The stack size of the drawing thread.
|
||||
* NOTE: If FreeType or ThorVG is enabled, it is recommended to set it to 32KB or more.
|
||||
*/
|
||||
-#define LV_DRAW_THREAD_STACK_SIZE (8 * 1024) /* [bytes] */
|
||||
+#define LV_DRAW_THREAD_STACK_SIZE (32 * 1024) /* [bytes] */
|
||||
|
||||
#define LV_USE_DRAW_SW 1
|
||||
#if LV_USE_DRAW_SW == 1
|
||||
@@ -147,7 +147,7 @@
|
||||
/* Set the number of draw unit.
|
||||
* > 1 requires an operating system enabled in `LV_USE_OS`
|
||||
* > 1 means multiple threads will render the screen in parallel */
|
||||
- #define LV_DRAW_SW_DRAW_UNIT_CNT 1
|
||||
+ #define LV_DRAW_SW_DRAW_UNIT_CNT 2
|
||||
|
||||
/* Use Arm-2D to accelerate the sw render */
|
||||
#define LV_USE_DRAW_ARM2D_SYNC 0
|
||||
@@ -979,8 +979,8 @@
|
||||
#define LV_USE_LINUX_FBDEV 1
|
||||
#if LV_USE_LINUX_FBDEV
|
||||
#define LV_LINUX_FBDEV_BSD 0
|
||||
- #define LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL
|
||||
- #define LV_LINUX_FBDEV_BUFFER_COUNT 0
|
||||
+ #define LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT
|
||||
+ #define LV_LINUX_FBDEV_BUFFER_COUNT 2
|
||||
#define LV_LINUX_FBDEV_BUFFER_SIZE 60
|
||||
#endif
|
||||
|
||||
@@ -1069,19 +1069,19 @@
|
||||
#define LV_USE_DEMO_WIDGETS 1
|
||||
|
||||
/* Demonstrate the usage of encoder and keyboard */
|
||||
-#define LV_USE_DEMO_KEYPAD_AND_ENCODER 1
|
||||
+#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0
|
||||
|
||||
/* Benchmark your system */
|
||||
#define LV_USE_DEMO_BENCHMARK 1
|
||||
|
||||
/* Render test for each primitives. Requires at least 480x272 display */
|
||||
-#define LV_USE_DEMO_RENDER 1
|
||||
+#define LV_USE_DEMO_RENDER 0
|
||||
|
||||
/* Stress test for LVGL */
|
||||
-#define LV_USE_DEMO_STRESS 1
|
||||
+#define LV_USE_DEMO_STRESS 0
|
||||
|
||||
/* Music player demo */
|
||||
-#define LV_USE_DEMO_MUSIC 1
|
||||
+#define LV_USE_DEMO_MUSIC 0
|
||||
#if LV_USE_DEMO_MUSIC
|
||||
#define LV_DEMO_MUSIC_SQUARE 0
|
||||
#define LV_DEMO_MUSIC_LANDSCAPE 0
|
||||
@@ -1091,16 +1091,16 @@
|
||||
#endif
|
||||
|
||||
/* Flex layout demo */
|
||||
-#define LV_USE_DEMO_FLEX_LAYOUT 1
|
||||
+#define LV_USE_DEMO_FLEX_LAYOUT 0
|
||||
|
||||
/* Smart-phone like multi-language demo */
|
||||
-#define LV_USE_DEMO_MULTILANG 1
|
||||
+#define LV_USE_DEMO_MULTILANG 0
|
||||
|
||||
/* Widget transformation demo */
|
||||
-#define LV_USE_DEMO_TRANSFORM 1
|
||||
+#define LV_USE_DEMO_TRANSFORM 0
|
||||
|
||||
/* Demonstrate scroll settings */
|
||||
-#define LV_USE_DEMO_SCROLL 1
|
||||
+#define LV_USE_DEMO_SCROLL 0
|
||||
|
||||
/* Vector graphic demo */
|
||||
#define LV_USE_DEMO_VECTOR_GRAPHIC 0
|
||||
--
|
||||
2.34.1
|
||||
|
||||
|
||||
Patch 2
|
||||
-------
|
||||
|
||||
Create the first patch file
|
||||
|
||||
.. code-block::
|
||||
|
||||
touch 0002-adapt-CMakeLists-file-to-compile-and-link-fbdev.patch
|
||||
|
||||
Content of ``0002-adapt-CMakeLists-file-to-compile-and-link-fbdev.patch``
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
From ad464e0683aced74085fb89895b8d040ecad0206 Mon Sep 17 00:00:00 2001
|
||||
From: Gabriel Catel Torres <gabriel.catel@edgemtech.ch>
|
||||
Date: Tue, 1 Oct 2024 10:31:29 +0200
|
||||
Subject: [PATCH] adapt CMakeLists file to compile and link only for fbdev
|
||||
|
||||
---
|
||||
CMakeLists.txt | 17 +++++------------
|
||||
1 file changed, 5 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 658193f..ad56cc2 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -1,8 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(lvgl)
|
||||
|
||||
-set(CMAKE_C_STANDARD 99)#C99 # lvgl officially support C99 and above
|
||||
-set(CMAKE_CXX_STANDARD 17)#C17
|
||||
+set(CMAKE_C_STANDARD 99)
|
||||
+set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
|
||||
@@ -10,15 +10,8 @@ set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
|
||||
add_subdirectory(lvgl)
|
||||
target_include_directories(lvgl PUBLIC ${PROJECT_SOURCE_DIR})
|
||||
|
||||
-add_executable(main main.c mouse_cursor_icon.c)
|
||||
+add_executable(lvglbenchmark main.c mouse_cursor_icon.c)
|
||||
|
||||
-include(${CMAKE_CURRENT_LIST_DIR}/lvgl/tests/FindLibDRM.cmake)
|
||||
-include_directories(${Libdrm_INCLUDE_DIRS})
|
||||
-
|
||||
-find_package(SDL2)
|
||||
-find_package(SDL2_image)
|
||||
-include_directories(${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS})
|
||||
-
|
||||
-target_link_libraries(main lvgl lvgl::examples lvgl::demos lvgl::thorvg ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES} ${Libdrm_LIBRARIES} m pthread)
|
||||
-add_custom_target (run COMMAND ${EXECUTABLE_OUTPUT_PATH}/main DEPENDS main)
|
||||
+target_link_libraries(lvglbenchmark lvgl lvgl::examples lvgl::demos lvgl::thorvg m pthread)
|
||||
+add_custom_target (run COMMAND ${EXECUTABLE_OUTPUT_PATH}/lvglbenchmark DEPENDS main)
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
||||
Build the recipe
|
||||
================
|
||||
|
||||
You should now be able to see the recipe listing the existing recipes
|
||||
|
||||
.. code-block::
|
||||
|
||||
bitbake-layers show-recipes | grep lvglbenchmarkfbdev
|
||||
|
||||
Now add the recipe to the project. Modify ``build/conf/local.conf`` file adding
|
||||
this line
|
||||
|
||||
.. code-block::
|
||||
|
||||
IMAGE_INSTALL:append = " lvglbenchmarkfbdev"
|
||||
|
||||
Now build the image
|
||||
|
||||
.. code-block::
|
||||
|
||||
bitbake core-image-base
|
||||
|
||||
Run this command to ensure the binary was generated and was installed in the
|
||||
rootfs
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Run this command in build/tmp folder
|
||||
find . -wholename "*bin/lvglbench*"
|
||||
196
docs/details/integration/os/yocto/terms_and_variables.rst
Normal file
196
docs/details/integration/os/yocto/terms_and_variables.rst
Normal file
@@ -0,0 +1,196 @@
|
||||
.. _yocto_project_terms:
|
||||
|
||||
===================
|
||||
Yocto Project Terms
|
||||
===================
|
||||
|
||||
Getting started in Yocto can be overwheming. There are many terms used that are
|
||||
specific to Yocto and Bitbake environment.
|
||||
|
||||
A list of terms and definitions users new to the Yocto Project
|
||||
development environment might find helpful can be found `here <https://docs.
|
||||
yoctoproject.org/ref-manual/terms.html>`_.
|
||||
|
||||
|
||||
Yocto Variables Glossary
|
||||
************************
|
||||
|
||||
This chapter lists basic variables used in the LVGL Yocto guide and gives an
|
||||
overview of their function and contents.
|
||||
|
||||
A More complete variable glossary can be found in `Yocto Variable Glossary
|
||||
<https://docs.yoctoproject.org/ref-manual/variables.html>`_. This section
|
||||
covers a lot of variables used in the OpenEmbedded build system.
|
||||
|
||||
.. _S:
|
||||
|
||||
S
|
||||
-
|
||||
|
||||
The location in the Build Directory where unpacked recipe source code resides.
|
||||
By default, this directory is ${WORKDIR}/${BPN}-${PV}, where ${BPN} is the
|
||||
base recipe name and ${PV} is the recipe version. If the source tarball
|
||||
extracts the code to a directory named anything other than ${BPN}-${PV}, or if
|
||||
the source code is fetched from an SCM such as Git or Subversion, then you
|
||||
must set S in the recipe so that the OpenEmbedded build system knows where to
|
||||
find the unpacked source.
|
||||
|
||||
As an example, assume a Source Directory top-level folder named poky and a
|
||||
default Build Directory at poky/build. In this case, the work directory the
|
||||
build system uses to keep the unpacked recipe for db is the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
poky/build/tmp/work/qemux86-poky-linux/db/5.1.19-r3/db-5.1.19
|
||||
|
||||
The unpacked source code resides in the db-5.1.19 folder.
|
||||
|
||||
This next example assumes a Git repository. By default, Git repositories are
|
||||
cloned to ${WORKDIR}/git during do_fetch. Since this path is different from the
|
||||
default value of S, you must set it specifically so the source can be located:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
SRC_URI = "git://path/to/repo.git;branch=main"
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
|
||||
.. _D:
|
||||
|
||||
D
|
||||
-
|
||||
|
||||
The destination directory. The location in the Build Directory where components
|
||||
are installed by the do_install task. This location defaults to:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
${WORKDIR}/image
|
||||
|
||||
.. note::
|
||||
|
||||
Tasks that read from or write to this directory should run under fakeroot.
|
||||
|
||||
.. _B:
|
||||
|
||||
B
|
||||
-
|
||||
|
||||
The directory within the Build Directory in which the OpenEmbedded build system
|
||||
places generated objects during a recipe's build process. By default, this
|
||||
directory is the same as the S directory, which is defined as:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
S = "${WORKDIR}/${BP}"
|
||||
|
||||
You can separate the (S) directory and the directory pointed to by the B
|
||||
variable. Most Autotools-based recipes support separating these directories.
|
||||
The build system defaults to using separate directories for gcc and some kernel
|
||||
recipes.
|
||||
|
||||
.. _WORKDIR:
|
||||
|
||||
WORKDIR
|
||||
-------
|
||||
|
||||
The pathname of the work directory in which the OpenEmbedded build system
|
||||
builds a recipe. This directory is located within the TMPDIR directory
|
||||
structure and is specific to the recipe being built and the system for which it
|
||||
is being built.
|
||||
|
||||
The WORKDIR directory is defined as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
${TMPDIR}/work/${MULTIMACH_TARGET_SYS}/${PN}/${EXTENDPE}${PV}-${PR}
|
||||
|
||||
The actual directory depends on several things:
|
||||
|
||||
- **TMPDIR**: The top-level build output directory
|
||||
- **MULTIMACH_TARGET_SYS**: The target system identifier
|
||||
- **PN**: The recipe name
|
||||
- **EXTENDPE**: The epoch — if PE is not specified, which is usually the
|
||||
case for most recipes, then EXTENDPE is blank.
|
||||
- **PV**: The recipe version
|
||||
- **PR**: The recipe revision
|
||||
|
||||
As an example, assume a Source Directory top-level folder name poky, a default
|
||||
Build Directory at poky/build, and a qemux86-poky-linux machine target system.
|
||||
Furthermore, suppose your recipe is named foo_1.3.0-r0.bb. In this case, the
|
||||
work directory the build system uses to build the package would be as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
poky/build/tmp/work/qemux86-poky-linux/foo/1.3.0-r0
|
||||
|
||||
.. _PN:
|
||||
|
||||
PN
|
||||
--
|
||||
|
||||
This variable can have two separate functions depending on the context: a
|
||||
recipe name or a resulting package name.
|
||||
|
||||
PN refers to a recipe name in the context of a file used by the OpenEmbedded
|
||||
build system as input to create a package. The name is normally extracted from
|
||||
the recipe file name. For example, if the recipe is named expat_2.0.1.bb, then
|
||||
the default value of PN will be “expat”.
|
||||
|
||||
The variable refers to a package name in the context of a file created or
|
||||
produced by the OpenEmbedded build system.
|
||||
|
||||
If applicable, the PN variable also contains any special suffix or prefix. For
|
||||
example, using bash to build packages for the native machine, PN is
|
||||
bash-native. Using bash to build packages for the target and for Multilib, PN
|
||||
would be bash and lib64-bash, respectively.
|
||||
|
||||
.. _PR:
|
||||
|
||||
PR
|
||||
--
|
||||
|
||||
The revision of the recipe. The default value for this variable is
|
||||
"r0". Subsequent revisions of the recipe conventionally have the
|
||||
values "r1", "r2", and so forth. When PV increases,
|
||||
PR is conventionally reset to "r0".
|
||||
|
||||
.. note::
|
||||
|
||||
The OpenEmbedded build system does not need the aid of PR to know when to
|
||||
rebuild a recipe. The build system uses the task input checksums along with
|
||||
the stamp and shared state cache mechanisms.
|
||||
|
||||
The PR variable primarily becomes significant when a package
|
||||
manager dynamically installs packages on an already built image. In
|
||||
this case, PR, which is the default value of
|
||||
PKGR, helps the package manager distinguish which
|
||||
package is the most recent one in cases where many packages have the
|
||||
same PV (i.e. PKGV). A component having many packages with
|
||||
the same PV usually means that the packages all install the same
|
||||
upstream version, but with later (PR) version packages including
|
||||
packaging fixes.
|
||||
|
||||
.. note::
|
||||
|
||||
PR does not need to be increased for changes that do not change the
|
||||
package contents or metadata.
|
||||
|
||||
Because manually managing PR can be cumbersome and error-prone,
|
||||
an automated solution exists. See the
|
||||
"`working with a pr service <https://docs.yoctoproject.org/dev-manual/packages.
|
||||
html#working-with-a-pr-service>`_" section in the Yocto Project Development
|
||||
Tasks Manual for more information.
|
||||
|
||||
.. _PV:
|
||||
|
||||
PV
|
||||
--
|
||||
|
||||
The version of the recipe. The version is normally extracted from the recipe
|
||||
filename. For example, if the recipe is named expat_2.0.1.bb, then the default
|
||||
value of PV will be “2.0.1”. PV is generally not overridden within a recipe
|
||||
unless it is building an unstable (i.e. development) version from a source code
|
||||
repository (e.g. Git or Subversion).
|
||||
|
||||
PV is the default value of the PKGV variable.
|
||||
194
docs/details/integration/os/zephyr.rst
Normal file
194
docs/details/integration/os/zephyr.rst
Normal file
@@ -0,0 +1,194 @@
|
||||
======
|
||||
Zephyr
|
||||
======
|
||||
|
||||
What is Zephyr?
|
||||
---------------
|
||||
|
||||
`Zephyr <https://zephyrproject.org/>`__ is an `open
|
||||
source <https://github.com/zephyrproject-rtos/zephyr>`__ real-time operating
|
||||
system (RTOS) that is easy to deploy, secure, connect and manage.
|
||||
It has a growing set of software libraries that can be used
|
||||
across various applications and industry sectors such as
|
||||
Industrial IoT, wearables, machine learning and more.
|
||||
Zephyr is built with an emphasis on broad chipset support,
|
||||
security, dependability, longterm support releases and a
|
||||
growing open source ecosystem.
|
||||
|
||||
Highlights of Zephyr
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **Small** - Runs on microcontrollers as small as 8 kB Flash
|
||||
and 5 kB of RAM.
|
||||
- **Scalable** - Usable for complex multicore systems.
|
||||
- **Customizable** - Out-of-the-box support for 500+ boards
|
||||
and high portability.
|
||||
- **Secure** - Built with safety and security in mind,
|
||||
offers Long-term support.
|
||||
- **Ecosystem** - Zephyr not only provides the RTOS kernel but
|
||||
also developer tooling, device drivers, connectivity, logging,
|
||||
tracing, power management and much more.
|
||||
- **Decoupling** - Leverages devicetree to describe and
|
||||
configure the target system.
|
||||
- **Compliant** - Apps are runnable as native Linux applications,
|
||||
which simplifies debugging and profiling.
|
||||
|
||||
How to run LVGL on Zephyr?
|
||||
--------------------------
|
||||
|
||||
To setup your development environment refer to the
|
||||
`getting started guide <https://docs.zephyrproject.org/latest/develop/getting_started/index.html>`__.
|
||||
|
||||
After you completed the setup above you can check out all of the `provided samples <https://docs.zephyrproject.org/latest/samples/>`__ for various boards.
|
||||
You can check the list of available boards using:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ west boards
|
||||
|
||||
After you chose a board you can build one of the LVGL demos for it. Here we are using the :code:`native_posix`
|
||||
board, which allows for running the application on your posix compliant host system:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ west build -b native_posix samples/modules/lvgl/demos
|
||||
|
||||
To run the application on your host:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ west build -t run
|
||||
|
||||
In case you chose any of the other supported boards you can flash to the device with:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ west flash
|
||||
|
||||
If you want to build any of the other demo applications check out the samples
|
||||
`README <https://docs.zephyrproject.org/latest/samples/modules/lvgl/demos/README.html>`__.
|
||||
|
||||
Leveraging Zephyr Features
|
||||
--------------------------
|
||||
|
||||
Shell
|
||||
~~~~~
|
||||
|
||||
Zephyr includes a powerful shell implementation that can be enabled with the Kconfig symbols
|
||||
:code:`CONFIG_SHELL` and :code:`CONFIG_LV_Z_SHELL` (the demos from above have it enabled by default).
|
||||
|
||||
The shell offers enabling/disabling of LVGL monkeys:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
# Create a new monkey with the given indev type
|
||||
uart$ lvgl monkey create [pointer|keypad|button|encoder]
|
||||
|
||||
# Enable/Disable a monkey
|
||||
uart$ lvgl monkey set <index> <inactive/active>
|
||||
|
||||
This is useful for checking your application for memory leaks and other bugs.
|
||||
Speaking of memory leaks, you can also acquire stats of the memory used by LVGL
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
uart$ lvgl stats memory
|
||||
|
||||
For more details refer to the `shell documentation <https://docs.zephyrproject.org/latest/services/shell/index.html>`__.
|
||||
|
||||
Devicetree
|
||||
~~~~~~~~~~
|
||||
|
||||
Zephyr uses the devicetree description language to create and manage LVGL input devices.
|
||||
|
||||
The pseudo device binding descriptions can be found at:
|
||||
|
||||
- `button input <https://docs.zephyrproject.org/latest/build/dts/api/bindings/input/zephyr,lvgl-button-input.html>`__
|
||||
- `pointer input <https://docs.zephyrproject.org/latest/build/dts/api/bindings/input/zephyr,lvgl-pointer-input.html>`__
|
||||
- `encoder input <https://docs.zephyrproject.org/latest/build/dts/api/bindings/input/zephyr,lvgl-encoder-input.html>`__
|
||||
- `keypad input <https://docs.zephyrproject.org/latest/build/dts/api/bindings/input/zephyr,lvgl-keypad-input.html>`__
|
||||
|
||||
Essentially those buffer the :code:`input_event` generated by the device pointed to by the :code:`input` phandle or if left
|
||||
empty the binding captures all events regardless of the source. You do not have to instantiate or manage the devices yourself,
|
||||
they are created at application start up before :code:`main()` is executed.
|
||||
|
||||
Most boards or shields that have a display or display connector have the pointer input device already declared:
|
||||
|
||||
.. code-block::
|
||||
|
||||
lvgl_pointer {
|
||||
compatible = "zephyr,lvgl-pointer-input";
|
||||
input = <&ft5336_touch>;
|
||||
};
|
||||
|
||||
You can access the underlying lvgl :code:`lv_indev_t` for configuration.
|
||||
Example with the encoder device to assign a :code:`lv_group_t`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const struct device *lvgl_encoder = DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_lvgl_encoder_input));
|
||||
|
||||
lv_obj_t *arc;
|
||||
lv_group_t *arc_group;
|
||||
|
||||
arc = lv_arc_create(lv_screen_active());
|
||||
lv_obj_align(arc, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_size(arc, 150, 150);
|
||||
|
||||
arc_group = lv_group_create();
|
||||
lv_group_add_obj(arc_group, arc);
|
||||
lv_indev_set_group(lvgl_input_get_indev(lvgl_encoder), arc_group);
|
||||
|
||||
|
||||
Kconfig
|
||||
~~~~~~~~
|
||||
|
||||
Aside from enabling the shell you can also use Kconfig to finetune
|
||||
the footprint of your application.
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Size of the memory region from which lvgl memory is allocated
|
||||
CONFIG_LV_Z_MEM_POOL_SIZE=8192
|
||||
|
||||
# Do not include every widget/theme by default, enable them as needed.
|
||||
CONFIG_LV_CONF_MINIMAL=y
|
||||
|
||||
Overlays can be used to enable/disable features for specific boards or build
|
||||
targets. For more information refer to the
|
||||
`application development guide <https://docs.zephyrproject.org/latest/develop/application/index.html#application-configuration>`__.
|
||||
|
||||
Performance Tuning in LVGL
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To optimize LVGL's performance, several `kconfig` options can be configured:
|
||||
|
||||
- **CONFIG_LV_Z_VDB_SIZE**: Sets the rendering buffer size as a percentage of the display area, adjustable from 1% to 100%. Larger buffers can enhance performance, especially when used with **CONFIG_LV_Z_FULL_REFRESH**.
|
||||
|
||||
- **CONFIG_LV_Z_DOUBLE_VDB**: Enables the use of two rendering buffers, allowing for parallel rendering and data flushing, thus improving responsiveness and reducing latency.
|
||||
|
||||
- **CONFIG_LV_Z_VDB_ALIGN**: Ensures that the rendering buffer is properly aligned, which is critical for efficient memory access based on the color depth.
|
||||
|
||||
- **CONFIG_LV_Z_VBD_CUSTOM_SECTION**: Allows rendering buffers to be placed in a custom memory section (e.g., `.lvgl_buf`), useful for leveraging specific memory types like tightly coupled or external memory to enhance performance.
|
||||
|
||||
Zephyr ≤ 3.7.0 Specific Options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For Zephyr versions 3.7.0 and below, additional options are available to manage LVGL's frame flushing:
|
||||
|
||||
- **CONFIG_LV_Z_FLUSH_THREAD**: Enables flushing LVGL frames in a separate thread, allowing the main thread to continue rendering the next frame simultaneously. This option can be disabled if the performance gain is not needed.
|
||||
|
||||
- **CONFIG_LV_Z_FLUSH_THREAD_STACK_SIZE**: Specifies the stack size for the flush thread, with a default of 1024 bytes.
|
||||
|
||||
- **CONFIG_LV_Z_FLUSH_THREAD_PRIO**: Sets the priority of the flush thread, with a default priority of 0, indicating cooperative priority.
|
||||
|
||||
For newer versions of Zephyr, the OSAL (Operating System Abstraction Layer) can be utilized, which takes care of the flushing.
|
||||
|
||||
Where can I find more information?
|
||||
----------------------------------
|
||||
|
||||
- Zephyr Documentation: `Zephyr Documentation <https://docs.zephyrproject.org/latest/index.html>`__
|
||||
- Zephyr mailing list: `Zepyhr Mailing
|
||||
List <https://lists.zephyrproject.org/g/main>`__
|
||||
- Zephyr Discord server: `Zepyhr Discord
|
||||
server <https://chat.zephyrproject.org/>`__
|
||||
70
docs/details/integration/renderers/arm2d.rst
Normal file
70
docs/details/integration/renderers/arm2d.rst
Normal file
@@ -0,0 +1,70 @@
|
||||
.. _arm2d:
|
||||
|
||||
==========
|
||||
Arm-2D GPU
|
||||
==========
|
||||
|
||||
Arm-2D is not a GPU but **an abstraction layer for 2D GPUs dedicated to
|
||||
Microcontrollers**. It supports all Cortex-M processors ranging from
|
||||
Cortex-M0 to the latest Cortex-M85.
|
||||
|
||||
Arm-2D accelerates LVGL9 with two modes: **Synchronous Mode** and
|
||||
**Asynchronous Mode**.
|
||||
|
||||
- When **Helium** and **ACI (Arm Custom Instruction)** are available, it is recommend
|
||||
to use **Synchronous Mode** to accelerate LVGL.
|
||||
- When Arm-2D backed 2D-GPUs are available, for example, **DMAC-350 based 2D
|
||||
GPUs**, it is recommend to use **Asynchronous Mode** to accelerate LVGL.
|
||||
|
||||
Arm-2D is an open-source project on GitHub. For more, please refer to:
|
||||
https://github.com/ARM-software/Arm-2D.
|
||||
|
||||
|
||||
How to Use
|
||||
**********
|
||||
|
||||
In general:
|
||||
|
||||
- you can set the macro :c:macro:`LV_USE_DRAW_ARM2D_SYNC` to ``1`` and
|
||||
:c:macro:`LV_DRAW_SW_ASM` to ``LV_DRAW_SW_ASM_HELIUM`` in ``lv_conf.h`` to
|
||||
enable Arm-2D synchronous acceleration for LVGL.
|
||||
- You can set
|
||||
the macro :c:macro:`LV_USE_DRAW_ARM2D_ASYNC` to ``1`` in ``lv_conf.h`` to enable
|
||||
Arm-2D Asynchronous acceleration for LVGL.
|
||||
|
||||
If you are using
|
||||
`CMSIS-Pack <https://github.com/lvgl/lvgl/tree/master/env_support/cmsis-pack>`__
|
||||
to deploy the LVGL. You don't have to define the macro
|
||||
:c:macro:`LV_USE_DRAW_ARM2D_SYNC` manually, instead the lv_conf_cmsis.h will
|
||||
check the environment and set the :c:macro:`LV_USE_DRAW_ARM2D_SYNC` accordingly.
|
||||
|
||||
Design Considerations
|
||||
*********************
|
||||
|
||||
As mentioned before, Arm-2D is an abstraction layer for 2D GPU; hence if
|
||||
there is no accelerator or dedicated instruction set (such as Helium or
|
||||
ACI) available for Arm-2D, it provides negligible performance boost for
|
||||
LVGL (sometimes worse) for regular Cortex-M processors.
|
||||
|
||||
**We highly recommend you enable Arm-2D acceleration for LVGL** when:
|
||||
|
||||
- The target processors are **Cortex-M55**, **Cortex-M52** and **Cortex-M85**
|
||||
- The target processors support
|
||||
`Helium <https://developer.arm.com/documentation/102102/0103/?lang=en>`__.
|
||||
- The device vendor provides an arm-2d compliant driver for their
|
||||
proprietary 2D accelerators and/or ACI (Arm Customized Instruction).
|
||||
- The target device contains
|
||||
`DMAC-350 <https://community.arm.com/arm-community-blogs/b/internet-of-things-blog/posts/arm-corelink-dma-350-next-generation-direct-memory-access-for-endpoint-ai>`__
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
- `A Cortex-M55 (supports Helium) based MDK Project, PC emulation is
|
||||
available. <https://github.com/lvgl/lv_port_an547_cm55_sim>`__
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
:ref:`lv_draw_sw_arm2d_h`
|
||||
|
||||
:ref:`lv_blend_arm2d_h`
|
||||
14
docs/details/integration/renderers/index.rst
Normal file
14
docs/details/integration/renderers/index.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
==================
|
||||
Renderers and GPUs
|
||||
==================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
sw
|
||||
arm2d
|
||||
nema_gfx
|
||||
nxp_pxp
|
||||
nxp_vglite
|
||||
sdl
|
||||
stm32_dma2d
|
||||
94
docs/details/integration/renderers/nema_gfx.rst
Normal file
94
docs/details/integration/renderers/nema_gfx.rst
Normal file
@@ -0,0 +1,94 @@
|
||||
.. _stm32_nema_gfx:
|
||||
|
||||
===================================
|
||||
NemaGFX Acceleration (AKA NeoChrom)
|
||||
===================================
|
||||
|
||||
Some of the more powerful STM32 MCUs such as the
|
||||
STM32U5 feature a 2.5D GPU which can natively draw most
|
||||
LVGL primitives.
|
||||
|
||||
Get Started with the Riverdi STM32U5 5-inch Display
|
||||
***************************************************
|
||||
|
||||
`lv_port_riverdi_stm32u5 <https://github.com/lvgl/lv_port_riverdi_stm32u5>`__
|
||||
is a ready-to-use port for the Riverdi STM32 5.0" Embedded Display
|
||||
(STM32U599NJH6Q or STM32U5A9NJH6Q) which has Nema enabled.
|
||||
Follow the instructions in the readme to get started.
|
||||
|
||||
Usage and Configuration
|
||||
***********************
|
||||
|
||||
Enable the renderer by setting :c:macro:`LV_USE_NEMA_GFX` to ``1`` in
|
||||
lv_conf.h. If using :c:macro:`LV_USE_NEMA_VG`,
|
||||
set :c:macro:`LV_NEMA_GFX_MAX_RESX` and :c:macro:`LV_NEMA_GFX_MAX_RESY`
|
||||
to the size of the display you will be using so that enough static
|
||||
memory will be reserved for VG. Without VG, more task types will be
|
||||
performed by the software renderer.
|
||||
|
||||
"libs/nema_gfx" contains pre-compiled binaries for the Nema GPU
|
||||
drivers. In `lv_port_riverdi_stm32u5 <https://github.com/lvgl/lv_port_riverdi_stm32u5>`__
|
||||
the project is already configured to link the binaries when building.
|
||||
With a different STM32CubeIDE project, you can configure the libraries to be linked
|
||||
by right-clicking the project in the "Project Explorer" sidebar, clicking
|
||||
"Properties", navigating to "C/C++ Build", "Settings", "MCU G++ Linker", and then
|
||||
"Libraries". Add an entry under "Libraries (-l)" that is "nemagfx-float-abi-hard".
|
||||
Add an entry under "Library search path (-L)" which is a path to
|
||||
"libs/nema_gfx/lib/core/cortex_m33/gcc" e.g.
|
||||
"${workspace_loc:/${ProjName}/Middlewares/LVGL/lvgl/libs/nema_gfx/lib/core/cortex_m33/gcc}".
|
||||
You will also want to add the "libs/nema_gfx/include" directory to your include
|
||||
search paths. Under "MCU GCC Compiler", "Include paths", add an entry to "Include paths (-I)"
|
||||
which is a path to "libs/nema_gfx/include" e.g.
|
||||
"${workspace_loc:/${ProjName}/Middlewares/LVGL/lvgl/libs/nema_gfx/include}".
|
||||
Click "Apply and Close".
|
||||
|
||||
32 and 16 bit :c:macro:`LV_COLOR_DEPTH` is supported.
|
||||
|
||||
At the time of writing, :c:macro:`LV_USE_OS` support is experimental
|
||||
and not yet working in
|
||||
`lv_port_riverdi_stm32u5 <https://github.com/lvgl/lv_port_riverdi_stm32u5>`__
|
||||
|
||||
"src/draw/nema_gfx/lv_draw_nema_gfx_hal.c" implements the HAL functionality
|
||||
required by Nema to allocate memory and lock resources (in this implementation,
|
||||
no locking is done). It may conflict with existing definitions
|
||||
if you have an existing Nema HAL implementation. You may
|
||||
simply be able to remove yours.
|
||||
|
||||
TSC Images
|
||||
**********
|
||||
|
||||
TSC (ThinkSillicon Compression) images can be drawn by this renderer. The
|
||||
TSC 4/6/6A/12/12A color formats are part of :cpp:type:`lv_color_format_t`.
|
||||
All other renderers will ignore images with these color formats.
|
||||
Define an image descriptor variable with the corresponding
|
||||
TSC color format and the GPU will be able to draw it directly.
|
||||
Stride does not need to be specified because it will be computed by the
|
||||
renderer.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const lv_image_dsc_t img_demo_widgets_avatar_tsc6a = {
|
||||
.header.cf = LV_COLOR_FORMAT_NEMA_TSC6A,
|
||||
.header.w = 144,
|
||||
.header.h = 144,
|
||||
.data = img_demo_widgets_avatar_tsc6a_map,
|
||||
.data_size = sizeof(img_demo_widgets_avatar_tsc6a_map),
|
||||
};
|
||||
|
||||
DMA2D
|
||||
*****
|
||||
|
||||
The Nema renderer uses DMA2D to flush in parallel with rendering in
|
||||
`lv_port_riverdi_stm32u5 <https://github.com/lvgl/lv_port_riverdi_stm32u5>`__.
|
||||
|
||||
If your STM does not have the Nema GPU, it may still support
|
||||
DMA2D. DMA2D is a simple peripheral which can draw fills
|
||||
and images independently of the CPU.
|
||||
See the LVGL :ref:`DMA2D support <dma2d>`.
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
:ref:`lv_draw_nema_gfx_h`
|
||||
|
||||
:ref:`lv_draw_nema_gfx_utils_h`
|
||||
15
docs/details/integration/renderers/nxp_pxp.rst
Normal file
15
docs/details/integration/renderers/nxp_pxp.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
===========
|
||||
NXP PXP GPU
|
||||
===========
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
:ref:`lv_draw_pxp_h`
|
||||
|
||||
:ref:`lv_pxp_cfg_h`
|
||||
|
||||
:ref:`lv_pxp_osa_h`
|
||||
|
||||
:ref:`lv_pxp_utils_h`
|
||||
|
||||
86
docs/details/integration/renderers/nxp_vglite.rst
Normal file
86
docs/details/integration/renderers/nxp_vglite.rst
Normal file
@@ -0,0 +1,86 @@
|
||||
.. _vglite:
|
||||
|
||||
===============
|
||||
NXP VG-Lite GPU
|
||||
===============
|
||||
|
||||
This is a generic VG-Lite rendering backend implementation that is designed to utilize
|
||||
`VeriSilicon <https://verisilicon.com/>`_'s generic API to operate GPU hardware as much as possible.
|
||||
|
||||
Even with different chip manufacturers, as long as they use the same version of VG-Lite API as the rendering backend,
|
||||
LVGL rendering acceleration can be supported without the need for LVGL adaptation work.
|
||||
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|
||||
1. Set :c:macro:`LV_USE_DRAW_VG_LITE` to 1 in ``lv_conf.h`` to enabled the VG-Lite rendering backend.
|
||||
Make sure that your hardware has been adapted to the VG-Lite API and that the absolute path to ``vg_lite.h``, which can be directly referenced by lvgl, has been exposed.
|
||||
|
||||
2. Confirm the GPU initialization method, there are two ways:
|
||||
|
||||
- The SDK calls the GPU initialization function on its own during system startup, and the GPU is available when LVGL starts; set :c:macro:`LV_VG_LITE_USE_GPU_INIT` to 0.
|
||||
- LVGL actively calls the GPU initialization function, and the SDK needs to implement the public function `gpu_init()`.
|
||||
LVGL will call it to complete the GPU hardware initialization during startup; set :c:macro:`LV_VG_LITE_USE_GPU_INIT` to 1.
|
||||
|
||||
3. Set the :c:macro:`LV_VG_LITE_USE_ASSERT` configuration to enable GPU call parameter checking.
|
||||
Due to the complexity of the parameters used in GPU calls, incorrect parameters can result in abnormal GPU hardware operation, such as forgetting to add an end symbol
|
||||
to the path or not meeting the alignment requirements for buffer stride.
|
||||
To quickly resolve such issues, strict parameter checking has been added before each VG-Lite call, including buffer stride validation and matrix invertibility check.
|
||||
When an error parameter is detected, an assertion will occur to print out the error parameter, allowing the user to promptly make corrections and reduce the time wasted on hardware simulation.
|
||||
Please note that enabling this check will decrease runtime performance. It is recommended to enable it in Debug mode and disable it in the Release version.
|
||||
|
||||
4. Set the :c:macro:`LV_VG_LITE_FLUSH_MAX_COUNT` configuration to specify the flush method.
|
||||
VG-Lite uses two sets of command buffer buffers to render instructions, and utilizing this mechanism well can greatly improve drawing efficiency.
|
||||
Currently, two buffering methods are supported:
|
||||
|
||||
- Set :c:macro:`LV_VG_LITE_FLUSH_MAX_COUNT` to zero (recommended). The rendering backend will obtain the GPU's working status every time it writes rendering instructions to the command buffer.
|
||||
|
||||
When the GPU is idle, it will immediately call ``vg_lite_flush`` to notify the GPU to start rendering and swap the command buffer. When the GPU is busy, it will continue to fill the command buffer cache with rendering instructions.
|
||||
The underlying driver will automatically determine if the command buffer has been filled. When it is about to be filled, it will forcibly wait for the unfinished drawing tasks to end and swap the command buffer.
|
||||
This method can effectively improve GPU utilization, especially in scenarios where rendering text, as the GPU's drawing time and the CPU's data preparation time are very close, allowing the CPU and GPU to run in parallel.
|
||||
|
||||
- Set :c:macro:`LV_VG_LITE_FLUSH_MAX_COUNT` to a value greater than zero, such as 8. After writing 8 rendering instructions to the command buffer, the rendering backend
|
||||
|
||||
will call ``vg_lite_flush`` to notify the GPU to start rendering and swap the command buffer.
|
||||
|
||||
5. Set the :c:macro:`LV_VG_LITE_USE_BOX_SHADOW` configuration to use GPU rendering for shadows.
|
||||
In fact, GPU hardware does not actually support shadow rendering. However, through experimentation, it has been found that a similar shadow effect
|
||||
can be achieved by using multiple layers of borders with different levels of transparency.
|
||||
It is recommended to enable this configuration in scenarios where the shadow quality requirements are not high, as it can significantly improve rendering efficiency.
|
||||
|
||||
6. Set the :c:macro:`LV_VG_LITE_GRAD_CACHE_CNT` configuration to specify the number of gradient cache entries.
|
||||
Gradient drawing includes linear gradients and radial gradients. Using a cache can effectively reduce the number of times the gradient image is created and improve drawing efficiency.
|
||||
Each individual gradient consumes around 4K of GPU memory pool. If there are many gradients used in the interface, you can try increasing the number of gradient cache entries.
|
||||
If the VG-Lite API returns the :c:macro:`VG_LITE_OUT_OF_RESOURCES` error, you can try increasing the size of the GPU memory pool or reducing the number of gradient cache entries.
|
||||
|
||||
7. Set the :c:macro:`LV_VG_LITE_STROKE_CACHE_CNT` configuration to specify the number of stroke path caches.
|
||||
When the stroke parameters do not change, the previously generated stroke parameters are automatically retrieved from the cache to improve rendering performance.
|
||||
The memory occupied by the stroke is strongly related to the path length. If the VG-Lite API returns the :c:macro:`VG_LITE_OUT_OF_RESOURCES` error,
|
||||
you can try increasing the size of the GPU memory pool or reducing the number of stroke cache entries.
|
||||
|
||||
NOTE: VG-Lite rendering backend does not support multi-threaded calls, please make sure :c:macro:`LV_USE_OS` is always configured as :c:macro:`LV_OS_NONE`.
|
||||
|
||||
|
||||
VG-Lite Simulator
|
||||
*****************
|
||||
|
||||
LVGL integrates a VG-Lite simulator based on ThorVG.
|
||||
Its purpose is to simplify the debugging of VG-Lite adaptation and reduce the time of debugging and locating problems on hardware devices.
|
||||
For detailed instructions, see :ref:`vg_lite_tvg`.
|
||||
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
:ref:`lv_draw_vglite_h`
|
||||
|
||||
:ref:`lv_vglite_buf_h`
|
||||
|
||||
:ref:`lv_vglite_matrix_h`
|
||||
|
||||
:ref:`lv_vglite_path_h`
|
||||
|
||||
:ref:`lv_vglite_utils_h`
|
||||
|
||||
|
||||
9
docs/details/integration/renderers/sdl.rst
Normal file
9
docs/details/integration/renderers/sdl.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
============
|
||||
SDL Renderer
|
||||
============
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
:ref:`lv_draw_sdl_h`
|
||||
|
||||
9
docs/details/integration/renderers/stm32_dma2d.rst
Normal file
9
docs/details/integration/renderers/stm32_dma2d.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
===============
|
||||
STM32 DMA2D GPU
|
||||
===============
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
:ref:`lv_draw_dma2d_h`
|
||||
|
||||
12
docs/details/integration/renderers/sw.rst
Normal file
12
docs/details/integration/renderers/sw.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
=================
|
||||
Software Renderer
|
||||
=================
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
:ref:`lv_draw_sw_h`
|
||||
|
||||
:ref:`lv_draw_sw_blend_h`
|
||||
|
||||
:ref:`lv_draw_sw_gradient_h`
|
||||
23
docs/details/libs/arduino_esp_littlefs.rst
Normal file
23
docs/details/libs/arduino_esp_littlefs.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
.. _arduino_esp_littlefs:
|
||||
|
||||
====================
|
||||
Arduino ESP littlefs
|
||||
====================
|
||||
|
||||
LittleFS is a little fail-safe filesystem designed for microcontrollers and integrated in the Arduino framework
|
||||
when used with ESP32 and ESP8266.
|
||||
|
||||
Detailed introduction:
|
||||
|
||||
- https://github.com/esp8266/Arduino
|
||||
- https://github.com/espressif/arduino-esp32
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_FS_ARDUINO_ESP_LITTLEFS` and define a :c:macro:`LV_FS_ARDUINO_ESP_LITTLEFS_LETTER` in ``lv_conf.h``.
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
24
docs/details/libs/arduino_sd.rst
Normal file
24
docs/details/libs/arduino_sd.rst
Normal file
@@ -0,0 +1,24 @@
|
||||
.. _arduino_sd:
|
||||
|
||||
==========
|
||||
Arduino SD
|
||||
==========
|
||||
|
||||
Enables reading and writing on SD cards.
|
||||
Once an SD memory card is connected to the SPI interface of the Arduino or Genuino board you can create files
|
||||
and read/write on them. You can also move through directories on the SD card..
|
||||
|
||||
Detailed introduction:
|
||||
|
||||
- https://www.arduino.cc/reference/en/libraries/sd/
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_FS_ARDUINO_SD` and define a :c:macro:`LV_FS_ARDUINO_SD_LETTER` in ``lv_conf.h``.
|
||||
You will need to initialize the SD card before LVGL can use it (i.e. :cpp:expr:`SD.begin(0, SPI, 40000000)`).
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
50
docs/details/libs/barcode.rst
Normal file
50
docs/details/libs/barcode.rst
Normal file
@@ -0,0 +1,50 @@
|
||||
.. _barcode:
|
||||
|
||||
=======
|
||||
Barcode
|
||||
=======
|
||||
|
||||
Barcode generation with LVGL. Uses
|
||||
`code128 <https://github.com/fhunleth/code128>`__ by
|
||||
`fhunleth <https://github.com/fhunleth>`__.
|
||||
|
||||
.. _barcode_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_BARCODE` in ``lv_conf.h``.
|
||||
|
||||
Use :cpp:func:`lv_barcode_create` to create a barcode object, and use
|
||||
:cpp:func:`lv_barcode_update` to generate a barcode.
|
||||
|
||||
Call :cpp:func:`lv_barcode_set_scale` to adjust scaling,
|
||||
call :cpp:func:`lv_barcode_set_dark_color` and :cpp:func:`lv_barcode_set_light_color`
|
||||
adjust color, call :cpp:func:`lv_barcode_set_direction` will set
|
||||
direction to display, and call :cpp:func:`lv_barcode_update` again to regenerate
|
||||
the barcode.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
- It is best not to manually set the width of the barcode, because when
|
||||
the width of the Widget is lower than the width of the barcode, the
|
||||
display will be incomplete due to truncation.
|
||||
- The scale adjustment can only be an integer multiple, for example,
|
||||
:cpp:expr:`lv_barcode_set_scale(barcode, 2)` means 2x scaling.
|
||||
- The direction adjustment can be :cpp:enumerator:`LV_DIR_HOR` or :cpp:enumerator:`LV_DIR_VER`
|
||||
|
||||
.. _barcode_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/barcode/index.rst
|
||||
|
||||
.. _barcode_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`code128_h`
|
||||
|
||||
54
docs/details/libs/bmp.rst
Normal file
54
docs/details/libs/bmp.rst
Normal file
@@ -0,0 +1,54 @@
|
||||
.. _bmp:
|
||||
|
||||
===========
|
||||
BMP decoder
|
||||
===========
|
||||
|
||||
This extension allows the use of BMP images in LVGL.
|
||||
|
||||
Library source: https://github.com/caj-johnson/bmp-decoder
|
||||
|
||||
The pixels are read on demand (not the whole image is loaded)
|
||||
so using BMP images requires very little RAM.
|
||||
|
||||
If enabled in ``lv_conf.h`` by :c:macro:`LV_USE_BMP` LVGL will register a new
|
||||
image decoder automatically so BMP files can be directly used as image
|
||||
sources. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_image_set_src(my_img, "S:path/to/picture.bmp");
|
||||
|
||||
Note that, a file system driver needs to registered to open images from
|
||||
files. Read more about it :ref:`overview_file_system` or just
|
||||
enable one in ``lv_conf.h`` with ``LV_USE_FS_...``
|
||||
|
||||
.. _bmp_limitations:
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
- Only BMP files are supported and BMP images as C array
|
||||
(:c:struct:`lv_image_dsc_t`) are not. It's because there is no practical
|
||||
differences between how the BMP files and LVGL's image format stores
|
||||
the image data.
|
||||
- BMP files can be loaded only from file. If you want to store them in
|
||||
flash it's better to convert them to C array with `LVGL's image converter <https://lvgl.io/tools/imageconverter>`__.
|
||||
- The BMP files color format needs to match with :c:macro:`LV_COLOR_DEPTH`.
|
||||
Use GIMP to save the image in the required format. Both RGB888 and
|
||||
ARGB888 works with :c:macro:`LV_COLOR_DEPTH` ``32``
|
||||
- Palette is not supported.
|
||||
- Because not the whole image is read in cannot be zoomed or rotated.
|
||||
|
||||
.. _bmp_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/bmp/index.rst
|
||||
|
||||
.. _bmp_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
52
docs/details/libs/ffmpeg.rst
Normal file
52
docs/details/libs/ffmpeg.rst
Normal file
@@ -0,0 +1,52 @@
|
||||
.. _ffmpeg:
|
||||
|
||||
==============
|
||||
FFmpeg support
|
||||
==============
|
||||
|
||||
A complete, cross-platform solution to record, convert and stream audio and video.
|
||||
|
||||
Detailed introduction: https://www.ffmpeg.org
|
||||
|
||||
Install FFmpeg
|
||||
--------------
|
||||
|
||||
Download first FFmpeg from `here <https://www.ffmpeg.org/download.html>`__, then install it:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
./configure --disable-all --disable-autodetect --disable-podpages --disable-asm --enable-avcodec --enable-avformat --enable-decoders --enable-encoders --enable-demuxers --enable-parsers --enable-protocol='file' --enable-swscale --enable-zlib
|
||||
make
|
||||
sudo make install
|
||||
|
||||
Add FFmpeg to your project
|
||||
--------------------------
|
||||
|
||||
- Add library: ``FFmpeg`` (for GCC: ``-lavformat -lavcodec -lavutil -lswscale -lm -lz -lpthread``)
|
||||
|
||||
.. _ffmpeg_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_FFMPEG` in ``lv_conf.h``.
|
||||
|
||||
See the examples below.
|
||||
|
||||
:note: FFmpeg extension doesn't use LVGL's file system. You can
|
||||
simply pass the path to the image or video as usual on your operating
|
||||
system or platform.
|
||||
|
||||
|
||||
.. _ffmpeg_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/ffmpeg/index.rst
|
||||
|
||||
.. _ffmpeg_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
121
docs/details/libs/freetype.rst
Normal file
121
docs/details/libs/freetype.rst
Normal file
@@ -0,0 +1,121 @@
|
||||
.. _freetype:
|
||||
|
||||
================
|
||||
FreeType support
|
||||
================
|
||||
|
||||
Interface to FreeType library to generate font bitmap at run time.
|
||||
|
||||
Detailed introduction: https://www.freetype.org
|
||||
|
||||
Add FreeType to your project
|
||||
----------------------------
|
||||
|
||||
First, Download FreeType from `here <https://sourceforge.net/projects/freetype/files/>`__.
|
||||
|
||||
There are two ways to use FreeType:
|
||||
|
||||
For UNIX
|
||||
~~~~~~~~
|
||||
|
||||
For UNIX systems, it is recommended to use the way of compiling and installing libraries.
|
||||
|
||||
- Enter the FreeType source code directory
|
||||
- ``make``
|
||||
- ``sudo make install``
|
||||
- Add include path: ``/usr/include/freetype2`` (for GCC: ``-I/usr/include/freetype2 -L/usr/local/lib``)
|
||||
- Link library: ``freetype`` (for GCC: ``-L/usr/local/lib -lfreetype``)
|
||||
|
||||
For Embedded Devices
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For embedded devices, it is more recommended to use the FreeType
|
||||
configuration file provided by LVGL, which only includes the most
|
||||
commonly used functions, which is very meaningful for saving limited
|
||||
FLASH space.
|
||||
|
||||
- Copy the FreeType source code to your project directory.
|
||||
- Refer to the following ``Makefile`` for configuration:
|
||||
|
||||
.. code-block:: make
|
||||
|
||||
# FreeType custom configuration header file
|
||||
CFLAGS += -DFT2_BUILD_LIBRARY
|
||||
CFLAGS += -DFT_CONFIG_MODULES_H=<lvgl/src/libs/freetype/ftmodule.h>
|
||||
CFLAGS += -DFT_CONFIG_OPTIONS_H=<lvgl/src/libs/freetype/ftoption.h>
|
||||
|
||||
# FreeType include path
|
||||
CFLAGS += -Ifreetype/include
|
||||
|
||||
# FreeType C source file
|
||||
FT_CSRCS += freetype/src/base/ftbase.c
|
||||
FT_CSRCS += freetype/src/base/ftbitmap.c
|
||||
FT_CSRCS += freetype/src/base/ftdebug.c
|
||||
FT_CSRCS += freetype/src/base/ftglyph.c
|
||||
FT_CSRCS += freetype/src/base/ftinit.c
|
||||
FT_CSRCS += freetype/src/cache/ftcache.c
|
||||
FT_CSRCS += freetype/src/gzip/ftgzip.c
|
||||
FT_CSRCS += freetype/src/sfnt/sfnt.c
|
||||
FT_CSRCS += freetype/src/smooth/smooth.c
|
||||
FT_CSRCS += freetype/src/truetype/truetype.c
|
||||
CSRCS += $(FT_CSRCS)
|
||||
|
||||
.. _freetype_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_FREETYPE` in ``lv_conf.h``.
|
||||
|
||||
Cache configuration:
|
||||
|
||||
- :c:macro:`LV_FREETYPE_CACHE_FT_GLYPH_CNT` Maximum number of cached glyphs., etc.
|
||||
|
||||
By default, the FreeType extension doesn't use LVGL's file system. You
|
||||
can simply pass the path to the font as usual on your operating system
|
||||
or platform.
|
||||
|
||||
If you want FreeType to use lvgl's memory allocation and file system
|
||||
interface, you can enable :c:macro:`LV_FREETYPE_USE_LVGL_PORT` in
|
||||
``lv_conf.h``, convenient for unified management.
|
||||
|
||||
The font style supports *Italic* and **Bold** fonts processed by
|
||||
software, and can be set with reference to the following values:
|
||||
|
||||
- :cpp:enumerator:`LV_FREETYPE_FONT_STYLE_NORMAL`: Default style.
|
||||
- :cpp:enumerator:`LV_FREETYPE_FONT_STYLE_ITALIC`: Italic style.
|
||||
- :cpp:enumerator:`LV_FREETYPE_FONT_STYLE_BOLD`: Bold style.
|
||||
|
||||
They can be combined.eg:
|
||||
:cpp:expr:`LV_FREETYPE_FONT_STYLE_BOLD | LV_FREETYPE_FONT_STYLE_ITALIC`.
|
||||
|
||||
The FreeType extension also supports colored bitmap glyphs such as emojis. Note
|
||||
that only bitmaps are supported at this time. Colored vector graphics cannot be
|
||||
rendered. An example on how to draw a colored bitmap glyph is shown below.
|
||||
|
||||
Use the :cpp:func:`lv_freetype_font_create` function to create a font. To
|
||||
delete a font, use :cpp:func:`lv_freetype_font_delete`. For more detailed usage,
|
||||
please refer to example code.
|
||||
|
||||
.. _freetype_example:
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. include:: ../../examples/libs/freetype/index.rst
|
||||
|
||||
Learn more
|
||||
----------
|
||||
|
||||
- FreeType`tutorial <https://www.freetype.org/freetype2/docs/tutorial/step1.html>`__
|
||||
- LVGL's :ref:`add_font`
|
||||
|
||||
.. _freetype_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`ftoption_h`
|
||||
|
||||
:ref:`ftmodule_h`
|
||||
|
||||
77
docs/details/libs/fs.rst
Normal file
77
docs/details/libs/fs.rst
Normal file
@@ -0,0 +1,77 @@
|
||||
.. _libs_filesystem:
|
||||
|
||||
======================
|
||||
File System Interfaces
|
||||
======================
|
||||
|
||||
LVGL has a :ref:`overview_file_system` module
|
||||
to provide an abstraction layer for various file system drivers.
|
||||
|
||||
LVG has built in support for:
|
||||
|
||||
- `FATFS <http://elm-chan.org/fsw/ff/00index_e.html>`__
|
||||
- STDIO (Linux and Windows using C standard function .e.g ``fopen``, ``fread``)
|
||||
- POSIX (Linux and Windows using POSIX function .e.g ``open``, ``read``)
|
||||
- WIN32 (Windows using Win32 API function .e.g ``CreateFileA``, ``ReadFile``)
|
||||
- MEMFS (read a file from a memory buffer)
|
||||
- LITTLEFS (a little fail-safe filesystem designed for microcontrollers)
|
||||
- Arduino ESP LITTLEFS (a little fail-safe filesystem designed for Arduino ESP)
|
||||
- Arduino SD (allows for reading from and writing to SD cards)
|
||||
|
||||
You still need to provide the drivers and libraries, this extension
|
||||
provides only the bridge between FATFS, STDIO, POSIX, WIN32 and LVGL.
|
||||
|
||||
.. _libs_filesystem_usage:
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
In ``lv_conf.h`` enable ``LV_USE_FS_...`` and assign an upper cased
|
||||
letter to ``LV_FS_..._LETTER`` (e.g. ``'S'``). After that you can access
|
||||
files using that driver letter. E.g. ``"S:path/to/file.txt"``.
|
||||
|
||||
Working with common prefixes
|
||||
""""""""""""""""""""""""""""
|
||||
|
||||
A **default driver letter** can be set by ``LV_FS_DEFAULT_DRIVE_LETTER``,
|
||||
which allows skipping the drive prefix in file paths.
|
||||
|
||||
For example if ``LV_FS_DEFAULT_DRIVE_LETTER`` is set the ``'S'`` *"path/to/file.txt"* will mean *"S:path/to/file.txt"*.
|
||||
|
||||
This feature is useful if you have only a single driver and don't want to bother with LVGL's driver layer in the file paths.
|
||||
It also helps to use a unified path with LVGL's file system and normal file systems.
|
||||
The original mechanism is not affected, so a path starting with drive letter will still work.
|
||||
|
||||
The **working directory** can be set with ``LV_FS_..._PATH``. E.g.
|
||||
``"/home/joe/projects/"`` The actual file/directory paths will be
|
||||
appended to it, allowing to skip the common part.
|
||||
|
||||
Caching
|
||||
"""""""
|
||||
|
||||
:ref:`Cached reading <overview_file_system_cache>` is also supported if ``LV_FS_..._CACHE_SIZE`` is set to
|
||||
not ``0`` value. :cpp:func:`lv_fs_read` caches this size of data to lower the
|
||||
number of actual reads from the storage.
|
||||
|
||||
To use the memory-mapped file emulation an ``lv_fs_path_ex_t`` object must be
|
||||
created and initialized. This object can be passed to :cpp:func:`lv_fs_open` as
|
||||
the file name:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_fs_path_ex_t mempath;
|
||||
lv_fs_file_t file;
|
||||
uint8_t *buffer;
|
||||
uint32_t size;
|
||||
|
||||
/* Initialize buffer */
|
||||
...
|
||||
|
||||
lv_fs_make_path_from_buffer(&mempath, LV_FS_MEMFS_LETTER, (void*)buffer, size);
|
||||
lv_fs_res_t res = lv_fs_open(&file, (const char *)&mempath, LV_FS_MODE_RD);
|
||||
|
||||
.. _libs_filesystem_api:
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
61
docs/details/libs/gif.rst
Normal file
61
docs/details/libs/gif.rst
Normal file
@@ -0,0 +1,61 @@
|
||||
.. _gif:
|
||||
|
||||
===========
|
||||
GIF decoder
|
||||
===========
|
||||
|
||||
Allow using GIF images in LVGL.
|
||||
|
||||
Detailed introduction: https://github.com/lecram/gifdec
|
||||
|
||||
When enabled in ``lv_conf.h`` with :c:macro:`LV_USE_GIF`
|
||||
:cpp:expr:`lv_gif_create(parent)` can be used to create a gif widget.
|
||||
|
||||
:cpp:expr:`lv_gif_set_src(widget, src)` works very similarly to :cpp:func:`lv_image_set_src`.
|
||||
As source, it also accepts images as variables (:c:struct:`lv_image_dsc_t`) or
|
||||
files.
|
||||
|
||||
Convert GIF files to C array
|
||||
----------------------------
|
||||
|
||||
To convert a GIF file to byte values array use `LVGL's online
|
||||
converter <https://lvgl.io/tools/imageconverter>`__. Select "Raw" color
|
||||
format and "C array" Output format.
|
||||
|
||||
Use GIF images from file
|
||||
------------------------
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_gif_set_src(widget, "S:path/to/example.gif");
|
||||
|
||||
Note that, a file system driver needs to be registered to open images
|
||||
from files. Read more about it :ref:`overview_file_system` or just
|
||||
enable one in ``lv_conf.h`` with ``LV_USE_FS_...``
|
||||
|
||||
Memory requirements
|
||||
-------------------
|
||||
|
||||
To decode and display a GIF animation the following amount of RAM is
|
||||
required:
|
||||
|
||||
- :c:macro:`LV_COLOR_DEPTH` ``8``: 3 x image width x image height
|
||||
- :c:macro:`LV_COLOR_DEPTH` ``16``: 4 x image width x image height
|
||||
- :c:macro:`LV_COLOR_DEPTH` ``32``: 5 x image width x image height
|
||||
|
||||
.. _gif_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/gif/index.rst
|
||||
|
||||
.. _gif_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`gifdec_h`
|
||||
|
||||
28
docs/details/libs/index.rst
Normal file
28
docs/details/libs/index.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
.. _3rd_party_libraries:
|
||||
|
||||
===================
|
||||
3rd-Party Libraries
|
||||
===================
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
arduino_esp_littlefs
|
||||
arduino_sd
|
||||
barcode
|
||||
bmp
|
||||
ffmpeg
|
||||
freetype
|
||||
fs
|
||||
gif
|
||||
lfs
|
||||
libjpeg_turbo
|
||||
libpng
|
||||
lodepng
|
||||
qrcode
|
||||
rle
|
||||
rlottie
|
||||
svg
|
||||
tiny_ttf
|
||||
tjpgd
|
||||
60
docs/details/libs/lfs.rst
Normal file
60
docs/details/libs/lfs.rst
Normal file
@@ -0,0 +1,60 @@
|
||||
.. _lfs:
|
||||
|
||||
==============
|
||||
littlefs
|
||||
==============
|
||||
|
||||
littlefs is a little fail-safe filesystem designed for microcontrollers.
|
||||
|
||||
Detailed introduction: https://github.com/littlefs-project/littlefs
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_FS_LITTLEFS` and define a :c:macro:`LV_FS_LITTLEFS_LETTER` in ``lv_conf.h``.
|
||||
|
||||
When enabled :c:macro:`lv_littlefs_set_handler` can be used to set up a mount point.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "lfs.h"
|
||||
|
||||
// configuration of the filesystem is provided by this struct
|
||||
const struct lfs_config cfg = {
|
||||
// block device operations
|
||||
.read = user_provided_block_device_read,
|
||||
.prog = user_provided_block_device_prog,
|
||||
.erase = user_provided_block_device_erase,
|
||||
.sync = user_provided_block_device_sync,
|
||||
|
||||
// block device configuration
|
||||
.read_size = 16,
|
||||
.prog_size = 16,
|
||||
.block_size = 4096,
|
||||
.block_count = 128,
|
||||
.cache_size = 16,
|
||||
.lookahead_size = 16,
|
||||
.block_cycles = 500,
|
||||
};
|
||||
|
||||
// mount the filesystem
|
||||
int err = lfs_mount(&lfs, &cfg);
|
||||
|
||||
// reformat if we can't mount the filesystem
|
||||
// this should only happen on the first boot
|
||||
if (err) {
|
||||
lfs_format(&lfs, &cfg);
|
||||
lfs_mount(&lfs, &cfg);
|
||||
}
|
||||
|
||||
lv_littlefs_set_handler(&lfs);
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
|
||||
56
docs/details/libs/libjpeg_turbo.rst
Normal file
56
docs/details/libs/libjpeg_turbo.rst
Normal file
@@ -0,0 +1,56 @@
|
||||
.. _libjpeg:
|
||||
|
||||
=====================
|
||||
libjpeg-turbo decoder
|
||||
=====================
|
||||
|
||||
**libjpeg-turbo** is a JPEG image codec that uses SIMD instructions to accelerate baseline JPEG compression and decompression on x86,
|
||||
x86-64, Arm, PowerPC, and MIPS systems, as well as progressive JPEG compression on x86, x86-64, and Arm systems.
|
||||
|
||||
Detailed introduction: https://libjpeg-turbo.org
|
||||
|
||||
Library source: https://github.com/libjpeg-turbo/libjpeg-turbo
|
||||
|
||||
.. _libjpeg_install:
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install libjpeg-turbo8-dev
|
||||
|
||||
Add libjpeg-turbo to your project
|
||||
---------------------------------
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(JPEG REQUIRED)
|
||||
include_directories(${JPEG_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${JPEG_LIBRARIES})
|
||||
|
||||
.. _libjpeg_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_LIBJPEG_TURBO` in ``lv_conf.h``.
|
||||
|
||||
See the examples below.
|
||||
It should be noted that each image of this decoder needs to consume ``image width x image height x 3`` bytes of RAM,
|
||||
and it needs to be combined with the :ref:`overview_image_caching` feature to ensure that the memory usage is within a reasonable range.
|
||||
|
||||
.. _libjpeg_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/libjpeg_turbo/index.rst
|
||||
|
||||
.. _libjpeg_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`lv_libjpeg_turbo_h`
|
||||
|
||||
52
docs/details/libs/libpng.rst
Normal file
52
docs/details/libs/libpng.rst
Normal file
@@ -0,0 +1,52 @@
|
||||
.. _libpng:
|
||||
|
||||
==============
|
||||
libpng decoder
|
||||
==============
|
||||
|
||||
libpng is the official PNG reference library. It supports almost all PNG features, is extensible, and has been extensively tested for over 28 years.
|
||||
|
||||
Detailed introduction: http://www.libpng.org/pub/png/libpng.html
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install libpng-dev
|
||||
|
||||
Add libpng to your project
|
||||
--------------------------
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(PNG REQUIRED)
|
||||
include_directories(${PNG_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${PNG_LIBRARIES})
|
||||
|
||||
.. _libpng_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_LIBPNG` in ``lv_conf.h``.
|
||||
|
||||
See the examples below.
|
||||
It should be noted that each image of this decoder needs to consume ``width x height x 4`` bytes of RAM,
|
||||
and it needs to be combined with the :ref:`overview_image_caching` feature to ensure that the memory usage is within a reasonable range.
|
||||
The decoded image is stored in RGBA pixel format.
|
||||
|
||||
.. _libpng_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/libpng/index.rst
|
||||
|
||||
.. _libpng_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`libpng`
|
||||
|
||||
51
docs/details/libs/lodepng.rst
Normal file
51
docs/details/libs/lodepng.rst
Normal file
@@ -0,0 +1,51 @@
|
||||
.. _lodepng_rst:
|
||||
|
||||
===============
|
||||
LodePNG decoder
|
||||
===============
|
||||
|
||||
Allow the use of PNG images in LVGL.
|
||||
|
||||
Detailed introduction: https://github.com/lvandeve/lodepng
|
||||
|
||||
If enabled in ``lv_conf.h`` by :c:macro:`LV_USE_LODEPNG` LVGL will register a new
|
||||
image decoder automatically so PNG files can be directly used as any
|
||||
other image sources.
|
||||
|
||||
:note: a file system driver needs to be registered to open images from
|
||||
files. Read more about it :ref:`overview_file_system` or just
|
||||
enable one in ``lv_conf.h`` with ``LV_USE_FS_...``
|
||||
|
||||
|
||||
The whole PNG image is decoded, so ``width x height x 4`` bytes free RAM space is required.
|
||||
The decoded image is stored in RGBA pixel format.
|
||||
|
||||
As it might take significant time to decode PNG images LVGL's :ref:`overview_image_caching` feature can be useful.
|
||||
|
||||
Compress PNG files
|
||||
------------------
|
||||
|
||||
PNG file format supports True color (24/32 bit), and 8-bit palette colors.
|
||||
Usually cliparts, drawings, icons and simple graphics are stored in PNG format,
|
||||
that do not use the whole color space, so it is possible to compress further
|
||||
the image by using 8-bit palette colors, instead of 24/32 bit True color format.
|
||||
Because embedded devices have limited (flash) storage, it is recommended
|
||||
to compress images.
|
||||
|
||||
One option is to use a free online PNG compressor site,
|
||||
for example Compress PNG: https://compresspng.com/
|
||||
|
||||
.. _lodepng_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/lodepng/index.rst
|
||||
|
||||
.. _lodepng_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`lodepng_h`
|
||||
|
||||
45
docs/details/libs/qrcode.rst
Normal file
45
docs/details/libs/qrcode.rst
Normal file
@@ -0,0 +1,45 @@
|
||||
.. _qrcode:
|
||||
|
||||
=======
|
||||
QR code
|
||||
=======
|
||||
|
||||
QR code generation with LVGL. Uses
|
||||
`QR-Code-generator <https://github.com/nayuki/QR-Code-generator>`__ by
|
||||
`nayuki <https://github.com/nayuki>`__.
|
||||
|
||||
.. _qrcode_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Enable :c:macro:`LV_USE_QRCODE` in ``lv_conf.h``.
|
||||
|
||||
Use :cpp:func:`lv_qrcode_create` to create a qrcode object, and use
|
||||
:cpp:func:`lv_qrcode_update` to generate a QR code.
|
||||
|
||||
If you need to re-modify the size and color, use
|
||||
:cpp:func:`lv_qrcode_set_size` and :cpp:func:`lv_qrcode_set_dark_color` or
|
||||
:cpp:func:`lv_qrcode_set_light_color`, and
|
||||
call :cpp:func:`lv_qrcode_update` again to regenerate the QR code.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
- QR codes with less data are smaller, but they scaled by an integer
|
||||
number to best fit to the given size.
|
||||
|
||||
.. _qrcode_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/qrcode/index.rst
|
||||
|
||||
.. _qrcode_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`qrcodegen_h`
|
||||
|
||||
BIN
docs/details/libs/rle-compress-statistics.png
Normal file
BIN
docs/details/libs/rle-compress-statistics.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
86
docs/details/libs/rle.rst
Normal file
86
docs/details/libs/rle.rst
Normal file
@@ -0,0 +1,86 @@
|
||||
.. _rle:
|
||||
|
||||
============
|
||||
RLE Compress
|
||||
============
|
||||
|
||||
LVGL provides a custom RLE compression method. It can be used to reduce binary
|
||||
image size. The RLE compression is a lossless compression method.
|
||||
|
||||
The LVGL's built-in binary image decoder supports RLE compressed images.
|
||||
The decoder supports both variable and file as image sources. The original
|
||||
binary data is directly decoded to RAM
|
||||
|
||||
Benefits
|
||||
--------
|
||||
|
||||
Based on test result from a watch project. Most of the images can be compressed
|
||||
to save more than 70% space as show in below statistic. It shows the file count
|
||||
of every compress level. For rare conditions, RLE compress may increase the file
|
||||
size if there's no large repetition in data.
|
||||
|
||||
.. image:: rle-compress-statistics.png
|
||||
:alt: RLE compress statistics from a watch project
|
||||
:align: center
|
||||
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
The RLE algorithm is a simple compression algorithm that is based on the fact that
|
||||
the for many pixels, the color is the same. The algorithm simply counts how many
|
||||
repeated data are there and store the count value and the color value.
|
||||
If the coming pixels are not repeated, it stores the non-repeat count value and
|
||||
original color value. For more details, the script used to compress the image
|
||||
can be found from ``lvgl/script/LVGLImage.py``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def rle_compress(self, data: bytearray, blksize: int, threshold=16):
|
||||
index = 0
|
||||
data_len = len(data)
|
||||
compressed_data = []
|
||||
while index < data_len:
|
||||
memview = memoryview(data)
|
||||
repeat_cnt = self.get_repeat_count(
|
||||
memview[index:], blksize)
|
||||
if repeat_cnt == 0:
|
||||
# done
|
||||
break
|
||||
elif repeat_cnt < threshold:
|
||||
nonrepeat_cnt = self.get_nonrepeat_count(
|
||||
memview[index:], blksize, threshold)
|
||||
ctrl_byte = uint8_t(nonrepeat_cnt | 0x80)
|
||||
compressed_data.append(ctrl_byte)
|
||||
compressed_data.append(
|
||||
memview[index: index + nonrepeat_cnt * blksize])
|
||||
index += nonrepeat_cnt * blksize
|
||||
else:
|
||||
ctrl_byte = uint8_t(repeat_cnt)
|
||||
compressed_data.append(ctrl_byte)
|
||||
compressed_data.append(memview[index: index + blksize])
|
||||
index += repeat_cnt * blksize
|
||||
|
||||
return b"".join(compressed_data)
|
||||
|
||||
.. _rle_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To use the RLE Decoder, enable it in ``lv_conf.h`` configuration file by setting :c:macro:`LV_USE_RLE` to `1`.
|
||||
The RLE image can be used same as other images.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_image_set_src(img, "path/to/image.rle");
|
||||
|
||||
Generate RLE compressed binary images
|
||||
-------------------------------------
|
||||
|
||||
The image can be directly generated using script ``lvgl/script/LVGLImage.py``
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./script/LVGLImage.py --ofmt BIN --cf I8 --compress RLE cogwheel.png
|
||||
291
docs/details/libs/rlottie.rst
Normal file
291
docs/details/libs/rlottie.rst
Normal file
@@ -0,0 +1,291 @@
|
||||
.. _rlottie:
|
||||
|
||||
==============
|
||||
Rlottie player
|
||||
==============
|
||||
|
||||
.. warning::
|
||||
Rlottie is deprecated. Consider using :ref:`lv_lottie` instead.
|
||||
|
||||
Allows playing Lottie animations in LVGL. Taken from `lv_rlottie <https://github.com/ValentiWorkLearning/lv_rlottie>`__.
|
||||
|
||||
LVGL provides the interface to `Samsung/rlottie <https://github.com/Samsung/rlottie>`__ library's C
|
||||
API. That is the actual Lottie player is not part of LVGL, it needs to
|
||||
be built separately.
|
||||
|
||||
Build Rlottie
|
||||
-------------
|
||||
|
||||
To build Samsung's Rlottie C++14 compatible compiler and optionally
|
||||
CMake 3.14 or higher is required.
|
||||
|
||||
To build on desktop you can follow the instructions from Rlottie's
|
||||
`README <https://github.com/Samsung/rlottie/blob/master/README.md>`__.
|
||||
|
||||
In the most basic case it looks like this:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
mkdir rlottie_workdir
|
||||
cd rlottie_workdir
|
||||
git clone https://github.com/Samsung/rlottie.git
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../rlottie
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
And finally add the ``-lrlottie`` flag to your linker.
|
||||
|
||||
On embedded systems you need to take care of integrating Rlottie to the
|
||||
given build system.
|
||||
|
||||
ESP-IDF example at bottom
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. _rlottie_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
You can use animation from files or raw data (text). In either case
|
||||
first you need to enable :c:macro:`LV_USE_RLOTTIE` in ``lv_conf.h``.
|
||||
|
||||
The ``width`` and ``height`` of the Widget be set in the *create*
|
||||
function and the animation will be scaled accordingly.
|
||||
|
||||
Use Rlottie from file
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To create a Lottie animation from file use:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * lottie = lv_rlottie_create_from_file(parent, width, height, "path/to/lottie.json");
|
||||
|
||||
Note that, Rlottie uses the standard STDIO C file API, so you can use
|
||||
the path "normally" and no LVGL specific driver letter is required.
|
||||
|
||||
Use Rlottie from raw string data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``lv_example_rlottie_approve.c`` contains an example animation in raw
|
||||
format. Instead storing the JSON string, a hex array is stored for the
|
||||
following reasons:
|
||||
|
||||
- avoid escaping ``"`` character in the JSON file
|
||||
- some compilers don't support very long strings
|
||||
|
||||
``lvgl/scripts/filetohex.py`` can be used to convert a Lottie file a hex
|
||||
array. E.g.:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
./filetohex.py path/to/lottie.json > out.txt
|
||||
|
||||
To create an animation from raw data:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
extern const uint8_t lottie_data[];
|
||||
lv_obj_t* lottie = lv_rlottie_create_from_raw(parent, width, height, (const char *)lottie_data);
|
||||
|
||||
Getting animations
|
||||
------------------
|
||||
|
||||
Lottie is standard and popular format so you can find many animation
|
||||
files on the web. For example: https://lottiefiles.com/
|
||||
|
||||
You can also create your own animations with Adobe After Effects or
|
||||
similar software.
|
||||
|
||||
Controlling animations
|
||||
----------------------
|
||||
|
||||
LVGL provides two functions to control the animation mode:
|
||||
:cpp:func:`lv_rlottie_set_play_mode` and :cpp:func:`lv_rlottie_set_current_frame`.
|
||||
You'll combine your intentions when calling the first method, like in
|
||||
these examples:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * lottie = lv_rlottie_create_from_file(scr, 128, 128, "test.json");
|
||||
lv_obj_center(lottie);
|
||||
// Pause to a specific frame
|
||||
lv_rlottie_set_current_frame(lottie, 50);
|
||||
lv_rlottie_set_play_mode(lottie, LV_RLOTTIE_CTRL_PAUSE); // The specified frame will be displayed and then the animation will pause
|
||||
|
||||
// Play backward and loop
|
||||
lv_rlottie_set_play_mode(lottie, LV_RLOTTIE_CTRL_PLAY | LV_RLOTTIE_CTRL_BACKWARD | LV_RLOTTIE_CTRL_LOOP);
|
||||
|
||||
// Play forward once (no looping)
|
||||
lv_rlottie_set_play_mode(lottie, LV_RLOTTIE_CTRL_PLAY | LV_RLOTTIE_CTRL_FORWARD);
|
||||
|
||||
The default animation mode is **play forward with loop**.
|
||||
|
||||
If you don't enable looping, a :cpp:enumerator:`LV_EVENT_READY` is sent when the
|
||||
animation cannot make more progress without looping.
|
||||
|
||||
To get the number of frames in an animation or the current frame index,
|
||||
you can cast the :c:struct:`lv_obj_t` instance to a :c:struct:`lv_rlottie_t` instance
|
||||
and inspect the ``current_frame`` and ``total_frames`` members.
|
||||
|
||||
ESP-IDF Example
|
||||
---------------
|
||||
|
||||
Background
|
||||
~~~~~~~~~~
|
||||
|
||||
Rlottie can be expensive to render on embedded hardware. Lottie
|
||||
animations tend to use a large amount of CPU time and can use large
|
||||
portions of RAM. This will vary from lottie to lottie but in general for
|
||||
best performance:
|
||||
|
||||
- Limit total # of frames in the animation
|
||||
- Where possible, try to avoid bezier type animations
|
||||
- Limit animation render size
|
||||
|
||||
If your ESP32 chip does not have SPIRAM you will face severe limitations
|
||||
in render size.
|
||||
|
||||
To give a better idea on this, lets assume you want to render a 240x320
|
||||
lottie animation.
|
||||
|
||||
In order to pass initialization of the lv_rlottie_t object, you need
|
||||
240x320x32/8 (307k) available memory. The latest ESP32-S3 has 256kb RAM
|
||||
available for this (before freeRtos and any other initialization starts
|
||||
taking chunks out). So while you can probably start to render a 50x50
|
||||
animation without SPIRAM, PSRAM is highly recommended.
|
||||
|
||||
Additionally, while you might be able to pass initialization of the
|
||||
lv_rlottie_t object, as rlottie renders frame to frame, this consumes
|
||||
additional memory. A 30 frame animation that plays over 1 second
|
||||
probably has minimal issues, but a 300 frame animation playing over 10
|
||||
seconds could very easily crash due to lack of memory as rlottie
|
||||
renders, depending on the complexity of the animation.
|
||||
|
||||
Rlottie will not compile for the IDF using the ``-02`` compiler option at
|
||||
this time.
|
||||
|
||||
For stability in lottie animations, I found that they run best in the
|
||||
IDF when enabling :c:macro:`LV_MEM_CUSTOM` (using ``stdlib.h``)
|
||||
|
||||
For all its faults, when running right-sized animations, they provide a
|
||||
wonderful utility to LVGL on embedded LCDs and can look really good when
|
||||
done properly.
|
||||
|
||||
When picking/designing a lottie animation consider the following
|
||||
limitations:
|
||||
|
||||
- Build the lottie animation to be sized for the intended size
|
||||
- it can scale/resize, but performance will be best when the base lottie size is as intended
|
||||
- Limit total number of frames, the longer the lottie animation is,
|
||||
the more memory it will consume for rendering (rlottie consumes IRAM for rendering)
|
||||
- Build the lottie animation for the intended frame rate
|
||||
- default lottie is 60fps, embedded LCDs likely won't go above 30fps
|
||||
|
||||
IDF Setup
|
||||
~~~~~~~~~
|
||||
|
||||
Where the LVGL simulator uses the installed rlottie lib, the IDF works
|
||||
best when using rlottie as a submodule under the components directory.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
cd 'your/project/directory'
|
||||
git add submodule
|
||||
git add submodule https://github.com/Samsung/rlottie.git ./components/rlottie/rlottie
|
||||
git submodule update --init --recursive
|
||||
|
||||
Now, Rlottie is available as a component in the IDF, but it requires
|
||||
some additional changes and a CMakeLists file to tell the IDF how to
|
||||
compile.
|
||||
|
||||
Rlottie patch file
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Rlottie relies on a dynamic linking for an image loader lib. This needs
|
||||
to be disabled as the IDF doesn't play nice with dynamic linking.
|
||||
|
||||
A patch file is available in lvgl under:
|
||||
``/env_support/esp/rlottie/0001-changes-to-compile-with-esp-idf.patch``
|
||||
|
||||
Apply the patch file to your rlottie submodule.
|
||||
|
||||
CMakeLists for IDF
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An example CMakeLists file has been provided at
|
||||
``/env_support/esp/rlottie/CMakeLists.txt``
|
||||
|
||||
Copy this CMakeLists file to
|
||||
``'your-project-directory'/components/rlottie/``
|
||||
|
||||
In addition to the component CMakeLists file, you'll also need to tell
|
||||
your project level CMakeLists in your IDF project to require rlottie:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
REQUIRES "lvgl" "rlottie"
|
||||
|
||||
From here, you should be able to use lv_rlottie objects in your ESP-IDF
|
||||
project as any other widget in LVGL ESP examples. Please remember that
|
||||
these animations can be highly resource constrained and this does not
|
||||
guarantee that every animation will work.
|
||||
|
||||
Additional Rlottie considerations in ESP-IDF
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
While unnecessary, removing the ``rlottie/rlottie/example`` folder can remove
|
||||
many un-needed files for this embedded LVGL application
|
||||
|
||||
From here, you can use the relevant LVGL lv_rlottie functions to create
|
||||
lottie animations in LVGL on embedded hardware!
|
||||
|
||||
Please note, that while lottie animations are capable of running on many
|
||||
ESP chips, below is recommended for best performance.
|
||||
|
||||
- ESP32-S3-WROOM-1-N16R8
|
||||
|
||||
- 16mb quad spi flash
|
||||
- 8mb octal spi PSRAM
|
||||
|
||||
- IDF4.4 or higher
|
||||
|
||||
The Esp-box devkit meets this spec and
|
||||
https://github.com/espressif/esp-box is a great starting point to adding
|
||||
lottie animations.
|
||||
|
||||
You will need to enable :c:macro:`LV_USE_RLOTTIE` through **idf.py** menuconfig under
|
||||
LVGL component settings.
|
||||
|
||||
Additional changes to make use of SPIRAM
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:cpp:expr:`lv_alloc/realloc` do not make use of SPIRAM. Given the high memory usage
|
||||
of lottie animations, it is recommended to shift as much out of internal
|
||||
DRAM into SPIRAM as possible. In order to do so, SPIRAM will need to be
|
||||
enabled in the menuconfig options for your given espressif chip.
|
||||
|
||||
There may be a better solution for this, but for the moment the
|
||||
recommendation is to make local modifications to the lvgl component in
|
||||
your espressif project. This is as simple as swapping
|
||||
:cpp:expr:`lv_alloc/lv_realloc` calls in `lv_rlottie.c`` with :cpp:expr:`heap_caps_malloc` (for
|
||||
IDF) with the appropriate :cpp:expr:`MALLOC_CAP` call - for SPIRAM usage this is
|
||||
:cpp:expr:`MALLOC_CAP_SPIRAM`.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
rlottie->allocated_buf = heap_caps_malloc(allocated_buf_size+1, MALLOC_CAP_SPIRAM);
|
||||
|
||||
.. _rlottie_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/rlottie/index.rst
|
||||
|
||||
.. _rlottie_api:
|
||||
|
||||
API
|
||||
---
|
||||
47
docs/details/libs/svg.rst
Normal file
47
docs/details/libs/svg.rst
Normal file
@@ -0,0 +1,47 @@
|
||||
.. _svg:
|
||||
|
||||
==============
|
||||
SVG support
|
||||
==============
|
||||
|
||||
Scalable Vector Graphics (SVG) Tiny 1.2 support in LVGL.
|
||||
|
||||
Detailed introduction: https://www.w3.org/TR/SVGTiny12/
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
Enable :c:macro:`LV_USE_SVG` in ``lv_conf.h``.
|
||||
|
||||
See the examples below.
|
||||
|
||||
If you need support SVG animation attribute parsing,
|
||||
you can enable :c:macro:`LV_USE_SVG_ANIMATION` in ``lv_conf.h``.
|
||||
|
||||
.. _svg_example:
|
||||
|
||||
Example
|
||||
*******
|
||||
|
||||
.. code:: c
|
||||
|
||||
lv_svg_node_t * svg_doc;
|
||||
const char* svg_data = "<svg><rect x=\"0\" y=\"0\" width=\"100\" height=\"100\"/></svg>";
|
||||
|
||||
/* Create an SVG DOM tree*/
|
||||
svg_doc = lv_svg_load_data(svg_data, svg_len);
|
||||
...
|
||||
|
||||
/* Draw SVG image*/
|
||||
lv_draw_svg(layer, svg_doc);
|
||||
...
|
||||
|
||||
/* Release the DOM tree*/
|
||||
lv_svg_node_delete(svg_doc);
|
||||
|
||||
.. _svg_api:
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
|
||||
55
docs/details/libs/tiny_ttf.rst
Normal file
55
docs/details/libs/tiny_ttf.rst
Normal file
@@ -0,0 +1,55 @@
|
||||
.. _tiny_ttf:
|
||||
|
||||
====================
|
||||
Tiny TTF font engine
|
||||
====================
|
||||
|
||||
.. _tiny_ttf_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Allow using TrueType fonts in LVGL.
|
||||
|
||||
Detailed introduction: https://github.com/nothings/stb
|
||||
|
||||
When enabled in ``lv_conf.h`` with :c:macro:`LV_USE_TINY_TTF`
|
||||
:cpp:expr:`lv_tiny_ttf_create_data(data, data_size, font_size)` can be used to
|
||||
create a TTF font instance at the specified line height. You can then
|
||||
use that font anywhere :c:struct:`lv_font_t` is accepted.
|
||||
|
||||
By default, the TTF or OTF file must be embedded as an array, either in
|
||||
a header, or loaded into RAM in order to function.
|
||||
|
||||
However, if :c:macro:`LV_TINY_TTF_FILE_SUPPORT` is enabled,
|
||||
:cpp:expr:`lv_tiny_ttf_create_file(path, font_size)` will also be available,
|
||||
allowing tiny_ttf to stream from a file. The file must remain open the
|
||||
entire time the font is being used.
|
||||
|
||||
After a font is created, you can change the font size in pixels by using
|
||||
:cpp:expr:`lv_tiny_ttf_set_size(font, font_size)`.
|
||||
|
||||
By default, a font will cache data for upto 256 glyphs elements to speed up rendering.
|
||||
This maximum can be changed by using
|
||||
:cpp:expr:`lv_tiny_ttf_create_data_ex(data, data_size, font_size, kerning, cache_size)`
|
||||
or :cpp:expr:`lv_tiny_ttf_create_file_ex(path, font_size, kerning, cache_size)` (when
|
||||
available). The cache size is indicated in number of entries. Kerning is whether to allow
|
||||
if supported, or disable.
|
||||
|
||||
|
||||
|
||||
.. _tiny_ttf_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/tiny_ttf/index.rst
|
||||
|
||||
.. _tiny_ttf_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`stb_rect_pack_h`
|
||||
|
||||
:ref:`stb_truetype_htcw_h`
|
||||
67
docs/details/libs/tjpgd.rst
Normal file
67
docs/details/libs/tjpgd.rst
Normal file
@@ -0,0 +1,67 @@
|
||||
.. _tjpgd:
|
||||
|
||||
================================
|
||||
Tiny JPEG Decompressor (TJpgDec)
|
||||
================================
|
||||
|
||||
Allow the use of JPEG (JPG) images in LVGL.
|
||||
|
||||
Detailed introduction: `TJpgDec <http://elm-chan.org/fsw/tjpgd/>`__
|
||||
|
||||
.. _tjpgd_overview:
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
- JPEG is decoded in 8x8 tiles.
|
||||
- Only baseline JPEG files are supported (no progressive JPEG support).
|
||||
- Read from file and C array are implemented.
|
||||
- Only the required portions of the JPEG images are decoded,
|
||||
therefore they can't be zoomed or rotated.
|
||||
|
||||
.. _tjpgd_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
If enabled in ``lv_conf.h`` by :c:macro:`LV_USE_TJPGD` LVGL will register a new
|
||||
image decoder automatically so JPEG files can be used directly
|
||||
as image sources.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_image_set_src(my_img, "S:path/to/picture.jpg");
|
||||
|
||||
:note: a file system driver needs to be registered to open images from
|
||||
files. Read more about :ref:`overview_file_system` or just
|
||||
enable one in ``lv_conf.h`` with ``LV_USE_FS_...`` config.
|
||||
|
||||
|
||||
Converter
|
||||
---------
|
||||
|
||||
Converting JPEG to C array
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Use lvgl online tool https://lvgl.io/tools/imageconverter
|
||||
- Color format = RAW, output format = C Array
|
||||
|
||||
.. _tjpgd_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../../examples/libs/tjpgd/index.rst
|
||||
|
||||
.. _tjpgd_api:
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
:ref:`lv_tjpgd_h`
|
||||
|
||||
:ref:`tjpgd_h`
|
||||
|
||||
:ref:`tjpgdcnf_h`
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user