Screen glitch on refreshing GUI on ESP32-S3

Description

Hello, I have a problem with refreshing GUI, because sometimes appears some kind of glitch (mostly on bottom side of display but simetimes whole screen). The screen is a little bit moved to the right, and then come back to the correct position.
It’s happen more often when there is some animation.

I have no idea what can I change to fix this behavior. Do you have explanation of this ? How can I fix it ?

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

MCU: ESP32-S3 WROOM 1
GUI: ESP32-8048S070 SPI, 800x480
Arduino/Platformio

What LVGL version are you using?

8.2.0

What do you want to achieve?

Screen not moving to the right side periodactly.

What have you tried so far?

I was trying to increase buffers:

  • LV_MEM_SIZE to 60 * 1024 (also LV_MEM_CUSTOM form 0 to 1)
  • LV_MEM_BUF_MAX_NUM to 32
  • LV_MEMCPY_MEMSET_STD to 1
  • lv_disp_draw_buf_init(.. , disp_draw_buf, ..) to 256 kB (ESP has around 350).
  • LV_DISP_DEF_REFR_PERIOD to 40
  • LV_INDEV_DEF_READ_PERIOD to 40

Also I have tried moved lv_timer_handler() to different RTOS task, but without result.

Code to reproduce

Here is a part of implementation


#define TFT_BL 2
Arduino_ESP32RGBPanel *bus = new Arduino_ESP32RGBPanel(
    GFX_NOT_DEFINED /* CS */, GFX_NOT_DEFINED /* SCK */, GFX_NOT_DEFINED /* SDA */,
    41 /* DE */, 40 /* VSYNC */, 39 /* HSYNC */, 42 /* PCLK */,
    14 /* R0 */, 21 /* R1 */, 47 /* R2 */, 48 /* R3 */, 45 /* R4 */,
    9 /* G0 */, 46 /* G1 */, 3 /* G2 */, 8 /* G3 */, 16 /* G4 */, 1 /* G5 */,
    15 /* B0 */, 7 /* B1 */, 6 /* B2 */, 5 /* B3 */, 4 /* B4 */
);

Arduino_RPi_DPI_RGBPanel *gfx = new Arduino_RPi_DPI_RGBPanel(
    bus,
    800 /* width */, 0 /* hsync_polarity */, 210 /* hsync_front_porch */, 30 /* hsync_pulse_width */, 16 /* hsync_back_porch */,
    480 /* height */, 0 /* vsync_polarity */, 22 /* vsync_front_porch */, 13 /* vsync_pulse_width */, 10 /* vsync_back_porch */,
    1 /* pclk_active_neg */, 16000000 /* prefer_speed */, true /* auto_flush */);

#include "touch.h"

void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);

#if (LV_COLOR_16_SWAP != 0)
    gfx->draw16bitBeRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
#else
    gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
#endif

    lv_disp_flush_ready(disp);
}

void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
    if (touch_has_signal())
    {
        if (touch_touched())
        {
            data->state = LV_INDEV_STATE_PR;
            data->point.x = touch_last_x;
            data->point.y = touch_last_y;
        }
        else if (touch_released())
        {
            data->state = LV_INDEV_STATE_REL;
        }
    }
    else
    {
        data->state = LV_INDEV_STATE_REL;
    }
}

