RP2 Pico: 'module' object has no attribute 'disp_drv_t'

Hey there! I’m trying to get my RP2 Pico working with LVGL but I had no luck so far.
Maybe I’m missing something obvious?

I am building lv_micropython using this GitHub Action:

on:
  push:
    branches:
      - main

jobs:
  local-build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Project
        uses: actions/checkout@v4
      - name: Checkout LVGL
        uses: actions/checkout@v4
        with:
          repository: lvgl/lv_micropython
          ref: "b1301ee8359454fd8b68b4063874e5034b4d9fe5" # Last commit on master
          path: "./lv_micropython"
          submodules: true
      - name: Update apt-get
        run: sudo apt-get update
      - name: Install packages
        run: sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential cmake git python3 -y
      - name: Init Submodules
        run: |
          cd "$GITHUB_WORKSPACE/lv_micropython"
          git submodule update --init --recursive lib/lv_bindings
      - name: Make RP2 / PICO Submodules
        run: |
          cd "$GITHUB_WORKSPACE/lv_micropython"
          make -j$(nproc) -C ports/rp2 BOARD=PICO USER_C_MODULES=../../lib/lv_bindings/bindings.cmake submodules
      - name: Make mpy-cross
        run: |
          cd "$GITHUB_WORKSPACE/lv_micropython"
          make -j$(nproc) -C mpy-cross
      - name: Make Firmware
        run: |
          cd "$GITHUB_WORKSPACE/lv_micropython"
          make -j$(nproc) -C ports/rp2 BOARD=PICO USER_C_MODULES=../../lib/lv_bindings/bindings.cmake
          mv $GITHUB_WORKSPACE/lv_micropython/ports/rp2/build-PICO/firmware.uf2 $GITHUB_WORKSPACE/firmware.uf2

The build works. Once I flash the UF2 to my Pico I can for example successfully import and init lvgl via

import lvgl as lv
lv.init()

but once I try to register a display driver I get the AttributeError: 'module' object has no attribute 'disp_drv_t' error.

# Register the display driver
disp_drv = lv.disp_drv_t()      # This line fails
disp_drv.init()
disp_drv.flush_cb = lvgl_flush_cb
disp_drv.hor_res = DISPLAY_WIDTH
disp_drv.ver_res = DISPLAY_HEIGHT
disp_drv.register()

Does anybody know what the issue is here?
Thanks in advance!

PS: Here is the complete main.py file that I am trying to run:

import lvgl as lv
import machine
import rp2_dma
import time


# Constants for the display
SPI_FREQUENCY = const(40000000)  # 40 MHz
SPI_MOSI = 7  # Change to your MOSI pin
SPI_SCK = 6   # Change to your SCK pin
SPI_CS = 9    # Change to your CS pin
DISPLAY_WIDTH = const(240)
DISPLAY_HEIGHT = const(320)


# Initialize LVGL
lv.init()

# Configure the SPI bus
spi = machine.SPI(
    0, 
    baudrate=SPI_FREQUENCY,
    sck=machine.Pin(SPI_SCK, machine.Pin.OUT),
    mosi=machine.Pin(SPI_MOSI, machine.Pin.OUT),
)

# Configure the CS pin for the display
cs = machine.Pin(SPI_CS, machine.Pin.OUT)
cs(1)  # Deselect the display

# Initialize DMA
dma = rp2_dma.DMA(0)  # Use DMA channel 0

# Configure the SPI for the ILI9341 initialization
spi.init(baudrate=SPI_FREQUENCY)

# Write ILI9341 initialization sequence using spi.write()
# ... (omitted for brevity, see ILI9341 datasheet or existing drivers for commands)

