LVGL Library migration STM32
LVGL Library profile
LVGL(Light and Versatile Graphics Library) It's a free one 、 Open source embedded graphics library , You can create rich 、 Beautiful interface , There are many controls that can be customized , Support key or touch response , Support for Chinese characters , And the memory occupation is low . Can be in https://lvgl.io/demos Use the web side experience LVGL The dynamic effect of , Then decide whether to use LVGL .
LVGL Use C Language writing , It can be used in raspberry pie 、ESP32 、STM32 Wait on the MCU , And support a variety of large and medium-sized screens ( Just provide a drawing of the screen API that will do ).LVGL The address of our website is :https://lvgl.io/ ,GitHub The address is :https://github.com/lvgl/lvgl .
LVGL Many sample programs are provided , It also provides PC The simulator at the end , It's all accelerating LVGL Development efficiency .
transplant LVGL
LVGL Not only for which single-chip and which screen , In fact, it's even PC The machine can also run . complete LVGL You can refer to the official documentation for the migration of https://docs.lvgl.io/master/porting/index.html . Before transplantation , Please understand the usage of the single chip microcomputer and the screen by yourself and provide the interface program .
Building engineering
Next, let's say STM32 Series single chip microcomputer as an example LVGL Transplantation , The transplant process of different single-chip computers can also refer to the following steps . The following table shows LVGL The required configuration , In the use of LVGL Please make sure that the performance of the single chip microcomputer meets the requirements :
Name | Minimal | Recommended |
---|---|---|
Architecture | 16, 32 or 64 bit microcontroller or processor | |
Clock | > 16 MHz | > 48 MHz |
Flash/ROM | > 64 kB | > 180 kB |
Static RAM | > 16 kB | > 48 kB |
Draw buffer | > 1 ×hor. res. pixels | > 1/10 screen size |
Compiler | C99 or newer |
Be careful : Use Keil5 Please turn on “C99 Mode”, Otherwise, it will fail to compile . Also in the use of Keil4 Please upgrade or replace the compiler .
First , stay https://github.com/lvgl/lvgl Download or clone the entire project .LVGL The latest version of is LVGL 8.2 , Be careful LVGL 7 It is no longer updated ,LVGL 7 and 8 Great changes have taken place in the library structure , The code is not very compatible , also LVGL 7 The sample code and simulator for seem to be already in GitHub On and off the shelf . This tutorial uses LVGL 8 For example , transplant LVGL 7 You can refer to , But some details need to be adjusted . It is recommended to use the latest version , Otherwise, the complete tool chain support will not be available .
Use Keil Note that ,LVGL 8 It doesn't seem to work in ARM CC v5 Compiled successfully , Please update the compiler version to ARM CC v6 .
Use STM32 Developers of also need to pay attention to ,STM32 The standard library cannot be used ARM CC v6 compile , Please use HAL Library or replace the compilation tool chain ( Such as LLVM-clang or GCC-none-eabi )
Next, prepare a single-chip computer project by yourself , stay User
Or other equivalent directory , Then create a new directory lvgl
And enter , From cloning LVGL Copy the following files or directories into the project :
demos
examples
src
lvgl.h
lv_conf_template.h
If you don't need to use the official sample code , It can be done without copying demos
Catalog .
Next , take lv_conf_template.h
Rename it to lv_conf.h
, And move it to the upper level directory .
Be careful :LVGL The directory of the library is complex , Header file references are relatively confusing , Before you fully understand what you are doing , Please do not change the folder name or file location .
Go back to the previous Directory , open lv_conf.h
, Will start with #if 0
Conditional compilation canceled , Enable the configuration contained in the file :
/* clang-format off */
#if 1 /*Set it to "1" to enable content*/
The configuration file still needs to be adjusted in several places , First, the front ( The first 27 That's ok ) A macro definition of represents the color depth of the display screen , It needs to be adjusted according to different display screens :
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16
If the color depth of the screen is inconsistent , Be sure to modify the macro .LVGL An appropriate color definition will be created based on this macro , If it is inconsistent with the actual situation, the color will be disordered in the display .
If set to 8 , On behalf of the use of 8 Bit color , among RBG Chromatic value 3 、3 、2 position ; If set to 16 , be RBG Chromatic value 5 、6 、5 position , This is a lot of TFT The color format of the screen ;32 It is PC Transparent for both mobile and mobile devices 32bit Bitmap ,RGB Color value and transparency occupy one byte each .
The first 52 There is also a macro in the line that represents the maximum memory usage , It can be modified according to the actual situation of single chip microcomputer , As long as it is greater than what is written in the notes 2kB Just go .
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
#define LV_MEM_SIZE (32U * 1024U) /*[bytes]*/
besides , In the 273 and 280 Line also has two macro definitions , If you set them to 1
, The current memory usage and frame rate can be displayed in the lower left and right corners of the screen , Very suitable for performance analysis :
#define LV_USE_PERF_MONITOR 0
#define LV_USE_MEM_MONITOR 0
Other settings can be modified by comparing notes and documents .
Next, import the project file , This step requires that lvgl/src
In addition to draw
Import all files in the directory , and draw
In the directory except the root directory .c
The documents , Import only sw
Source files in the directory .LVGL 8 The directory depth of is large , Please be patient to add , Check carefully , Don't miss the document .
Use STM32 If the single-chip microcomputer is used, you also need to pay attention to modifying the heap in the startup file 、 Stack size , At least each setting 8kB Space :
Stack_Size EQU 0x00002000
Heap_Size EQU 0x00002000
After adding all , Try to compile the entire project , It should be zero error Passed .
Use ARM CC v6 It could happen
__aeabi_assert
Problems with undefined symbols , Macros can be defined in advance throughout project managementNDEBUG
Disable the symbol .
Displays the of the device API docking
LVGL Only the algorithm of drawing is provided , Other contents need to be prepared by ourselves .LVGL The interface provided is in lvgl/examples/porting
Directory , This directory contains the following files :
lv_port_disp
: Display device interfacelv_port_indev
: Input device interfacelv_port_fs
: File system interface
End each file name with template
Remove . Next, write the interface of the display device , At least make sure you can show something to .
stay lv_port_disp.c
And its header file , First, you need to remove conditional compilation , Enable this section :
/*Copy this file as "lv_port_disp.h" and set this value to "1" to enable content*/
#if 1
Because the file was renamed before , Therefore, you need to modify the corresponding name in the source file :
#include "lv_port_disp.h"
The source file has two macro definitions in the macro definition area , It needs to be modified to the actual display size . Remember to change after #warning
Preprocessing statements remove :
#ifndef MY_DISP_HOR_RES
//#warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now.
#define MY_DISP_HOR_RES 320
#endif
/* ... same as above ... */
lv_port_disp_init()
Is a top-level function to initialize the display device , In the main function, you need to call it to initialize the function of the display device at one time . The modification method of this function has been clearly stated in the notes , Next, a modification example is provided .
First of all, will 91~102 The two statements of the line that provide the display cache are all commented or deleted , Only keep /* Example for 1) */
. And then modify 114~115 The two values of the line are the actual screen sharpness .
/* Example for 1) */
static lv_disp_draw_buf_t draw_buf_dsc_1;
static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
/*Set the resolution of the display*/
disp_drv.hor_res = 320;
disp_drv.ver_res = 240;
There are also two functions in this file disp_init()
and disp_flush()
, The interface of the actual display device shall be provided .
disp_init()
in , You need to provide the initialization code of the screen , If it has been initialized externally, it can be ignored .
disp_flush()
in , You need to draw a pixel at the position of the annotation according to the provided parameters ,. This process can also be faster using padding functions , You can even use GPU And so on , For details on how to write code, please refer to the notes . for example , The test screen draws pixels one by one , So as to fill an area :
/* ... */
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
ILI9341_SetFrontColor(&ili9341, color_p->full);
ILI9341_DrawPixel(&ili9341, x, y);
color_p++;
}
}
/* ... */
thus ,API The transplant is over . Next, you can write program tests LVGL The effect has been achieved. .
LVGL The initialization
In the use of LVGL front , You need to call the following two functions to complete LVGL Library initialization and LVGL Display the initialization of the device interface :
lv_init();
lv_port_disp_init();
Then you can draw the graph . Here is a simple code , You can draw a button :
lv_obj_t* btn = lv_btn_create(lv_scr_act());
lv_obj_set_pos(btn, 10, 10);
lv_obj_set_size(btn, 120, 50);
lv_obj_t* label = lv_label_create(btn);
lv_label_set_text(label, "Button");
lv_obj_center(label);
After drawing , You also need to call... In the main loop lv_task_handler()
function , In this way, the drawn content can be updated to the screen in real time :
while (1) {
/* ... */
lv_task_handler();
}
Then download the compiled results to the MCU , You can see a button on the screen :
LVGL Import device migration
The above describes how to migrate display devices . however LVGL Is a user interface library , Light has a display device , It's not enough to do some user interaction , So you need to use an input device .
LVGL Support 5 Types of input devices :
- Touchpad : Touch screen
- Mouse : mouse
- Keypad : keyboard
- Encoder : Encoder
- Button : Key
At the time of transplantation , Don't get the type of input device wrong , otherwise LVGL Unable to respond to input .
LVGL All interfaces to input devices are stored in lv_port_indev.c
And its header file . Next, take the touch screen as an example to introduce the transplantation of input devices , Different equipment API There's a difference , Please use the official documents for migration .
First , You need to remove... From both files #if 0
Conditional compilation , Enable two files .
stay lv_port_indev.c
in , Contains 5 Of a device API , But they can't all be used , So you need to cut out useless functions and definitions . Especially when initializing functions lv_port_indev_init()
in , If you do not remove the initialization statements of useless devices , Then there may be problems when calling .
The source code has highlighted the differences in the comments API The partition , Just keep the required code according to the partition .
According to the idea of the code ( The simplified source code is not long , And a high degree of abstraction , You can read it completely ), Next, implement the functions of the three functions .
First of all touchpad_init()
, Here, you need to initialize the input device , Just like initializing the touch screen above .
stay touchpad_is_pressed()
in , A display screen touch function is required , Determine whether a touch event has occurred :
static bool touchpad_is_pressed(void) {
if (XPT2046_TouchDetect() == TOUCH_PRESSED)
return true;
return false;
}
If a touch event occurs , Then it will enter touchpad_get_xy()
Function , Get touch point coordinates :
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y) {
static XPT2046_Coordinate coord = { -1, -1, -1, -1 };
XPT2046_Get_TouchedPoint(&xpt2046, &coord);
(*x) = coord.x;
(*y) = coord.y;
}
If these functions are written correctly , In theory, the input function can be realized . But before that , There is another key step :LVGL Use one tick The system manages global events , It's like LVGL My heart beats like , Without this heartbeat, events cannot be detected .
To give LVGL Provide heartbeat , Need to constantly call lv_tick_inc()
function , The parameter of this function is the millisecond interval of each heartbeat :
while (1)
{
lv_tick_inc(1);
lv_task_handler();
delay_ms(1);
}
It is more recommended to use the timer to complete the function call when using the single chip microcomputer , Set the timer overflow time to 1 Call it in the timer interrupt function after milliseconds .
Here is an example , It can detect whether the input device can be used normally . First, in the main
The initialization of the input device is performed at the beginning of the function :
lv_port_indev_init();
Then write the following functions :
static void btn_event_cb(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* btn = lv_event_get_target(e);
if (code == LV_EVENT_CLICKED) {
static uint8_t cnt = 0;
cnt++;
lv_obj_t* label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "Button: %d", cnt);
}
}
void lv_example(void) {
lv_obj_t* btn = lv_btn_create(lv_scr_act());
lv_obj_set_pos(btn, 10, 10);
lv_obj_set_size(btn, 120, 50);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
lv_obj_t* label = lv_label_create(btn);
lv_label_set_text(label, "Button");
lv_obj_center(label);
}
Call in main function lv_example()
, Compile and download to the MCU , You can get the same button as the previous example , But after each click , The text of the button will change :
The rest of the content will be updated as soon as possible :http://frozencandles.fun/archives/307
Use LVGL Simulator
LVGL It's a graphics library , So when drawing graphics, it is inevitable to make some fine adjustments to the drawing results . So it is obviously a troublesome choice to download the program to the MCU for each fine-tuning , But fortunately, LVGL A simulator is provided , Can be in PC Directly generate an interactive interface on the end , You don't need to download to view the painting effect .
LVGL It can be simulated on various platforms , For a complete guide to using the simulator, please refer to https://docs.lvgl.io/master/get-started/platforms/pc-simulator.html . Next, let's say Windows The platform is based on Visual Studio As an example, this paper introduces the general use method .
First , stay https://github.com/lvgl/lv_port_win_visual_studio Download Visual Studio Engineering source . Be careful , stay LVGL.Simulator
The catalog contains 3 An external warehouse , You need to download them together and put them in the right place .
then , Use Visual Studio open LVGL.Simulator.sln
engineering , Click compile to get GUI Executable file .
It should be noted that ,Visual Studio The provided simulator uses C++ Compiling , If you need a custom function , You need to use... In the header file
#ifdef __cplusplus
extern "C" {
#endif
/* ... function prototypes ... */
#ifdef __cplusplus
}
#endif
Surround the function prototype , Otherwise, it is in use C There will be errors when using language symbols .