Starting from scratch with ESP-IDF (ESP32) and lvgl

Hello,

I’m trying to implement my first project with lvgl and have got several problems (to understand the mandatory code flow).

  1. In the documentation (“3.1.2 Add LVGL into your project”) it is first mentioned that the file “lv_conf_template.h” should be copied under the name “lv_conf.h” “next to the lvgl folder”, but what does “next” really mean? You can imagine a lot places under that. In the ESP32 environment with ESP-IDF it would be in “$ {PROJECT_ROOT}/components”, but that would be a “sin”! I placed it in the lvgl directory, it seems to work…

  2. In the same chapter below, it is unclear where “lv_tick_inc(x)” to place in your own code and how to use it. There is not a single example that shows this.

A small, complete example project would be very helpful in order to be able to understand the complete initialization with a known hardware (for example ESP32 with ILI9488 and FT6x36). It is precisely at this point that I have problems recognizing what is required!

Can somebody help me to understand it?

Thanks in advance,
Michael

3 Likes

Hi,

I had the same problem 5-6 months ago. after a lot of head scratching and few sleepless nights i made the LVGL work with ESP32. created a public git repo too for my own usage. If you want you can clone it and start using it.

this is something i have done with the LVGL and ESP32.

When you checkout the git repo be mindful that i am using ILI9341 as the display driver. So you will have to change that from menuconfig. Other than that you are good to go.

you will be able to see where i have put the lv_conf.h file.

In a STM32 FreeRTOS based project the lv_tick_inc(x) usually i create a FreeRTOS task that runs once every 10ms or so.
In ESP32 projects i uasually create a Hardware timer with Interrupts and place the lv_tick_inc(x) inside that hardware timer isr

It has been done and is documented in the Getting Started section here.

Hello Jupeos,

In most cases I read the documentation before asking anything in the forums. I have read this chapter, but it was insufficient for me.

Often there is a problem when the same person writes the software and the documentation for this software: You think that the others would understand it exactly as you see/understand it. But that is usually wrong. A “tabula rasa” person (as me at the moment) sees these things very strange and can’t do anything with it.

Hello om3gaki113r,

many thanks for your help.

I’ve downloaded your code and I’ll check it out in the near future.

1 Like

Maybe you missed it but in that link that I provided there is a complete github repo oriented around a port of the ESP32 including LVGL which answers…

A small, complete example project would be very helpfu

Hello jupeos,

Sorry, you are right, the link to “lv_port_esp32” contains similar code.

Hello jupeos,

I use ESP-IDF 4.3.1 under Linux openSUSE Tumbleweed.
I use as hardware ESP32-DevKitC-VIE (V4) and an ER-TFTM035-6 (ILI9488 with FT6236).
For logical and physical connections I use (as I also use it in other projects):

    VSPI-HOST
    GPIO19 LCD-MISO
    GPIO23 LCD MOSI
    GPIO18 LCD-SCLK
    GPIO5  LCD-/CS
    GPIO32 LCD-D/C
    GPIO27 LCD-/RESET
    GPIO33 LCD backlight

    I2C-0
    GPIO25 CTP-SDA
    GPIO26 CTP-SCL

After the command “idf.py set-target esp32” I configured the code from the repository “lv_port_esp32” according to these connections:

    "Lv_examples configuration"                 unchanged
    "LVGL configuration"                        unchanged
    "LVGL TFT Display controller"               modified
        "Select a display controller model"     ILI9488
        "TFT SPI Bus"                           VSPI
        "User custom SPI clock frequency"       20 MHz
        "Display Pin Assignment"
            "GPIO for MOSI"                     23
            "GPIO for MISO"                     19
            "GPIO for CLK"                      18
            "GPIO for CS"                       5
            "GPIO for DC"                       32
            "GPIO for Reset"                    27
            "GPIO for backlight control"        33
    "LVGL Touch controller"                     modified
        "Touch panel controller model"          "FT6x06"
        "Touch I2C port"                        "I2C PORT 0"
        "Touchpanel Pin Assignment"
            "GPIO for SDA"                      25
            "GPIO for SCL"                      26