# Helper function to transfer data using DMA
def dma_transfer(spi, cs, data):
    cs(0)  # Select the display
    # Configure the DMA to transfer data to SPI TX, then start the transfer
    dma.config(
        src_addr=uctypes.addressof(data),
        dst_addr=spi._spi[1],  # SPI1 TX FIFO
        count=len(data),
        src_inc=True,
        dst_inc=False,
        trig_dreq=rp2_dma.DMA.DREQ_SPI1_TX
    )
    dma.enable()
    # Wait for the transfer to complete
    while dma.is_busy():
        pass
    cs(1)  # Deselect the display

# LVGL Display Driver Flush Callback
def lvgl_flush_cb(drv, area, color_p):
    # Convert the LVGL color buffer to a byte array compatible with DMA transfer
    color_size = lv.color_t.SIZE * area.get_size()
    buf = bytearray(color_size)
    color_p_buf = uctypes.bytearray_at(color_p.__dereference__(color_size), color_size)
    buf[:] = color_p_buf
    # Use the helper function to transfer the buffer to the display
    dma_transfer(spi, cs, buf)
    # Indicate to LVGL that flushing is done
    drv.flush_ready()

# Register the display driver
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.flush_cb = lvgl_flush_cb
disp_drv.hor_res = DISPLAY_WIDTH
disp_drv.ver_res = DISPLAY_HEIGHT
disp_drv.register()

# Create a screen and a simple label
scr = lv.obj()
label = lv.label(scr)
label.set_text("Hello, ILI9341!")
label.align(lv.ALIGN.CENTER, 0, 0)
lv.scr_load(scr)

# Your main loop
while True:
    lv.task_handler()
    time.sleep_ms(5)

Solved the issue myself.
The problem was that I was cloning lv_micropython from master.
This somehow had lv_bindings_micropython and lvgl submodules that had no HAL at all.

Switched to using lv_micropython from the release/v8 branch instead.
Problem solve :slight_smile:

Hi,
I a same problem
Could you tell me the step of build ?

thank you

Hello PAT,

if you want people to be able to help you, you should include all relevant informations like:

  • OS you´re working with
  • your installed Python version
  • which version of micropython you downloaded
  • which version of LVGL
  • the platform and board you´re compiling for

… and the error you encounter, which steps you followed that lead to this error

Hi,
I did this with no error (board = PICO, operating system = Raspbian)

  1. git clone https://github.com/lvgl/lv_micropython.git
  2. cd lv_micropython
  3. git submodule update --init --recursive lib/lv_bindings
  4. make -C ports/rp2 BOARD=PICO submodules
  5. make -j -C mpy-cross
  6. make -j -C ports/rp2 BOARD=PICO USER_C_MODULES=../../lib/lv_bindings/bindings.cmake
MicroPython v1.20.0-700-g841ece132-dirty on 2024-01-22; Raspberry Pi Pico with RP2040

Type "help()" for more information.

>>> import lvgl as lv
lv.init()
>>> disp_drv = lv.disp_drv_t()      # This line fails
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'disp_drv_t'
>>> 

Thank you

Hello!

There are a lot of breaking changes (refactors, renamings, drawing architecture change) in v9 compared to v8, so many objects/structs are renamed.
For example in v9 there is no more lv.disp_drv_t, but lv.display_t. But please check documentation.

The actual (2024-01-23) status of LVGL - MicroPython binding (lv_micropython repo):

  1. master branch: an “old” version of MicroPython v1.20 and LVGL v9-dev → this is unstable, and will be updated soon from feat/multi-instance branch
  2. feat/multi-instance branch: it contains the latest LVGL v9 version (still MicroPython v1.20), and this will be merged to master branch (after PICO CI build is fixed)
  3. release/v8 branch: it contains the previous LVGL 8.3 version, so if you want to use it, checkout this branch: GitHub - lvgl/lv_micropython at release/v8. Please use the LVGL 8.3 documentation for it: Welcome to the documentation of LVGL! — LVGL documentation

thank you for your reply

I wanted to try the release/v8 but the construction failed.

