Periodic full-screen flicker on ESP32-S3 RGB display (LVGL 9 + Arduino_GFX, Arduino IDE) that survives buffer/timing/touch tweaks — suspect only ESP-IDF's avoid_tearing flag fixes it

What do you want to achieve?

Eliminate an intermittent, periodic full-screen flicker/glitch on an ESP32-S3 RGB parallel display (Sunton ESP32-8048S070C, 800x480), using the Arduino framework (Arduino IDE). A constant/subtle flicker was already resolved by lowering PCLK. What remains is a rare, roughly periodic full-screen flash that I have not been able to eliminate through any Arduino-side configuration.

I’ve since discovered that Espressif’s official esp_lvgl_port component exposes an avoid_tearing flag specifically designed for this class of problem, but this component is ESP-IDF only and has no equivalent in Arduino_GFX or LovyanGFX. I’d like to confirm whether that’s really the only path, or if there’s something within the Arduino ecosystem I’m missing.

What have you tried so far?

  • Moved the LVGL draw buffer from a plain static array to heap_caps_malloc with MALLOC_CAP_DMA — improved FPS from ~9 to ~26 and reduced a constant subtle flicker significantly.
  • Reduced prefer_speed (PCLK) from 16MHz to 12MHz on Arduino_ESP32RGBPanel — this fully eliminated the constant flicker. Confirmed via community reports that PCLK too high causes flicker under CPU load on this exact board.
  • Tried several different hsync/vsync porch/pulse timing combinations sourced from different community repos for the same board model — no measurable effect on the remaining periodic flick.
  • Tried increasing buffer size (up to 1/4 and 1/8 of the screen) and different heap_caps flags (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT vs MALLOC_CAP_DMA) — no improvement over the DMA + 40-line buffer baseline; larger allocations sometimes failed outright due to internal RAM fragmentation.
  • Switched the display driver to LovyanGFX (Bus_RGB/Panel_RGB, including the officially bundled lgfx_user/LGFX_Sunton_ESP32-8048S070.h config and use_psram=1 via config_detail()) — introduced new artifacts (sync corruption / wrong colors) that I couldn’t resolve, so I reverted to Arduino_GFX.
  • Suspected the GT911 I2C touch polling (happening inside the read_cb, same core as lv_timer_handler) as the cause of the periodic flick. Tried throttling the I2C read to once per 50ms — no change. Then moved touch polling entirely to a separate FreeRTOS task pinned to Core 0 (away from the core running lv_timer_handler/display refresh) — still no change.
  • Confirmed via Espressif’s own FAQ that the ESP32-S3 RGB “screen drift” bug is fixed as of ESP-IDF 5.1+/arduino-esp32 v3.x (already on 3.3.11), so that specific known bug shouldn’t apply here.
  • Found a related open GitHub issue reporting that Arduino’s precompiled esp32 core libraries ship with CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32, while Octal PSRAM DDR mode uses 64-byte wrap bursts — a mismatch that could cause periodic cache-coherency glitches. Another maker confirmed that manually patching this setting does not take effect reliably in Arduino IDE builds.

Code to reproduce

Simplified version of my current setup (Arduino_GFX + confirmed-working pinout/timing for this exact board):

#include <Arduino_GFX_Library.h>
#include <TAMC_GT911.h>
#include <lvgl.h>
#include <Wire.h>
#include "esp_heap_caps.h"

Arduino_ESP32RGBPanel *rgbpanel = 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, 8, 2, 43,     // hsync
    0, 8, 2, 12,     // vsync
    1, 12000000, false // pclk_active_neg, prefer_speed, useBigEndian
);
Arduino_RGB_Display *gfx = new Arduino_RGB_Display(800, 480, rgbpanel);

lv_color_t *buf1;

void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);
    gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)px_map, w, h);
    lv_display_flush_ready(disp);
}

void setup() {
    gfx->begin();
    pinMode(2, OUTPUT);
    digitalWrite(2, HIGH);

    size_t buf_size = 800 * 40 * sizeof(lv_color_t);
    buf1 = (lv_color_t *)heap_caps_malloc(buf_size, MALLOC_CAP_DMA);

    lv_init();
    lv_tick_set_cb(millis);

    lv_display_t *disp = lv_display_create(800, 480);
    lv_display_set_flush_cb(disp, my_disp_flush);
    lv_display_set_buffers(disp, buf1, NULL, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
    lv_display_set_default(disp);

    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello, world!");
}

void loop() {
    lv_timer_handler();
    delay(5);
}

The remaining flicker manifests as a brief full-screen flash, roughly periodic (every few seconds), even with a completely static UI (no animations, no periodic redraws in my own code) and no touch interaction at all.

Screenshot and/or video

I have a photo of an earlier, worse symptom (before the PCLK fix — full misalignment/corruption, resolved since). The current remaining issue is a brief full-screen flash that’s hard to capture in a still photo; I can try to record a video if it would help diagnose this.

Environment

  • MCU/Board: ESP32-S3-WROOM-1 (Sunton ESP32-8048S070C, 7" 800x480 RGB parallel TFT, EK9716 display driver, GT911 capacitive touch, 8MB PSRAM/OPI, 16MB Flash)
  • LVGL version: 9.2.2 (installed via Arduino Library Manager)
  • Display driver: GFX Library for Arduino (Arduino_GFX) 1.6.7
  • arduino-esp32 core: 3.3.11
  • IDE: Arduino IDE 2.3.10
  • Board settings: ESP32S3 Dev Module, USB CDC On Boot: Disabled, Flash Size 16MB, Partition Scheme 16M Flash (3MB APP/9.9MB FATFS), PSRAM: OPI PSRAM, Flash Mode QIO 80MHz, Upload Speed 921600

Hi @LeandroCesarr ,

I have the same board specs, that might help you configure hsync and vsync.

Also, I recommend you check those links :