Esp32 LVGL 8.3 initialization problem ili9341

I’ve got problem with display anything on display and got stuck totally. I’m trying to run display on esp32 with lvgl 8.3.4 and lvgl_esp32_drivers from master branch but after initialization I get only flickering white/black screen with no image (its looks like the white screen is flickering with display refreshrate). I did not have any errors.


What MCU/Processor/Board and compiler are you using?

esp32 wrover with espidf 4.4.3

What do you want to achieve?

Proper display initialization

What have you tried so far?

Code to reproduce


#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_freertos_hooks.h"
#include "freertos/event_groups.h"
#include "display.h"

#include "../lvgl_tft/disp_driver.h"
#include "../lvgl_helpers.h"
#include "sdkconfig.h"

static struct display_ctx disp_ctx = 
    .backlight = NULL, 
    .disp = NULL, 
    .indev = NULL, 
    .is_valid = false

static lv_disp_draw_buf_t draw_buf;
static lv_disp_drv_t disp_drv;
static lv_color_t buf_1[320 * 10];

disp_backlight_config_t backlight_config;
disp_backlight_h backlight_h = NULL;

static lv_indev_drv_t indev_drv;
lv_indev_t* indev = NULL;
lv_disp_t* disp = NULL;

static const char *TAG = "Display";

void display_task(void* param)
    ESP_LOGI(TAG, "Display task created");
        vTaskDelay(10 / portTICK_RATE_MS);

void IRAM_ATTR lv_tick_task(void)

lv_disp_t* init_display()
    lv_disp_draw_buf_init(&draw_buf, buf_1, NULL, LV_HOR_RES*10);

    disp_drv.hor_res = LV_HOR_RES;
    disp_drv.ver_res = LV_VER_RES;
    disp_drv.draw_buf = &draw_buf;
    disp_drv.flush_cb = disp_driver_flush;
    disp = lv_disp_drv_register(&disp_drv);

    if(disp == NULL)
        disp_ctx.is_valid = false;
        return NULL;

    xTaskCreate(display_task, "DisplayTask", 4096, NULL, 1, NULL);
    disp_ctx.is_valid = true;
    ESP_LOGI(TAG, "Display created");

    return disp;

disp_backlight_h* init_backlight()
    ESP_LOGI(TAG, "Initializing backlight");
    backlight_config.gpio_num = CONFIG_LV_DISP_PIN_BCKL;
    backlight_config.pwm_control = true;
    backlight_config.channel_idx = 0;
    backlight_config.timer_idx = 0;
    backlight_h = disp_backlight_new(&backlight_config);
    if(backlight_h == NULL)
        ESP_LOGE(TAG, "Cannot init baclight");
        disp_ctx.is_valid = false;
        return NULL;
    ESP_LOGI(TAG, "Backlight initialized");
    disp_ctx.is_valid = true;
    return &backlight_h;

void set_backlight(int percentage)
    disp_backlight_set(backlight_h, percentage);

lv_indev_t* init_indev()
    ESP_LOGI(TAG, "Creating indev");

    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touch_driver_read;
    indev = lv_indev_drv_register(&indev_drv);
    if(indev == NULL)
        ESP_LOGE(TAG, "Cannot register indev driver");  
        disp_ctx.is_valid = false;      
        return NULL;

    ESP_LOGI(TAG, "Indev created");
    disp_ctx.is_valid = true;
    return indev;

display_ctx* create_display_ctx()
    ESP_LOGI(TAG, "Creating display context");
    disp_ctx.disp = init_display();
    disp_ctx.backlight = init_backlight();
    disp_ctx.indev = init_indev();
    if(!disp_ctx.is_valid || disp_ctx.disp == NULL || 
        disp_ctx.backlight == NULL || disp_ctx.indev == NULL)
        ESP_LOGE(TAG, "Cannot create display context");
        return NULL;

    ESP_LOGI(TAG, "Display context created");
    return &disp_ctx;

esp_err_t dispose(display_ctx** ctx)
    ESP_LOGI(TAG, "Disposing ");
    *ctx = NULL;
    disp_ctx.is_valid = false;
    disp_ctx.disp = NULL;
    disp_ctx.indev = NULL;
    disp_ctx.backlight = NULL;
    disp = NULL;
    indev = NULL;

    return ESP_OK;


