Build LVGL for Raspberry Pi PICO

Hello,

It is possible to build lvgl for raspberry pi PICO? I cloned dev-8.0 branch and triying to build but looks that lvgl library is not included for this platform.
As I know, micropython-lvgl can be built for ESP32 platforms that, as PICO, have a build system based on cmake, so it should be easy to adapt.

Has anyone build it?

Of course it’s possible, but no one has integrated it yet.
Currently Micropython+LVGL bindings is available for ESP32, STM32 and Linux.

We will be happy to accept RPI PICO integration into lv_micropython, if anyone is interested in working on that.

I saw that /ports/esp32/CMakeLists.txt include these commands to enable LVGL:

#include LVGL component, ignore KCONFIG
idf_build_component(${CMAKE_SOURCE_DIR}/…/…/lib/lv_bindings/lvgl)
idf_build_set_property(COMPILE_DEFINITIONS “-DLV_KCONFIG_IGNORE” APPEND)
separate_arguments(LV_CFLAGS_ENV UNIX_COMMAND $ENV{LV_CFLAGS})
list(APPEND LV_CFLAGS ${LV_CFLAGS_ENV})
idf_build_set_property(COMPILE_DEFINITIONS “${LV_CFLAGS}” APPEND)

But such idf_build_x are just available under esp build system. Maybe I can find these commands on esp-idf and copy to rp2 cmake…
If someone can help, cause I never work with cmake and I dont know how to do it

CMakeLists.txt (11.7 KB)
I added the required sources to the CMakeLists.txt and get the built fw with but looks that something still wrong cause it dosnt boot up (I cant see the device on my COM ports)

To generate lv_mpy.c I still dont know how to call gen_mpy.py so I take it from stm32 build.
But the code for esp32 version is something like that (form lv_bindings/mkrules.cmake)

add_custom_command(
    OUTPUT ${LV_OUTPUT}
    COMMAND ${Python3_EXECUTABLE} ${LV_BINDINGS_DIR}/gen/gen_mpy.py ${LV_GEN_OPTIONS} -MD ${LV_MPY_METADATA} -E ${LV_PP_FILTERED} ${LV_INPUT} > ${LV_OUTPUT} || (rm -f ${LV_OUTPUT} && /bin/false)
)

And now I can debug the with the .elf file or check if there is a problem with the ROOT_POINTERS in mpconfigport.h that I set like this:

#define MICROPY_PORT_ROOT_POINTERS \
    LV_ROOTS \
    void *mp_lv_user_data; \
    const char *readline_hist[8]; \
    void *machine_pin_irq_obj[30]; \
    void *rp2_pio_irq_obj[2]; \
    void *rp2_state_machine_irq_obj[8]; \

I Attached the CMakeLists.txt, it is not enought to build from github clone, but maybe somebody can help to make it works.

@jgpeiro Please have a look at mkrules.cmake on lv_binding_micropython.
It contains a generic CMake function “lv_bindings” that runs gen_mpy.py and also handles dependencies, preprocessing etc.

You can see how it is used in the function “all_lv_bindings” which creates bindings for LVGL, for lodePNG library and for the ESP-IDF API for ESP32.

Thank you @amirgon. I included such file, removed few esp32 stuff and now wrappers are generated properly and handled in qstr generation.

I dont know why, but compilations crashed cause some functions from lv_mp.c where unused and I bypassed the error simply adding a gcc pragma on gen_mpy.py generator.

Now I can get a firmware image, still cant boot-up, but I think It should work soon.
So I have all sources compiled, wrappers generated and LVGL handle in root pointers. Is there any other thing that Im missing?

ok, finally I got my fw image. The procedure should be easy if you have previous experience with cmake. I attached the most important modified files, mpconfigport.h and CMakeLists.txt

After build with lv_bindings dev-8.0 branch I create a simple screen with a button and dump the fb to the stdout, to verify that really works, and everything was ok. Then I had problems adding a label inside button (maybe the API change a little bit on this version I dont know) but also I saw some crazy behavior checking allocated memory with gc.mem_alloc() so finally I decide to move to lvgl v7 (dev branch) and now LVGL v7 is working ok on raspberry pi pico.

I think that someone with more experience on cmake can easily review these files and add to the dev branch.
CMakeLists.txt (12.0 KB) mpconfigport.h (10.6 KB)

Nice progress @jgpeiro!

What are the problems did you notice with v8?
What crazy behavior of gc.mem_alloc() did you see? Did you try to call gc.collect()?

Did you try or are you planning to try this with an actual display driver?

Most development is done now on dev-v8 branch, so I really recommend adding new things there.
Latest Micropython version (with RPi-Pico support) would only be officially supported with LVGL v8.