git clone --single-branch --branch release/v8 https://github.com/lvgl/lv_micropython.git
cd lv_micropython 
git submodule update --init --recursive lib/lv_bindings
make -C ports/rp2 BOARD=PICO submodules
make -C mpy-cross
make -C ports/rp2 BOARD=PICO USER_C_MODULES=../../lib/lv_bindings/bindings.cmake
[ 91%] Building C object CMakeFiles/firmware.dir/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c.obj
In file included from /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:8:
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_erase' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:69:91:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_erase' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:70:67:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_erase' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:71:76:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_erase' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:72:76:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_program' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:92:91:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_program' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:93:67:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_program' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:94:82:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_range_program' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:95:76:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_do_cmd' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:125:91:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_do_cmd' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:126:67:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
In function 'rom_func_lookup_inline',
    inlined from 'flash_do_cmd' at /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c:127:76:
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:129:66: note: in expansion of macro 'rom_hword_as_ptr'
  129 |     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
      |                                                                  ^~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:120:59: error: array subscript 0 is outside array bounds of 'uint16_t[0]' {aka 'short unsigned int[]'} [-Werror=array-bounds]
  120 | #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
      |                                                          ~^~~~~~~~~~~~~~~~~~~~~~~~~
/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/pico_bootrom/include/pico/bootrom.h:130:41: note: in expansion of macro 'rom_hword_as_ptr'
  130 |     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
      |                                         ^~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[3]: *** [CMakeFiles/firmware.dir/build.make:7617 : CMakeFiles/firmware.dir/home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/lib/pico-sdk/src/rp2_common/hardware_flash/flash.c.obj] Erreur 1
make[3] : on quitte le répertoire « /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/ports/rp2/build-PICO »
make[2]: *** [CMakeFiles/Makefile2:1329 : CMakeFiles/firmware.dir/all] Erreur 2
make[2] : on quitte le répertoire « /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/ports/rp2/build-PICO »
make[1]: *** [Makefile:91 : all] Erreur 2
make[1] : on quitte le répertoire « /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/ports/rp2/build-PICO »
make: *** [Makefile:27 : all] Erreur 2
make : on quitte le répertoire « /home/cb/.local/share/Trash/files/lv_micropython.2/lv_micropython/ports/rp2 »

Thank you

UPDATE - 2024-01-24

master branch is updated from feat/multi-instance branch, so it contains now LVGL v9 (release version).
For better image rendering performance please set LV_CACHE_DEF_SIZE and LV_IMAGE_HEADER_CACHE_DEF_CNT configs in lv_conf.h for your device’s available memory, and build new firmware.
I’ve tested Unix, and ESP32 ports, but other ports (including RP2 (PICO) board) not yet.
There can still be some bugs and issues, so please report those here: Issues · lvgl/lv_binding_micropython · GitHub

Hi !
Perfect, Build success 100%.

I have 2 questions

  1. Are there any simple, ready-to-use examples for v9 ?
  2. Are the display drivers included in the build or do they have to be added to the flash ?

Thank you

update : unfortunately I still have problems

import time
from machine import SPI, Pin
import ili9xxx
import lvgl as lv
import sys
lv.init()

spi = SPI(
    0,
    baudrate=24_000_000,
    sck=Pin(18),
    mosi=Pin(19),
    miso=Pin(16),
)
drv = ili9xxx.Ili9341(spi=spi, cs=17, dc=15, rst=14)

Traceback (most recent call last):
  File "<stdin>", line 15, in <module>
  File "ili9xxx.py", line 167, in __init__
  File "st77xx.py", line 467, in __init__
AttributeError: 'module' object has no attribute 'disp_create'

Thank you

Hi!

  1. You can check LVGL documentation (you can figure out the MicroPython code from C code, but later we will add again MicroPython examples to documenation), or see LVGL-MicroPython binding examples
  2. For some ports and boards drivers are added (frozen drivers), for some not, so you have to add yourself.

Your issue with disp_create:
it’s a bug in LVGL binding, I will fix it.

