Skip to content

Commit 8292989

Browse files
committed
modules: lvgl: Add zephyr OSAL implementation
This patch adds the OSAL implementation of dynamic thread creation, mutex and thread syncronization primitive (semaphore) enabling the use of the parallel rendering architecture provided with LVGL 9.0. To use it, set `CONFIG_LV_Z_USE_OSAL` and your preferred dynamic thread stack allocation method (pool or heap). Signed-off-by: Fabian Blatz <[email protected]>
1 parent 7c7bf42 commit 8292989

File tree

5 files changed

+195
-0
lines changed

5 files changed

+195
-0
lines changed

modules/lvgl/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ zephyr_library_sources_ifdef(CONFIG_LV_Z_BUTTON_INPUT input/lvgl_button_input.c)
329329
zephyr_library_sources_ifdef(CONFIG_LV_Z_ENCODER_INPUT input/lvgl_encoder_input.c)
330330
zephyr_library_sources_ifdef(CONFIG_LV_Z_KEYPAD_INPUT input/lvgl_keypad_input.c)
331331

332+
zephyr_library_sources_ifdef(CONFIG_LV_Z_USE_OSAL lvgl_zephyr_osal.c)
333+
332334
zephyr_library_link_libraries(LVGL)
333335
target_link_libraries(LVGL INTERFACE zephyr_interface)
334336

modules/lvgl/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ config LV_DRAW_DMA2D_HAL_INCLUDE
155155
Must be defined to include path of CMSIS header of target processor
156156
e.g. "stm32f769xx.h" or "stm32f429xx.h"
157157

158+
config LV_Z_USE_OSAL
159+
bool "Use OSAL enabling parallel rendering"
160+
depends on DYNAMIC_THREAD
161+
help
162+
Use the Zephyr LVGL OSAL to enable parallel rendering
163+
pipelines.
164+
158165
rsource "Kconfig.memory"
159166
rsource "Kconfig.input"
160167
rsource "Kconfig.shell"

modules/lvgl/include/lv_conf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
#define LV_COLOR_16_SWAP 1
4040
#endif /* CONFIG_LV_COLOR_16_SWAP */
4141

42+
#ifdef CONFIG_LV_Z_USE_OSAL
43+
#define LV_USE_OS LV_OS_CUSTOM
44+
#define LV_OS_CUSTOM_INCLUDE "lvgl_zephyr_osal.h"
45+
#endif /* CONFIG_LV_Z_USE_OSAL */
46+
4247
/*
4348
* Needed because of a workaround for a GCC bug,
4449
* see https://github.com/lvgl/lvgl/issues/3078
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) 2024 Fabian Blatz <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_MODULES_LVGL_ZEPHYR_OSAL_H_
8+
#define ZEPHYR_MODULES_LVGL_ZEPHYR_OSAL_H_
9+
10+
#include <zephyr/kernel.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
typedef struct {
17+
k_tid_t tid;
18+
k_thread_stack_t *stack;
19+
struct k_thread thread;
20+
} lv_thread_t;
21+
22+
typedef struct k_mutex lv_mutex_t;
23+
24+
typedef struct k_sem lv_thread_sync_t;
25+
26+
#ifdef __cplusplus
27+
}
28+
#endif
29+
30+
#endif /* ZEPHYR_MODULES_LVGL_ZEPHYR_OSAL_H_ */

