Update LVGL to v9.1.0

This commit is contained in:
jacqueline
2024-06-12 17:54:40 +10:00
parent 611176ed66
commit 64bd9053a2
2244 changed files with 278442 additions and 118864 deletions
@@ -0,0 +1,5 @@
===
Cpp
===
In progress: https://github.com/lvgl/lv_binding_cpp
@@ -0,0 +1,12 @@
========
Bindings
========
.. toctree::
:maxdepth: 2
micropython
cpp
pikascript
javascript
@@ -0,0 +1,133 @@
==========
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
@@ -0,0 +1,294 @@
.. _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 objects, 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:: 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 `LVGL examples <https://docs.lvgl.io/master/examples.html>`__ 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 `CODING STYLE <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>`__
@@ -0,0 +1,203 @@
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:: 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:: 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:: 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:: 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:: 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:: 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
::
$ ./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
@@ -0,0 +1,71 @@
.. _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
Prerequsites
------------
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 grafics 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 follwoing commands
- cmake --preset windows-base
- cmake --build --preset windows-base_dbg
- ctest --preset windows-base_dbg
@@ -0,0 +1,10 @@
=============
Build systems
=============
.. toctree::
:maxdepth: 2
make
cmake
@@ -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``.
@@ -0,0 +1,85 @@
=============================
Espressif (ESP32 chip series)
=============================
LVGL can be used and configured as a standard `ESP-IDF <https://github.com/espressif/esp-idf>`__ component.
More information about ESP-IDF build system can be found `here <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html>`__.
LVGL demo project for ESP32
---------------------------
We've created `lv_port_esp32 <https://github.com/lvgl/lv_port_esp32>`__,
a project using ESP-IDF and LVGL to show one of the demos from
`demos <https://github.com/lvgl/lvgl/demos>`__. You can configure the
project to use one of the many supported display controllers and targets
(chips).
See `lvgl_esp32_drivers <https://github.com/lvgl/lvgl_esp32_drivers>`__
repository for a complete list of supported display and indev (touch)
controllers and targets.
Using LVGL in your ESP-IDF project
----------------------------------
Prerequisites
~~~~~~~~~~~~~
- ESP-IDF v4.1 and above
- ESP evaluation board with a display
Obtaining LVGL
~~~~~~~~~~~~~~
**Option 1:** git submodule
Simply clone LVGL into your ``project_root/components`` directory and it
will be automatically integrated into the project. If the project is a
git repository you can include LVGL as a git submodule:
.. code:: sh
git submodule add https://github.com/lvgl/lvgl.git components/lvgl
The above command will clone LVGL's main repository into the
``components/lvgl`` directory. LVGL includes a ``CMakeLists.txt`` file
that sets some configuration options so you can use LVGL right away.
**Option 2:** IDF Component Manager
LVGL is also distributed through `IDF Component Manager <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html>`__.
It allows users to seamlessly integrate `LVGL component <https://components.espressif.com/component/lvgl/lvgl>`__ into
their project with following command:
.. code:: sh
idf.py add-dependency lvgl/lvgl>=8.*
During next project build, LVGL component will be fetched from the
component registry and added to project build.
Configuration
~~~~~~~~~~~~~
When you are ready to configure LVGL, launch the configuration menu with
``idf.py menuconfig`` in your project root directory, go to
``Component config`` and then ``LVGL configuration``.
Using lvgl_esp32_drivers in ESP-IDF project
-------------------------------------------
You can also add ``lvgl_esp32_drivers`` as a "component". This component
should be located inside a directory named "components" in your project
root directory.
When your project is a git repository you can include
``lvgl_esp32_drivers`` as a git submodule:
.. code:: sh
git submodule add https://github.com/lvgl/lvgl_esp32_drivers.git components/lvgl_esp32_drivers
+10
View File
@@ -0,0 +1,10 @@
============
Chip vendors
============
.. toctree::
:maxdepth: 2
nxp
stm32
espressif
+398
View File
@@ -0,0 +1,398 @@
===
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 need 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 NXPs 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_DRAW_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, no user code is required:
.. code:: c
#if LV_USE_DRAW_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:
.. code:: 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:: c
#if LV_USE_OS
lv_thread_init(&draw_pxp_unit->thread, LV_THREAD_PRIO_HIGH, _pxp_render_thread_cb, 2 * 1024, draw_pxp_unit);
#endif
If `LV_USE_OS` 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:: 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::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:: c
#if LV_USE_GPU_NXP_VG_LITE
#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:: 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:: 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:: c
#if LV_USE_OS
lv_thread_init(&draw_vglite_unit->thread, LV_THREAD_PRIO_HIGH, _vglite_render_thread_cb, 2 * 1024, draw_vglite_unit);
#endif
If `LV_USE_OS` 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:: 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:: 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 opration 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
+259
View File
@@ -0,0 +1,259 @@
=====
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 for `Porting <https://docs.lvgl.io/master/porting/project.html>`__ your
project 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:: c
//Frame buffers
/*Static or global buffer(s). The second buffer is optional*/
static lv_color_t buf_1[BUFF_SIZE]; //TODO: Chose a buffer size. DISPLAY_WIDTH * 10 is one suggestion.
static lv_color_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:: 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 objects to test the output:
.. code:: c
// Change the 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:: 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:: 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:: 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:`os_interrupt`
\* ``#include "lvgl.h"`` \* Create your frame buffer(s) as global
variables:
.. code:: c
//Frame buffers
/*Static or global buffer(s). The second buffer is optional*/
static lv_color_t buf_1[BUFF_SIZE]; //TODO: Declare your own BUFF_SIZE appropriate to your system.
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:: 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*/
// Register the touch controller with LVGL - Not included here for brevity.
- Create some dummy objects to test the output:
.. code:: c
// Change the 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:: 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:: 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:: 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);
}
+127
View 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:: c
#define LV_USE_X11 1
2. Optional configuration options:
- Direct Exit
.. code:: 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:: c
#define LV_X11_DOUBLE_BUFFER 1 /*preferred default*/
// or
#define LV_X11_DOUBLE_BUFFER 0 /*not recommended*/
- Render mode
.. code:: 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:: 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_task handler */
lv_task_handler();
}
}
| Full initialisation with mouse pointer symbol and own application exit handling
| (dependent on LV_X11_DIRECT_EXIT (can be 1 or 0))
.. code:: 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_IMG_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_task handler */
lv_task_handler();
}
}
@@ -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:: 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:: 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.
@@ -0,0 +1,210 @@
=================================================
Generic MIPI DCS compatible LCD Controller driver
=================================================
Overview
-------------
From the `Wikipedia <https://en.wikipedia.org/wiki/MIPI_Alliance>`__:
`MIPI Allience <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 Allience 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:: c
#define LV_USE_GENERIC_MIPI 1
.. note::
``LV_USE_GENERIC_MIPI`` is automatically enabled when a compatible driver is enabled.
Usage
-----
You need to implement two platform-dependent functions:
.. code:: 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:: 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. */
lv_color_t * buf1 = NULL;
lv_color_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:: 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 | 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:: 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>`__.
@@ -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:: c
#define LV_USE_ILI9341 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: 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:: 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`
@@ -0,0 +1,14 @@
=======
Display
=======
.. toctree::
:maxdepth: 2
fbdev
gen_mipi
ili9341
lcd_stm32_guide
st7735
st7789
st7796
@@ -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 controllers 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:: 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:: 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:: 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:: 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:: 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:: 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:: 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:: c
osThreadId LvglTaskHandle;
lv_display_t *lcd_disp;
volatile int lcd_bus_busy = 0;
#. Add the following line to the Private function prototypes:
.. code:: 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:: 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:: 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 endianess */
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:: 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:: 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(obj, LV_ALIGN_CENTER);
lv_obj_set_height(obj, LV_SIZE_CONTENT);
lv_obj_set_width(obj, LV_SIZE_CONTENT);
lv_obj_set_style_text_font(obj, &lv_font_montserrat_14, 0);
lv_obj_set_style_text_color(obj, lv_color_black(), 0);
lv_label_set_text(obj, "Hello World!");
}
@@ -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:: c
#define LV_USE_ST7735 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: 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:: 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`
@@ -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:: c
#define LV_USE_ST7789 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: 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:: 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`
@@ -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:: c
#define LV_USE_ST7796 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: 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:: 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`
@@ -0,0 +1,12 @@
=======
Drivers
=======
.. toctree::
:maxdepth: 2
display/index
touchpad/index
libinput
X11
windows
@@ -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:: 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:: c
#define LV_USE_LIBINPUT 1
Full keyboard support needs to be enabled separately.
.. code:: 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:: 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:: 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:: 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);
@@ -0,0 +1,5 @@
======
FT6X36
======
TODO
@@ -0,0 +1,8 @@
=======
Touchpad
=======
.. toctree::
:maxdepth: 2
ft6x36
@@ -0,0 +1,109 @@
=============================
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:: c
#define LV_USE_WINDOWS 1
Usage
-----
.. code:: 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_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();
while (1)
{
uint32_t time_till_next = lv_timer_handler();
lv_delay_ms(time_till_next);
}
return 0;
}
@@ -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 `requirements of LVGL <https://docs.lvgl.io/master/intro/index.html#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:: 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.
@@ -0,0 +1,11 @@
==========
Frameworks
==========
.. toctree::
:maxdepth: 2
arduino
platformio
tasmota-berry
@@ -0,0 +1,5 @@
==========
Platformio
==========
TODO
@@ -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 objects, 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:: 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
View File
@@ -0,0 +1,9 @@
====
IDEs
====
.. toctree::
:maxdepth: 2
pc-simulator
mdk
+5
View File
@@ -0,0 +1,5 @@
===
MDK
===
TODO
@@ -0,0 +1,185 @@
.. _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. So it's a good idea to
reproduce a bug in the simulator and use that code snippet in the
`Forum <https://forum.lvgl.io>`__.
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 SDLdriver <https://github.com/lvgl/lv_sim_eclipse_sdl>`__: Recommended on Linux and Mac
- `CodeBlocks <https://github.com/lvgl/lv_sim_codeblocks_win>`__: Recommended on Windows
- `VisualStudio <https://github.com/lvgl/lv_sim_visual_studio_sdl>`__: For Windows
- `VSCode with SDL/X11 driver <https://github.com/lvgl/lv_sim_vscode_sdl>`__: Recommended on Linux (SDL/X11) and Mac (SDL)
- `PlatformIO with SDL driver <https://github.com/lvgl/lv_platformio>`__: Recommended on Linux and Mac
- `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
You can use any IDE for development but, for simplicity, the
configuration for Eclipse CDT is what we'll focus on in this tutorial.
The following section describes the set-up guide of Eclipse CDT in more
detail.
:Note: If you are on Windows, it's usually better to use the Visual
Studio or CodeBlocks projects instead. They work out of the box without
requiring extra steps.**
Set-up Eclipse CDT
------------------
Install Eclipse CDT
~~~~~~~~~~~~~~~~~~~
`Eclipse CDT <https://eclipse.org/cdt/>`__ is a C/C++ IDE.
Eclipse is a Java-based tool so be sure **Java Runtime Environment** is installed on your system.
On Debian-based distros (e.g. Ubuntu): ``sudo apt-get install default-jre``
:note: If you are using other distros, then please install a 'Java
Runtime Environment' suitable to your distro. Note: If you are using
macOS and get a "Failed to create the Java Virtual Machine" error,
uninstall any other Java JDK installs and install Java JDK 8u. This
should fix the problem.
You can download Eclipse's CDT from:
https://www.eclipse.org/cdt/downloads.php. Start the installer and
choose *Eclipse CDT* from the list.
Install SDL 2
~~~~~~~~~~~~~
The PC simulator uses
- `SDL2 <https://www.libsdl.org/download-2.0.php>`__ cross-platform library or
- `X11 <https://www.x.org/releases/current/doc/libX11/libX11/libX11.html>`__ Linux library
to simulate a TFT display and a touchpad.
Linux
^^^^^
On **Linux** you can easily install SDL2 using a terminal:
1. Find the current version of SDL2: ``apt-cache search libsdl2 (e.g. libsdl2-2.0-0)``
2. Install SDL2: ``sudo apt-get install libsdl2-2.0-0`` (replace with the found version)
3. Install SDL2 development package: ``sudo apt-get install libsdl2-dev``
4. If build essentials are not installed yet: ``sudo apt-get install build-essential``
On **Linux** X11 is even easier to install by terminal:
1. Install XLib: ``sudo apt-get install libx11-6`` (should be installed already)
2. Install XLib development package: ``sudo apt-get install libx11-dev``
Windows
^^^^^^^
If you are using **Windows** firstly you need to install
MinGW (`64 bit version <https://www.mingw-w64.org/downloads/#msys2>`__). After
installing MinGW, do the following steps to add SDL2:
1. Download the development libraries of SDL. Go to
https://www.libsdl.org/download-2.0.php and download *Development Libraries: SDL2-devel-2.0.5-mingw.tar.gz*
2. Decompress the file and go to *x86_64-w64-mingw32* directory (for 64 bit MinGW) or to *i686-w64-mingw32* (for 32 bit MinGW)
3. Copy *mingw32/include/SDL2* folder to *C:/MinGW/…/x86_64-w64-mingw32/include*
4. Copy *mingw32/lib/* content to *C:/MinGW/…/x86_64-w64-mingw32/lib*
5. Copy *mingw32/bin/SDL2.dll* to *{eclipse_workspace}/pc_simulator/Debug/\_*. Do it later when Eclipse is installed.
:Note: If you are using **Microsoft Visual Studio** instead of Eclipse
then you don't have to install MinGW.
OSX
^^^
On **OSX** you can easily install SDL2 with brew: ``brew install sdl2``
If something is not working, then please refer `this tutorial <http://lazyfoo.net/tutorials/SDL/01_hello_SDL/index.php>`__ to
get started with SDL.
Pre-configured project
~~~~~~~~~~~~~~~~~~~~~~
A pre-configured graphics library project (based on the latest release)
is always available to get started easily. You can find the latest one
on `GitHub <https://github.com/lvgl/lv_sim_eclipse_sdl>`__.
(Please note that, the project is configured for Eclipse CDT).
Add the pre-configured project to Eclipse CDT
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Eclipse CDT. It will show a dialogue about the **workspace path**.
Before accepting the path, check that path and copy (and unzip) the
downloaded pre-configured project there. After that, you can accept the
workspace path. Of course you can modify this path but in that case copy
the project to the corresponding location.
Close the start-up window and go to **File->Import** and choose
**General->Existing project into Workspace**. **Browse the root
directory** of the project and click **Finish**
On **Windows** you have to do two additional things:
- Copy the **SDL2.dll** into the project's Debug folder
- Right-click on the project -> Project properties -> C/C++ Build ->
Settings -> Libraries -> Add … and add *mingw32* above SDLmain and
SDL. (The order is important: mingw32, SDLmain, SDL)
Compile and Run
~~~~~~~~~~~~~~~
Now you are ready to run LVGL on your PC. Click on the Hammer Icon on
the top menu bar to Build the project. If you have done everything
right, then you will not get any errors. Note that on some systems
additional steps might be required to "see" SDL 2 from Eclipse but in
most cases the configuration in the downloaded project is enough.
After a successful build, click on the Play button on the top menu bar
to run the project. Now a window should appear in the middle of your
screen.
Now you are ready to use LVGL and begin development on your PC.
Using SDL manually
------------------
In case you don't use a supported IDE, you can also use LVGL's SDL support manually:
.. code:: cmake
#include <lvgl.h>
#include <unistd.h>
int main()
{
lv_init();
lv_display_t *display = lv_sdl_window_create(800, 600);
lv_indev_t *mouse = lv_sdl_mouse_create();
lv_indev_t *keyboard = lv_sdl_keyboard_create();
...
while (true) {
uint32_t ms_delay = lv_timer_handler();
usleep(ms_delay * 1000);
}
}
+14
View File
@@ -0,0 +1,14 @@
=======================
Integration and Drivers
=======================
.. toctree::
:maxdepth: 2
building/index
chip/index
driver/index
framework/index
ide/index
os/index
bindings/index
@@ -0,0 +1,5 @@
========
FreeRTOS
========
TODO
+11
View File
@@ -0,0 +1,11 @@
======
(RT)OS
======
.. toctree:: :maxdepth: 2
nuttx
rt-thread
freertos
zephyr
px5
+146
View File
@@ -0,0 +1,146 @@
==========
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:: 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:: shell
$ mkdir ~/nuttxspace
$ cd ~/nuttxspace
Clone the NuttX and Apps repositories:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: 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:: 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:: 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:: 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:: shell
nsh> lvgldemo
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/>`__
+8
View File
@@ -0,0 +1,8 @@
========
PX5 RTOS
========
See `PX5 RTOS's homepage <https://px5rtos.com/>`__
TODO
@@ -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/>`__
+168
View File
@@ -0,0 +1,168 @@
======
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:: 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:: shell
$ west build -b native_posix samples/modules/lvgl/demos
To run the application on your host:
.. code:: shell
$ west build -t run
In case you chose any of the other supported boards you can flash to the device with:
.. code:: 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:: 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:: 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>`__
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::
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:: 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::
# 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>`__.
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/>`__