task_handler: fix LVGL time running ~1.8x fast (double tick_inc) - #13
Open
bitcoin3us wants to merge 1 commit into
Open
bitcoin3us wants to merge 1 commit into
bitcoin3us wants to merge 1 commit into
Conversation
LVGL time ran ~1.8x faster than wall clock on ESP32 builds: _timer_cb added the nominal period on every machine.Timer tick while _task_handler also added the elapsed time on every scheduled pass (plus a third increment covering the FINISHED callbacks). Every lv timer, animation, scroll throw and long-press threshold therefore fired early; a 12 fps lv.timer produced 14 frames per second. Measured on a Waveshare ESP32-S3-Touch-LCD-3.5 (MicroPythonOS 0.18): lv.tick_get() advanced 1.834 ms per wall-clock ms when idle. With TaskHandler.disable() (timer path only) the ratio was exactly 1.000, and under load the timer path alone lost ~20% of ticks because scheduled callbacks coalesce. Make _timer_cb the only place ticks are added, and have it add the real elapsed milliseconds since its previous run instead of the nominal period, so LVGL time equals wall time regardless of load. Verified 1.000 idle and under flash-read load; a stalled scheduler now catches up instead of losing time. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
LVGL time runs about 1.8x faster than wall clock on ESP32 builds.
task_handler.pyfeedslv.tick_inc()from two places at once:_timer_cbadds the nominal period on everymachine.Timertick (2 ms on MicroPythonOS, which callschange_task_handler(period_ms=2)), and_task_handleradds the elapsed time since its previous pass on every scheduled run, plus a third increment covering theTASK_HANDLER_FINISHEDcallbacks.Every
lv.timer, animation, scroll throw and long-press threshold therefore fires early. It was noticed because a video player'slv.timer_create(cb, 1000 // 12)produced 14 frames per second.Measurements (Waveshare ESP32-S3-Touch-LCD-3.5, MicroPythonOS 0.18)
lv.tick_get()advance pertime.ticks_ms()advance:TaskHandler.disable()(timer path only)deinit()'dThe stock timer path alone loses ~20% of ticks under load because timer callbacks are delivered through the scheduler and coalesce or drop; the handler-side increment was masking that loss by double counting.
Fix
Make
_timer_cbthe only place ticks are added, and have it add the real elapsed milliseconds since its previous run instead of the nominal period. LVGL time then equals wall time regardless of load, and a stalled scheduler (long C call, raw-REPL transfer) catches up afterwards instead of losing time. Net diff: 8 insertions, 14 deletions in one file.Verification
mpos.ui.change_task_handler(): ratio 1.000 idle and under load, exactly 500 ms per 500 ms sleep.scripts/build_mpos.sh esp32s3, headroom unchanged at 50288 bytes): ratio 1.000 in every settled window across two boots; a 12 fpslv.timernow paces at 11.4 fps instead of running free at 14.2.Notes
tick_inccalls exist in upstream lvgl-micropython/lvgl_micropython, so the bug is inherited, not local.scripts/web_port/staged_lib/task_handler.pyin the MicroPythonOS repo) has no timer-side increment and is not affected by the 1.8x error; it only carries the minor FINISHED-callback double count.🤖 Generated with Claude Code
With thanks to the scientists and engineers who did the hard, unglamorous work that got us here.