After the successful compilation and flashing, I get the following relevant output with the command “idf.py monitor”:

I (1355) lvgl_helpers: Display hor size: 480, ver size: 320
I (1355) lvgl_helpers: Display buffer size: 19200
I (1365) lvgl_helpers: Initializing SPI master for display
I (1365) lvgl_helpers: Configuring SPI host VSPI_HOST (2)
I (1365) lvgl_helpers: MISO pin: 19, MOSI pin: 23, SCLK pin: 18, IO2/WP pin: -1, IO3/HD pin: -1
I (1385) lvgl_helpers: Max transfer size: 57600 (bytes)
I (1385) lvgl_helpers: Initializing SPI bus...
I (1385) disp_spi: Adding SPI device
I (1395) disp_spi: Clock speed: 20000000Hz, mode: 0, CS pin: 5
I (1605) ILI9488: ILI9488 initialization.
I (1905) ILI9488: Enabling backlight.
I (1905) ILI9488: Display orientation: PORTRAIT
I (1905) ILI9488: 0x36 command value: 0x48
I (1905) lvgl_helpers: Initializing I2C master for touch
I (1915) lvgl_helpers: Initializing I2C master port 0...
I (1925) lvgl_helpers: SDA pin: 25, SCL pin: 26, Speed: 400000 (Hz)
I (1925) lvgl_helpers: Setting I2C master configuration...
I (1935) lvgl_helpers: Installing I2C master driver...
I (1945) FT6X36: Found touch panel controller
E (1945) FT6X36: Error reading from device: ERROR
I (1945) FT6X36: 	Device ID: 0x1a
I (1955) FT6X36: 	Chip ID: 0x1a
I (1955) FT6X36: 	Device mode: 0x1a
I (1965) FT6X36: 	Firmware ID: 0x1a
I (1965) FT6X36: 	Release code: 0x1a

On the display appears a white eagle on a white background as Germans say.

The first thing that catches my eye: The “Device ID” is wrong.

Even if I configure the project without the touch panel, the display remains white.

I’ve checked the connections between the ESP32 DevKit and the display several times, they are wired correctly.

Do you have any idea why it’s not working before I reach for the Logic Analyzer and do the tedious troubleshooting?

Thanks in advance,
Michael

I have to apologize several times !!!
I don’t know what’s wrong with my eyes: On one side of the DevKit, all connections were offset by one pin.

Now it works!

I’m so sorry…

Hello,

Some weeks ago I started with ESP-IDF v4.3.1 and LVGL 8.0.2.

At the beginning the code seemed to work. But later it worked any more! And I don’t know why.

I’ve tried everything and tried all possible ways, but nothing helps.

My code looked very simple to start with:

/*
 * File:    main.c
 * Author:  Mick P. F.
 * Created: 2021-11-06
 */

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"

#include "driver/gpio.h"
#include "esp_timer.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#if defined(CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488)
    #if defined(CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE) || defined(CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED)
        #define DISPLAY_WIDTH               480
        #define DISPLAY_HEIGHT              320
    #else
        #define DISPLAY_WIDTH               320
        #define DISPLAY_HEIGHT              480
    #endif
#endif

#include "lvgl.h"
#include "lvgl_helpers.h"

#define DEBUG_MODULE

#ifndef DELAY_MS
#define DELAY_MS(ms)                        vTaskDelay((ms) / portTICK_PERIOD_MS)
#endif

#define LV_TICK_PERIOD_MS                   10                  // Call every 10 ms the LVGL Ticker

