lvgl-micropython / lvgl_micropython

LVGL module for MicroPython
MIT License
62 stars 19 forks source link

How to use this firmware? #18

Closed yusuhua closed 4 months ago

yusuhua commented 5 months ago

My board is LILYGO T-Display-S3, I successfully compiled this firmware without any errors. But when I followed the example in the code to use the display driver, the lvgl widget I wrote was not displayed on the screen, and there were no errors on the console. The background light only lit up when I set the backlight_on_state to st7789.STATE-LOW, but the widget I wrote still did not display, and I don't know where the problem lies.


from micropython import const

_WIDTH = const(170)
_HEIGHT = const(320)

import lcd_bus

_DC_PIN = const(7)
_WR_PIN = const(8)
_DATA0_PIN = const(39)
_DATA1_PIN = const(40)
_DATA2_PIN = const(41)
_DATA3_PIN = const(42)
_DATA4_PIN = const(45)
_DATA5_PIN = const(46)
_DATA6_PIN = const(47)
_DATA7_PIN = const(48)
_CS_PIN = const(6)

_FREQ = const(80000000)

display_bus = lcd_bus.I80Bus(
    dc=_DC_PIN,
    wr=_WR_PIN,
    data0=_DATA0_PIN,
    data1=_DATA1_PIN,
    data2=_DATA2_PIN,
    data3=_DATA3_PIN,
    data4=_DATA4_PIN,
    data5=_DATA5_PIN,
    data6=_DATA6_PIN,
    data7=_DATA7_PIN,
    cs=_CS_PIN,
    freq=_FREQ
)

import st7789

_RESET_PIN = const(5)
_POWER_PIN = const(15)
_BACKLIGHT_PIN = const(38)
_OFFSET_X = const(0)
_OFFSET_Y = const(0)

import lvgl as lv

display = st7789.ST7789(
    data_bus=display_bus,
    display_width=_WIDTH,
    display_height=_HEIGHT,
    frame_buffer1=None,
    frame_buffer2=None,
    reset_pin=_RESET_PIN,
    reset_state=st7789.STATE_HIGH,
    power_pin=_POWER_PIN,
    power_on_state=st7789.STATE_HIGH,
    backlight_pin=_BACKLIGHT_PIN,
    backlight_on_state=st7789.STATE_LOW,
    offset_x=_OFFSET_X,
    offset_y=_OFFSET_Y,
#     color_space=lv.COLOR_FORMAT.RGB565,
#     rgb565_byte_swap=True
)

display.power = True

display.init()

