How to build LVGL applications using STM32CubeIDE

Applicable for STM32MP13x lines, STM32MP15x lines

This article gives information about how to easily develop a LVGL application on STM32MP1 using STM32CubeIDE.

1. Architecture overview[edit source]

The following diagram summarizes all the configurations of the LVGL library. In this article we will detail each of the possibilities and we will see how to generate the SDK.

1.1. Component presentation[edit source]

1.1.1. LVGL[edit source]

LVGL (Light and Versatile Graphics Library) is an open-source embedded GUI library that is written in C (with C++ compatibility) and is released under the MIT license. It’s optimized for deployment on micro-controllers and bare metal (no OS) devices, but on this article, we will see how to develop LVGL applications for our STM32MP1 microprocessor that runs the OpenSTLinux linux distribution.

1.1.2. SDL2[edit source]


  • SDL or Simple Direct Media Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware. It allows to show windows, show images, play sounds, manage keyboards...
  • SDL is written in C, works natively with C++, and there are bindings available for several other languages, including C# and Python.
  • SDL 2.0 is distributed under the zlib license. This license allows you to use SDL freely in any software.

1.1.3. Wayland / Weston[edit source]

  • Wayland is a protocol that allows a composer to communicate with multiple windows. It works only with systems using KMS (Kernel-based mode-setting), a kernel feature dependent on the graphics card driver used, hence the need to use a composer.
  • A composer implementing the Wayland protocol (Mutter, Kwin, Enlightenment, Weston...) is necessary (otherwise Wayland alone does nothing, and it is always an X server that would be used).
  • The composer is a window manager who uses a buffer in memory to manage each window and apply visual effects to it.
  • Weston is the reference implementation of a graphical composer window manager for the Wayland display protocol, its existence is justified by the need to develop Wayland without depending on the ups and downs of the development of libraries and environments, by the need to be able to rigorously test Wayland without experiencing bugs independent of Wayland.



1.1.4. DRM / KMS[edit source]

For more information about drm /kms, you can see the following article: DRM/KMS

1.2. Different configurations[edit source]

1.2.1. Weston Wayland SDL2 configuration with GPU[edit source]

1.2.2. DRM-KMS / SDL2 configuration with GPU[edit source]

1.2.3. DRM-KMS / SDL2 configuration without GPU[edit source]

1.2.4. Direct DRM-KMS configuration without GPU[edit source]

2. How to generate SDK for the configuration[edit source]

2.1. Purpose to generate SDK[edit source]

  • SDK or Software development kit is a programming package that enables a programmer to develop applications for a specific platform .
  • In our case, this SDK will allow us to use the SDL2 library, without the need to download it, and include it in our LVGL project.
Info white.png Information
Since STM32MP1-ecosystem-v4.1.0, SDL2 library are integrated on SDK and Starter Package

2.2. Generate SDK for SDL2 with GPU configuration[edit source]

  • Before generating the SDK, we will start by creating a recipe append file for the SDL2 library in our distribution package.
 mkdir /local/STM32MP15-Ecosystem-v4.0.0/Distribution-Package/openstlinux-5.15-yocto-kirkstone-mp1-v22.06.15/layers/meta-st/meta-st-openstlinux/recipes-graphics/libsdl2
 cd /local/STM32MP15-Ecosystem-v4.0.0/Distribution-Package/openstlinux-5.15-yocto-kirkstone-mp1-v22.06.15/layers/meta-st/meta-st-openstlinux/recipes-graphics/libsdl2
 touch libsdl2_%.bbappend
  • To configure SDL2 for stm32mp1 platform and Vivante GPU, copy or modify the following script into the recipe.
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI += "file://0001-Correction-of-bad-dlopen-for-libEGL.patch"

PACKAGECONFIG_GL = ""
PACKAGECONFIG ??= " \
    ${PACKAGECONFIG_GL} \
    ${@bb.utils.filter('DISTRO_FEATURES', 'alsa pulseaudio', d)} \
    ${@bb.utils.contains('DISTRO_FEATURES', 'wayland', 'wayland gles2', '', d)} \
    ${@bb.utils.contains("TUNE_FEATURES", "neon","arm-neon","",d)} \
    kmsdrm \
"
 
EXTRA_OECONF += " \
    -DSDL_VIVANTE=OFF \
    -DSDL_VULKAN=OFF \
    -DSDL_OPENGL=OFF \
"
  • To solve some problems of reading the symbols for the lib libegl , we need to create a patch called by the recipe .
  • On the same directory (workspace) , we create a subdirectory with the name of files and in it we create our patch with the name of 0001-Correction-of-bad-dlopen-for-libEGL.patch
  • Copy the following script into our patch.
--- a/src/loadso/dlopen/SDL_sysloadso.c
+++ b/src/loadso/dlopen/SDL_sysloadso.c
@@ -46,8 +46,13 @@ SDL_LoadObject(const char *sofile)
         return NULL;
     }
#endif
+    // SDL will skip dlopen'ing libEGL.so after it spots EGL symbols on our
+    // wrapper, so force loading it here.
+    if (strncmp(sofile, "libEGL.so", 9) != 0)
+        handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL | RTLD_GLOBAL | RTLD_LAZY);
+    else
+        handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL);