void GUI::init()
{
    gfx->begin();

#ifdef TFT_BL
    pinMode(TFT_BL, OUTPUT);
    digitalWrite(TFT_BL, HIGH);

    ledcSetup(0, 300, 8);
    ledcAttachPin(TFT_BL, 0);
    setBrightness(DEFAULT_BRIGHTNESS_VALUE);
#endif

    lv_init();

    // Init touch device
    pinMode(TOUCH_GT911_RST, OUTPUT);
    digitalWrite(TOUCH_GT911_RST, LOW);
    delay(10);
    digitalWrite(TOUCH_GT911_RST, HIGH);
    delay(10);
    touch_init();

    screenWidth = gfx->width();
    screenHeight = gfx->height();

    std::uint32_t targetDrawBuffSize = (screenWidth * screenHeight * sizeof(lv_color_t)) / 3;
    disp_draw_buf = (lv_color_t *)heap_caps_malloc(targetDrawBuffSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);

    if (!disp_draw_buf)
    {
        Serial.println("LVGL disp_draw_buf allocate failed!");
    }
    else
    {
        // lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, disp_draw_buf2, (screenWidth * screenHeight) / 8);
        lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, targetDrawBuffSize / sizeof(lv_color_t));

        /* Initialize the display */
        lv_disp_drv_init(&disp_drv);
        /* Change the following line to your display resolution */
        disp_drv.hor_res = screenWidth;
        disp_drv.ver_res = screenHeight;
        disp_drv.flush_cb = my_disp_flush;
        disp_drv.draw_buf = &draw_buf;
        lv_disp_drv_register(&disp_drv);

        /* Initialize the (dummy) input device driver */
        static lv_indev_drv_t indev_drv;
        lv_indev_drv_init(&indev_drv);
        indev_drv.type = LV_INDEV_TYPE_POINTER;
        indev_drv.read_cb = my_touchpad_read;
        lv_indev_drv_register(&indev_drv);

        ui_init();

        Serial.println("Setup done");
    }

    // And code with RTOS
    SERIALCONSOLE.println(xTaskCreatePinnedToCore(
        refreshGuiTask,
        "Refresh GUI Task",
        4024,
        NULL,
        19,
        NULL,
        0));
}

And some implementation of GUI