#define SCREEN_BACKGROUND_OPACITY           LV_OPA_COVER
#define SCREEN_FOREGROUND_OPACITY           LV_OPA_COVER
#define COLOR_BACKGROUND_RED                0x36
#define COLOR_BACKGROUND_GREEN              0x2C
#define COLOR_BACKGROUND_BLUE               0x1C
#define COLOR_FOREGROUND_RED                0xFF
#define COLOR_FOREGROUND_GREEN              0x66
#define COLOR_FOREGROUND_BLUE               0x00
#define COLOR_INDOOR_SENSOR_RED             0x33
#define COLOR_INDOOR_SENSOR_GREEN           0xCC
#define COLOR_INDOOR_SENSOR_BLUE            0x66
#define COLOR_OUTDOOR_SENSOR_RED            0x00
#define COLOR_OUTDOOR_SENSOR_GREEN          0xCC
#define COLOR_OUTDOOR_SENSOR_BLUE           0xFF

static const char          *MODULE_TAG = "MAIN";

static int16_t              screen_width, screen_height;
static lv_color_t          *display_cache;
static lv_disp_draw_buf_t   display_buffer;
static lv_disp_drv_t        display_driver;
static lv_disp_t           *display;
static lv_obj_t            *screen;

static lv_color_t           color_bg, color_fg;

static void lv_tick_task(void *arg)
{
    lv_tick_inc(LV_TICK_PERIOD_MS);
}