-    handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL);
     loaderror = dlerror();
     if (handle == NULL) {
         SDL_SetError("Failed loading %s: %s", sofile, loaderror);
  • Add libsdl2 to our image (if it's not alreay made) for sdk in CORE_IMAGE_EXTRA_INSTALL variable:
  cd /local/STM32MP15-Ecosystem-v4.0.0/Distribution-Package/openstlinux-5.15-yocto-kirkstone-mp1-v22.06.15/layers/meta-st/meta-st-openstlinux/packagegroups/

  • Modify the script of 'packagegroup-framework-core-base.bb as follows :
...
SUMMARY:packagegroup-framework-core-base-display = "Framework core base components for display" 
RDEPENDS:packagegroup-framework-core-base-display = "\
   libdrm          \
   libdrm-tests    \
   \
   ${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'libsdl2', , d)} \
   "
...


  • To create SDK :
 cd /local/STM32MP15-Ecosystem-v4.0.0/Distribution-Package/openstlinux-5.15-yocto-kirkstone-mp1-v22.06.15
 DISTRO=openstlinux-weston MACHINE=stm32mp1 source layers/meta-st/scripts/envsetup.sh
 bitbake -c populate_sdk st-image-weston
  • Bitbake generates the sdk in the following directory:
  cd /local/STM32MP15-Ecosystem-v4.0.0/Distribution-Package/openstlinux-5.15-yocto-kirkstone-mp1-v22.06.15/build-openstlinuxweston-stm32mp1/tmp-glibc/deploy/sdk
  • To give the right of execution :
 chmod +x st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-yocto-kirkstone-mp1-v22.06.15-snapshot.sh
  • Run the SDK and copy it back to the developer package.
 ./st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-yocto-kirkstone-mp1-v22.06.15-snapshot.sh -d /local/STM32MP15-Ecosystem-v4.0.0/Developer-Package/SDK_SDL2_WITH_GPU

2.3. Generate SDK for SDL2 without GPU configuration[edit source]

To generate the SDK for sdl2 without using GPU , you can follow the same steps as with GPU , just add a line in the recipe that disables the GPU :

PACKAGECONFIG_remove = "gles2"

3. How to build LVGL project with STM32CubeIDE[edit source]

3.1. Get LVGL project[edit source]

  • Create a new folder.
  • Open a terminal in this folder.
  • Download the LVGL project with the following command:
 git clone --recursive https://github.com/lvgl/lv_port_pc_eclipse.git
 git checkout -b WORKING origin/release/v8.1
 git submodule init
 git submodule update

If you are using Windows, you can go to LVGL's GitHub and download the folder and unzip it.

  • Import your project :

Click on file ==> Import ==> Projects from folder or archive ==> Next==> Directory ==> upload your LVGL project.

Chemin.png
  • Change the toolchain .

By default, stm32CubeIDE uses a Tool Chain for a x86_64 architecture, in our case we want to compile for our microprocessor with an ARM architecture. For this we need to change it:

Right-Click on you project ==> Properties ==> C/C++ Build ==> Tool Chain Editor ==> select OpenSTLinux SDK ==> Apply and Close

Toolchain.png

3.2. Configure CubeIDE with SDK[edit source]

  • To be able to use the SDK that we have generated , stm32CubeIDE needs the absolute path to access it :

Right-click on you project ==> Properties ==> C/C++ Build ==>Environment ==> Double click on SDKPATH ==> Paste the the absolute path ==> click on "OK" ==> click on "Apply an close "

SDK.png

3.2.1. For usage of DRM/KMS configuration[edit source]

  • Add include path (for libdrm) :

Right-click on you project ==> Properties ==> C/C++ Build ==>Settings ==> MPU GCC Compiler ==> Include paths == > add the followings path :

"${SDKPATH}/sysroots/cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi/usr/include/libdrm/"
Path.png
  • Add drm library for linker :

Right-click on you project ==> Properties ==> C/C++ Build ==>Settings ==> MPU GCC Linker ==> Libraries== > add a new library that we call drm

Drmm.png
  • Remove SDL2 and SDL2 Main libraries for linker

Right-click on you project ==> Properties ==> C/C++ Build ==>Settings ==> MPU GCC Linker ==> Libraries== >Remove SDL2main and SDL2

3.2.2. For usage of SDL2 configuration[edit source]

  • Remove SDL2 Main libraries for linker

Right-click on you project ==> Properties ==> C/C++ Build ==>Settings ==> MPU GCC Linker ==> Libraries== >Remove SDL2main

Drmm.png

3.3. Proposed modifications on LVGL project for configuration 1 to 3 (SDL configuration)[edit source]

To adapt LVGL to our stmp32mp1 board some modification are needed.

  • Replace the content of the main file of your project , by the following script :

/**
 * @file main
 *
 */

/*********************
 *      INCLUDES
 *********************/
#define _DEFAULT_SOURCE /* needed for usleep() */
#include <stdlib.h>
#include <unistd.h>
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
#include <SDL2/SDL.h>
#include "lvgl/lvgl.h"
#include "lvgl/examples/lv_examples.h"
#include "lv_demos/lv_demo.h"
#include "lv_drivers/display/monitor.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/mouse.h"
#include "lv_drivers/indev/keyboard.h"
#include "lv_drivers/indev/mousewheel.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void hal_init(void);
static int tick_thread(void *data);

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *      VARIABLES
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

#define COMPILE_WIDGET 1
//#define COMPILE_MUSIC 1
//#define COMPILE_KEYPAD 1

int main(int argc, char **argv)
{
  (void)argc; /*Unused*/
  (void)argv; /*Unused*/

  /*Initialize LVGL*/
  lv_init();

  /*Initialize the HAL (display, input devices, tick) for LVGL*/
  hal_init();

//  lv_example_switch_1();
//  lv_example_calendar_1();
//  lv_example_btnmatrix_2();
//  lv_example_checkbox_1();
//  lv_example_colorwheel_1();
//  lv_example_chart_6();
//  lv_example_table_2();
//  lv_example_scroll_2();
//  lv_example_textarea_1();
//  lv_example_msgbox_1();
//  lv_example_dropdown_2();
//  lv_example_btn_1();
//  lv_example_scroll_1();
//  lv_example_tabview_1();
//  lv_example_tabview_1();
//  lv_example_flex_3();
//  lv_example_label_1();

    SDL_Log("Using video target '%s'.\n", SDL_GetCurrentVideoDriver());

#ifdef COMPILE_WIDGET
    lv_demo_widgets();
#endif
#ifdef COMPILE_MUSIC
    lv_demo_music();
#endif
#ifdef COMPILE_KEYPAD
    lv_demo_keypad_encoder();
#endif

  while(1) {
      /* Periodically call the lv_task handler.
       * It could be done in a timer interrupt or an OS task too.*/
      lv_timer_handler();
      usleep(5 * 1000);
  }

  return 0;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/**
 * Initialize the Hardware Abstraction Layer (HAL) for the LVGL graphics
 * library
 */
static void hal_init(void)
{
  /* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/
  monitor_init();
  /* Tick init.
   * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about
   * how much time were elapsed Create an SDL thread to do this*/
  SDL_CreateThread(tick_thread, "tick", NULL);

  /*Create a display buffer*/
  static lv_disp_draw_buf_t disp_buf1;
  static lv_color_t buf1_1[MONITOR_HOR_RES * 100];
  static lv_color_t buf1_2[MONITOR_HOR_RES * 100];
  lv_disp_draw_buf_init(&disp_buf1, buf1_1, buf1_2, MONITOR_HOR_RES * 100);

  /*Create a display*/
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv); /*Basic initialization*/
  disp_drv.draw_buf = &disp_buf1;
  disp_drv.flush_cb = monitor_flush;
  disp_drv.hor_res = MONITOR_HOR_RES;
  disp_drv.ver_res = MONITOR_VER_RES;
  disp_drv.antialiasing = 1;

  SDL_Log("Display hor %d ver %d \n", MONITOR_HOR_RES, MONITOR_VER_RES);

  lv_disp_t * disp = lv_disp_drv_register(&disp_drv);

  lv_theme_t * th = lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT);
  lv_disp_set_theme(disp, th);

  lv_group_t * g = lv_group_create();
  lv_group_set_default(g);

  /* Add the mouse as input device
   * Use the 'mouse' driver which reads the PC's mouse*/
  mouse_init();
  static lv_indev_drv_t indev_drv_1;
  lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
  indev_drv_1.type = LV_INDEV_TYPE_POINTER;

  /*This function will be called periodically (by the library) to get the mouse position and state*/
  indev_drv_1.read_cb = mouse_read;
  lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);

  keyboard_init();
  static lv_indev_drv_t indev_drv_2;
  lv_indev_drv_init(&indev_drv_2); /*Basic initialization*/
  indev_drv_2.type = LV_INDEV_TYPE_KEYPAD;
  indev_drv_2.read_cb = keyboard_read;
  lv_indev_t *kb_indev = lv_indev_drv_register(&indev_drv_2);
  lv_indev_set_group(kb_indev, g);
  mousewheel_init();
  static lv_indev_drv_t indev_drv_3;
  lv_indev_drv_init(&indev_drv_3); /*Basic initialization*/
  indev_drv_3.type = LV_INDEV_TYPE_ENCODER;
  indev_drv_3.read_cb = mousewheel_read;

  lv_indev_t * enc_indev = lv_indev_drv_register(&indev_drv_3);
  lv_indev_set_group(enc_indev, g);

  /*Set a cursor for the mouse*/
  LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/
  lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
  lv_img_set_src(cursor_obj, &mouse_cursor_icon);           /*Set the image source*/
  lv_indev_set_cursor(mouse_indev, cursor_obj);             /*Connect the image  object to the driver*/
}

