init Files

This commit is contained in:
2024-12-09 19:47:18 +01:00
parent b55a8cd2bc
commit 528e862838
3471 changed files with 1105029 additions and 0 deletions

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_timer handler */
lv_timer_handler();
}
}
| Full initialisation with mouse pointer symbol and own application exit handling
| (dependent on LV_X11_DIRECT_EXIT (can be 1 or 0))
.. code:: c
bool terminated = false;
#if !LV_X11_DIRECT_EXIT
static void on_close_cb(lv_event_t * e)
{
...
terminate = true;
}
#endif
int main(int argc, char ** argv)
{
...
/* initialize X11 display driver */
lv_display_t * disp = lv_x11_window_create("LVGL X11 Simulation", monitor_hor_res, monitor_ver_res);
lv_display_add_event_cb(disp, on_close_cb, LV_EVENT_DELETE, disp);
/* initialize X11 input drivers (for keyboard, mouse & mousewheel) */
LV_IMAGE_DECLARE(my_mouse_cursor_icon);
lv_x11_inputs_create(disp, &my_mouse_cursor_icon);
#if !LV_X11_DIRECT_EXIT
/* set optional window close callback to enable application cleanup and exit */
lv_x11_window_set_close_cb(disp, on_close_cb, disp);
#endif
...
while(!terminated)
{
...
/* Periodically call the lv_timer handler */
lv_timer_handler();
}
}

View File

