Avoiding the refresh timer when there is no update

Description

The question is related to the pull request I posted here:

Once the UI has been set up, the LVGL program is structured around an event loop, driven by the window manager. The loop waits on a new event and then handles it. The loop also needs to handle any timers set by LVGL, so it should sleep for at most the time specified by the nearest timer.

The issue is that the display refresh timer is set up for 33ms (at least by default), which means that the blocking call to get an event wakes up every such period, regardless if there is anything to do.

What MCU/Processor/Board and compiler are you using?

Raspberry Pi 4

What LVGL version are you using?

Latest master (as of this week)

What do you want to achieve?

Avoid excessive wakeups

What have you tried so far?

Added the following to the beginning of the function that runs the loop

lv_display_delete_refr_timer(disp);

and then inside the loop

        /*Draw explicitly, since the refresh timer is disabled.*/
        _lv_display_refr_timer(NULL);

        /*Calculate the next timeout*/
        uint32_t timeout_ms = lv_timer_handler();
        if(timeout_ms == LV_NO_TIMER_READY) {
            timeout_ns = -1UL;
        }
        else {
            timeout_ns = (uint64_t)timeout_ms * 1000000UL;
        }

The problem with this approach is that now _lv_display_refr_timer(NULL) is called for every event (think moving the mouse across the window). Ideally there would be some flag to say “refresh needed”, and then I can set up a one-shot timer to do a refresh once.

The solution should handle two cases:

  1. Synchronous: the window needs to be redrawn as a result of some LVGL callback invoked by the current event (e.g., a window changing its state after being clicked)
  2. Asynchronous: An element changing its state in response to some external event, likely handled by a separate thread (e.g., a new sensor reading sets a value to be displayed in a label)

Thanks,
–Elad

OK, I think I figured it out, but I could really use some feedback.
To ensure that the window is redrawn if, and only if, needed, I have taken over the refresh timer’s callback. The new callback calls lv_refr_now() and then pauses the refresh timer. It is assumed that any future event that triggers redrawing will resume the timer.

Does this make sense? Are there any edge conditions that get missed?
This is the diff:

–Elad