/**
 * A task to measure the elapsed time for LVGL
 * @param data unused
 * @return never return
 */
static int tick_thread(void *data) {
    (void)data;

    while(1) { 
        SDL_Delay(5);
        lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
    }

    return 0;
}
  • Create a file in the project with the name of lv_demo_conf.h and copy the following content into it :
/**
 * @file lv_example_conf.h
 *
 */

#ifndef LV_EX_CONF_H
#define LV_EX_CONF_H


/*******************
 * GENERAL SETTING
 *******************/
#define LV_EX_PRINTF       1       /*Enable printf-ing data in demoes and examples*/
#define LV_EX_KEYBOARD     1       /*Add PC keyboard support to some examples (`lv_drivers` repository is required)*/
#define LV_EX_MOUSEWHEEL   1       /*Add 'encoder' (mouse wheel) support to some examples (`lv_drivers` repository is required)*/

/*********************
 * DEMO USAGE
 *********************/

/*Show some widget*/
#define LV_USE_DEMO_WIDGETS        1
#if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW  0
#endif


/*Printer demo, optimized for 800x480*/
#define LV_USE_DEMO_PRINTER   0

/*Demonstrate the usage of encoder and keyboard*/
#define LV_USE_DEMO_KEYPAD_AND_ENCODER    1

/*Benchmark your system*/
#define LV_USE_DEMO_BENCHMARK   1

/*Stress test for LVGL*/
#define LV_USE_DEMO_STRESS     1

#define LV_USE_DEMO_MUSIC      1
#if LV_USE_DEMO_MUSIC
# define LV_DEMO_MUSIC_LANDSCAPE    1
# define LV_DEMO_MUSIC_LARGE        0
#define LV_DEMO_MUSIC_AUTO_PLAY     0
#endif

#endif /*LV_EX_CONF_H*/
  • In lvgl root directory replace the content of lv_drv_conf.h with following code

(portrait configuration)

/**
 * @file lv_drv_conf.h
 *
 */

/*
 * COPY THIS FILE AS lv_drv_conf.h
 */

#if 1 /*Set it to "1" to enable the content*/

#ifndef LV_DRV_CONF_H
#define LV_DRV_CONF_H

#include "lv_conf.h"

/*********************
 * DELAY INTERFACE
 *********************/
#define LV_DRV_DELAY_INCLUDE  <stdint.h>            /*Dummy include by default*/
#define LV_DRV_DELAY_US(us)  /*delay_us(us)*/       /*Delay the given number of microseconds*/
#define LV_DRV_DELAY_MS(ms)  /*delay_ms(ms)*/       /*Delay the given number of milliseconds*/