@@ -0,0 +1,41 @@
========================
Linux Framebuffer Driver
========================
Overview
--------
The Linux framebuffer (fbdev) is a linux subsystem used to display graphics. It is a hardware-independent API that gives user space software
access to the framebuffer (the part of a computer's video memory containing a current video frame) using only the Linux kernel's own basic
facilities and its device file system interface, avoiding the need for libraries that implement video drivers in user space.
Prerequisites
-------------
Your system has a framebuffer device configured (usually under ``/dev/fb0``).
Configuring the driver
----------------------
Enable the framebuffer driver support in lv_conf.h, by cmake compiler define or by KConfig. Additionally you may configure the rendering
mode.
.. code:: 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.

View File

@@ -0,0 +1,210 @@
=================================================
Generic MIPI DCS compatible LCD Controller driver
=================================================
Overview
--------
From the `Wikipedia <https://en.wikipedia.org/wiki/MIPI_Alliance>`__:
`MIPI Alliance <https://www.mipi.org/>`__ is a global business alliance that develops technical specifications
for the mobile ecosystem, particularly smart phones but including mobile-influenced industries. MIPI was founded in 2003 by Arm, Intel, Nokia, Samsung,
STMicroelectronics and Texas Instruments.
MIPI Alliance published a series of specifications related to display devices, including DBI (Display Bus Interface), DSI (Display Serial Interface) and DCS
(Display Command Set). Usually when one talks about a MIPI-compatible display, one thinks of a device with a DSI serial interface. However, the Display Bus Interface specification
includes a number of other, legacy interfaces, like SPI serial, or i8080-compatible parallel interface, which are often used to interface LCD displays to lower-end microcontrollers.
Furthermore, the DCS specification contains a standard command set, which is supported by a large number of legacy TFT LCD controllers, including the popular Sitronix
(ST7735, ST7789, ST7796) and Ilitek (ILI9341) SOCs. These commands provide a common interface to configure display orientation, color resolution, various power modes, and provide generic video memory access. On top
of that standard command set each LCD controller chip has a number of vendor-specific commands to configure voltage generator levels, timings, or gamma curves.
.. note::
It is important to understand that this generic MIPI LCD driver is not a hardware driver for displays with the DSI ("MIPI") serial interface. Instead, it implements the MIPI DCS command set used in many LCD controllers with an SPI or i8080 bus, and provides a common framework for chip-specific display controllers.
.. tip::
Although this is a generic driver, it can be used to support compatible chips which do not have a specific driver.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the generic MIPI LCD driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: 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. */
uint8_t * buf1 = NULL;
uint8_t * buf2 = NULL;
uint32_t buf_size = LCD_H_RES * LCD_BUF_LINES * lv_color_format_get_size(lv_display_get_color_format(my_disp));
buf1 = lv_malloc(buf_size);
if(buf1 == NULL) {
LV_LOG_ERROR("display draw buffer malloc failed");
return;
}
/* Allocate secondary buffer if needed */
...
lv_display_set_buffers(my_disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
ui_init(my_disp);
while(true) {
...
/* Periodically call the lv_timer handler */
lv_timer_handler();
}
}
Advanced topics
---------------
Create flags
^^^^^^^^^^^^
The third argument of the :cpp:func:`lv_lcd_generic_mipi_create()` function is a flag array. This can be used to configure the orientation and RGB ordering of the panel if the
default settings do not work for you. In particular, the generic MIPI driver accepts the following flags:
.. code:: 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>`__.

View File

@@ -0,0 +1,73 @@
=============================
ILI9341 LCD Controller driver
=============================
Overview
--------
The `ILI9341 <https://www.buydisplay.com/download/ic/ILI9341.pdf>`__ is a 262,144-color single-chip SOC driver for a-TFT liquid crystal display with resolution of 240RGBx320
dots, comprising a 720-channel source driver, a 320-channel gate driver, 172,800 bytes GRAM for graphic
display data of 240RGBx320 dots, and power supply circuit.
ILI9341 supports parallel 8-/9-/16-/18-bit data bus MCU interface, 6-/16-/18-bit data bus RGB interface and
3-/4-line serial peripheral interface (SPI).
The ILI9341 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/ili9341>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ILI9341 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: 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`

View File

@@ -0,0 +1,15 @@
=======
Display
=======
.. toctree::
:maxdepth: 2
fbdev
gen_mipi
ili9341
lcd_stm32_guide
st7735
st7789
st7796
renesas_glcdc

View File

@@ -0,0 +1,320 @@
.. _lcd_stm32_guide:
=========================================================================
Step-by-step Guide: How to use the LVGL v9 LCD drivers with STM32 devices
=========================================================================
Introduction
------------
This guide is intended to be a step-by-step instruction of how to configure the STM32Cube HAL with the new TFT-LCD display drivers introduced in LVGL v9.0. The example code has been tested on the STM32F746-based Nucleo-F746ZG board with an ST7789-based LCD panel connected via SPI. The application itself and the hardware configuration code were generated with the STM32CubeIDE 1.14.0 tool.
.. tip::
ST Micro provide their own TFT-LCD drivers in their X-CUBE-DISPLAY Software Extension Package. While these drivers can be used with LVGL as well, the LVGL LCD drivers do not depend on this package.
The LVGL LCD drivers are meant as an alternative, simple to use API to implement LCD support for your LVGL-based project on any platform. Moreover, even in the initial release we support more LCD controllers than X-CUBE-DISPLAY currently provides, and we plan to add support for even more LCD controllers in the future.
Please note however, that unlike X-CUBE-DISPLAY the LVGL LCD drivers do not implement the communication part, whether SPI, parallel i8080 bus or other. It is the user's responsibility to implement and optimize these on their chosen platform. LVGL will only provide examples for the most popular platforms.
By following the steps you will have a fully functional program, which can be used as the foundation of your own LVGL-based project. If you are in a hurry and not interested in the details, you can find the final project `here <https://github.com/lvgl/lv_port_lcd_stm32>`__. You will only need to configure LVGL to use the driver corresponding to your hardware (if it is other than the ST7789), and implement the function ``ui_init()`` to create your widgets.
.. note::
This example is not meant as the best possible implementation, or the recommended solution. It relies solely on the HAL drivers provided by ST Micro, which favor portability over performance. Despite of this the performance is very good, thanks to the efficient, DMA-based implementation of the drivers.
.. note::
Although the example uses FreeRTOS, this is not a strict requirement with the LVGL LCD display drivers.
You can find the source code snippets of this guide in the `lv_port_lcd_stm32_template.c <https://github.com/lvgl/lvgl/examples/porting/lv_port_lcd_stm32_template.c>`__ example.
Hardware configuration
----------------------
In this example we'll use the SPI1 peripheral to connect the microcontroller to the LCD panel. Besides the hardware-controlled SPI pins SCK and MOSI we need some additional output pins for the chip select, command/data select, and LCD reset:
==== ============= ======= ==========
pin configuration LCD user label
==== ============= ======= ==========
PA4 GPIO_Output CS LCD_CS
PA5 SPI1_SCK SCK --
PA7 SPI1_MOSI SDI --
PA15 GPIO_Output RESET LCD_RESET
PB10 GPIO_Output DC LCD_DCX
==== ============= ======= ==========
Step-by-step instructions
-------------------------
#. Create new project in File/New/STM32 Project.
#. Select target processor/board.
#. Set project name and location.
#. Set Targeted Project Type to STM32Cube and press Finish.
#. Say "Yes" to Initialize peripherals with their default Mode? After the project is created, the configuration file (.ioc) is opened automatically.
#. Switch to the Pinout & Configuration tab.
#. In the System Core category switch to RCC.
#. Set High Speed Clock to "BYPASS Clock Source", and Low Speed Clock to "Crystal/Ceramic Resonator".
#. In the System Core category select SYS, and set Timebase Source to other than SysTick (in our example, TIM2).
#. Switch to the Clock Configuration tab.
#. Set the HCLK clock frequency to the maximum value (216 MHz for the STM32F746).
#. Switch back to the Pinout & Configuration tab, and in the Middleware and Software Packs category select FREERTOS.
#. Select Interface: CMSIS_V1.
#. In the Advanced Settings tab enable USE_NEWLIB_REENTRANT. We are finished here.
#. In the Pinout view configure PA5 as SPI1_SCK, PA7 as SPI1_MOSI (right click the pin and select the function).
#. In the Pinout & Configuration/Connectivity category select SPI1.
#. Set Mode to Transmit Only Master, and Hardware NSS Signal to Disable.
#. In the Configuration subwindow switch to Parameter Settings.
#. Set Frame Format to Motorola, Data Size to 8 Bits, First Bit to MSB First.
#. Set the Prescaler to the maximum value according to the LCD 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 endianness */
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
HAL_SPI_Init(&hspi1);
lcd_bus_busy = 1;
HAL_SPI_Transmit_DMA(&hspi1, param, (uint16_t)param_size / 2);
/* NOTE: CS will be reset in the transfer ready callback */
}
}
#. Add the LVGL_Task() function. Replace the ``lv_st7789_create()`` call with the appropriate driver. You can change the default orientation by adjusting the parameter of ``lv_display_set_rotation()``. You will also need to create the display buffers here. This example uses a double buffering scheme with 1/10th size partial buffers. In most cases this is a good compromise between the required memory size and performance, but you are free to experiment with other settings.
.. code:: 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!");
}