UPDATE:
bug fixed, please pull latest of lv_micropython repo.

(PS: I’m also waiting my ordered RP Pico, so when it has arrived, I will test MP with it and fix all the remaining bugs)

thank you very much for your responsiveness

I’ll have to wait, I lack the skill to find the problem.

The screen changes state but nothing is displayed.

import time
from machine import SPI, Pin
import ili9xxx
import lvgl as lv
import sys
lv.init()

try :
    spi = SPI(
        0,
        baudrate=24_000_000,
        sck=Pin(18),
        mosi=Pin(19),
        miso=Pin(16),
    )


    drv = ili9xxx.Ili9341(spi=spi, cs=17, dc=15, rst=14)


    scr = lv.obj()
    label = lv.label(scr)
    label.set_text("Hello World!")
    lv.screen_load(scr)
    
except Exception as e:
    print(e)

Thank you

Thx for sending your code.
I can test RP Pico tomorrow afternoon, so will let you know the result.

Thank you very much for your support

Hello @PAT ,
There was a bug in st77xx.py generic driver, that is fixed in lv_micropython repo.
Please pull and build again, and test it.
I have also tested RP Pico with ILI9341, and it works now.
See similar issue: Abnormal color display on LCD with RP pico · Issue #322 · lvgl/lv_binding_micropython · GitHub

Hello @PGNet

Thank you very much, it’s work ! Can I ask you 2 more questions ?

  1. What’s missing in my code because every time I make a change I have to unplug the USB from my PICO (I use Thonny IDE) ?

  2. How do I increase the size of the text in countdown_label.set_text(“00h00m00s”) ?

import time
from machine import SPI, Pin
import ili9xxx
import lvgl as lv
import sys
lv.init()

import lvgl as lv

try:
    if not lv.is_initialized():
        print("Init LVGL")
        lv.init()
        print("Init LVGL - DONE")

    import lv_utils
    if lv_utils.event_loop.is_running():
        print("Deinit lv_utils.event_loop")
        lv_utils.event_loop.current_instance.deinit()
        print("Deinit lv_utils.event_loop - DONE")

    print("Create SPI")
    import machine
    spi = machine.SPI(
        0,
        baudrate=24_000_000,
        sck=machine.Pin(18, machine.Pin.OUT),
        mosi=machine.Pin(19, machine.Pin.OUT)
    )
    print("Create SPI - DONE")

    print("Init Ili9341")
    import ili9xxx
    drv = ili9xxx.Ili9341(rot=3, spi=spi, cs=17, dc=15,
                          rst=14, factor=8, doublebuffer=False)
    print("Init Ili9341 - DONE")

    print("Show screen")
    # Créer une fenêtre
    win = lv.obj()
    
    # Créer un label pour afficher le compte à rebours
    countdown_label = lv.label(win)
    countdown_label.set_text("00h00m00s")
    countdown_label.align(lv.ALIGN.TOP_MID, 0, 0)
    
    # Créer des boutons
    btn1 = lv.button(win)
    btn1.align(lv.ALIGN.BOTTOM_LEFT, 0, 0)
    btn1_label = lv.label(btn1)
    btn1_label.set_text("15 min")

    btn2 = lv.button(win)
    btn2.align(lv.ALIGN.BOTTOM_MID, 0, 0)
    btn2_label = lv.label(btn2)
    btn2_label.set_text("STOP")

    btn3 = lv.button(win)
    btn3.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0)
    btn3_label = lv.label(btn3)
    btn3_label.set_text("120 min")
    
    adc1 = lv.label(win)
    adc1.set_text("0.12")
    adc1.align(lv.ALIGN.LEFT_MID, 0, 0)
    
    adc2 = lv.label(win)
    adc2.set_text("0.75")
    adc2.align(lv.ALIGN.CENTER, 0, 0)
    
    adc3 = lv.label(win)
    adc3.set_text("0.20")
    adc3.align(lv.ALIGN.RIGHT_MID, 0, 0)
    
    lv.screen_load(win)
    print("Show screen - DONE")
    
    