/*********************
 * DISPLAY INTERFACE
 *********************/

/*------------
 *  Common
 *------------*/
#define LV_DRV_DISP_INCLUDE         <stdint.h>           /*Dummy include by default*/
#define LV_DRV_DISP_CMD_DATA(val)  /*pin_x_set(val)*/    /*Set the command/data pin to 'val'*/
#define LV_DRV_DISP_RST(val)       /*pin_x_set(val)*/    /*Set the reset pin to 'val'*/

/*---------
 *  SPI
 *---------*/
#define LV_DRV_DISP_SPI_CS(val)          /*spi_cs_set(val)*/     /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_DISP_SPI_WR_BYTE(data)    /*spi_wr(data)*/        /*Write a byte the SPI bus*/
#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/  /*Write 'n' bytes to SPI bus from 'adr'*/

/*------------------
 *  Parallel port
 *-----------------*/
#define LV_DRV_DISP_PAR_CS(val)          /*par_cs_set(val)*/   /*Set the Parallel port's Chip select to 'val'*/
#define LV_DRV_DISP_PAR_SLOW             /*par_slow()*/        /*Set low speed on the parallel port*/
#define LV_DRV_DISP_PAR_FAST             /*par_fast()*/        /*Set high speed on the parallel port*/
#define LV_DRV_DISP_PAR_WR_WORD(data)    /*par_wr(data)*/      /*Write a word to the parallel port*/
#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/

/***************************
 * INPUT DEVICE INTERFACE
 ***************************/

/*----------
 *  Common
 *----------*/
#define LV_DRV_INDEV_INCLUDE     <stdint.h>             /*Dummy include by default*/
#define LV_DRV_INDEV_RST(val)    /*pin_x_set(val)*/     /*Set the reset pin to 'val'*/
#define LV_DRV_INDEV_IRQ_READ    0 /*pn_x_read()*/      /*Read the IRQ pin*/

/*---------
 *  SPI
 *---------*/
#define LV_DRV_INDEV_SPI_CS(val)            /*spi_cs_set(val)*/     /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_INDEV_SPI_XCHG_BYTE(data)    0 /*spi_xchg(val)*/     /*Write 'val' to SPI and give the read value*/

/*---------
 *  I2C
 *---------*/
#define LV_DRV_INDEV_I2C_START              /*i2c_start()*/       /*Make an I2C start*/
#define LV_DRV_INDEV_I2C_STOP               /*i2c_stop()*/        /*Make an I2C stop*/
#define LV_DRV_INDEV_I2C_RESTART            /*i2c_restart()*/     /*Make an I2C restart*/
#define LV_DRV_INDEV_I2C_WR(data)           /*i2c_wr(data)*/      /*Write a byte to the I1C bus*/
#define LV_DRV_INDEV_I2C_READ(last_read)    0 /*i2c_rd()*/        /*Read a byte from the I2C bud*/


/*********************
 *  DISPLAY DRIVERS
 *********************/
#ifndef USE_WAYLAND
#  define USE_WAYLAND       0
#endif

#if USE_WAYLAND
#  define WAYLAND_HOR_RES      480
#  define WAYLAND_VER_RES      320
#  define WAYLAND_SURF_TITLE   "LVGL"
#endif
/*-------------------
 *  Monitor of PC
 *-------------------*/
#ifndef USE_MONITOR
#  define USE_MONITOR         1
#endif

//#define USE_480_272 1
#if USE_MONITOR
#ifdef USE_480_272
#  define MONITOR_HOR_RES     480
#  define MONITOR_VER_RES     272
#elif USE_272_480
#  define MONITOR_HOR_RES     272
#  define MONITOR_VER_RES     480
#else
#  define MONITOR_HOR_RES     480
#  define MONITOR_VER_RES     800
#endif
/* Scale window by this factor (useful when simulating small screens) */
#  define MONITOR_ZOOM        1

/* Used to test true double buffering with only address changing.
 * Set LV_draw_buf_SIZE = (LV_HOR_RES * LV_VER_RES) and  LV_draw_buf_DOUBLE = 1 and LV_COLOR_DEPTH = 32" */
#  define MONITOR_DOUBLE_BUFFERED 0

/*Eclipse: <SDL2/SDL.h>    Visual Studio: <SDL.h>*/
#  define MONITOR_SDL_INCLUDE_PATH    <SDL2/SDL.h>

/*Different rendering might be used if running in a Virtual machine*/
#  define MONITOR_VIRTUAL_MACHINE 0

/*Open two windows to test multi display support*/
#  define MONITOR_DUAL            0
#endif

/*-----------------------------------
 *  Native Windows (including mouse)
 *----------------------------------*/
#ifndef USE_WINDOWS
#  define USE_WINDOWS       0
#endif

#define USE_WINDOWS         0
#if USE_WINDOWS
#  define WINDOW_HOR_RES      480
#  define WINDOW_VER_RES      320
#endif

/*----------------------------------------
 *  GTK drivers (monitor, mouse, keyboard
 *---------------------------------------*/
#ifndef USE_GTK
#  define USE_GTK       0
#endif

/*----------------
 *    SSD1963
 *--------------*/
#ifndef USE_SSD1963
#  define USE_SSD1963         0
#endif

#if USE_SSD1963
#  define SSD1963_HOR_RES     LV_HOR_RES
#  define SSD1963_VER_RES     LV_VER_RES
#  define SSD1963_HT          531
#  define SSD1963_HPS         43
#  define SSD1963_LPS         8
#  define SSD1963_HPW         10
#  define SSD1963_VT          288
#  define SSD1963_VPS         12
#  define SSD1963_FPS         4
#  define SSD1963_VPW         10
#  define SSD1963_HS_NEG      0   /*Negative hsync*/
#  define SSD1963_VS_NEG      0   /*Negative vsync*/
#  define SSD1963_ORI         0   /*0, 90, 180, 270*/
#  define SSD1963_COLOR_DEPTH 16
#endif

