Screen glitch while touching

I am using a Panlee ZX7D00CE01S 7-inch (800×480) display with an ESP32-S3. When I touch the screen, I experience glitches, and interacting with widgets makes it worse. According to the datasheet, the display supports RGB888 color, but in SquareLine, I can only use 16-bit (RGB565) or 32-bit (ARGB8888), both of which produce the same issue. Could this be a color format compatibility issue? If so, how can I use 24-bit RGB888? Or could the problem be related to display flushing, touch handling, or DMA? Any suggestions would be greatly appreciated.

|-- lvgl @ 8.3.9
|-- SPI @ 2.0.0
|-- LovyanGFX @ 1.1.12

#include <Arduino.h>
#include <lvgl.h>
#include "PanelLan.h"
#include "ui/ui.h"

// BOARD_SC01_PLUS, BOARD_SC02, BOARD_SC05, BOARD_KC01, BOARD_BC02, BOARD_SC07
PanelLan tft(BOARD_SC05);

/*Change to your screen resolution*/
static const uint16_t screenWidth  = 800;
static const uint16_t screenHeight = 480;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[2][ screenWidth * 10 ];

/* Display flushing */
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p )
{
    if (tft.getStartCount() == 0)
    {   // Processing if not yet started
        tft.startWrite();
    }
    tft.pushImageDMA( area->x1
                    , area->y1
                    , area->x2 - area->x1 + 1
                    , area->y2 - area->y1 + 1
                    , ( lgfx::argb8888_t* )&color_p->full);
    lv_disp_flush_ready( disp );
}

/*Read the touchpad*/

void my_touch_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
  uint16_t touchX, touchY;
  bool touched = tft.getTouch(&touchX, &touchY);
  if (!touched)
  {
    data->state = LV_INDEV_STATE_REL;
  }
  else
  {
    data->state = LV_INDEV_STATE_PR;
    data->point.x = touchX;
    data->point.y = touchY;

#if DEBUG_TOUCH != 0
    Serial.print("Data x ");
    Serial.println(touchX);
    Serial.print("Data y ");
    Serial.println(touchY);
#endif
  }
}

void setup()
{
    tft.begin();

    tft.setRotation(0);
    tft.setBrightness(255);

    lv_init();
    lv_disp_draw_buf_init( &draw_buf, buf[0], buf[1], screenWidth * 10);

    /*Initialize the display*/
    static lv_disp_drv_t disp_drv;
    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 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_touch_read;
    lv_indev_drv_register( &indev_drv );

    ui_init();
}

void loop()
{
  lv_timer_handler(); /* let the GUI do its work */
}

Hi, looking at your code, I have a few suggestions that might help with your screen glitching issue:

  1. Your buffer size seems quite small for an 800x480 display. You’re only using screenWidth * 10 pixels for the buffer, which means LVGL has to do many small updates. Try increasing your buffer size to at least 1/4 or 1/2 of the screen if your ESP32-S3 has enough RAM.
static lv_color_t buf[2][screenWidth * (screenHeight / 4)]; // 1/4 screen
  1. You’re using DMA with pushImageDMA, which is good, but you might need to manage the DMA timing better. Try adding a small delay or wait for DMA completion:
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    if (tft.getStartCount() == 0) {
        tft.startWrite();
    }
    tft.pushImageDMA(area->x1, area->y1, 
                   area->x2 - area->x1 + 1, 
                   area->y2 - area->y1 + 1,
                   (lgfx::argb8888_t*)&color_p->full);
    tft.waitDMA(); // Add this line if available in your library
    lv_disp_flush_ready(disp);
}
  1. Your touch handling looks correct, but you might want to add debouncing:
void my_touch_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
  static uint32_t lastTouchTime = 0;
  const uint32_t touchDebounce = 10; // ms
  
  uint16_t touchX, touchY;
  bool touched = tft.getTouch(&touchX, &touchY);
  
  if (millis() - lastTouchTime < touchDebounce) {
    return; // Skip if too soon after last touch
  }
  
  if (touched) {
    lastTouchTime = millis();
    data->state = LV_INDEV_STATE_PR;
    data->point.x = touchX;
    data->point.y = touchY;
  } else {
    data->state = LV_INDEV_STATE_REL;
  }
}
  1. In your loop(), try adding a small delay to give the ESP32 some breathing room:
void loop()
{
  lv_timer_handler();
  delay(5); // Give CPU some time for other tasks
}

Let me know if any of these suggestions help with your issue!

1 Like