except Exception as e:
    print(e)

Thank you

Hi!

  1. There seems to be a bug in MicroPython or LVGL, that soft-reset does not clear everything. I started to use mpremote reset after every file upload.
  2. Increasing text size => change font.
    In LVGL we have the standard binary font engine, and an optional tinyttf engine. In MicroPython binding the tinyttf is disabled.

Read more about font loading: Fonts — LVGL documentation

File system drivers needs to be registered to load dynamically fonts.
Copy fs_driver.py file to Pico.

Example of loading font:

font = lv.binfont_create("A:KeepCalmMedium-32.font")
label2 = lv.label(screen)
label2.align(lv.ALIGN.TOP_MID, 0, 10)
label2.set_style_text_color(lv.color_black(), 0)
label2.set_style_text_font(font, 0)
label2.set_text("Hello World!")

(the full example: Raspberry Pi Pico W with ILI9341 display - LVGL v9 example · GitHub )

Convert TTF font to LVGL binary font:

Hello,
Thanks to you I now have all the tools I need to explore LVGL.

I tested the :
button events
timers
FT6x36 for my display

I still have to find a 7seg font for my countdown and put the values of my ADC (multiplexed) in the textarea.

I’m sharing the code in case it helps anyone.

import time
from machine import SPI, Pin, I2C
import ili9xxx
import fs_driver
import lvgl as lv
from ft6x36 import ft6x36

from lv_utils import event_loop
import sys

lv.init()

import lvgl as lv

compte_a_rebours = None  # Initialiser à None
class CompteARebours:
    def __init__(self, minutes):
        self.temps_debut = time.time()
        self.minutes = minutes

    def get_temps_restant(self):
        temps_ecoule = time.time() - self.temps_debut
        temps_restant = self.minutes * 60 - temps_ecoule
        return time.gmtime(temps_restant) if temps_restant > 0 else time.gmtime(0)