scr = lv.obj()
btn = lv.button(scr)
btn.align(lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text('Hello World!')
lv.screen_load(scr)

import task_handler

task_handler.TaskHandler()
TecDroiD commented 4 months ago

hi, it's been a while and noone answered..

I don't know the taskhandler import but for what i currently know you need to implement a main loop like this:

        mainview = create_mainview() # well, that's what you do by hand 
        lv.screen_load(mainview)

        while True:
            time.sleep_ms(ticktime) # ticktime is good around 10ms (for me)
            lv.tick_inc(ticktime)
            lv.task_handler()

hope this helps

yusuhua commented 4 months ago

Thank you very much for your reply.

I rebuilt the firmware with python3 make.py esp32 submodules clean mpy_cross BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=st7789 again without any errors.

Erased flash with python3 ./lib/esp-idf/components/esptool_py/esptool/esptool.py -p /dev/cu.usbmodem14301 -b 460800 erase_flash and burned the firmware with python3 ./lib/esp-idf/components/esptool_py/esptool/esptool.py -p /dev/cu.usbmodem14301 -b 921600 --before default_reset --after no_reset --chip esp32s3 write_flash 0x0 ./lib/micropython/ports/esp32/build-ESP32_GENERIC_S3-SPIRAM_OCT/build-ESP32_GENERIC_S3-SPIRAM_OCT.bin

Reconnected the data cable and opened Thonny. Found that thonny does not recognize this device:

Device is busy or does not respond. Your options:

I don't know if anyone has ever encountered this situation.

kdschlosser commented 4 months ago

first thing is to stop using Thonny. Thonny causes strange behavior when running LVGL. My suggestion is to use a terminal program like Putty (For Windows) or GNOME Terminal (For Ubuntu) etc....

TecDroiD commented 4 months ago

After flashing, you need to restart the device since it stays in bootloader mode.

what i did:

python -m pip install --break-systemrules mpremote
mpremote cp localfile.py :remotefile.py
mpremote cp main.py : 
mpremote

Firstly, you install mpremote. To copy files you use almost same syntax like linux cp. local files are named directly, files on the device need a preceeding :
using mpremote without any parameter runs repl on the connected device.

well.. just to say it.. I'm a nerd.. for most things, I use vim. So using console is just normal for me..

kdschlosser commented 4 months ago

I modified a copy of ampy so it works better with the ESP32. I am able to upload multiple files at the same time and it does this at 921600 bps instead of 115200 bps...

I can upload a single file and optionally specify a path where to put it or I can have it iterate a directory tree copying everything to the ESP32.

If I specify a file like this..

some/folder/some_file.py

it will put the file in

some/folder/some_file.py

or I can do this.

some/folder/some_file.py /

the slash on the end is the target directory. I can also do this.

some/folder/some_file.py /main.py

which will rename the file to main.py and place it in the root.

I am also able to alter the path when doing a tree copy

some/folder /

That will do a recursive copy of the contents of some/folder and place it into the root. if I leave the last / off it will recreate the folder structure as /some/folder.

I have put into place a simple checksum for each chunk of data that gets passed to make sure nothing got dropped. That does happen from time to time because of pushing the speeds up that high.

kdschlosser commented 4 months ago

as far as the task_handler is concerned.

This is an easy way to handle calling lv.tick_inc and lv.task_handler. It uses timers so the callbacks take place in an ISR which works fine for calling lv.tick_inc and then it uses the Scheduler to schedule a MicroPython task to call lv.task_handler

It works well for simple GUI's and it leaves the REPL available so the user is able to connect to the device and enter commands while the GUI is running.

There are some downsides to it. First is the scheduled task is only going to get called when there is available time to do so, that leave a big ? as to when it will occur. So the time keeping is not going to be exact. The second thing is if you decrease the delay from the factory set 33 milliseconds you will be triggering a lot more interrupts. Interrupts have quite a bit of overhead, it has to save the CPU state and load the code to run, run it and then restore the saved state. The more interrupts that are occurring the more CPU time gets gobbled up because of saving and restoring states.

In the official MicroPython port you were not given a choice if you wanted to use this. It did it for you automatically. I did not like that so I changed it to allow the user to make the choice if they wanted top run it or not.

It makes it easier for newbies and for simple GUI's. I use ESP32's typically and you are able to use threads with the ESP32. So I run LVGL in a thread and leave the main thread open for other non LVGL related tasks.

kdschlosser commented 4 months ago

as a note... putting in a sleep is a blocking call. It stops everything from running even scheduled tasks. the only thing that is able to break in are ISR's.. This is not the most ideal thing to use because there are a lot of things in MicroPython that get scheduled under the hood... It is better to let it drop to the REPL if possible. Or if the program is large in size like this one

https://www.youtube.com/watch?v=35j4p78OJAs

to just let the loop run continually and do time comparisons.

yusuhua commented 4 months ago

I feel like the problem is that it stays in bootloader mode, no matter if I press the reset button or disconnect it from the computer and then reconnect it to the computer. I don't have this problem when I use this firmware to burn, but there is a problem when I use my compiled firmware.

yusuhua commented 4 months ago

I don't know what is causing this problem in Lilygo's T-Display-S3. I will try other development boards when I have the opportunity. Thank you very much for your replies.

kdschlosser commented 4 months ago

if you just upload the firmware and nothing else, don't upload any scripts when you connect to it do you get the >>> prompt?

kdschlosser commented 4 months ago

OK I made some corrections to your script...


# compile command is
# python3 make.py esp32 submodules clean mpy_cross BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=st7789

from micropython import const

_TP_RESET = const(21)
_SCL = const(17)
_SDA = const(18)

from micropython import const

_WIDTH = const(170)
_HEIGHT = const(320)

import lcd_bus

_DC_PIN = const(7)
_WR_PIN = const(8)
_DATA0_PIN = const(39)
_DATA1_PIN = const(40)
_DATA2_PIN = const(41)
_DATA3_PIN = const(42)
_DATA4_PIN = const(45)
_DATA5_PIN = const(46)
_DATA6_PIN = const(47)
_DATA7_PIN = const(48)
_CS_PIN = const(6)
_RD_PIN = const(9)

_FREQ = const(10000000)

display_bus = lcd_bus.I80Bus(
    dc=_DC_PIN,
    wr=_WR_PIN,
    rd=_RD_PIN,
    data0=_DATA0_PIN,
    data1=_DATA1_PIN,
    data2=_DATA2_PIN,
    data3=_DATA3_PIN,
    data4=_DATA4_PIN,
    data5=_DATA5_PIN,
    data6=_DATA6_PIN,
    data7=_DATA7_PIN,
    cs=_CS_PIN,
    freq=_FREQ,
    cs_active_high=False,
    pclk_active_low=False,
    pclk_idle_low=False,
    dc_data_high=True,
    dc_dummy_high=False,
    dc_cmd_high=False,
    dc_idle_high=False
)

fb1 = display_bus.allocate_framebuffer(int(_WIDTH * _HEIGHT * 2 / 10), lcd_bus.MEMORY_DMA | lcd_bus.MEMORY_INTERNAL)
fb2 = display_bus.allocate_framebuffer(int(_WIDTH * _HEIGHT * 2 / 10), lcd_bus.MEMORY_DMA | lcd_bus.MEMORY_INTERNAL)

import st7789

_RESET_PIN = const(5)
_POWER_PIN = const(15)
_BACKLIGHT_PIN = const(38)
_OFFSET_X = const(0)
_OFFSET_Y = const(0)

import lvgl as lv

display = st7789.ST7789(
    data_bus=display_bus,
    display_width=_WIDTH,
    display_height=_HEIGHT,
    frame_buffer1=fb1,
    frame_buffer2=fb2,
    reset_pin=_RESET_PIN,
    reset_state=st7789.STATE_HIGH,
    power_pin=_POWER_PIN,
    power_on_state=st7789.STATE_HIGH,
    backlight_pin=_BACKLIGHT_PIN,
    backlight_on_state=st7789.STATE_PWM,
    offset_x=_OFFSET_X,
    offset_y=_OFFSET_Y,
    color_space=lv.COLOR_FORMAT.RGB565,
    rgb565_byte_swap=True
)

display.set_power(True)
display.init()
display.set_backlight(100)

scr = lv.obj(lv.screen_active())
btn = lv.button(scr)
btn.center()
label = lv.label(btn)
label.set_text('Hello World!')
label.center()

import task_handler

task_handler.TaskHandler()

Lets starts from scratch. clone the repository into a new folder. once it is cloned go into that directory and run the following command.

python3 make.py esp32 submodules clean mpy_cross BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=st7789

That will compile it. when the compilation has finished you will be given directions and 2 commands to run. Run both of those commands.

Once the commands have finished unplug the display from the USB and plug it back in again... copy the code from above into a file named main.py. upload that file to the board using a micropython file manager like ampy or mpremote. DO NOT use Thonney. For some reason Thonney causes issues. I don't know why it does but it does.

Once you have the script uploaded unplug the display and then plug it in again. see if you get something on the display.

I do not know what version of the display you have, they make one with touch and one without. if you have the one that has the touch let me know and I will tell you the compile command and change the code so the touchscreen will work.

yusuhua commented 4 months ago

if you just upload the firmware and nothing else, don't upload any scripts when you connect to it do you get the >>> prompt?

I only uploaded the firmware and nothing else, and when I disconnected from the computer after uploading and then reconnected, I didn't get the >>> prompt.

yusuhua commented 4 months ago

My macbook pro is based on Intel chips, and I saw this in the requirements description: OSX brew install llvm I tried running it and found that the return is like this.

brew install llvm Running brew update --auto-update... ==> Auto-updated Homebrew! Updated 1 tap (homebrew/cask). No changes to formulae.

Error: llvm: unknown or unsupported macOS version: :dunno

I don't know if this is the reason.

yusuhua commented 4 months ago

My T-Display-S3 is a version without touch. I delete the entire folder and start over every time I compile, but the result is always the same. My Macbook system version is 14.4.1.

kdschlosser commented 4 months ago

what command are you using to compile the firmware??

yusuhua commented 4 months ago

This is my compilation and burning log. log.txt After I finished burning, I disconnected from the computer and reconnected, but my device remained in bootloader mode. This is the firmware that I compiled successfully. build-ESP32_GENERIC_S3-SPIRAM_OCT.bin.zip

kdschlosser commented 4 months ago

Do you get a REPL prompt when you connect to it over serial?

yusuhua commented 4 months ago

No, that's what I'm confused about. Generally, after burning the firmware, disconnect from the computer and then reconnect to the computer, the port number will change. But after I burned the firmware, disconnected it from the computer, and reconnected it to the computer, the port number was still the original port number, and I could even erase the firmware again without holding down the bot key before reconnecting. So I think that after burning, the firmware will always be in the bootloader state, whether it is restarting or disconnecting and reconnecting.

yusuhua commented 4 months ago

I bought a new T-Display-S3, and this problem still exists after compilation and burning, so I think it may not be a problem with my device.

yusuhua commented 4 months ago

I have compiled it on both the m1 chip macbook and the intel chip macbook, and the results are the same. No errors are reported during compilation. After erasing, the firmware is re-burned, and the firmware is always in the bootloader state.

kdschlosser commented 4 months ago

It's the compiling on macOS that I am sure is causing the problem. I am going to start working on writing the scripts needed to set up a CI. This way I will be able to test the compilations across the different OS's

kdschlosser commented 4 months ago

I have corrected the issue with compiling on macOS. so if you want to give it a try again it should be fixed.

kdschlosser commented 4 months ago

You need to have Apple clang installed in order to compile.

There is information in the readme as to what you need to have installed in order to have it compile properly.

yusuhua commented 4 months ago

Duplicate issue