/*----------------
 *    R61581
 *--------------*/
#ifndef USE_R61581
#  define USE_R61581          0
#endif

#if USE_R61581
#  define R61581_HOR_RES      LV_HOR_RES
#  define R61581_VER_RES      LV_VER_RES
#  define R61581_HSPL         0       /*HSYNC signal polarity*/
#  define R61581_HSL          10      /*HSYNC length (Not Implemented)*/
#  define R61581_HFP          10      /*Horitontal Front poarch (Not Implemented)*/
#  define R61581_HBP          10      /*Horitontal Back poarch (Not Implemented */
#  define R61581_VSPL         0       /*VSYNC signal polarity*/
#  define R61581_VSL          10      /*VSYNC length (Not Implemented)*/
#  define R61581_VFP          8       /*Vertical Front poarch*/
#  define R61581_VBP          8       /*Vertical Back poarch */
#  define R61581_DPL          0       /*DCLK signal polarity*/
#  define R61581_EPL          1       /*ENABLE signal polarity*/
#  define R61581_ORI          0       /*0, 180*/
#  define R61581_LV_COLOR_DEPTH 16    /*Fix 16 bit*/
#endif

/*------------------------------
 *  ST7565 (Monochrome, low res.)
 *-----------------------------*/
#ifndef USE_ST7565
#  define USE_ST7565          0
#endif

#if USE_ST7565
/*No settings*/
#endif  /*USE_ST7565*/

/*------------------------------
 *  GC9A01 (color, low res.)
 *-----------------------------*/
#ifndef USE_GC9A01
#  define USE_GC9A01          0
#endif

#if USE_GC9A01
/*No settings*/
#endif  /*USE_GC9A01*/

/*------------------------------------------
 *  UC1610 (4 gray 160*[104|128])
 *  (EA DOGXL160 160x104 tested)
 *-----------------------------------------*/
#ifndef USE_UC1610
#  define USE_UC1610          0
#endif

#if USE_UC1610
#  define UC1610_HOR_RES         LV_HOR_RES
#  define UC1610_VER_RES         LV_VER_RES
#  define UC1610_INIT_CONTRAST   33   /* init contrast, values in [%] */
#  define UC1610_INIT_HARD_RST   0    /* 1 : hardware reset at init, 0 : software reset */
#  define UC1610_TOP_VIEW        0    /* 0 : Bottom View, 1 : Top View */
#endif  /*USE_UC1610*/

/*-------------------------------------------------
 *  SHARP memory in pixel monochrome display series
 *      LS012B7DD01 (184x38  pixels.)
 *      LS013B7DH03 (128x128 pixels.)
 *      LS013B7DH05 (144x168 pixels.)
 *      LS027B7DH01 (400x240 pixels.) (tested)
 *      LS032B7DD02 (336x536 pixels.)
 *      LS044Q7DH01 (320x240 pixels.)
 *------------------------------------------------*/
#ifndef USE_SHARP_MIP
#  define USE_SHARP_MIP       0
#endif

#if USE_SHARP_MIP
#  define SHARP_MIP_HOR_RES             LV_HOR_RES
#  define SHARP_MIP_VER_RES             LV_VER_RES
#  define SHARP_MIP_SOFT_COM_INVERSION  0
#  define SHARP_MIP_REV_BYTE(b)         /*((uint8_t) __REV(__RBIT(b)))*/  /*Architecture / compiler dependent byte bits order reverse*/
#endif  /*USE_SHARP_MIP*/

/*-------------------------------------------------
 *  ILI9341 240X320 TFT LCD
 *------------------------------------------------*/
#ifndef USE_ILI9341
#  define USE_ILI9341       0
#endif

#if USE_ILI9341
#  define ILI9341_HOR_RES       LV_HOR_RES
#  define ILI9341_VER_RES       LV_VER_RES
#  define ILI9341_GAMMA         1
#  define ILI9341_TEARING       0
#endif  /*USE_ILI9341*/

/*-----------------------------------------
 *  Linux frame buffer device (/dev/fbx)
 *-----------------------------------------*/
#ifndef USE_FBDEV
#  define USE_FBDEV           1
#endif

#if USE_FBDEV
#  define FBDEV_PATH          "/dev/fb0"
#endif

/*-----------------------------------------
 *  FreeBSD frame buffer device (/dev/fbx)
 *.........................................*/
#ifndef USE_BSD_FBDEV
#  define USE_BSD_FBDEV		0
#endif

#if USE_BSD_FBDEV
# define FBDEV_PATH		"/dev/fb0"
#endif

/*-----------------------------------------
 *  DRM/KMS device (/dev/dri/cardX)
 *-----------------------------------------*/
#ifndef USE_DRM
#  define USE_DRM           0
#endif

#if USE_DRM
#  define DRM_CARD          "/dev/dri/card0"
#  define DRM_CONNECTOR_ID  -1	/* -1 for the first connected one */
#endif

/*********************
 *  INPUT DEVICES
 *********************/

/*--------------
 *    XPT2046
 *--------------*/
#ifndef USE_XPT2046
#  define USE_XPT2046         0
#endif

#if USE_XPT2046
#  define XPT2046_HOR_RES     480
#  define XPT2046_VER_RES     320
#  define XPT2046_X_MIN       200
#  define XPT2046_Y_MIN       200
#  define XPT2046_X_MAX       3800
#  define XPT2046_Y_MAX       3800
#  define XPT2046_AVG         4
#  define XPT2046_X_INV       0
#  define XPT2046_Y_INV       0
#  define XPT2046_XY_SWAP     0
#endif

/*-----------------
 *    FT5406EE8
 *-----------------*/
#ifndef USE_FT5406EE8
#  define USE_FT5406EE8       0
#endif

