Fix load-dependent DSI flicker: TRIPLE_PARTIAL -> TRIPLE_FULL tear-avoid
Test, Build and Push / test-gateway (push) Successful in 11s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped

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 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 11:31:25 +02:00
co-authored by Claude Fable 5
parent b462dff082
commit 6b3b9ce0ed
+12 -1
View File
@@ -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();