From 6b3b9ce0edb8c241cf45921a456f7e3d380e4392 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 15 Jul 2026 11:31:25 +0200 Subject: [PATCH] Fix load-dependent DSI flicker: TRIPLE_PARTIAL -> TRIPLE_FULL tear-avoid Root cause (investigation): the BSP default tear-avoid mode is TRIPLE_PARTIAL. On ESP-IDF 5.5 the MIPI-DSI driver has no on_frame_buf_complete callback (added in IDF 6.0 -> the boot warning "buffer-switch...may not function on MIPI DSI"), so the adapter falls back to on_refresh_done, which fires every refresh (~60Hz) as a fake vsync. In PARTIAL mode that release path is NOT submit-gated, so when one LVGL frame takes >1 refresh to render it over-releases the buffer that is still being scanned out -> LVGL draws into the live front buffer -> tearing/flicker. Why it only started with the wake word, and only under load: at idle (sparse rain) a frame renders in <16.6ms so exactly one submit per refresh -> harmless. The always-on WakeNet added constant CPU/PSRAM load that pushed the heavy-rain frames (listening=16, thinking=40 streams) past one refresh -> triggered the over-release. User correctly identified it as a resource starve exposing the latent bug. Fix: switch to TRIPLE_FULL, which IS submit-gated even without the callback (one release per actual submit). Same 3 framebuffers, zero memory cost, app-side one-liner via bsp_display_start_with_config so the managed component is untouched. Trade-off: full-screen redraw per frame; if the rain gets choppy under load, cheaper rain rendering (canvas / half-rate tick) is the follow-up. Co-Authored-By: Claude Fable 5 --- firmware/main/desklock_main.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/firmware/main/desklock_main.c b/firmware/main/desklock_main.c index 2e036f5..fbde868 100644 --- a/firmware/main/desklock_main.c +++ b/firmware/main/desklock_main.c @@ -142,7 +142,18 @@ void app_main(void) s_events = xQueueCreate(8, sizeof(app_event_t)); - bsp_display_start(); + /* TRIPLE_FULL, not the BSP default TRIPLE_PARTIAL: on IDF 5.5 the DSI driver + * lacks the on_frame_buf_complete callback, so PARTIAL mode falls back to a + * per-refresh "fake vsync" that over-releases the scanout buffer when a frame + * takes >1 refresh to draw (heavy rain + always-on WakeNet) -> tearing/flicker. + * TRIPLE_FULL is submit-gated even without that callback. Same 3 framebuffers. */ + bsp_display_cfg_t disp_cfg = { + .lv_adapter_cfg = ESP_LV_ADAPTER_DEFAULT_CONFIG(), + .rotation = ESP_LV_ADAPTER_ROTATE_0, + .tear_avoid_mode = ESP_LV_ADAPTER_TEAR_AVOID_MODE_TRIPLE_FULL, + .touch_flags = { .swap_xy = 0, .mirror_x = 0, .mirror_y = 0 }, + }; + bsp_display_start_with_config(&disp_cfg); bsp_display_backlight_on(); face_init();