#if USE_FT5406EE8
# define FT5406EE8_I2C_ADR   0x38                  /*7 bit address*/
#endif

/*---------------
 *  AD TOUCH
 *--------------*/
#ifndef USE_AD_TOUCH
#  define USE_AD_TOUCH        0
#endif

#if USE_AD_TOUCH
/*No settings*/
#endif


/*---------------------------------------
 * Mouse or touchpad on PC (using SDL)
 *-------------------------------------*/
#ifndef USE_MOUSE
#  define USE_MOUSE           1
#endif

#if USE_MOUSE
/*No settings*/
#endif

/*-------------------------------------------
 * Mousewheel as encoder on PC (using SDL)
 *------------------------------------------*/
#ifndef USE_MOUSEWHEEL
#  define USE_MOUSEWHEEL      1
#endif

#if USE_MOUSEWHEEL
/*No settings*/
#endif

/*-------------------------------------------------
 * Touchscreen as libinput interface (for Linux based systems)
 *------------------------------------------------*/
#ifndef USE_LIBINPUT
#  define USE_LIBINPUT           0
#endif

#if USE_LIBINPUT
#  define LIBINPUT_NAME   "/dev/input/event0"        /*You can use the "evtest" Linux tool to get the list of devices and test them*/
#endif  /*USE_LIBINPUT*/

/*-------------------------------------------------
 * Mouse or touchpad as evdev interface (for Linux based systems)
 *------------------------------------------------*/
#ifndef USE_EVDEV
#  define USE_EVDEV           0
#endif

#ifndef USE_BSD_EVDEV
#  define USE_BSD_EVDEV       0
#endif

#if USE_EVDEV || USE_BSD_EVDEV
#  define EVDEV_NAME   "/dev/input/event0"        /*You can use the "evtest" Linux tool to get the list of devices and test them*/
#  define EVDEV_SWAP_AXES         0               /*Swap the x and y axes of the touchscreen*/

#  define EVDEV_CALIBRATE         0               /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/

#  if EVDEV_CALIBRATE
#    define EVDEV_HOR_MIN         0               /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/
#    define EVDEV_HOR_MAX      4096               /*"evtest" Linux tool can help to get the correct calibraion values>*/
#    define EVDEV_VER_MIN         0
#    define EVDEV_VER_MAX      4096
#  endif  /*EVDEV_CALIBRATE*/
#endif  /*USE_EVDEV*/

/*-------------------------------
 *   Keyboard of a PC (using SDL)
 *------------------------------*/
#ifndef USE_KEYBOARD
#  define USE_KEYBOARD        1
#endif

#if USE_KEYBOARD
/*No settings*/
#endif

#endif  /*LV_DRV_CONF_H*/

#endif /*End of "Content enable"*/

for landscape we apply the following changes Replace this part of the code :

//#define USE_480_272 1
#if USE_MONITOR
#ifdef USE_480_272
#  define MONITOR_HOR_RES     480
#  define MONITOR_VER_RES     272
#elif USE_272_480
#  define MONITOR_HOR_RES     272
#  define MONITOR_VER_RES     480
#else
#  define MONITOR_HOR_RES     480
#  define MONITOR_VER_RES     800
#endif

with


#if USE_MONITOR
#  define MONITOR_HOR_RES     800




#  define MONITOR_VER_RES     480
//#  define MONITOR_HOR_RES     480
//#  define MONITOR_VER_RES     800

3.4. Proposed modifications on LVGL project for configuration 4 (DRM/KMS only configuration)[edit source]

To adapt LVGL to our stmp32mp1 board some modification are needed.

  • Remplace the content of the main file of your project , by the following script :

#include <stdio.h>
#include <stdlib.h>

#include "lvgl/lvgl.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/display/drm.h"
#include "lv_drivers/indev/evdev.h"
#include "lv_demo_conf.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>

#define DISP_BUF_SIZE (128 * 1024)

#define COMPILE_WIDGET 1
//#define COMPILE_MUSIC 1
//#define COMPILE_KEYPAD 1

int main(void)
{
    /*LittlevGL init*/
    lv_init();

#if USE_FBDEV
    /*Linux frame buffer device init*/
    fbdev_init();
#endif
#if USE_DRM
    drm_init();
#endif

    /*A small buffer for LittlevGL to draw the screen's content*/
    static lv_color_t buf[DISP_BUF_SIZE];

    /*Initialize a descriptor for the buffer*/
    static lv_disp_draw_buf_t disp_buf;
    lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);

    /*Initialize and register a display driver*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.draw_buf   = &disp_buf;
#if USE_FBDEV
    disp_drv.flush_cb   = fbdev_flush;
#endif
#if USE_DRM
    disp_drv.flush_cb   = drm_flush;
#endif

    const char *width, *height, *rotate;
    width = getenv("LVGL_DRM_WIDTH");
    height = getenv("LVGL_DRM_HEIGHT");
fprintf(stderr, " ----> %s %s\n", width, height);
    if (width && height) {
        disp_drv.hor_res    = atoi(width);
        disp_drv.ver_res    = atoi(height);
    } else {
        disp_drv.hor_res    = 480;
        disp_drv.ver_res    = 800;
    }
    lv_disp_drv_register(&disp_drv);


    evdev_init();
#if USE_EVDEV
  const char *device_evdev;
  device_evdev = getenv("LVGL_EVDEV");
  if (device_evdev) 
     evdev_init_with_device(device_evdev);
  else
     evdev_init();
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = evdev_read;
  lv_indev_t *evdev_indev = lv_indev_drv_register(&indev_drv);
#endif



#ifdef COMPILE_WIDGET
    lv_demo_widgets();
#endif
#ifdef COMPILE_MUSIC
    lv_demo_music();
#endif
#ifdef COMPILE_KEYPAD
    lv_demo_keypad_encoder();
#endif

    /*Handle LitlevGL tasks (tickless mode)*/
    while(1) {
        lv_task_handler();
        usleep(5000);
    }

    return 0;
}



