Skip to content

Commit a2008e5

Browse files
PGNetHunCarglglz
andauthored
Update LVGL binding to use USER_C_MODULE approach (#365)
* gen: update to MicroPython v1.23.x * lib: Allow using lv_utils in unix-macos port. Fix to allow using lv_utils with asyncio in unix-macos. * unix: Enable lv_binding_micropython as user C mod. * esp32: Enable lv_binding_micropython as user C mod. * feat(tests): Add tests for MicroPython test suite. * fix(init/deinit): Properly init/deinit lvgl module. Properly handle root pointers on lvgl init/deinit which fixes init error after a soft reset (see #343). * fix(gen_mpy.py): update lv_to_mp float conversion. Upate for lvgl 9.2.x see diff in lvgl @ 84b28ff * fix(esp32): lvgl component error in idf v5.2.x. * fix(lv_conf): enable LV_USE_PRIVATE_API for v9.2.0 * fix(build): enable LV_CONF_PATH option This allows to set custom `lv_conf.h` file per board in `mpconfigboard.(h,cmake)` * fix(tests): fix testdisplay, add hwdisplay example * feat(lvgl): update to lvgl v9.2.2 * fix(makefile): use CLFAGS_USERMOD * feat(lvgl): update to latest v9.3.0 * fix(tests): fix testdisplay and add calibrate tool * fix(build): fix LV_CONF_PATH option for CMake --------- Co-authored-by: Carlosgg <[email protected]>
1 parent 96d6d35 commit a2008e5

34 files changed

+3361
-861
lines changed

gen/gen_mpy.py

Lines changed: 1596 additions & 830 deletions
Large diffs are not rendered by default.

lib/lv_utils.py

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,27 @@
1212
# event_loop = lv_utils.event_loop()
1313
#
1414
#
15-
# uasyncio example with SDL:
15+
# asyncio example with SDL:
1616
#
1717
# SDL.init(auto_refresh=False)
1818
# # Register SDL display driver.
1919
# # Register SDL mouse driver
2020
# event_loop = lv_utils.event_loop(asynchronous=True)
21-
# uasyncio.Loop.run_forever()
21+
# asyncio.Loop.run_forever()
2222
#
23-
# uasyncio example with ili9341:
23+
# asyncio example with ili9341:
2424
#
2525
# event_loop = lv_utils.event_loop(asynchronous=True) # Optional!
2626
# self.disp = ili9341(asynchronous=True)
27-
# uasyncio.Loop.run_forever()
27+
# asyncio.Loop.run_forever()
2828
#
2929
# MIT license; Copyright (c) 2021 Amir Gonnen
3030
#
3131
##############################################################################
3232

3333
import lvgl as lv
3434
import micropython
35-
import usys
35+
import sys
3636

3737
# Try standard machine.Timer, or custom timer from lv_timer, if available
3838

@@ -42,34 +42,45 @@
4242
try:
4343
from lv_timer import Timer
4444
except:
45-
raise RuntimeError("Missing machine.Timer implementation!")
45+
if sys.platform != "darwin":
46+
raise RuntimeError("Missing machine.Timer implementation!")
47+
Timer = False
4648

4749
# Try to determine default timer id
4850

4951
default_timer_id = 0
50-
if usys.platform == 'pyboard':
52+
if sys.platform == "pyboard":
5153
# stm32 only supports SW timer -1
5254
default_timer_id = -1
53-
54-
if usys.platform == 'rp2':
55+
56+
if sys.platform == "rp2":
5557
# rp2 only supports SW timer -1
5658
default_timer_id = -1
5759

58-
# Try importing uasyncio, if available
60+
# Try importing asyncio, if available
5961

6062
try:
61-
import uasyncio
62-
uasyncio_available = True
63+
import asyncio
64+
65+
asyncio_available = True
6366
except:
64-
uasyncio_available = False
67+
asyncio_available = False
6568

6669
##############################################################################
6770

68-
class event_loop():
6971

72+
class event_loop:
7073
_current_instance = None
7174

72-
def __init__(self, freq=25, timer_id=default_timer_id, max_scheduled=2, refresh_cb=None, asynchronous=False, exception_sink=None):
75+
def __init__(
76+
self,
77+
freq=25,
78+
timer_id=default_timer_id,
79+
max_scheduled=2,
80+
refresh_cb=None,
81+
asynchronous=False,
82+
exception_sink=None,
83+
):
7384
if self.is_running():
7485
raise RuntimeError("Event loop is already running!")
7586

@@ -80,28 +91,41 @@ def __init__(self, freq=25, timer_id=default_timer_id, max_scheduled=2, refresh_
8091

8192
self.delay = 1000 // freq
8293
self.refresh_cb = refresh_cb
83-
self.exception_sink = exception_sink if exception_sink else self.default_exception_sink
94+
self.exception_sink = (
95+
exception_sink if exception_sink else self.default_exception_sink
96+
)
8497

8598
self.asynchronous = asynchronous
8699
if self.asynchronous:
87-
if not uasyncio_available:
88-
raise RuntimeError("Cannot run asynchronous event loop. uasyncio is not available!")
89-
self.refresh_event = uasyncio.Event()
90-
self.refresh_task = uasyncio.create_task(self.async_refresh())
91-
self.timer_task = uasyncio.create_task(self.async_timer())
100+
if not asyncio_available:
101+
raise RuntimeError(
102+
"Cannot run asynchronous event loop. asyncio is not available!"
103+
)
104+
self.refresh_event = asyncio.Event()
105+
self.refresh_task = asyncio.create_task(self.async_refresh())
106+
self.timer_task = asyncio.create_task(self.async_timer())
92107
else:
93-
self.timer = Timer(timer_id)
108+
if Timer:
109+
self.timer = Timer(timer_id)
110+
self.timer.init(
111+
mode=Timer.PERIODIC, period=self.delay, callback=self.timer_cb
112+
)
94113
self.task_handler_ref = self.task_handler # Allocation occurs here
95-
self.timer.init(mode=Timer.PERIODIC, period=self.delay, callback=self.timer_cb)
96114
self.max_scheduled = max_scheduled
97115
self.scheduled = 0
98116

117+
def init_async(self):
118+
self.refresh_event = asyncio.Event()
119+
self.refresh_task = asyncio.create_task(self.async_refresh())
120+
self.timer_task = asyncio.create_task(self.async_timer())
121+
99122
def deinit(self):
100123
if self.asynchronous:
101124
self.refresh_task.cancel()
102125
self.timer_task.cancel()
103126
else:
104-
self.timer.deinit()
127+
if Timer:
128+
self.timer.deinit()
105129
event_loop._current_instance = None
106130

107131
def disable(self):
@@ -122,12 +146,21 @@ def task_handler(self, _):
122146
try:
123147
if lv._nesting.value == 0:
124148
lv.task_handler()
125-
if self.refresh_cb: self.refresh_cb()
149+
if self.refresh_cb:
150+
self.refresh_cb()
126151
self.scheduled -= 1
127152
except Exception as e:
128153
if self.exception_sink:
129154
self.exception_sink(e)
130155

156+
def tick(self):
157+
self.timer_cb(None)
158+
159+
def run(self):
160+
if sys.platform == "darwin":
161+
while True:
162+
self.tick()
163+
131164
def timer_cb(self, t):
132165
# Can be called in Interrupt context
133166
# Use task_handler_ref since passing self.task_handler would cause allocation.
@@ -149,15 +182,15 @@ async def async_refresh(self):
149182
except Exception as e:
150183
if self.exception_sink:
151184
self.exception_sink(e)
152-
if self.refresh_cb: self.refresh_cb()
185+
if self.refresh_cb:
186+
self.refresh_cb()
153187

154188
async def async_timer(self):
155189
while True:
156-
await uasyncio.sleep_ms(self.delay)
190+
await asyncio.sleep_ms(self.delay)
157191
lv.tick_inc(self.delay)
158192
self.refresh_event.set()
159-
160193

161194
def default_exception_sink(self, e):
162-
usys.print_exception(e)
163-
event_loop.current_instance().deinit()
195+
sys.print_exception(e)
196+
# event_loop.current_instance().deinit()

lv_conf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,11 +295,16 @@
295295
/*-------------
296296
* Others
297297
*-----------*/
298+
/* PRIVATE API */
299+
300+
#define LV_USE_PRIVATE_API 1
298301

299302
/*Garbage Collector settings
300303
*Used if LVGL is bound to higher level language and the memory is managed by that language*/
301304
extern void mp_lv_init_gc();
305+
extern void mp_lv_deinit_gc();
302306
#define LV_GC_INIT() mp_lv_init_gc()
307+
#define LV_GC_DEINIT() mp_lv_deinit_gc()
303308

304309
#define LV_ENABLE_GLOBAL_CUSTOM 1
305310
#if LV_ENABLE_GLOBAL_CUSTOM

lvgl

Submodule lvgl updated 3169 files

micropython.cmake

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
# This file is to be given as "make USER_C_MODULES=..." when building Micropython port
3+
4+
# Include LVGL component, ignore KCONFIG
5+
6+
idf_build_set_property(LV_MICROPYTHON 1)
7+
idf_build_component(${CMAKE_CURRENT_LIST_DIR}/lvgl)
8+
idf_build_set_property(COMPILE_DEFINITIONS "-DLV_KCONFIG_IGNORE" APPEND)
9+
separate_arguments(LV_CFLAGS_ENV UNIX_COMMAND $ENV{LV_CFLAGS})
10+
idf_build_set_property(COMPILE_DEFINITIONS "${LV_CFLAGS}" APPEND)
11+
idf_build_set_property(COMPILE_OPTIONS "-Wno-unused-function" APPEND)
12+
idf_build_set_property(SRCS "${LV_SRC}" APPEND)
13+
idf_build_set_property(INCLUDE_DIRS "${LV_INCLUDE}" APPEND)
14+
15+
# idf_build_set_property(INCLUDE_DIRS "${LV_INCLUDE}" APPEND)
16+
17+
# DEBUG LV_CONF_PATH
18+
message(STATUS "LV_CONF_PATH=${LV_CONF_PATH}")
19+
20+
# Fix for idf 5.2.x
21+
idf_build_get_property(component_targets __COMPONENT_TARGETS)
22+
string(REPLACE "___idf_lvgl" "" component_targets "${component_targets}")
23+
idf_build_set_property(__COMPONENT_TARGETS "${component_targets}")
24+
25+
include(${CMAKE_CURRENT_LIST_DIR}/mkrules_usermod.cmake)
26+
27+
# Add lv_bindings rules
28+
29+
all_lv_bindings()
30+
31+
32+
# # # make usermod (target declared by Micropython for all user compiled modules) link to bindings
33+
# # # this way the bindings (and transitively lvgl_interface) get proper compilation flags
34+
# target_link_libraries(usermod INTERFACE usermod_lvgl)
35+
36+
file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_LIST_DIR}/lvgl/src/*.c)
37+
38+
add_library(lvgl_interface INTERFACE)
39+
40+
target_sources(lvgl_interface INTERFACE ${SOURCES})
41+
target_compile_options(lvgl_interface INTERFACE ${LV_CFLAGS})
42+
43+
# # lvgl bindings target (the mpy module)
44+
45+
add_library(usermod_lvgl INTERFACE)
46+
target_sources(usermod_lvgl INTERFACE ${LV_SRC})
47+
target_include_directories(usermod_lvgl INTERFACE ${LV_INCLUDE})
48+
if (DEFINED LV_CONF_DIR)
49+
target_include_directories(usermod_lvgl INTERFACE ${LV_CONF_DIR})
50+
endif()
51+
52+
file(WRITE ${LV_MP} "")
53+
54+
target_link_libraries(usermod_lvgl INTERFACE lvgl_interface)
55+
56+
# # # make usermod (target declared by Micropython for all user compiled modules) link to bindings
57+
# # # this way the bindings (and transitively lvgl_interface) get proper compilation flags
58+
if (DEFINED LV_CONF_DIR)
59+
target_include_directories(usermod INTERFACE ${LV_CONF_DIR})
60+
endif()
61+
target_compile_options(usermod INTERFACE -DLV_CONF_PATH="${LV_CONF_PATH}")
62+
target_link_libraries(usermod INTERFACE usermod_lvgl)
63+

micropython.mk

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
2+
################################################################################
3+
# LVGL unix optional libraries
4+
# Update CFLAGS_USERMOD and LDFLAGS_USERMOD for LVGL extenral library,
5+
# but do that only on the unix port, for unix specific dependencies
6+
ifeq ($(notdir $(CURDIR)),unix)
7+
ifneq ($(UNAME_S),Darwin)
8+
CFLAGS_USERMOD += -DMICROPY_FB=1
9+
endif
10+
11+
SDL_CFLAGS_USERMOD := $(shell pkg-config --silence-errors --cflags sdl2)
12+
SDL_LDFLAGS_USERMOD := $(shell pkg-config --silence-errors --libs sdl2)
13+
ifneq ($(SDL_LDFLAGS_USERMOD),)
14+
CFLAGS_USERMOD += $(SDL_CFLAGS_USERMOD) -DMICROPY_SDL=1
15+
LDFLAGS_USERMOD += $(SDL_LDFLAGS_USERMOD)
16+
endif
17+
18+
# Avoid including unwanted local headers other than sdl2
19+
ifeq ($(UNAME_S),Darwin)
20+
CFLAGS_USERMOD:=$(filter-out -I/usr/local/include,$(CFLAGS_USERMOD))
21+
endif
22+
23+
RLOTTIE_CFLAGS_USERMOD := $(shell pkg-config --silence-errors --cflags rlottie)
24+
RLOTTIE_LDFLAGS_USERMOD := $(shell pkg-config --silence-errors --libs rlottie)
25+
ifneq ($(RLOTTIE_LDFLAGS_USERMOD),)
26+
CFLAGS_USERMOD += $(RLOTTIE_CFLAGS_USERMOD) -DMICROPY_RLOTTIE=1
27+
LDFLAGS_USERMOD += $(RLOTTIE_LDFLAGS_USERMOD)
28+
endif
29+
30+
FREETYPE_CFLAGS_USERMOD := $(shell pkg-config --silence-errors --cflags freetype2)
31+
FREETYPE_LDFLAGS_USERMOD := $(shell pkg-config --silence-errors --libs freetype2)
32+
ifneq ($(FREETYPE_LDFLAGS_USERMOD),)
33+
CFLAGS_USERMOD += $(FREETYPE_CFLAGS_USERMOD) -DMICROPY_FREETYPE=1
34+
LDFLAGS_USERMOD += $(FREETYPE_LDFLAGS_USERMOD)
35+
endif
36+
37+
# Enable FFMPEG
38+
# FFMPEG_LIBS := libavformat libavcodec libswscale libavutil
39+
# FFMPEG_CFLAGS_USERMOD := $(shell pkg-config --silence-errors --cflags $(FFMPEG_LIBS))
40+
# FFMPEG_LDFLAGS_USERMOD := $(shell pkg-config --silence-errors --libs $(FFMPEG_LIBS))
41+
# ifneq ($(FFMPEG_LDFLAGS_USERMOD),)
42+
# CFLAGS_USERMOD += $(FFMPEG_CFLAGS_USERMOD) -DMICROPY_FFMPEG=1
43+
# LDFLAGS_USERMOD += $(FFMPEG_LDFLAGS_USERMOD)
44+
# endif
45+
46+
endif
47+
48+
################################################################################
49+
50+
# LVGL build rules
51+
52+
53+
LVGL_BINDING_DIR := $(USERMOD_DIR)
54+
ifeq ($(LV_CONF_PATH),)
55+
LV_CONF_PATH = $(LVGL_BINDING_DIR)/lv_conf.h
56+
endif
57+
58+
# LV_CONF_PATH DEBUG
59+
$(info LV_CONF_PATH is $(LV_CONF_PATH))
60+
61+
62+
LVGL_DIR = $(LVGL_BINDING_DIR)/lvgl
63+
LVGL_GENERIC_DRV_DIR = $(LVGL_BINDING_DIR)/driver/generic
64+
INC += -I$(LVGL_BINDING_DIR)
65+
ALL_LVGL_SRC = $(shell find $(LVGL_DIR) -type f -name '*.h') $(LV_CONF_PATH)
66+
LVGL_PP = $(BUILD)/lvgl/lvgl.pp.c
67+
LVGL_MPY = $(BUILD)/lvgl/lv_mpy.c
68+
LVGL_MPY_METADATA = $(BUILD)/lvgl/lv_mpy.json
69+
CFLAGS_USERMOD += $(LV_CFLAGS)
70+
71+
# MAKE SURE LV_CONF_PATH is a STRING
72+
CFLAGS_USERMOD += -DLV_CONF_PATH='"$(LV_CONF_PATH)"'
73+
# CFLAGS_USERMOD += -DLV_CONF_PATH=$(LV_CONF_PATH)
74+
75+
76+
# CFLAGS DEBUG
77+
$(info CFLAGS_USERMOD is $(CFLAGS_USERMOD))
78+
79+
$(LVGL_MPY): $(ALL_LVGL_SRC) $(LVGL_BINDING_DIR)/gen/gen_mpy.py
80+
$(ECHO) "LVGL-GEN $@"
81+
$(Q)mkdir -p $(dir $@)
82+
$(Q)$(CPP) $(CFLAGS_USERMOD) -DPYCPARSER -x c -I $(LVGL_BINDING_DIR)/pycparser/utils/fake_libc_include $(INC) $(LVGL_DIR)/lvgl.h > $(LVGL_PP)
83+
$(Q)$(PYTHON) $(LVGL_BINDING_DIR)/gen/gen_mpy.py -M lvgl -MP lv -MD $(LVGL_MPY_METADATA) -E $(LVGL_PP) $(LVGL_DIR)/lvgl.h > $@
84+
85+
.PHONY: LVGL_MPY
86+
LVGL_MPY: $(LVGL_MPY)
87+
88+
CFLAGS_USERMOD += -Wno-unused-function
89+
CFLAGS_EXTRA += -Wno-unused-function
90+
SRC_USERMOD_LIB_C += $(subst $(TOP)/,,$(shell find $(LVGL_DIR)/src $(LVGL_DIR)/examples $(LVGL_GENERIC_DRV_DIR) -type f -name "*.c"))
91+
SRC_USERMOD_C += $(LVGL_MPY)

0 commit comments

Comments
 (0)