From 4665fd91914d84d60ea16e888d65c1a52e1cc1d0 Mon Sep 17 00:00:00 2001 From: _VIFEXTech Date: Wed, 14 Jun 2023 19:57:34 +0800 Subject: [PATCH] feat(timer): implementation of adaptive call timer handler cycle method (#4236) --- docs/porting/timer_handler.rst | 10 ++++++++ src/misc/lv_timer.c | 47 ++++++++++++++++++++++++++++++---- src/misc/lv_timer.h | 12 +++++++++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/docs/porting/timer_handler.rst b/docs/porting/timer_handler.rst index db0a4a907..56c896756 100644 --- a/docs/porting/timer_handler.rst +++ b/docs/porting/timer_handler.rst @@ -32,6 +32,16 @@ the porting: ... } +Or use the sleep time automatically calculated by LVGL: + +.. code:: c + + while(1) { + ... + lv_timer_periodic_handler(); + ... + } + In an OS environment, you can use it together with the **delay** or **sleep** provided by OS to release CPU whenever possible: diff --git a/src/misc/lv_timer.c b/src/misc/lv_timer.c index 2aed52f33..ddec6dad3 100644 --- a/src/misc/lv_timer.c +++ b/src/misc/lv_timer.c @@ -29,6 +29,7 @@ **********************/ static bool lv_timer_exec(lv_timer_t * timer); static uint32_t lv_timer_time_remaining(lv_timer_t * timer); +static void lv_timer_handler_resume(void); /********************** * STATIC VARIABLES @@ -37,6 +38,7 @@ static bool lv_timer_run = false; static uint8_t idle_last = 0; static bool timer_deleted; static bool timer_created; +static uint32_t timer_time_until_next; /********************** * MACROS @@ -121,13 +123,13 @@ LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void) } } while(LV_GC_ROOT(_lv_timer_act)); - uint32_t time_till_next = LV_NO_TIMER_READY; + uint32_t time_until_next = LV_NO_TIMER_READY; next = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll)); while(next) { if(!next->paused) { uint32_t delay = lv_timer_time_remaining(next); - if(delay < time_till_next) - time_till_next = delay; + if(delay < time_until_next) + time_until_next = delay; } next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), next); /*Find the next timer*/ @@ -142,11 +144,23 @@ LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void) idle_period_start = lv_tick_get(); } + timer_time_until_next = time_until_next; already_running = false; /*Release the mutex*/ - TIMER_TRACE("finished (%" LV_PRIu32 " ms until the next timer call)", time_till_next); + TIMER_TRACE("finished (%" LV_PRIu32 " ms until the next timer call)", time_until_next); LV_PROFILER_END; - return time_till_next; + return time_until_next; +} + +LV_ATTRIBUTE_TIMER_HANDLER void lv_timer_periodic_handler(void) +{ + static uint32_t last_tick = 0; + + if(lv_tick_elaps(last_tick) >= timer_time_until_next) { + TIMER_TRACE("calling lv_timer_handler()"); + lv_timer_handler(); + last_tick = lv_tick_get(); + } } /** @@ -185,6 +199,8 @@ lv_timer_t * lv_timer_create(lv_timer_cb_t timer_xcb, uint32_t period, void * us timer_created = true; + lv_timer_handler_resume(); + return new_timer; } @@ -222,6 +238,7 @@ void lv_timer_pause(lv_timer_t * timer) void lv_timer_resume(lv_timer_t * timer) { timer->paused = false; + lv_timer_handler_resume(); } /** @@ -261,6 +278,7 @@ void lv_timer_set_repeat_count(lv_timer_t * timer, int32_t repeat_count) void lv_timer_reset(lv_timer_t * timer) { timer->last_run = lv_tick_get(); + lv_timer_handler_resume(); } /** @@ -270,6 +288,7 @@ void lv_timer_reset(lv_timer_t * timer) void lv_timer_enable(bool en) { lv_timer_run = en; + if(en) lv_timer_handler_resume(); } /** @@ -281,6 +300,15 @@ uint8_t lv_timer_get_idle(void) return idle_last; } +/** + * Get idle period start tick + * @return the lv_timer idle period start tick + */ +uint32_t lv_timer_get_time_until_next(void) +{ + return timer_time_until_next; +} + /** * Iterate through the timers * @param timer NULL to start iteration or the previous return value to get the next timer @@ -351,3 +379,12 @@ static uint32_t lv_timer_time_remaining(lv_timer_t * timer) return 0; return timer->period - elp; } + +/** + * Call the ready lv_timer + */ +static void lv_timer_handler_resume(void) +{ + /*If there is a timer which is ready to run then resume the timer loop*/ + timer_time_until_next = 0; +} diff --git a/src/misc/lv_timer.h b/src/misc/lv_timer.h index 6857c58df..883e8d843 100644 --- a/src/misc/lv_timer.h +++ b/src/misc/lv_timer.h @@ -87,6 +87,12 @@ static inline LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler_run_in_period return 1; } +/** + * Call it in the super-loop of main() or threads. It will automatically call lv_timer_handler() at the right time. + * This function is used to simplify the porting. + */ +LV_ATTRIBUTE_TIMER_HANDLER void lv_timer_periodic_handler(void); + /** * Create an "empty" timer. It needs to be initialized with at least * `lv_timer_set_cb` and `lv_timer_set_period` @@ -165,6 +171,12 @@ void lv_timer_enable(bool en); */ uint8_t lv_timer_get_idle(void); +/** + * Get the time remaining until the next timer will run + * @return the time remaining in ms + */ +uint32_t lv_timer_get_time_until_next(void); + /** * Iterate through the timers * @param timer NULL to start iteration or the previous return value to get the next timer