/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
uint32_t custom_tick_get(void)
{
    static uint64_t start_ms = 0;
    if(start_ms == 0) {
        struct timeval tv_start;
        gettimeofday(&tv_start, NULL);
        start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
    }

    struct timeval tv_now;
    gettimeofday(&tv_now, NULL);
    uint64_t now_ms;
    now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;

    uint32_t time_ms = now_ms - start_ms;
    return time_ms;
}
  • Remplace the content of the Makefile of your project , by the following script :
#
# Makefile
#
CC ?= gcc
LVGL_DIR_NAME ?= lvgl
LVGL_DIR ?= ${shell pwd}
CFLAGS += -O3 -g0 -I$(LVGL_DIR)/ -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -Wall -Wextra -Wno-unused-function -Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized -Wmaybe-uninitialized -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers -Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated -Wempty-body -Wtype-limits -Wshift-negative-value -Wstack-usage=2048 -Wno-unused-value -Wno-unused-parameter -Wno-missing-field-initializers -Wuninitialized -Wmaybe-uninitialized -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wpointer-arith -Wno-cast-qual -Wmissing-prototypes -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wno-discarded-qualifiers -Wformat-security -Wno-ignored-qualifiers -Wno-sign-compare
LDFLAGS += -lm -ldrm
BIN = demo


#Collect the files to compile
MAINSRC = ./main.c

include $(LVGL_DIR)/lvgl/lvgl.mk
include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
include $(LVGL_DIR)/lv_demos/lv_demo.mk

OBJEXT ?= .o

AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))

MAINOBJ = $(MAINSRC:.c=$(OBJEXT))

SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
OBJS = $(AOBJS) $(COBJS)

## MAINOBJ -> OBJFILES

all: default

%.o: %.c
	@echo "$(CC) $(CFLAGS) -c $< -o $@"
	@$(CC)  $(CFLAGS) -c $< -o $@
    
default: $(AOBJS) $(COBJS) $(MAINOBJ)
	$(CC) -o $(BIN) $(MAINOBJ) $(AOBJS) $(COBJS) $(LDFLAGS)

clean: 
	rm -f $(BIN) $(AOBJS) $(COBJS) $(MAINOBJ)

  • Create a file in the project with the name of lv_demo_conf.h and copy the following script into it :
/**
 * @file lv_demo_conf.h
 * Configuration file for v8.1.0-dev
 *
 */
/*
 * COPY THIS FILE AS lv_demo_conf.h
 */

#if 1 /*Set it to "1" to enable the content*/

#ifndef LV_EX_CONF_H
#define LV_EX_CONF_H


/*******************
 * GENERAL SETTING
 *******************/
#define LV_EX_PRINTF       0       /*Enable printf-ing data in demoes and examples*/
#define LV_EX_KEYBOARD     0       /*Add PC keyboard support to some examples (`lv_drivers` repository is required)*/
#define LV_EX_MOUSEWHEEL   0       /*Add 'encoder' (mouse wheel) support to some examples (`lv_drivers` repository is required)*/

/*********************
 * DEMO USAGE
 *********************/

/*Show some widget*/
#define LV_USE_DEMO_WIDGETS        1
#if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW  0
#endif

/*Printer demo, optimized for 800x480*/
#define LV_USE_DEMO_PRINTER     1

/*Demonstrate the usage of encoder and keyboard*/
#define LV_USE_DEMO_KEYPAD_AND_ENCODER     1

/*Benchmark your system*/
#define LV_USE_DEMO_BENCHMARK   1

/*Stress test for LVGL*/
#define LV_USE_DEMO_STRESS      1

/*Music player demo*/
#define LV_USE_DEMO_MUSIC      1
#if LV_USE_DEMO_MUSIC
# define LV_DEMO_MUSIC_LANDSCAPE    0
# define LV_DEMO_MUSIC_LARGE        0
#define LV_DEMO_MUSIC_AUTO_PLAY     0
#endif

#endif /*LV_EX_CONF_H*/

#endif /*End of "Content enable"*/

we create a new patch that we rename 0001-extend-evdev.patch and we copy the following script :

From a9b0e2008e35e23910238bd1bac562c36499f765 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@foss.st.com>
Date: Mon, 23 Aug 2021 09:42:17 +0200
Subject: [PATCH] extend evdev

---
 indev/evdev.c | 15 +++++++++++++++
 indev/evdev.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/lv_drivers/indev/evdev.c b/lv_drivers/indev/evdev.c
index e85b7f4..b6f4f13 100644
--- a/lv_drivers/indev/evdev.c
+++ b/lv_drivers/indev/evdev.c
@@ -75,6 +75,21 @@ void evdev_init(void)
     evdev_key_val = 0;
     evdev_button = LV_INDEV_STATE_REL;
 }
+void evdev_init_with_device(char *device)
+{
+    evdev_fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
+    if(evdev_fd == -1) {
+        perror("unable open evdev interface:");
+        return;
+    }
+
+    fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK);
+    evdev_root_x = 0;
+    evdev_root_y = 0;
+    evdev_key_val = 0;
+    evdev_button = LV_INDEV_STATE_REL;
+}
+
 /**
  * reconfigure the device file for evdev
  * @param dev_name set the evdev device filename
diff --git a/lv_drivers/indev/evdev.h b/lv_drivers/indev/evdev.h
index dcb9114..bc82cb4 100644
--- a/lv_drivers/indev/evdev.h
+++ b/lv_drivers/indev/evdev.h
@@ -45,6 +45,8 @@ extern "C" {
  * Initialize the evdev
  */
 void evdev_init(void);