void app_main(void)
{
    esp_timer_handle_t          gui_timer;
    esp_timer_create_args_t     timer_args;

    lv_area_t                   draw_area, clip_area;
    lv_draw_rect_dsc_t          frame;

    lv_init();
    lvgl_driver_init();

    color_bg      = lv_color_make(COLOR_BACKGROUND_RED, COLOR_BACKGROUND_GREEN, COLOR_BACKGROUND_BLUE);
    color_fg      = lv_color_make(COLOR_FOREGROUND_RED, COLOR_FOREGROUND_GREEN, COLOR_FOREGROUND_BLUE);

    display_cache = (lv_color_t *) heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    if (display_cache == NULL)
    {
        ESP_LOGE(MODULE_TAG, "Allocating space for display buffer failed!");
        abort();
    }
    lv_disp_draw_buf_init(&display_buffer, display_cache, NULL, DISP_BUF_SIZE);

    lv_disp_drv_init(&display_driver);
    display_driver.hor_res  = DISPLAY_WIDTH;
    display_driver.ver_res  = DISPLAY_HEIGHT;
    display_driver.flush_cb = disp_driver_flush;
    display_driver.draw_buf = &display_buffer;
    display = lv_disp_drv_register(&display_driver);
    if (display == NULL)
    {
        ESP_LOGE(MODULE_TAG, "Register display driver failed!");
        abort();
    }
    lv_disp_set_default(display);

    /* Create and start a periodic timer interrupt to call lv_tick_inc */
    timer_args.callback = lv_tick_task;
    timer_args.name = "gui_timer";
    ESP_ERROR_CHECK(esp_timer_create(&timer_args, &gui_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(gui_timer, LV_TICK_PERIOD_MS * 1000));

    display       = lv_disp_get_default();
    screen        = lv_disp_get_scr_act(display);
    screen_width  = lv_disp_get_hor_res(display);
    screen_height = lv_disp_get_ver_res(display);

    lv_draw_rect_dsc_init(&frame);
    frame.radius       = 7;
    frame.bg_color     = color_bg;
    frame.bg_opa       = SCREEN_BACKGROUND_OPACITY;
    frame.border_color = color_fg;
    frame.border_width = 3;
    frame.border_opa   = SCREEN_FOREGROUND_OPACITY;

    draw_area.x1 = 3; draw_area.y1 = 3;
    draw_area.x2 = 299; draw_area.y2 = 199;
    clip_area.x1 = 0; clip_area.y1 = 0;
    clip_area.x2 = DISPLAY_WIDTH - 1; clip_area.y2 = DISPLAY_HEIGHT - 1;
    lv_draw_rect(&draw_area, &clip_area, &frame);

    while (1)
    {
        lv_task_handler();
        DELAY_MS(2000);
    }
}

Running this code resulted in an exception with a crash:

I (911) lvgl_helpers: Display buffer size: 19200
I (911) lvgl_helpers: Initializing SPI master for display
I (921) lvgl_helpers: Configuring SPI host VSPI_HOST (2)
I (931) lvgl_helpers: MISO pin: 19, MOSI pin: 23, SCLK pin: 18, IO2/WP pin: -1, IO3/HD pin: -1
I (941) lvgl_helpers: Max transfer size: 57600 (bytes)
I (941) lvgl_helpers: Initializing SPI bus...
I (951) disp_spi: Adding SPI device
I (951) disp_spi: Clock speed: 20000000Hz, mode: 0, CS pin: 5
I (961) ILI9488: ILI9488 initialization.
I (1261) ILI9488: Display orientation: LANDSCAPE
I (1261) ILI9488: 0x36 command value: 0x28
I (1261) disp_backlight: Setting LCD backlight: 100%
I (1261) FT6X36: Found touch panel controller
I (1261) lvgl_i2c: Starting I2C master at port 0.
I (1271) lvgl_i2c: Initialised port 0 (SDA: 25, SCL: 26, speed: 400000 Hz.)
I (1281) FT6X36: 	Device ID: 0x11
I (1281) FT6X36: 	Chip ID: 0x36
I (1291) FT6X36: 	Device mode: 0x00
I (1291) FT6X36: 	Firmware ID: 0x03
I (1291) FT6X36: 	Release code: 0x01
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x4010ea73  PS      : 0x00060030  A0      : 0x8008ab3c  A1      : 0x3ffbe760  
0x4010ea73: lv_disp_get_draw_buf at /home/mick/Projects/ESP32/ESP32/ER-TFTM035/build/../components/lvgl/src/hal/lv_hal_disp.c:503

A2      : 0x00000000  A3      : 0x0000000a  A4      : 0x00000005  A5      : 0x3ffb44d4  
A6      : 0x3ffb44c0  A7      : 0x00000005  A8      : 0x3ffb3320  A9      : 0x3ffbe740  
A10     : 0x00000000  A11     : 0x00000005  A12     : 0x00000000  A13     : 0x3ffb435c  
A14     : 0x00000000  A15     : 0x00000000  SAR     : 0x00000009  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000000  LBEG    : 0x4008df32  LEND    : 0x4008df3d  LCOUNT  : 0x00000000  
0x4008df32: memset at /builds/idf/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/newlib/libc/machine/xtensa/memset.S:150

0x4008df3d: memset at /builds/idf/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/newlib/libc/machine/xtensa/memset.S:160


Backtrace:0x4010ea70:0x3ffbe760 0x4008ab39:0x3ffbe780 0x400e2616:0x3ffbe7e0 0x4008a041:0x3ffbe8b0 0x400e2ae0:0x3ffbe8f0 0x400d9e10:0x3ffbe910 0x401104f9:0x3ffbe990 0x40093791:0x3ffbe9b0
0x4010ea70: lv_disp_get_draw_buf at /home/mick/Projects/ESP32/ESP32/ER-TFTM035/build/../components/lvgl/src/hal/lv_hal_disp.c:502

0x4008ab39: _lv_blend_fill at /home/mick/Projects/ESP32/ESP32/ER-TFTM035/build/../components/lvgl/src/draw/lv_draw_blend.c:138

0x400e2616: draw_border_generic at /home/mick/Projects/ESP32/ESP32/ER-TFTM035/build/../components/lvgl/src/draw/lv_draw_rect.c:1171

0x4008a041: draw_border at /home/mick/Projects/ESP32/ESP32/ER-TFTM035/build/../components/lvgl/src/draw/lv_draw_rect.c:406

0x400e2ae0: lv_draw_rect at /home/mick/Projects/ESP32/ESP32/ER-TFTM035/build/../components/lvgl/src/draw/lv_draw_rect.c:111

0x400d9e10: app_main at /home/mick/Projects/ESP32/ESP32/ER-TFTM035/build/../main/main.c:137 (discriminator 2)

0x401104f9: main_task at /opt/ESP32/v4.3.1/esp-idf/components/freertos/port/port_common.c:133

0x40093791: vPortTaskWrapper at /opt/ESP32/v4.3.1/esp-idf/components/freertos/port/xtensa/port.c:168

The cause was quickly found because the variable disp in “lvgl/src/hal/lv_hal_disp.c:503” has the value NULL; the value of NULL is returned in code line 137 of the source file “lv_draw_blend.c” by calling “_lv_refr_get_disp_refreshing()” in the funtion “_lv_blend_fill”. The global variable “disp_ref” is not set anywhere in the source file “lv_refr.c”.

So I built the call of the function “_lv_refr_set_disp_refreshing(display)” into my code after calling “lv_disp_set_default(display)”.

Since then there have been no crashes, but the display stays white and my rectangle is not drawn.

I noticed a few uncomfortable things in the library LVGL:

  1. There are no calls to erase the whole display or a part of it.
  2. As a rule, functions in a library that begin with an underscore are only intended for internal use and should therefore not be called from outside.

What am I doing wrong?

Can someone please help me get the code working (again)?

Thanks in advance,
Michael

Problems incoming all from setup.h file i think, so when build a library for many devices and many screen and many compilers need also give a setup.h for any device supported, or problems incoming and not display none, also if not are errors in compiler.
Bodmer TFT_eSPI library provide a series of setup for any display, and troubles is much more minor.
I have call for help in another post, also how use files C generated by Edgeline but i dont receive any reply…need just test…test…test by editing the setup file …and start from a minimal example…
good luck

A question, your touch screen is a i2C ?

Sorry to answer so late.

I have configured the I2C interface and the touch controller, but so far only tested with the examples, not with my code. The reason: I don’t actually need a touch function because I will write my own driver for IR-RC if one day the display will work!

The display module (BuyDisplay’s ER-TFTM035-6) has a FT6263 as the touch controller connected via I2C.

Apparently there is no one at LVGL who could help me with this elementary problem.

As in most cases (in 99% of the cases / problems) I have to help myself.

Unfortunately, as I have already told you in another post, the use of universal libraries is not so simple and immediate, especially the first impact, but after a couple of weeks I can say I understand something.
I just posted a complete example which includes both a screenshot of the display and SPIFFS memory management via the Arduino IDE serial port.
I saw you have an Ili9488 but it is I2C, mind mine is SPI, but apart from the different configuration, you can see if my example helps you.
I don’t know what you have to do, I also enjoy 3D RC flying and I like to build my own models.
I tried to control 4 servos and 3 motors with an Arduino Nano, but if it worked for the servos, the speed varied too much for the motors.
Esp32 is certainly better but I have not yet had time to try it connected to the receiver and above all to the motors.
My post if you are interested is here: Esp32 use with LVGL library...need a little example - #4 by gabriele_ponte and the screen I use it I bought it here: Driver ottico ILI9341 del pannello di tocco dello schermo di visualizzazione del modulo LCD TFT seriale SPI 3.5x320 da 480 pollici per MCU|Car Monitors| - AliExpress
Hello and good fun

Hello,

I give up!

For weeks I’ve been trying to get LVGL working with ESP-IDF. While it works fine in demo mode with “lv_port_esp32” and the old LVGL version 7.x, with version 8.1, the actual code “lvgl_esp32_drivers” and the code shown above, I only get garbage on the display.
It doesn’t matter whether I use the ER-MTFT035-6 with ILI9844 or the NHD-4.3 with FT813: the result is always the same.
Version 8.1 is completely immature: Some parts of the code have been taken over unchanged from version 7.x and do not fit with the rest. Especially “lvgl_esp32_drivers” does not fit with the library at all.

In this state the library is completely unusable.

A good idea, but poorly implemented.

Try a step by step that works - the documentation for lvgl is appalling and there are no stand alone examples that don’t include all the boat of your built in examples. Its impossible to start from scratch and build anything that will work.