modules/lvgl/lvgl_zephyr_osal.c

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* Copyright (c) 2024 Fabian Blatz <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "lvgl_zephyr_osal.h"
8+
#include <lvgl.h>
9+
10+
#include <zephyr/logging/log.h>
11+
LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL);
12+
13+
typedef void (*lv_thread_entry)(void *);
14+
static void thread_entry(void *thread, void *cb, void *user_data);
15+
16+
lv_result_t lv_thread_init(lv_thread_t *thread, lv_thread_prio_t prio, void (*callback)(void *),
17+
size_t stack_size, void *user_data)
18+
{
19+
int thread_priority;
20+
21+
thread->stack = k_thread_stack_alloc(stack_size, 0);
22+
if (thread->stack == NULL) {
23+
return LV_RESULT_INVALID;
24+
}
25+
26+
thread_priority = (CONFIG_NUM_PREEMPT_PRIORITIES - 1) -
27+
((prio * (CONFIG_NUM_PREEMPT_PRIORITIES - 1)) / LV_THREAD_PRIO_HIGHEST);
28+
29+
thread->tid = k_thread_create(&thread->thread, thread->stack, stack_size, thread_entry,
30+
thread, callback, user_data, thread_priority, 0, K_NO_WAIT);
31+
32+
return LV_RESULT_OK;
33+
}
34+
35+
lv_result_t lv_thread_delete(lv_thread_t *thread)
36+
{
37+
int ret;
38+
39+
k_thread_abort(thread->tid);
40+
ret = k_thread_stack_free(thread->stack);
41+
if (ret < 0) {
42+
LOG_ERR("Failled to delete thread: %d", ret);
43+
return LV_RESULT_INVALID;
44+
}
45+
46+
return LV_RESULT_OK;
47+
}
48+
49+
lv_result_t lv_mutex_init(lv_mutex_t *mutex)
50+
{
51+
k_mutex_init(mutex);
52+
return LV_RESULT_OK;
53+
}
54+
55+
lv_result_t lv_mutex_lock(lv_mutex_t *mutex)
56+
{
57+
int ret;
58+
59+
ret = k_mutex_lock(mutex, K_FOREVER);
60+
if (ret != 0) {
61+
LOG_ERR("Failed to lock mutex: %d", ret);
62+
return LV_RESULT_INVALID;
63+
}
64+
65+
return LV_RESULT_OK;
66+
}
67+
68+
lv_result_t lv_mutex_lock_isr(lv_mutex_t *mutex)
69+
{
70+
int ret;
71+
72+
ret = k_mutex_lock(mutex, K_NO_WAIT);
73+
if (ret != 0) {
74+
LOG_ERR("Failed to lock mutex: %d", ret);
75+
return LV_RESULT_INVALID;
76+
}
77+
78+
return LV_RESULT_OK;
79+
}
80+
81+
lv_result_t lv_mutex_unlock(lv_mutex_t *mutex)
82+
{
83+
int ret;
84+
85+
ret = k_mutex_unlock(mutex);
86+
if (ret != 0) {
87+
LOG_ERR("Failed to unlock mutex: %d", ret);
88+
return LV_RESULT_INVALID;
89+
}
90+
91+
return LV_RESULT_OK;
92+
}
93+
94+
lv_result_t lv_mutex_delete(lv_mutex_t *mutex)
95+
{
96+
ARG_UNUSED(mutex);
97+
return LV_RESULT_OK;
98+
}
99+
100+
lv_result_t lv_thread_sync_init(lv_thread_sync_t *sync)
101+
{
102+
int ret;
103+
104+
ret = k_sem_init(sync, 0, 1);
105+
if (ret != 0) {
106+
LOG_ERR("Failed to init thread sync: %d", ret);
107+
return LV_RESULT_INVALID;
108+
}
109+
110+
return LV_RESULT_OK;
111+
}
112+
113+
lv_result_t lv_thread_sync_wait(lv_thread_sync_t *sync)
114+
{
115+
int ret;
116+
117+
ret = k_sem_take(sync, K_FOREVER);
118+
if (ret < 0) {
119+
LOG_ERR("Error waiting on thread sync: %d", ret);
120+
return LV_RESULT_INVALID;
121+
}
122+
123+
return LV_RESULT_OK;
124+
}
125+
126+
lv_result_t lv_thread_sync_signal(lv_thread_sync_t *sync)
127+
{
128+
k_sem_give(sync);
129+
return LV_RESULT_OK;
130+
}
131+
132+
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t *sync)
133+
{
134+
k_sem_give(sync);
135+
return LV_RESULT_OK;
136+
}
137+
138+
lv_result_t lv_thread_sync_delete(lv_thread_sync_t *sync)
139+
{
140+
ARG_UNUSED(sync);
141+
return LV_RESULT_OK;
142+
}
143+
144+
void thread_entry(void *thread, void *cb, void *user_data)
145+
{
146+
__ASSERT_NO_MSG(cb != NULL);
147+
lv_thread_entry entry_cb = (lv_thread_entry)cb;
148+
149+
entry_cb(user_data);
150+
lv_thread_delete((lv_thread_t *)thread);
151+
}

0 commit comments

Comments
 (0)