+void evdev_init_with_device(char *device);
+
 /**
  * reconfigure the device file for evdev
  * @param dev_name set the evdev device filename
-- 
2.25.1
  • Apply patch 0001-extend-evdev.patch in lvgl root directory
 patch -p1 < 0001-extend-evdev.patch
  • In lvgl root directory (in file lv_conf.h ), we apply the following changes:

Replace this part of the code :

 /*Use a custom tick source that tells the elapsed time in milliseconds.
  *It removes the need to manually update the tick with `lv_tick_inc()`)*/
#define LV_TICK_CUSTOM 0
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h"         /*Header for the system time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis())    /*Expression evaluating to current system time in ms*/
*Expression evaluating to current system time in ms*/
 #endif   /*LV_TICK_CUSTOM*/

with :

  /*Use a custom tick source that tells the elapsed time in milliseconds.
  *It removes the need to manually update the tick with `lv_tick_inc()`)*/
uint32_t custom_tick_get(void);

#define LV_TICK_CUSTOM     1
 #if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE  <stdint.h>         /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (custom_tick_get())     /*Expression evaluating to current system time in ms*/
 #endif   /*LV_TICK_CUSTOM*/


Change maximum buffer size to allocate for rotation by replacing the following line :

#define LV_DISP_ROT_MAX_BUF (32*1024)

with :

#define LV_DISP_ROT_MAX_BUF (10*1024)
  • In lvgl root directory (in lv_drv_conf.h ), we apply the following changes:

Change the resolution by modifying the following parameters :

#if USE_MONITOR
#  define MONITOR_HOR_RES     480
#  define MONITOR_VER_RES     320

with :

#if USE_MONITOR
#  define MONITOR_HOR_RES     800
#  define MONITOR_VER_RES     480

we choose to use DRM/KMS by changing :

#  define USE_DRM           0

with :

#  define USE_DRM           1

we choose to use EVDEV by replacing :

#  define USE_EVDEV           0

with :

#  define USE_EVDEV          1

Replacing the following part of code :

#if USE_EVDEV || USE_BSD_EVDEV
#  define EVDEV_NAME   "/dev/input/event0"        /*You can use the "evtest" Linux tool to get the list of devices and test them*/

with :

#if USE_EVDEV || USE_BSD_EVDEV
#  define EVDEV_NAME   "/dev/input/event1"        /*You can use the "evtest" Linux tool to get the list of devices and test them*/

3.5. Run the demo[edit source]

  • You need to build binary for your configuration
  • Build the project

Right-Click on you project ==> Build project

  • If everything works well, in your project (folder "Debug") you find the binary file.
  • Setup terminal on the board.
 minicom  -D /dev/ttyACM0
  • To get the IP address of your target, type the following commands:
 ifconfig

inet is the ip address of your target

  • You can copy binary to the board by using the following command:
 scp <name_of_your_binary> root@<IP_address>:/

To force binary writting on the sdcard

 sync
  • Run your binary

In configuration 1,2,3 we are using SDL, so we have to configure SDL_VIDEODRIVER variable on the board.

In configuration 1,

export SDL_VIDEODRIVER=wayland

In configuration 2,3

export SDL_VIDEODRIVER=kmsdrm 

In configuration 2,3,4 we are using DRM/KMS, so we will stop wayland/ weston before running the binary

 systemctl stop weston@root  

if your are using OpenSTLinuxV4.0 , you can stop wayland with the following command :

 systemctl stop weston-launch 

to run the binary :

 cd /
 ./<name_of_your_binary >

To kill the current project:

 CTRL + c
  • As a summary, to run the different configurations

In configuration 1, use binary with patch for configuration 1 to 3 generated with SDK_SDL_with_GPU

export SDL_VIDEODRIVER=wayland
 ./<name_of_your_binary >

In configuration 2,use binary with patch for configuration 1 to 3 generated with SDK_SDL_with_GPU

stop wayland 
export SDL_VIDEODRIVER=kmsdrm 
 ./<name_of_your_binary >

In configuration 3, use binary with patch for configuration 1 to 3 generated with SDK_SDL_without_GPU

stop wayland 
export SDL_VIDEODRIVER=kmsdrm 
 ./<name_of_your_binary >

In configuration 4, use binary with patch for configuration 4 and generated with SDK_SDL_without_GPU

stop wayland 
 ./<name_of_your_binary >


3.6. Display performances[edit source]

To measure performances, you will need two terminals, the first to launch the application and the second to display the performances in real time.

  • After copying the binary, we launch the first terminal on the board with the following commands :
  minicom  -D /dev/ttyACM0
   ./<name_of_your_binary>
  • we launch the second terminal with SSH .
  ssh root@<IP_address>

on the same terminal paste and run the following script :


 (while true; do \
 
gpu_last_gc=$(cat /sys/kernel/debug/gc/idle); \
 
m=$(mpstat 4 1 | grep "Average:     all" | awk -F" " '{print "cpu load " $3 "%"}'); \
 
echo "-------------------------"; \
 
export fps=`cat /sys/kernel/debug/dri/0/state | grep fps -m1 | grep -o '[0-9]\+'`; echo display  ${fps}fps; \
 
gpu_on=$(echo $gpu_last_gc | tr -d '\n' | tr -d ',' | awk -F" " '{printf("%f\n", $2)}'); \
 
gpu_start=$(echo $gpu_last_gc | tr -d '\n' | tr -d ',' | awk -F" " '{printf("%f\n", ($2+$5+$8+$11))}'); \
 
tr -d '\n' < /sys/kernel/debug/gc/idle | tr -d ',' | awk -v on=$gpu_on -v start=$gpu_start -F" " '{printf ("gpu load %.0f%%\n", ($2 - on) * 100/($2+$4+$6+$8 - start));}'; \
 
echo $m; \
 
done) &

to stop the script: Click on

                      > 'f' +'g'+ ENTER  
                      > CTRL+C

4. To go further[edit source]

"LVGL project examples"[1] "Learn LVGL"[2] "LVGL forum"[3]

5. References[edit source]

"LVGL official web site"[4] "SDL official web site"[5] "Wayland official web site"[6]