We would be happy to review GitHub Pull Requests with RPi-Pico support on dev-v8 branch, if you or someone else would be interested in working on that.

As far as I know, the MicroPython garbage collector is not concurrent or generational, meaning it essentially waits for the entire heap to be full before attempting a collection.

Therefore, as @amirgon noted, calling gc.collect() is definitely necessary to check how much RAM is really being used at a particular time.

I used this code:

scr = lv.obj()
btn = lv.btn( scr )
lbl = lv.label( btn )
lbl.set_text( "BTN" )
lv.scr_load( scr )

On v7 works ok. On v8, without label works and I can see a correct button drawn on framebuffer, but with the label, code is halted before flush callback.

Yes, I called gc.collect()…Now Im wondering, maybe it wasnt a problem with gc. I used thonny and call few times to gc.mem_alloc() from terminal and got results that I didnt expected. I tried to reproduce again but now looks normal so maybe the “crazy” values I saw where related to the “automatic variable inpection” feature that thonny ide has. ( Thonny IDE adds some code to every REPL command to visualize variables on the ide, like a light debugger)

Here I executed above script and then (without reset) called few times to gc funtions. The values returned from gc.mem_free() move from 70k, 100k, 100k, 25k…its not what you should expect

Yes, any ILI9xxx with an SPI interface cause PICO hasent too many pins. But I will write on python side, so it dosent affect to LVGL build.

Cool!

I like how v8 looks, and today I came back to v7 cause that “gc problems”. Tomorrow I will check again better to understand if its really a problem or not…but another problem with v8 is that API has too many changes so I need to learn again how todo too many things, even python demos dosent works or API doc is not available…

After check on plain terminal (putty) I confirm that “crazy” values where caused by Thonny IDE variable inspection stuff.

This code works just fine for me in on v8.
Maybe something is not up to date on your workspace?
After checking out dev-v8 branch of lv_micropython, did you remember to run git submodule update --recursive?
Maybe some problem related to Thonny?

Actually @uraich did a lot of work on Python examples for LVGL v8.
These examples will eventually be part of the official docs, but you can already see them on GitHub:

#!/opt/bin/lv_micropython -i
import time
import lvgl as lv
import display_driver

btn = lv.btn( lv.scr_act() )
btn.center()
lbl = lv.label( btn )
lbl.set_text( "BTN" )

image
I did that on my lv_micropython V8, unix port

Just clone again dev-8.0 with that commands
image
then make minimal required modifications to that files.


(Note that src/* files has been modified to avoid compilation errors with some snprintf “%d” that should be “%ld” )
Then I tried the example from @uraich repo lv_example_btn_1.py and still dosent works. (But works if I remove the labels)

I wonder that maybe something related with fonts, but check that default montserrat fonts are enabled on lv_conf.h…so I dont know what is happening here. Also cause I dont have rp2 debug IDE I dont know what is happening on background…


This image shows on the top cell the micropython code with lv_example_btn_1.py that is executed on raspberry pico and on bottom cell the PC code to visualize the framebuffer(that is dumped via REPL). I can see two buttons on the screen, but if I uncomment the labels, the code dosent work…

I hope I can solve the problem with labels cause with @uraich examples will be easy use lvgl v8

Here are the modified files
files.zip (52.8 KB)

First step for solving this is identifying where the problem is.

  • It could be related to LVGL C code when built for Ri PICO
  • It could be related to Micropython or the LVGL binding code between Micropython and LVGL

Let’s see if it’s related to Micropython or to LVGL.

I suggest trying to reproduce the same problem without Micropython:
Create a small C program that builds with the same LVGL workspace that you use for Micropython (including your changes to LVGL code, including lv_conf.h) but without Micropython itself.
In that C program just create a button and a label in C and let’s see if it works correctly or not.

You could also compile the unix port of micropython first and try the program there. If it works correctly there, then the problem is in the RPi port. If not, then something is wrong in the way you create your micropython binary.

You are right. I build unix port and test it and worked OK, so problem should be on rp2 port (upy, biddings or somewhere)
image

Im new on rp2 so I need some time to build a C project and add LVGL sources. I also can debug the current .elf file that I have, but I also need time to get required setup (ide, pico probe…)
Meanwhile I enabled LVGL log traces and now behavior is different(also I came back to snprintf("%d") that linux port requires and then add (int) castings on rp2 port snprintfs). I can add the label, but text is blank and is tooo long…
log btn.txt (21.0 KB)

log btn lbl.txt (25.9 KB)

I tried to debug source code, but it takes some time get the correct toolchain setup for this new platform…I tried with vscode, segger ozone, platformio…and forund a different problem on each one…

Finally I bypassed the problem changing the default font from montserrat_14 to montserrat_16. I dont know what this can cause a problem for pico platform, but looks that v8 demos are working now.