#ifndef __DISPLAY_H__
#define __DISPLAY_H__

#include "esp_log.h"
#include "esp_err.h"
#include "lvgl.h"
#include "esp_lcd_backlight.h"

#ifdef	__cplusplus
extern "C" {

typedef struct display_ctx 
    bool is_valid; // should be allways checked and modified
    lv_disp_t* disp;
    lv_indev_t* indev;
    disp_backlight_h* backlight;
} display_ctx;

// Creating display context is recommended for create diaplay
display_ctx* create_display_ctx();
lv_disp_t* init_display();
lv_indev_t* init_indev();
disp_backlight_h* init_backlight();
void set_backlight(int percentage);
esp_err_t dispose(display_ctx** ctx);

#ifdef	__cplusplus


Logs from serial port:

I (4640) Display: Creating display context
I (4640) lvgl_helpers: Display buffer size: 0
I (4650) lvgl_helpers: Initializing SPI master for display
I (4660) lvgl_helpers: Configuring SPI host SPI2_HOST
I (4660) lvgl_helpers: MISO pin: -1, MOSI pin: 23, SCLK pin: 18, IO2/WP pin: -1, IO3/HD pin: -1
I (4670) lvgl_helpers: Max transfer size: 0 (bytes)
I (4680) lvgl_helpers: Initializing SPI bus…
I (4680) disp_spi: Adding SPI device
I (4690) disp_spi: Clock speed: 40000000Hz, mode: 0, CS pin: 5
I (4890) ILI9341: Initialization.
I (5090) ILI9341: Display orientation: LANDSCAPE
I (5090) ILI9341: 0x36 command value: 0x28
I (5090) disp_backlight: Setting LCD backlight: 100%
I (5090) lvgl_helpers: Initializing SPI master for touch
I (5100) lvgl_helpers: Configuring SPI host SPI3_HOST
I (5100) lvgl_helpers: MISO pin: 12, MOSI pin: 13, SCLK pin: 14, IO2/WP pin: -1, IO3/HD pin: -1
I (5110) lvgl_helpers: Max transfer size: 0 (bytes)
I (5120) lvgl_helpers: Initializing SPI bus…
I (5120) XPT2046: XPT2046 Initialization
I (5130) gpio: GPIO[26]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (5140) Display: Display task created
I (5140) Display: Display created
I (5150) Display: Initializing backlight
I (5150) Display: Backlight initialized
I (5150) Display: Creating indev
I (5160) Display: Indev created
I (5160) Display: Display context created
I (5170) disp_backlight: Setting LCD backlight: 100%

Can somebody tell me where I did mistake?

I found the problem. After updating lvgl from 7 to 8, lvgl drivers lost definitions for #define DISP_BUF_SIZE. I forgot that changed LV_HOR_RES_MAX to LV_HOR_RES but it doesn’t work properly. Temporarly hardcoded this variable to display horizontal dimmension.


1 Like

@tomacaster I have a similar issue

I’m struggling to use the display MPI3501 with ESP32.
I tested with Bodmer TFT_eSPI library on Arduino IDE, and everything works.
Then I start using ESP-IDF
I tested with an example from maker fans (Sunton 2.8 but I edit for a 3.5”)with the proper drivers from the lvgl_esp32_drivers.

At first it worked, the display shows everything but the touch didn’t work, but I soon noticed that on the xpt2046.h the pins assignments were incorrect for my pin configuration. I change it to be the same than display SPI, and the problem started. The touch works because I can see the x y values on the monitor but the display do not shows nothing (sometimes garbage, or blinks at fast rate).

I’m using the same SPI Bus, both Half duplex. The display is RPI TOUCHSCREEN 3.5” MPI3501, with xpt2046 controller, using Ili9486, 20MHZ for SPI and 2.5Mhz.

I opted for the lvgl cause I want to build an interface with multiple tabs

Thanks In advance

it sounds like you aren’t driving your CS line high when the display is not being written to. The CS line is what controls which device is supposed to read the data. You should have one for the touch and another for the Display. when one is high the other is supposed to be low.