View File

@@ -0,0 +1,82 @@
.. _renesas_glcdc:
=============
Renesas GLCDC
=============
Overview
--------
.. image:: /misc/renesas/glcdc.png
:alt: Architectural overview of Renesas GLCDC
:align: center
|
GLCDC is a multi-stage graphics output peripheral used in Renesas MCUs.
It is designed to automatically generate timing and data signals for different LCD panels.
- Supports LCD panels with RGB interface (up to 24 bits) and sync signals (HSYNC, VSYNC and Data Enable optional)
- Supports various color formats for input graphics planes (RGB888, ARGB8888, RGB565, ARGB1555, ARGB4444, CLUT8, CLUT4, CLUT1)
- Supports the Color Look-Up Table (CLUT) usage for input graphics planes (ARGB8888) with 512 words (32 bits/word)
- Supports various color formats for output (RGB888, RGB666, RGB565, Serial RGB888)
- Can input two graphics planes on top of the background plane and blend them on the screen
- Generates a dot clock to the panel. The clock source is selectable from internal or external (LCD_EXTCLK)
- Supports brightness adjustment, contrast adjustment, and gamma correction
- Supports GLCDC interrupts to handle frame-buffer switching or underflow detection
| Setting up a project and further integration with Renesas' ecosystem is described in detail on :ref:`page Renesas <renesas>`.
| Check out the following repositories for ready-to-use examples:
- `EK-RA8D1 <https://github.com/lvgl/lv_port_renesas_ek-ra8d1>`__
- `EK-RA6M3G <https://github.com/lvgl/lv_port_renesas_ek-ra6m3g>`__
- `RX72N Envision Kit <https://github.com/lvgl/lv_port_renesas_rx72n-envision-kit>`__
Prerequisites
-------------
- This diver relies on code generated by e² studio. Missing the step while setting up the project will cause a compilation error.
- Activate the diver by setting :c:macro:`LV_USE_RENESAS_GLCDC` to ``1`` in your *"lv_conf.h"*.
Usage
-----
There is no need to implement any platform-specific functions.
The following code demonstrates using the diver in :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_DIRECT` mode.
.. code:: c
lv_display_t * disp = lv_renesas_glcdc_direct_create();
lv_display_set_default(disp);
To use the driver in :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL` mode, an extra buffer must be allocated,
preferably in the fastest available memory region.
Buffer swapping can be activated by passing a second buffer of same size instead of the :cpp:expr:`NULL` argument.
.. code:: c
static lv_color_t partial_draw_buf[DISPLAY_HSIZE_INPUT0 * DISPLAY_VSIZE_INPUT0 / 10] BSP_PLACE_IN_SECTION(".sdram") BSP_ALIGN_VARIABLE(1024);
lv_display_t * disp = lv_renesas_glcdc_partial_create(partial_draw_buf, NULL, sizeof(partial_draw_buf));
lv_display_set_default(disp);
.. note::
Partial mode can be activated via the macro in ``src/board_init.c`` file of the demo projects.
Screen rotation
"""""""""""""""
Software based screen rotation is supported in partial mode. It uses the common API, no extra configuration is required:
.. code:: c
lv_display_set_rotation(lv_display_get_default(), LV_DISP_ROTATION_90);
/* OR */
lv_display_set_rotation(lv_display_get_default(), LV_DISP_ROTATION_180);
/* OR */
lv_display_set_rotation(lv_display_get_default(), LV_DISP_ROTATION_270);
Make sure the heap is large enough, as a buffer with the same size as the partial buffer will be allocated.

View File

@@ -0,0 +1,75 @@
============================
ST7735 LCD Controller driver
============================
Overview
--------
The `ST7735S <https://www.buydisplay.com/download/ic/ST7735S.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 396
source line and 162 gate line driving circuits. This chip is capable of connecting directly to an external
microprocessor, and accepts Serial Peripheral Interface (SPI), 8-bit/9-bit/16-bit/18-bit parallel interface.
Display data can be stored in the on-chip display data RAM of 132 x 162 x 18 bits. It can perform display data
RAM read/write operation with no external operation clock to minimize power consumption. In addition,
because of the integrated power supply circuits necessary to drive liquid crystal, it is possible to make a
display system with fewer components.
The ST7735 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/st7735>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ST7735 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: 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`

View File

@@ -0,0 +1,74 @@
============================
ST7789 LCD Controller driver
============================
Overview
--------
The `ST7789 <https://www.buydisplay.com/download/ic/ST7789.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 720
source line and 320 gate line driving circuits. This chip is capable of connecting directly to an external
microprocessor, and accepts, 8-bits/9-bits/16-bits/18-bits parallel interface. Display data can be stored in the
on-chip display data RAM of 240x320x18 bits. It can perform display data RAM read/write operation with no
external operation clock to minimize power consumption. In addition, because of the integrated power supply
circuit necessary to drive liquid crystal; it is possible to make a display system with the fewest components.
The ST7789 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/st7789>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ST7789 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: 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`

View File

@@ -0,0 +1,75 @@
============================
ST7796 LCD Controller driver
============================
Overview
--------
The `ST7796S <https://www.buydisplay.com/download/ic/ST7796S.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 960
source lines and 480 gate lines driving circuits. The ST7796S is capable of connecting directly to an external
microprocessor, and accepts 8-bit/9-bit/16-bit/18-bit parallel interface, SPI, and the ST7796S also provides
MIPI interface. Display data can be stored in the on-chip display data RAM of 320x480x18 bits. It can perform
display data RAM read-/write-operation with no external clock to minimize power consumption. In addition,
because of the integrated power supply circuit necessary to drive liquid crystal; it is possible to make a display
system with fewest components.
The ST7796 LCD controller `driver <https://github.com/lvgl/lvgl/src/drivers/display/st7796>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ST7796 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: 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`

View File

@@ -0,0 +1,14 @@
=======
Drivers
=======
.. toctree::
:maxdepth: 2
display/index
touchpad/index
libinput
X11
windows
opengles
wayland

View File

@@ -0,0 +1,87 @@
===============
Libinput Driver
===============
Overview
--------
Libinput is an input stack for processes that need to provide events from commonly used input devices. That includes mice, keyboards, touchpads,
touchscreens and graphics tablets. Libinput handles device-specific quirks and provides an easy-to-use API to receive events from devices.
Prerequisites
-------------
You have the development version of libinput installed (usually ``libinput-dev``). If your input device requires quirks, make sure they are
installed as well (usually in ``/usr/share/libinput/*.quirks``). To test if your device is set up correctly for use with libinput, you can
run ``libinput list-devices``.
.. code:: 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);

View File

@@ -0,0 +1,197 @@
===============================
OpenGL ES Display/Inputs driver
===============================
Overview
--------
| The **OpenGL ES** display/input `driver <https://github.com/lvgl/lvgl/src/drivers/opengles>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in an desktop window created via GLFW.
| It is an alternative to **Wayland**, **XCB**, **SDL** or **Qt**.
The main purpose for this driver is for testing/debugging the LVGL application in an **OpenGL** simulation window.
Prerequisites
-------------
The OpenGL driver uses GLEW GLFW to access the OpenGL window manager.
1. Install GLEW and GLFW: ``sudo apt-get install libglew-dev libglfw3-dev``
Configure OpenGL driver
-----------------------
1. Required linked libraries: -lGL -lGLEW -lglfw
2. Enable the OpenGL driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: c
#define LV_USE_OPENGLES 1
Basic usage
-----------
.. code:: c
#include "lvgl/lvgl.h"
#include "lvgl/examples/lv_examples.h"
#include "lvgl/demos/lv_demos.h"
#define WIDTH 640
#define HEIGHT 480
int main()
{
/* initialize lvgl */
lv_init();
/* create a window and initialize OpenGL */
lv_glfw_window_t * window = lv_glfw_window_create(WIDTH, HEIGHT, true);
/* create a display that flushes to a texture */
lv_display_t * texture = lv_opengles_texture_create(WIDTH, HEIGHT);
lv_display_set_default(texture);
/* add the texture to the window */
unsigned int texture_id = lv_opengles_texture_get_texture_id(texture);
lv_glfw_texture_t * window_texture = lv_glfw_window_add_texture(window, texture_id, WIDTH, HEIGHT);
/* get the mouse indev of the window texture */
lv_indev_t * mouse = lv_glfw_texture_get_mouse_indev(window_texture);
/* add a cursor to the mouse indev */
LV_IMAGE_DECLARE(mouse_cursor_icon);
lv_obj_t * cursor_obj = lv_image_create(lv_screen_active());
lv_image_set_src(cursor_obj, &mouse_cursor_icon);
lv_indev_set_cursor(mouse, cursor_obj);
/* create objects on the screen */
lv_demo_widgets();
while (1)
{
uint32_t time_until_next = lv_timer_handler();
lv_delay_ms(time_until_next);
}
return 0;
}
Advanced usage
--------------
The OpenGL driver can draw textures from the user. A third-party library could be
used to add content to a texture and the driver will draw the texture in the window.
.. code:: c
#include "lvgl/lvgl.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define WIDTH 640
#define HEIGHT 480
void custom_texture_example(void)
{
/*****************
* MAIN WINDOW
*****************/
/* create a window and initialize OpenGL */
/* multiple windows can be created */
lv_glfw_window_t * window = lv_glfw_window_create(WIDTH, HEIGHT, true);
/****************************
* OPTIONAL MAIN TEXTURE
****************************/
/* create a main display that flushes to a texture */
lv_display_t * main_texture = lv_opengles_texture_create(WIDTH, HEIGHT);
lv_display_set_default(main_texture);
/* add the main texture to the window */
unsigned int main_texture_id = lv_opengles_texture_get_texture_id(main_texture);
lv_glfw_texture_t * window_main_texture = lv_glfw_window_add_texture(window, main_texture_id, WIDTH, HEIGHT);
/* get the mouse indev of this main texture */
lv_indev_t * main_texture_mouse = lv_glfw_texture_get_mouse_indev(window_main_texture);
/* add a cursor to the mouse indev */
LV_IMAGE_DECLARE(mouse_cursor_icon);
lv_obj_t * cursor_obj = lv_image_create(lv_screen_active());
lv_image_set_src(cursor_obj, &mouse_cursor_icon);
lv_indev_set_cursor(main_texture_mouse, cursor_obj);
/* create objects on the screen of the main texture */
lv_demo_widgets();
/**********************
* ANOTHER TEXTURE
**********************/
/* create a sub display that flushes to a texture */
const int32_t sub_texture_w = 300;
const int32_t sub_texture_h = 300;
lv_display_t * sub_texture = lv_opengles_texture_create(sub_texture_w, sub_texture_h);
/* add the sub texture to the window */
unsigned int sub_texture_id = lv_opengles_texture_get_texture_id(sub_texture);
lv_glfw_texture_t * window_sub_texture = lv_glfw_window_add_texture(window, sub_texture_id, sub_texture_w, sub_texture_h);
/* create objects on the screen of the sub texture */
lv_display_set_default(sub_texture);
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_black(), 0);
lv_example_anim_2();
lv_display_set_default(main_texture);
/* position the sub texture within the window */
lv_glfw_texture_set_x(window_sub_texture, 250);
lv_glfw_texture_set_y(window_sub_texture, 150);
/* optionally change the opacity of the sub texture */
lv_glfw_texture_set_opa(window_sub_texture, LV_OPA_80);
/*********************************************
* USE AN EXTERNAL OPENGL TEXTURE IN LVGL
*********************************************/
unsigned int external_texture_id;
glGenTextures(1, &external_texture_id);
glBindTexture(GL_TEXTURE_2D, external_texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
LV_IMAGE_DECLARE(img_cogwheel_argb);
#if LV_COLOR_DEPTH == 8
const int texture_format = GL_R8;
#elif LV_COLOR_DEPTH == 16
const int texture_format = GL_RGB565;
#elif LV_COLOR_DEPTH == 24
const int texture_format = GL_RGB;
#elif LV_COLOR_DEPTH == 32
const int texture_format = GL_RGBA;
#else
#error("Unsupported color format")
#endif
glTexImage2D(GL_TEXTURE_2D, 0, texture_format, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h, 0, GL_BGRA, GL_UNSIGNED_BYTE, img_cogwheel_argb.data);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
/* add the external texture to the window */
lv_glfw_texture_t * window_external_texture = lv_glfw_window_add_texture(window, external_texture_id, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h);
/* set the position and opacity of the external texture within the window */
lv_glfw_texture_set_x(window_external_texture, 20);
lv_glfw_texture_set_y(window_external_texture, 20);
lv_glfw_texture_set_opa(window_external_texture, LV_OPA_70);
/*********************************************
* USE AN LVGL TEXTURE IN ANOTHER LIBRARY
*********************************************/
lv_refr_now(sub_texture);
/* the texture is drawn on by LVGL and can be used by anything that uses OpenGL textures */
third_party_lib_use_texture(sub_texture_id);
}

View File

@@ -0,0 +1,57 @@
==================
Linux Evdev Driver
==================
Overview
--------
The Linux event device (evdev) is a hardware-independent API that gives access to input events from,
for example, a mouse or touchscreen. It is exposed via the Linux device file system interface.
Prerequisites
-------------
Your system has an input device configured (usually under ``/dev/input/`` such as ``/dev/input/event0``).
Configuring the driver
----------------------
Enable the Linux LVGL evdev driver support in ``lv_conf.h``.
.. code:: c
#define LV_USE_EVDEV 1
Usage
-----
To set up an event input, first create an input device with ``lv_edev_create`` setting it to the correct Linux event device.
Then link this to the LVGL display with ``lv_indev_set_display``.
.. code:: c
lv_indev_t *touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0");
lv_indev_set_display(touch, disp);
Ensure that an ``lv_display_t`` object is already created for ``disp``. An example for this is shown below, using the Linux framebuffer driver.
.. code:: c
lv_display_t * disp = lv_linux_fbdev
lv_linux_fbdev_set_file(disp, "/dev/fb0");_create();
Locating your input device
--------------------------
If you can't determine your input device, first run
```$cat /proc/bus/input/devices```
This should show input devices and there will be entries with the word ``event`` which give a clue as to the device to use eg. ``event1`` would be ``/dev/input/event1``.
You can use ``evtest`` to show data from that event source to see if it is actually the one you want.
Try:
``$evtest /dev/input/event1`` replacing ``eventX`` with your event device from above.

View File

@@ -0,0 +1,5 @@
======
FT6X36
======
TODO

View File

@@ -0,0 +1,9 @@
=======
Touchpad
=======
.. toctree::
:maxdepth: 2
ft6x36
evdev

View File

@@ -0,0 +1,180 @@
=============================
Wayland Display/Inputs driver
=============================
Overview
--------
| The **Wayland** `driver <https://github.com/lvgl/lvgl/tree/master/src/drivers/wayland>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in a desktop window.
| It is an alternative to **X11** or **SDL2**
The main purpose for this driver is for testing/debugging the LVGL application, it can also be used to run applications in 'kiosk mode'
Dependencies
------------
The wayland driver requires some dependencies.
On Ubuntu
.. code:: bash
sudo apt-get install libwayland-dev libxkbcommon-dev libwayland-bin wayland-protocols
On Fedora
.. code:: bash
sudo dnf install wayland-devel libxkbcommon-devel wayland-utils wayland-protocols-devel
Configuring the wayland driver
------------------------------
1. Enable the wayland driver in ``lv_conf.h``
.. code:: c
#define LV_USE_WAYLAND 1
2. Optional configuration options:
- Enable window decorations, only required on GNOME because out of all the available wayland compositors
**only** Mutter/GNOME enforces the use of client side decorations
.. code:: c
#define LV_WAYLAND_WINDOW_DECORATIONS 1
- Enable support for the deprecated 'wl_shell', Only useful when the BSP on the target has weston ``9.x``
.. code:: c
#define LV_WAYLAND_WL_SHELL 1
Example
-------
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
Usage
-----
#. In ``main.c`` ``#incude "lv_drivers/wayland/wayland.h"``
#. Enable the Wayland driver in ``lv_conf.h`` with ``LV_USE_WAYLAND 1``
#. ``LV_COLOR_DEPTH`` should be set either to ``32`` or ``16`` in ``lv_conf.h``
#. Add a display using ``lv_wayland_window_create()``,
possibly with a close callback to track the status of each display:
.. code:: c
#define H_RES (800)
#define V_RES (480)
/* Create a display */
lv_disp_t * disp = lv_wayland_create_window(H_RES, V_RES, "Window Title", close_cb);
As part of the above call, the Wayland driver will register four input devices
for each display:
* a KEYPAD connected to Wayland keyboard events
* a POINTER connected to Wayland touch events
* a POINTER connected to Wayland pointer events
* an ENCODER connected to Wayland pointer axis events
Handles for input devices of each display can be obtained using
``lv_wayland_get_indev_keyboard()``, ``lv_wayland_get_indev_touchscreen()``,
``lv_wayland_get_indev_pointer()`` and ``lv_wayland_get_indev_pointeraxis()`` respectively.
Fullscreen mode
^^^^^^^^^^^^^^^
To programmatically fullscreen the window,
use the ``lv_wayland_window_set_fullscreen()`` function respectively with ``true``
or ``false`` for the ``fullscreen`` argument.
Maximized mode
^^^^^^^^^^^^^^
To programmatically maximize the window,
use the ``lv_wayland_window_set_maximized()`` function respectively with ``true``
or ``false`` for the ``maximized`` argument.
Custom timer handler
^^^^^^^^^^^^^^^^^^^^
Always call ``lv_wayland_timer_handler()`` in your timer loop instead of the regular ``lv_timer_handler()``.
**Note:** ``lv_wayland_timer_handler()`` internally calls ``lv_timer_handler()``
This allows the wayland client to work on well on weston, resizing shared memory buffers during
a commit does not work well on weston.
Wrapping the call to ``lv_timer_hander()`` is a necessity to have more control over
when the LVGL flush callback is called.
The custom timer handler returns ``false`` if the frame from previous cycle is not rendered.
When this happens, it usually means that the application is minimized or hidden behind another window.
Causing the driver to wait until the arrival of any message on the wayland socket, the process is in interruptible sleep.
Building the wayland driver
---------------------------
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
If there is a need to use driver with another build system. The source and header files for the XDG shell
must be generated from the definitions for the XDG shell protocol.
In the example Cmake is used to perform the operation by invoking the ``wayland-scanner`` utility
To achieve this manually,
Make sure the dependencies listed at the start of the article are installed.
The wayland protocol is defined using XML files which are present in ``/usr/share/wayland-protocols``
To generate the required files run the following commands:
.. code-block:: sh
wayland-scanner client-header </usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml > wayland_xdg_shell.h
wayland-scanner private-code </usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml > wayland_xdg_shell.c
The resulting files can then be integrated into the project, it's better to re-run ``wayland-scanner`` on
each build to ensure that the correct versions are generated, they must match the version of the ``wayland-client``
dynamically linked library installed on the system.
Current state and objectives
----------------------------
* Add direct rendering mode
* Refactor the shell integrations to avoid excessive conditional compilation
* Technically, the wayland driver allows to create multiple windows - but this feature is experimental.
* Eventually add enhanced support for XDG shell to allow the creation of desktop apps on Unix-like platforms,
similar to what the win32 driver does.
* Add a support for Mesa, currently wl_shm is used and it's not the most effective technique.
Bug reports
-----------
The wayland driver is currently under construction, bug reports, contributions and feedback is always welcome.
It is however important to create detailed issues when a problem is encountered, logs and screenshots of the problem are of great help.
Please enable ``LV_USE_LOG`` and launch the simulator executable like so
.. code::
WAYLAND_DEBUG=1 ./path/to/simulator_executable > /tmp/debug 2>&1
This will create a log file called ``debug`` in the ``/tmp`` directory, copy-paste the content of the file in the github issue.
The log file contains LVGL logs and the wayland messages.
Be sure to replicate the problem quickly otherwise the logs become too big

View File

@@ -0,0 +1,113 @@
=============================
Windows Display/Inputs driver
=============================
Overview
--------
The **Windows** display/input `driver <https://github.com/lvgl/lvgl/src/drivers/windows>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in a Windows Win32 window.
The main purpose for this driver is for testing/debugging the LVGL application in a **Windows** simulation window via **simulator mode**, or developing a standard **Windows** desktop application with LVGL via **application mode**.
Here are the **similarity** for simulator mode and application mode.
- Support LVGL pointer, keypad and encoder devices integration.
- Support Windows touch input.
- Support Windows input method integration input.
- Support Per-monitor DPI Aware (both V1 and V2).
Here are the **differences** for simulator mode and application mode.
Simulator Mode
^^^^^^^^^^^^^^
- Designed for LVGL simulation scenario.
- Keep the LVGL display resolution all time for trying best to simulate UI layout which will see in their production devices.
- When Windows DPI scaling setting is changed, Windows backend will stretch the display content.
Application Mode
^^^^^^^^^^^^^^^^
- Designed for Windows desktop application development scenario.
- Have the Window resizing support and LVGL display resolution will be changed.
- When Windows DPI scaling setting is changed, the LVGL display DPI value will also be changed.
Prerequisites
-------------
The minimum Windows OS requirement for this driver is Windows Vista RTM.
If you use Windows API shim libraries like `YY-Thunks <https://github.com/Chuyu-Team/YY-Thunks>`__, the tested minimum Windows OS requirement for this driver is Windows XP RTM.
According to the Windows GDI API this driver used. Maybe the minimum Windows OS requirement limitation for this driver is Windows 2000 RTM.
Configure Windows driver
------------------------
Enable the Windows driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: 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_lock();
lv_indev_t* pointer_device = lv_windows_acquire_pointer_indev(display);
if (!pointer_device)
{
return -1;
}
lv_indev_t* keypad_device = lv_windows_acquire_keypad_indev(display);
if (!keypad_device)
{
return -1;
}
lv_indev_t* encoder_device = lv_windows_acquire_encoder_indev(display);
if (!encoder_device)
{
return -1;
}
lv_demo_widgets();
lv_unlock();
while (1)
{
uint32_t time_till_next = lv_timer_handler();
lv_delay_ms(time_till_next);
}
return 0;
}