try:
    if not lv.is_initialized():
        print("Init LVGL")
        lv.init()
        print("Init LVGL - DONE")

    print("Init LVGL FS driver")
    fs_drv = lv.fs_drv_t()
    fs_driver.fs_register(fs_drv, 'A', 0)
    print("Init LVGL FS driver - DONE")

    import lv_utils

    if lv_utils.event_loop.is_running():
        print("Deinit lv_utils.event_loop")
        lv_utils.event_loop.current_instance.deinit()
        print("Deinit lv_utils.event_loop - DONE")

    print("Create SPI")
    import machine

    spi = machine.SPI(
        0,
        baudrate=24_000_000,
        sck=machine.Pin(18, machine.Pin.OUT),
        mosi=machine.Pin(19, machine.Pin.OUT)
    )
    print("Create SPI - DONE")

    print("Init Ili9341")
    import ili9xxx

    drv = ili9xxx.Ili9341(rot=1, spi=spi, cs=17, dc=15,
                          rst=14, factor=8, doublebuffer=False)
    print("Init Ili9341 - DONE")

    print("I2C creation")
    touch = ft6x36(scl=13, sda=12, width=240, height=320, swap_xy=True, inv_y=True)
    print("I2C ok")

    print("Show screen")
    # Créer une fenêtre

    win = lv.obj()
    win.set_style_bg_color(lv.color_hex(0xFFA500), 0)  # Change la couleur de fond en orange

    countdown_label = lv.label(win)
    countdown_label.set_text("00h00m00s")
    countdown_label.align(lv.ALIGN.TOP_MID, 0, 20)

    # Créer des boutons
    btn1 = lv.button(win)
    btn1.align(lv.ALIGN.BOTTOM_LEFT, 5, -5)
    btn1_label = lv.label(btn1)
    btn1_label.set_text("15 min")

    btn2 = lv.button(win)
    btn2.align(lv.ALIGN.BOTTOM_MID, 0, -5)
    btn2_label = lv.label(btn2)
    btn2_label.set_text("STOP")

    btn3 = lv.button(win)
    btn3.align(lv.ALIGN.BOTTOM_RIGHT, -5, -5)
    btn3_label = lv.label(btn3)
    btn3_label.set_text("120 min")

    adc1 = lv.textarea(win)
    adc1.set_size(60,40)
    adc1.align(lv.ALIGN.LEFT_MID, 0, -22)

    adc2 = lv.textarea(win)
    adc2.set_size(60, 40)
    adc2.align(lv.ALIGN.LEFT_MID, 65, -22)

    adc3 = lv.textarea(win)
    adc3.set_size(60, 40)
    adc3.align(lv.ALIGN.CENTER, 0, -22)

    adc4 = lv.textarea(win)
    adc4.set_size(60, 40)
    adc4.align(lv.ALIGN.RIGHT_MID, -65, -22)

    adc5 = lv.textarea(win)
    adc5.set_size(60, 40)
    adc5.align(lv.ALIGN.RIGHT_MID, 0, -22)

    adc6 = lv.textarea(win)
    adc6.set_size(60, 40)
    adc6.align(lv.ALIGN.LEFT_MID, 0, 22)

    adc7 = lv.textarea(win)
    adc7.set_size(60, 40)
    adc7.align(lv.ALIGN.LEFT_MID, 65, 22)

    adc8 = lv.textarea(win)
    adc8.set_size(60, 40)
    adc8.align(lv.ALIGN.CENTER, 0, 22)

    adc9 = lv.textarea(win)
    adc9.set_size(60, 40)
    adc9.align(lv.ALIGN.RIGHT_MID, -65, 22)

    adc10 = lv.textarea(win)
    adc10.set_size(60, 40)
    adc10.align(lv.ALIGN.RIGHT_MID, 0, 22)

    lv.screen_load(win)
    print("Show screen - DONE")


    def button1_event_cb(event):
        global compte_a_rebours
        print("click 1")
        win.set_style_bg_color(lv.color_hex(0xFF0000), 0)  # Change la couleur de fond en rouge
        compte_a_rebours = CompteARebours(15)

    def button2_event_cb(event):
        global compte_a_rebours
        print("click 2")
        compte_a_rebours = None  # Arrête le compte à rebours
        win.set_style_bg_color(lv.color_hex(0xFFA500), 0)  # Change la couleur de fond en orange
        countdown_label.set_text("************")

    def button3_event_cb(event):
        global compte_a_rebours
        print("click 3")
        compte_a_rebours = CompteARebours(120)
        adc1.add_text("1.28")

    def update_time(t):
        global compte_a_rebours
        if compte_a_rebours is None:  # Si compte_a_rebours est None, ne faites rien
            return
        temps = compte_a_rebours.get_temps_restant()
        countdown_label.set_text(("%02d H %02d M %02d S" % (temps[3], temps[4], temps[5])))

        if temps[3] == 0 and temps[4] == 0 and temps[5] == 0:  # Si le compte à rebours est à 0
            win.set_style_bg_color(lv.color_hex(0x008000), 0)  # Change la couleur de fond en vert


    # Création du timer
    timer = lv.timer_create(update_time, 1000, None)

    btn1.add_event_cb(button1_event_cb, lv.EVENT.CLICKED, None)
    btn2.add_event_cb(button2_event_cb, lv.EVENT.CLICKED, None)
    btn3.add_event_cb(button3_event_cb, lv.EVENT.CLICKED, None)

    while True:
        print("pass")
        time.sleep(3)

except Exception as e:
    print(e)

image

PS : I have another question but I’ll create another topic
Thanks again for your help

@PAT

You are looking for something like this for a 7seg font?

Hello

Wouah !!! :star_struck:
Yes, I’d like to