Skip to content

modules: lvgl: add automatic lv_timer_handler call #93281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions modules/lvgl/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,31 @@ config LV_Z_INIT_PRIORITY
help
Priority used for the automatic initialization of LVGL.

config LV_Z_RUN_LVGL_ON_WORKQUEUE
bool "Use a dedicated workqueue to run LVGL core"
imply LV_Z_AUTO_INIT
help
Runs the LVGL in a separate workqueue automatically
without requiring user to add a timed loop for that. User can
disable this option if periodic calls of LV timer
is application responsibillity

if LV_Z_RUN_LVGL_ON_WORKQUEUE

config LV_Z_LVGL_WORKQUEUE_STACK_SIZE
int "Stack size of LVGL workqueue"
default 4096
help
Stack size of the LVGL dedicated workqueue

config LV_Z_LVGL_WORKQUEUE_PRIORITY
int "Priority of the LVGL workqueue"
default 0
help
Priority of the LVGL dedicated workequeue.

endif # LV_Z_RUN_LVGL_ON_WORKQUEUE

config LV_USE_DRAW_DMA2D
bool

Expand Down
14 changes: 14 additions & 0 deletions modules/lvgl/include/lvgl_zephyr.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ extern "C" {
*/
int lvgl_init(void);

#ifdef CONFIG_LV_Z_RUN_LVGL_ON_WORKQUEUE
/**
* @brief Gets the instance of LVGL's workqueue
*
* This function returns the workqueue instance used
* by LVGL core, allowing user to submit their own
* work items to it.
*
* @return pointer to LVGL's workqueue instance
*/
struct k_work_q *lvgl_get_workqueue(void);

#endif /* CONFIG_LV_Z_RUN_LVGL_ON_WORKQUEUE */

#ifdef __cplusplus
}
#endif
Expand Down
34 changes: 34 additions & 0 deletions modules/lvgl/lvgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,31 @@ static int lvgl_allocate_rendering_buffers(lv_display_t *display)
}
#endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */

#ifdef CONFIG_LV_Z_RUN_LVGL_ON_WORKQUEUE

static K_THREAD_STACK_DEFINE(lvgl_workqueue_stack, CONFIG_LV_Z_LVGL_WORKQUEUE_STACK_SIZE);
static struct k_work_q lvgl_workqueue;

static void lvgl_timer_handler_work(struct k_work *work)
{
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
uint32_t wait_time = lv_timer_handler();

/* schedule next timer verification */
if (wait_time == LV_NO_TIMER_READY) {
wait_time = CONFIG_LV_DEF_REFR_PERIOD;
}

k_work_schedule_for_queue(&lvgl_workqueue, dwork, K_MSEC(wait_time));
}
static K_WORK_DELAYABLE_DEFINE(lvgl_work, lvgl_timer_handler_work);

struct k_work_q *lvgl_get_workqueue(void)
{
return &lvgl_workqueue;
}
#endif /* CONFIG_LV_Z_RUN_LVGL_ON_WORKQUEUE */

void lv_mem_init(void)
{
#ifdef CONFIG_LV_Z_MEM_POOL_SYS_HEAP
Expand Down Expand Up @@ -326,6 +351,15 @@ int lvgl_init(void)
return err;
}

#ifdef CONFIG_LV_Z_RUN_LVGL_ON_WORKQUEUE
k_work_queue_init(&lvgl_workqueue);
k_work_queue_start(&lvgl_workqueue, lvgl_workqueue_stack,
K_THREAD_STACK_SIZEOF(lvgl_workqueue_stack),
CONFIG_LV_Z_LVGL_WORKQUEUE_PRIORITY, NULL);

k_work_submit_to_queue(&lvgl_workqueue, &lvgl_work.work);
#endif

return 0;
}

Expand Down