diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index 41fbca0..a7c4e95 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -1,4 +1,18 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# Grow LVGL's invalidation buffer (default 32) so the ~80 moving rain labels of the +# busy face states stay as separate partial-redraw rects instead of collapsing into +# one full-screen redraw. Secondary mitigation for the DSI PSRAM-bandwidth underrun +# (primary fix is the reduced DPI clock in the BSP): a full-screen redraw dumps a +# ~1.3 MB PSRAM write burst that competes with the DSI's continuous framebuffer read +# and can re-trigger the underrun; keeping busy states partial avoids that. Applied +# globally so LVGL and esp_lvgl_adapter (both size inv_areas[] by LV_INV_BUF_SIZE) +# agree. The partial-flush path's stack scales with this, so app_main starts the LVGL +# task with a 16 KB stack (see desklock_main.c) — the 8 KB default overflows at 128. +# Must sit after the project.cmake include (defines idf_build_set_property) and before +# project() consumes it. +idf_build_set_property(COMPILE_OPTIONS "-DLV_INV_BUF_SIZE=128" APPEND) + project(desklock) diff --git a/firmware/main/face.c b/firmware/main/face.c index 7b16b42..93495b6 100644 --- a/firmware/main/face.c +++ b/firmware/main/face.c @@ -153,6 +153,15 @@ static void stream_hide(stream_t *s) static void rain_tick(void) { const face_def_t *d = &DEFS[F.state]; + /* Half-rate: advance the rain every OTHER tick (double the step so the fall + * looks identical). Halves how often the 80 rain labels invalidate, cutting the + * per-frame PSRAM write traffic that competes with the DSI framebuffer read on + * the same bus — a secondary easing of the underrun the reduced DPI clock fixes. + * The clock/face still update every tick. */ + static uint8_t phase; + if (phase++ & 1) { + return; + } /* Rain is the reachability signal: it only falls when the gateway is live. * A disconnect drains it gracefully (streams finish falling, none respawn). */ int target = (F.power == 2 || !gw_connected()) ? 0 : d->rain_streams; @@ -163,7 +172,7 @@ static void rain_tick(void) continue; } alive++; - s->y += s->speed; + s->y += s->speed * 2; lv_obj_set_pos(s->tail, s->x, s->y); lv_obj_set_pos(s->head, s->x, s->y + s->len * 26); if (F.mutate == 0 && (esp_random() % 3) == 0) {