void ui_screen_charts_init()
{
    ui_ScreenCharts = lv_obj_create(NULL);
    lv_obj_clear_flag(ui_ScreenCharts, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_style_bg_img_src(ui_ScreenCharts, &ui_img_background_png, LV_PART_MAIN | LV_STATE_DEFAULT);

    lv_obj_t *ui_buttonPrev = ui_ButtonPrev_create(ui_ScreenCharts);
    lv_obj_align_to(ui_buttonPrev, ui_ScreenCharts, LV_ALIGN_BOTTOM_LEFT, 10, -10);
    lv_obj_add_event_cb(ui_buttonPrev, ui_event_buttonGoToControl, LV_EVENT_ALL, NULL);

    ui_cellsChart = lv_chart_create(ui_ScreenCharts);
    lv_obj_clear_flag(ui_cellsChart, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_width(ui_cellsChart, 690);
    lv_obj_set_height(ui_cellsChart, 360);
    lv_obj_set_align(ui_cellsChart, LV_ALIGN_CENTER);
    lv_obj_align_to(ui_cellsChart, ui_ScreenCharts, LV_ALIGN_TOP_RIGHT, -10, 56);
   ...
    lv_obj_add_event_cb(ui_cellsChart, chart_cell_series_event_cb, LV_EVENT_ALL, NULL);

    ui_cellsChart2 = lv_chart_create(ui_ScreenCharts);
    lv_obj_clear_flag(ui_cellsChart2, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_width(ui_cellsChart2, 690);
    lv_obj_set_height(ui_cellsChart2, 180);
    lv_obj_align_to(ui_cellsChart2, ui_ScreenCharts, LV_ALIGN_BOTTOM_RIGHT, -10, -30);
   ...
    lv_obj_add_flag(ui_cellsChart2, LV_OBJ_FLAG_HIDDEN);
    lv_obj_add_event_cb(ui_cellsChart2, chart_cell_series_event_cb, LV_EVENT_ALL, NULL);
}

void ui_init(void)
{
    LV_EVENT_GET_COMP_CHILD = lv_event_register_id();

    lv_disp_t *dispp = lv_disp_get_default();
    lv_theme_t *theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), true, LV_FONT_DEFAULT);
    lv_disp_set_theme(dispp, theme);
    ui_screen_charts_init();
    ui____initial_actions0 = lv_obj_create(NULL);

    lv_disp_load_scr(ui_ScreenHome);
    ui_currentScreen = Home;
}

Screenshot and/or video

Example of glitch (it happens not only on charts, but in any case of content type)
20240111_012658-ezgif.com-video-to-gif-converter (1)

I don’t know what version of the Arduino GFX library you are using but the most recent version would make your code look like this.

Arduino_ESP32RGBPanel *gfx = new Arduino_ESP32RGBPanel(
    41 /* DE */, 40 /* VSYNC */, 39 /* HSYNC */, 42 /* PCLK */,
    14 /* R0 */, 21 /* R1 */, 47 /* R2 */, 48 /* R3 */, 45 /* R4 */,
    9 /* G0 */, 46 /* G1 */, 3 /* G2 */, 8 /* G3 */, 16 /* G4 */, 1 /* G5 */,
    15 /* B0 */, 7 /* B1 */, 6 /* B2 */, 5 /* B3 */, 4 /* B4 */
    0 /* hsync_polarity */, 210 /* hsync_front_porch */, 30 /* hsync_pulse_width */, 16 /* hsync_back_porch */,
    0 /* vsync_polarity */, 22 /* vsync_front_porch */, 13 /* vsync_pulse_width */, 10 /* vsync_back_porch */,
    1 /* pclk_active_neg */, 16000000 /* prefer_speed */, false /* useBigEndian */,
    0 /* de_idle_high */, 0 /* pclk_idle_high */
);

void GUI::init()
{
    gfx->begin(GFX_NOT_DEFINED);

#ifdef TFT_BL
    pinMode(TFT_BL, OUTPUT);
    digitalWrite(TFT_BL, HIGH);

    ledcSetup(0, 300, 8);
    ledcAttachPin(TFT_BL, 0);
    setBrightness(DEFAULT_BRIGHTNESS_VALUE);
#endif

    lv_init();

    pinMode(TOUCH_GT911_RST, OUTPUT);
    digitalWrite(TOUCH_GT911_RST, LOW);
    delay(10);
    digitalWrite(TOUCH_GT911_RST, HIGH);
    delay(10);
    touch_init();



    uint16_t *disp_draw_buf = gfx->getFrameBuffer(800 /* width */, 480 /* height */);

    if (!disp_draw_buf)
    {
        Serial.println("LVGL disp_draw_buf allocate failed!");
    }
    else
    {
        // I am not sure where draw_buf and displ_drv are declared.

        lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, 800 * 480 * 2);

        /* Initialize the display */
        lv_disp_drv_init(&disp_drv);
        /* Change the following line to your display resolution */
        disp_drv.hor_res = 800;
        disp_drv.ver_res = 480;
        disp_drv.flush_cb = my_disp_flush;
        disp_drv.draw_buf = &draw_buf;
        disp_drv.direct_mode = true;

        lv_disp_drv_register(&disp_drv);

        /* Initialize the (dummy) input device driver */
        static lv_indev_drv_t indev_drv;
        lv_indev_drv_init(&indev_drv);
        indev_drv.type = LV_INDEV_TYPE_POINTER;
        indev_drv.read_cb = my_touchpad_read;
        lv_indev_drv_register(&indev_drv);

        ui_init();

        Serial.println("Setup done");
    }
    
    // And code with RTOS
    SERIALCONSOLE.println(xTaskCreatePinnedToCore(
        refreshGuiTask,
        "Refresh GUI Task",
        4024,
        NULL,
        19,
        NULL,
        0));
}

The allocation of the frame buffer gets handled internally by the arduino GFX library. I personally don’t care for how it is going about handling the creation of the panel and it forcing you to only be able to use a single frame buffer but it is what it is.

Have you tried this new library that supports those 8040SXXX boards?