Support ESP32-S2, ESP32-C3, ESP32-S3

Micropython already supports ESP32, ESP32-S2, ESP32-C3, ESP32-S3.
However lv_micropython only supports ESP32 today.
The goal is to add support for ESP32-S2, ESP32-C3, ESP32-S3 in lv_binding_micropython and lv_micropython.
This includes:

[ ] Fix lv_micropython and lv_binding_micropython to correctly build the lv_micropython ESP32 port for GENERIC_S2, GENERIC_S3, GENERIC_C3 boards (or their equivalents).
Each should be built with the correct ESP-IDF version as explained in Micropython ESP32 port README.
[ ] Fix the CI to test them. Currently these boards are disabled in the CI on lv_micropython.
[ ] Fix the esp-idf micropython module (auto generated from espidf.c and espidf.h) to build correctly on all ESP32, ESP32-S2, ESP32-C3, ESP32-S3 and provide the ESP-IDF API needed for the drivers (gpio, spi, dma, adc, i2s, pcnt, mdns, http client, sh2lib). Currently all these APIs are provided for ESP32 only.
[ ] Fix and test the ESP32 display drivers ili9341 ili9488 gc9a01 st7789 st7735 and input drivers modrtch.c modxpt2046.c xpt2046.py with ESP32-S2, ESP32-C3, ESP32-S3.
[ ] Fix documentation (lv_binding_micropython README.md and lv_micropython README.md) to reflect the support for ESP32-S2, ESP32-C3, ESP32-S3 and provide information on how to build them.
[ ] Provide at least one video for each of ESP32-S2, ESP32-C3, ESP32-S3, with at least one display, showing lv_micropython running some examples.
[ ] Make sure existing ESP32 support is not impacted by these changes and runs correctly.

Related issues:

https://github.com/lvgl/lv_binding_micropython/issues/208
https://github.com/lvgl/lv_binding_micropython/issues/197
https://forum.lvgl.io/t/micropython-v1-19-1-and-lvgl-v8-3/9340/2

This is a sponsored issue, meaning that if someone implements it he or she gets a payment from the Accumulated donations of LVGL. Learn more HERE.
We can give 100 USD for fully implementing this.
CC: @kisvegabor @embeddedt

When I compiled esp32-s3, I got these errors:

Run in to this issue while I was looking for support for imxrt11xx platforms, since the main repo already supported them.
I would like to do it my own, but I could not find any detailed document for what exactly need to be done.
The readme of this repo is all about how to use this lvgl as a mp module, but mothing about porting.
Another article I could find is this https://blog.lvgl.io/2019-02-20/micropython-bindings
"Can I use LittlevGL binding on XXXX Micropython fork?
Probably yes!
You would need to add Micropython Binding for LittlevGL as a submodule in your fork, and make some small changes to the Makefile and mpconfigport.h in your port, but that’s about it.
For more details please have a look at the README."
The readme link is link to this repo's readme, bruh...
And about "make some small changes", sure, but what?
This is the same felling of MS error messages says "Something went wrong"
My honest suggestion, better use that $100 hire someone for documentation on and create some examples, that allows people who want help could help right the way, instad of read all sources and scripts to understand what to do first.

@424778940z - See https://github.com/lvgl/lv_binding_micropython/pull/242. That PR still needs some work, but when it's merged you will be able to add LVGL as an Micropython external C module, so porting to new architectures will be much easier.
This issue is about supporting ESP32-S2, ESP32-C3, ESP32-S3 because ESP ports have an extra complication where in addition to LVGL, the ESP BSP library API (ESP-IDF) is automatically converted too, so users can use it directly in Python code. (See Pure Micropython Display Driver in the blog).
You are right that the documentation focuses mostly on how to use the Micropython bindings. That's what interest most users. Advanced users who want to port to new architectures are welcome to diff micropython repo with lv_micropython and learn from the differences.
Remember that all the work, including the documentation, was done by volunteers on their spare time.  So comparing this to Microsoft error message is not really fair.
If you are unhappy with the documentation or any other part, feel free to contribute by submitting a PR!

I have been using esp32s3 for a whole day, and I keep reporting errors. It turns out that esp32s3 chip is not supported yet!!

It turns out that esp32s3 chip is not supported yet!!

Correct.
See https://github.com/lvgl/lv_binding_micropython/pull/243

Waiting for Support ESP32-S2, ESP32-C3, ESP32-S3!
Lvgl docs has a lot of micropython examples codes, that's cool!
Especially ESP32-S3，many borads use it instead of ESP32, but they can't be used in micropython yet,
what's pity

Especially ESP32-S3，many borads use it instead of ESP32, but they can't be used in micropython yet,

@jd3096-mpy see https://github.com/lvgl/lv_binding_micropython/pull/243 - this adds ESP32-S3 support.
Could you try this PR on your side and see if it works for you?

I hope this gets added soon. I just wrote a python driver for the ili934 using an 8bit parallel interface. all of the work functions are decorated with micropython.viper so it should run with ample speed.
I am not able to test it because I only have s3's on hand at the moment.
It looks like it should work without an issue.
There are a couple of things that I have forced like setting the d0-d7 pins sequentially to GPIO pins that are also sequential and are all in the same GPIO register. Makes setting the state of the GPIOs easier to deal with. I still have to tie in the touch interface and this is going to be a tad more challenging to do because of the shared pins. I need to know more about the mechanics of how the input side of things works in lvgl to be able to do this. Or if a Python driver can be written for a touch interface. I don't know how the loop in lvgl works.
I am hoping that the use of viper code isn't going to mess with lvgl either. I am making an assumption that the viper code runs in the same manner as the native code and when the code is running things like ISRs don't break into the running code. The parallel interface should offer a HUGE speed increase because there is no need to swap the high and low bytes for the colors. I am also directly accessing the registers for the GPIOs through pointers and not using the built in machine.Pin class.
Maybe there is someone that would be willing to lend a hand with getting the touch interface working.

On a side note I will match the 100.00  already being given to get this done.

There is a choice to make here. Code can either be duplicated from the latest micropython esp32 port in the drivers for the esp32 port in lv_binding_micropython  OR there can be a minimum micropython version that gets set into place for the esp32 port and includes from micropython can be made in the drivers for lvgl so the code isn't duplicated.
with the esp32s3 there is no adc_gpio_init function available and the way the adc blocks are handled is different. micropython has already sorted out the mechanics of this and created helper functions to deal with it. I think that setting a minimum version of micropython that lv_binding_micropython is allowed to use would the cleanest and also the easiest way to get it working with all of the different esp32 variants.
Most of the issues are differences in the macro names or some macros not being defined all together.
I corrected the errors in the gpio_to_adc array in the modrtch.c file using the following code
#define GPIO_TO_ADC_ELEMENT(adc, x) [x] = CONCAT3(CONCAT3(ADC, adc, _GPIO), x, _CHANNEL)
static const int gpio_to_adc[] = {
#if CONFIG_IDF_TARGET_ESP32
    GPIO_TO_ADC_ELEMENT(2, 0),
#elif CONFIG_IDF_TARGET_ESP32C3
    GPIO_TO_ADC_ELEMENT(1, 0),
#endif
#if CONFIG_IDF_TARGET_ESP32
    GPIO_TO_ADC_ELEMENT(2, 2),
    GPIO_TO_ADC_ELEMENT(2, 4),
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
    GPIO_TO_ADC_ELEMENT(1, 1),
    GPIO_TO_ADC_ELEMENT(1, 2),
    GPIO_TO_ADC_ELEMENT(1, 3),
    GPIO_TO_ADC_ELEMENT(1, 4),
#endif
#if CONFIG_IDF_TARGET_ESP32C3
    GPIO_TO_ADC_ELEMENT(2, 5),
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2
    GPIO_TO_ADC_ELEMENT(1, 5),
#endif
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
    GPIO_TO_ADC_ELEMENT(1, 6),
    GPIO_TO_ADC_ELEMENT(1, 7),
    GPIO_TO_ADC_ELEMENT(1, 8),
    GPIO_TO_ADC_ELEMENT(1, 9),
    GPIO_TO_ADC_ELEMENT(1, 10),
    GPIO_TO_ADC_ELEMENT(2, 11),
#endif
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
    GPIO_TO_ADC_ELEMENT(2, 12),
    GPIO_TO_ADC_ELEMENT(2, 13),
    GPIO_TO_ADC_ELEMENT(2, 14),
    GPIO_TO_ADC_ELEMENT(2, 15),
#endif
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
    GPIO_TO_ADC_ELEMENT(2, 16),
    GPIO_TO_ADC_ELEMENT(2, 17),
    GPIO_TO_ADC_ELEMENT(2, 18),
    GPIO_TO_ADC_ELEMENT(2, 19),
    GPIO_TO_ADC_ELEMENT(2, 20),
#endif
#if CONFIG_IDF_TARGET_ESP32
    GPIO_TO_ADC_ELEMENT(2, 25),
    GPIO_TO_ADC_ELEMENT(2, 26),
    GPIO_TO_ADC_ELEMENT(2, 27),
    GPIO_TO_ADC_ELEMENT(1, 32),
    GPIO_TO_ADC_ELEMENT(1, 33),
    GPIO_TO_ADC_ELEMENT(1, 34),
    GPIO_TO_ADC_ELEMENT(1, 35),
    GPIO_TO_ADC_ELEMENT(1, 36),
    GPIO_TO_ADC_ELEMENT(1, 37),
    GPIO_TO_ADC_ELEMENT(1, 38),
    GPIO_TO_ADC_ELEMENT(1, 39)
#endif
};

and that has left me with the following compilation errors.
/home/***/lv_micropython/lib/lv_bindings/driver/esp32/modrtch.c: In function 'measure_axis':
/home/***/lv_micropython/lib/lv_bindings/driver/esp32/modrtch.c:440:5: error: implicit declaration of function 'adc_gpio_init'; did you mean 'gpio_init'? [-Werror=implicit-function-declaration]
     adc_gpio_init(ADC_UNIT_1, adc_channel);
     ^~~~~~~~~~~~~
     gpio_init

/home/***/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:85:18: error: implicit declaration of function 'I2S_TIMING_REG'; did you mean 'I2S_RX_TIMING_REG'? [-Werror=implicit-function-declaration]
     REG_SET_BIT( I2S_TIMING_REG(i2s_num), BIT(9));
                  ^~~~~~~~~~~~~~
/home/***/esp/components/soc/esp32s3/include/soc/soc.h:151:36: note: in definition of macro 'REG_SET_BIT'
             (*(volatile uint32_t*)(_r) |= (_b));                                                                       \
                                    ^~
/home/***/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:86:18: error: implicit declaration of function 'I2S_CONF_REG'; did you mean 'I2S_TX_CONF_REG'? [-Werror=implicit-function-declaration]
     REG_SET_BIT( I2S_CONF_REG(i2s_num), I2S_RX_MSB_SHIFT);
                  ^~~~~~~~~~~~
/home/***/esp/components/soc/esp32s3/include/soc/soc.h:151:36: note: in definition of macro 'REG_SET_BIT'
             (*(volatile uint32_t*)(_r) |= (_b));                                                                       \
                                    ^~
In file included from /home/***/lv_micropython/lib/lv_bindings/driver/esp32/espidf.c:7:
/home/***/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h: At top level:
/home/***/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:180:21: error: 'SPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
     ENUM_SPI_HOST = SPI_HOST,
                     ^~~~~~~~
                     SPI3_HOST
/home/***/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:181:22: error: 'HSPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
     ENUM_HSPI_HOST = HSPI_HOST,
                      ^~~~~~~~~
                      SPI3_HOST
/home/***/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:182:22: error: 'VSPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
     ENUM_VSPI_HOST = VSPI_HOST,
                      ^~~~~~~~~
                      SPI3_HOST

as you can see most of the issues at this point are simple macro naming problems. the only one that is a big hand up is the missing adc_gpio_init function and that function is not so simple to replicate what it does.
If a decision is made to use the already written functions to handle this issue in the esp32 port of micropython ass new esp32 boards get released changes will be made to micropython to handle those boards and little to no changes will need to be made in lv_binding_micropython to support the newer boards.

If anyone wants to give this a go to see if it works I would appreciate it.
It should compile without errors. I do not have an SPI display to test it with.
https://github.com/kdschlosser/lv_binding_micropython/tree/esp32-s-c-h_support

If anyone wants to give this a go to see if it works I would appreciate it.
It should compile without errors. I do not have an SPI display to test it with.
https://github.com/kdschlosser/lv_binding_micropython/tree/esp32-s-c-h_support

Good job!
I tried your ways, like this:
git clone https://github.com/lvgl/lv_micropython.git
cd lv_micropython
git submodule update --init --recursive lib/lv_bindings
download your dirvers.esp32.zip ,unzip the files and overwrite it.
try
make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_S3_SPIRAM IDF_TARGET=esp32s3
but report errors in the last stage:
[1497/1499] Linking CXX executable micropython.elf
FAILED: micropython.elf
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/driver/libdriver.a(gpio.c.obj):(.literal.gpio_force_hold_all+0x0): undefined reference to rtc_gpio_force_hold_all'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/driver/libdriver.a(gpio.c.obj): in function gpio_force_hold_all': /home/jd3096/esp/esp-idf/components/driver/gpio.c:685: undefined reference to rtc_gpio_force_hold_all'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.literal.esp_eth_phy_new_lan8720+0x0): undefined reference to esp_eth_phy_new_lan87xx' /home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj): in function esp_eth_phy_new_lan8720':
/home/jd3096/esp/esp-idf/components/esp_eth/include/esp_eth_phy.h:271: undefined reference to esp_eth_phy_new_lan87xx' /home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_xt_clock_freq_mpobj+0xc): undefined reference to xt_clock_freq'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_lldesc_build_chain_mpobj+0xc): undefined reference to lldesc_build_chain' /home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_gpio_input_get_high_mpobj+0xc): undefined reference to gpio_input_get_high'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_gpio_output_set_high_mpobj+0xc): undefined reference to gpio_output_set_high' /home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_esp_eth_phy_new_ksz8081_mpobj+0xc): undefined reference to esp_eth_phy_new_ksz8081'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_esp_eth_phy_new_ksz8041_mpobj+0xc): undefined reference to esp_eth_phy_new_ksz8041' /home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_esp_eth_phy_new_dp83848_mpobj+0xc): undefined reference to esp_eth_phy_new_dp83848'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_esp_eth_phy_new_lan87xx_mpobj+0xc): undefined reference to esp_eth_phy_new_lan87xx' /home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_esp_eth_phy_new_rtl8201_mpobj+0xc): undefined reference to esp_eth_phy_new_rtl8201'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_esp_eth_phy_new_ip101_mpobj+0xc): undefined reference to esp_eth_phy_new_ip101' /home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_lldesc_set_owner_mpobj+0xc): undefined reference to lldesc_set_owner'
/home/jd3096/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-8.4.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/main/libmain.a(lv_espidf.c.obj):(.rodata.mp_lldesc_num2link_mpobj+0xc): undefined reference to lldesc_num2link' collect2: error: ld returned 1 exit status ninja: build stopped: subcommand failed. ninja failed with exit code 1 make: *** [Makefile:34: all] Error 2 make: Leaving directory '/home/jd3096/Desktop/01/lv_micropython/ports/esp32'
the same error as yours?

did you use the repo I linked to or did you use the files I attached in a zip?? If you used the zipped files don't use the linked repo instead

make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_S3_SPIRAM IDF_TARGET=esp32s3

Both ways make mistakes,if I use the reop,some wrong like this:
/home//lv_micropython/lib/lv_bindings/driver/esp32/espidf.h: At top level:
/home//lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:180:21: error: 'SPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
ENUM_SPI_HOST = SPI_HOST,
^~~~~~~~
SPI3_HOST
/home//lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:181:22: error: 'HSPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
ENUM_HSPI_HOST = HSPI_HOST,
^~~~~~~~~
SPI3_HOST
/home//lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:182:22: error: 'VSPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
ENUM_VSPI_HOST = VSPI_HOST,
^~~~~~~~~
SPI3_HOST
that's the error you make at the fisrt time?

git submodule update --init --recursive

Sorry，I git the wrong repo branch.
Now it can be compiled without errors,I will test it later.

did you use the repo I linked to or did you use the files I attached in a zip?? If you used the zipped files don't, use the linked repo instead

Sorry，I git the wrong repo branch.
Now it can be compiled without errors,I will test it later.

make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_S3_SPIRAM IDF_TARGET=esp32s3

Mabey something wrong with SPI,
Screen show like this:

did you use the repo I linked to or did you use the files I attached in a zip?? If you used the zipped files don't, use the linked repo instead

I think there is still something wrong with SPI,
Init the screen there is a mistake：
("Failed initializing SPI bus")
I tried to trace the source code in ili9XXX
ret = esp.spi_bus_initialize(self.spihost, buscfg, 1)
ret return value:258 that's not right.
I change to ret = esp.spi_bus_initialize(self.spihost, buscfg, 0)
it works,but the screen show like this:

OK so there is a result at least. That's a good thing. going to have to hammer out any kinks in it.
Can you post the exact Micropython code you are using?
And do you have the exact model number of the Lillygo piece you are using? I want to see if everything is aligning properly between the screen the Micropython code and the c code..
Gotta develop a data path to see what is happening.

and that returned value is ESP_ERR_INVALID_ARG
hmmm...
Time to go digging.

I believe I found the issue.
I committed the changes to that same branch on my fork that I linked to in a previous post.
Give it a try again. It has to do with the DMA channel being used. If you have the repl open when you boot the ESP it will spit out any error codes if one does show up.

Use the script below to run the test with
import machine
import ili9XXX
import lvgl as lv

disp = ili9XXX.st7789(
    mosi=11,
    clk=12,
    cs=10,
    dc=13,
    rst=9,
    power=46,
    backlight=15,
    backlight_on=0,
    power_on=0,
    width=170,
    height=240,
    rot=ili9XXX.LANDSCAPE
)

lv.init()
scr = lv.obj()
btn = lv.btn(scr)
label = lv.label(btn)
label.set_text("Button")

Traceback (most recent call last):
File "", line 2, in
File "ili9XXX.py", line 64, in
AttributeError: 'module' object has no attribute 'ENUM_SPI_HOST'
Also no attribute:
SPI_DMA_DISABLED
ENUM_VSPI_HOST
ENUM_HSPI_HOST

import espidf as esp
help(esp)

SPI_HOST -- 0
VSPI_HOST -- 1
HSPI_HOST -- 2
SPI1_HOST -- 0
SPI2_HOST -- 1
SPI3_HOST -- 2
portMAX_DELAY -- -1
I2S_PIN_NO_CHANGE -- -1
only these const are defined
I try to chagne these const with value instead
It shows the same screen.
I think mabey I should change another st7789 screen 320x240
That's more easy to use.

Especially ESP32-S3，many borads use it instead of ESP32, but they can't be used in micropython yet,

@jd3096-mpy see #243 - this adds ESP32-S3 support. Could you try this PR on your side and see if it works for you?

Oh my god ,this repo works!!!
Here is my mpy code:
import machine
import ili9XXX
import lvgl as lv
power=machine.Pin(46, machine.Pin.OUT)
power.value(1)
bl=machine.Pin(15, machine.Pin.OUT)
bl.value(1)
disp = ili9XXX.st7789(
mosi=11,
clk=12,
cs=10,
dc=13,
rst=9,
width=320,
height=170,
start_x=0,
start_y=35,
rot=-2
)
lv.init()
style_base = lv.style_t()
style_base.init()
style_base.set_bg_color(lv.palette_main(lv.PALETTE.LIGHT_BLUE))
style_base.set_border_color(lv.palette_darken(lv.PALETTE.LIGHT_BLUE, 3))
style_base.set_border_width(2)
style_base.set_radius(10)
style_base.set_shadow_width(10)
style_base.set_shadow_ofs_y(5)
style_base.set_shadow_opa(lv.OPA._50)
style_base.set_text_color(lv.color_white())
style_base.set_width(100)
style_base.set_height(lv.SIZE_CONTENT)
Set only the properties that should be different
style_warning = lv.style_t()
style_warning.init()
style_warning.set_bg_color(lv.palette_main(lv.PALETTE.YELLOW))
style_warning.set_border_color(lv.palette_darken(lv.PALETTE.YELLOW, 3))
style_warning.set_text_color(lv.palette_darken(lv.PALETTE.YELLOW, 4))
Create an object with the base style only
obj_base = lv.obj(lv.scr_act())
obj_base.add_style(style_base, 0)
obj_base.align(lv.ALIGN.LEFT_MID, 20, 0)
label = lv.label(obj_base)
label.set_text("Base")
label.center()
Create another object with the base style and earnings style too
obj_warning = lv.obj(lv.scr_act())
obj_warning.add_style(style_base, 0)
obj_warning.add_style(style_warning, 0)
obj_warning.align(lv.ALIGN.RIGHT_MID, -20, 0)
label = lv.label(obj_warning)
label.set_text("Warning")
label.center()
screen:

If anyone wants to give this a go to see if it works I would appreciate it.
It should compile without errors. I do not have an SPI display to test it with.
https://github.com/kdschlosser/lv_binding_micropython/tree/esp32-s-c-h_support

GOD,I just found this repo works!
https://github.com/imliubo/lv_binding_micropython/tree/dev_esp32_s3
Thanks for you working,too.

Alot of the same changes I made except the adc blocks that can be used for the touch interfaces. With my changes all of the adc blocks are available.

I have a board with esp32s3 N16R8 which I would like to use with lv_micropython. I am glad to read that you guys are developing patches for the lvgl implementation to work with the esp32s3. However, I fail in trying to compile the lv_micropython code for esp32-s3. It is not clear to  me which repository to use. I tried the following:

using idf 4.4
cloning lv_micropython
git clone https://github.com/lvgl/lv_micropython.git
cd lv_micropython/
git submodule update --init --recursive lib/lv_bindings

then 1)
cloning the esp32-s-c-h_support branch from https://github.com/kdschlosser/lv_binding_micropython

copying all the files in this reposotry to the lv_micropython directory

then following the steps to compile lvgl:

make -C mpy-cross
make -C ports/esp32 submodules
make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_S3_SPIRAM IDF_TARGET=esp32s3

I get this error:

In file included from /opt/esp/idf/components/esp_rom/include/esp32s3/rom/ets_sys.h:19,
                 from /opt/esp/idf/components/freertos/port/xtensa/include/freertos/FreeRTOSConfig_arch.h:51,
                 from /opt/esp/idf/components/freertos/include/esp_additions/freertos/FreeRTOSConfig.h:16,
                 from /opt/esp/idf/components/freertos/include/freertos/FreeRTOS.h:57,
                 from /project/lv_micropython/ports/esp32/mpconfigport.h:10,
                 from /project/lv_micropython/py/mpconfig.h:62,
                 from /project/lv_micropython/py/obj.h:31,
                 from /project/lv_micropython/ports/esp32/build-GENERIC_S3_SPIRAM/lv_espidf.c:20:
/project/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h: In function 'SPH0645_WORKAROUND':
/project/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:85:18: error: implicit declaration of function 'I2S_TIMING_REG'; did you mean 'I2S_TX_TIMING_REG'? [-Werror=implicit-function-declaration]
     REG_SET_BIT( I2S_TIMING_REG(i2s_num), BIT(9));
                  ^~~~~~~~~~~~~~
/opt/esp/idf/components/soc/esp32s3/include/soc/soc.h:151:36: note: in definition of macro 'REG_SET_BIT'
             (*(volatile uint32_t*)(_r) |= (_b));
\
                                    ^~
/project/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:86:18: error: implicit declaration of function 'I2S_CONF_REG'; did you mean 'I2S_TX_CONF_REG'? [-Werror=implicit-function-declaration]
     REG_SET_BIT( I2S_CONF_REG(i2s_num), I2S_RX_MSB_SHIFT);
                  ^~~~~~~~~~~~
/opt/esp/idf/components/soc/esp32s3/include/soc/soc.h:151:36: note: in definition of macro 'REG_SET_BIT'
             (*(volatile uint32_t*)(_r) |= (_b));
\
                                    ^~
In file included from /project/lv_micropython/ports/esp32/build-GENERIC_S3_SPIRAM/lv_espidf.c:33:
/project/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h: At top level:
/project/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:180:21: error: 'SPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
     ENUM_SPI_HOST = SPI_HOST,
                     ^~~~~~~~
                     SPI3_HOST
/project/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:181:22: error: 'HSPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
     ENUM_HSPI_HOST = HSPI_HOST,
                      ^~~~~~~~~
                      SPI3_HOST
/project/lv_micropython/lib/lv_bindings/driver/esp32/espidf.h:182:22: error: 'VSPI_HOST' undeclared here (not in a function); did you mean 'SPI3_HOST'?
     ENUM_VSPI_HOST = VSPI_HOST,
                      ^~~~~~~~~
                      SPI3_HOST
cc1: some warnings being treated as errors
[33/187] Building C object esp-idf/lvgl/CMakeFiles/__idf_lvgl.dir/src/draw/sw/lv_draw_sw_rect.c.obj
ninja: build stopped: subcommand failed.
ninja failed with exit code 1
make: *** [Makefile:34: all] Error 2
make: Leaving directory '/project/lv_micropython/ports/esp32'

2- cloning the https://github.com/imliubo/lv_binding_micropython/tree/dev_esp32_s3 repository. Trying same steps as above, results in the same error.
Question:
can someone describe the stept I have to follow to compile a correct version of lv_micropython for the esp32s3. I would be glad to test the firmware on my board and comment on the results.

It's all still a work in progress I don't have an SPI TFT to test with and only having an esp32-s3 makes it a bit harder for me to make changes ans test because I don't know what would be broken the 8 bit parallel side of things or the esp32-s3 side of things.
I am going to order up an SPI screen pretty soon tho and that will make it easier for me to get running.

If I only could get a firmware that would run on my 16MB flash/8MBpsram, I could test it on my self-developed s3 board. Would it be possible to build one that I test?
Here is what I developed: an ESP32-s3 board with an SPI  ili9341 touch display. The tft and touch share the same SPI.

Here is a compiled firmware for the ESP32-S3 That has modified partitions to support the larger firmware and also supports SPIRAM.
Everything should be good to go with it you just need to upload it to your ESP32-S3 and then create a main.py file with the code for the display.
lvgl.zip
uncompress that into a folder and navigate to that folder and run the following command. You have to replace {port} with the serial port that you have the ESP attached to
You need to have the esptool python library installed.
esptool -p {PORT} -b 460800 --before default_reset --after no_reset --chip esp32s3  write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 bootloader.bin 0x8000 partition-table.bin 0x10000 micropython.bin

I uploaded the firmware (after a full erase) using your suggested esptool parameters, but unfortunately, I do not see the USB-CDC serial device being activated. On my board, I only use the native USB interface to the ESP32-S3, so the firmware should instantiate the USB serial port. Using one of the latest micropython firmwares, that works great and I can use REPL over the USB-CDC port.
Would it be possible to share the whole patched lv_micropython tree that you currently are using for building this firmware?

I linked to it in an earlier post

Found the problem with my ESP32S3-N16R8 module. It uses octal spi psram esp32. In the latest micropython distribution, a board called 'GENERIC_S3_SPIRAM_OCT' is added. By dropping that board in the lv_micopython boards directory solved at least the booting problem. Now everything builds fine. This is what I have done:
cd ~/esp32
git clone https://github.com/lvgl/lv_micropython.git
git clone --branch esp32-s-c-h_support https://github.com/kdschlosser/lv_binding_micropyth
on.git

cd ~/esp32/lv_micropython/
git submodule update --init --recursive lib/lv_bindings

cd ~/esp32/lv_binding_micropython
cp -a * ../lv_micropython/lib/lv_bindings/.

cd make -C mpy-cross
cd  ~/esp32/lv_micropython/ports/esp32
make submodules
# got some errors regarding git ownership, solved those with the suggestions in the error messages
make  LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_S3_SPIRAM_OCT IDF_TARGET=esp32s3

I had to change the partition-16MiB.csv to get some more space for the program:
# Notes: the offset of the partition table itself is set in
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x6000,
phy_init, data, phy,     0xf000,  0x1000,
factory,  app,  factory, 0x10000, 0x2F0000,
vfs,      data, fat,     0x300000, 0xD00000,

Using this program (which works with the same display on a ESP32-WROOM with 4MB PSRAM):
import espidf as esp
import lvgl as lv
from ili9XXX import ili9341,LANDSCAPE
from xpt2046 import xpt2046

#init display
disp = ili9341(miso=11, mosi=12, clk=13, cs=14, dc=8, rst=9,
               backlight=-1,power=-1,width=320, height=240,
               rot=LANDSCAPE,double_buffer=True)
# use same SPI as display, init touch
#touch = xpt2046(spihost=esp.HSPI_HOST,cs=2,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)

lv.init()
scr = lv.obj()
btn = lv.btn(scr)
label = lv.label(btn)
label.set_text("Button")
btn.center()
label.center()

results in the following:
Double buffer
ILI9341 initialization completed

and shows this on the screen:

disp = ili9341(miso=11, mosi=12, clk=13, cs=14, dc=8, rst=9,
               backlight=-1,power=-1,width=320, height=240,
               rot=LANDSCAPE,double_buffer=True)

I found the problem,too.
You can try these two ways:
1
change:
disp = ili9341(miso=11, mosi=12, clk=13, cs=14, dc=8, rst=9,
backlight=-1,power=-1,width=320, height=240,
rot=LANDSCAPE,double_buffer=True)
to
disp = ili9341(miso=11, mosi=12, clk=13, cs=14, dc=8, rst=9,
backlight=-1,power=-1,width=320, height=200,
rot=LANDSCAPE,double_buffer=True)
it can show normally
2 modify the drivers ili9XXX.py
156:
self.disp_buf.init(self.buf1, self.buf2, self.buf_size // 10)
it can work normally,too
the problem is about fbbuf
But I can't let xpt2046 work,Can you try it?

Found the problem with my ESP32S3-N16R8 module. It uses octal spi psram esp32. In the latest micropython distribution, a board called `GENERIC_S3_SPIRAM_OCT' is added. By dropping that board in the lv_micopython boards directory solved at least the booting problem. Now everything builds fine. This is what I have done:
cd ~/esp32
git clone https://github.com/lvgl/lv_micropython.git
git clone --branch esp32-s-c-h_support https://github.com/kdschlosser/lv_binding_micropyth
on.git

cd ~/esp32/lv_micropython/
git submodule update --init --recursive lib/lv_bindings

cd ~/esp32/lv_binding_micropython
cp -a * ../lv_micropython/lib/lv_bindings/.

cd make -C mpy-cross
cd  ~/esp32/lv_micropython/ports/esp32
make submodules
# got some errors regarding git ownership, solved those with the suggestions in the error messages
make  LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_S3_SPIRAM_OCT IDF_TARGET=esp32s3

I had to change the partition-16MiB.csv to get some more space for the program:
# Notes: the offset of the partition table itself is set in
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x6000,
phy_init, data, phy,     0xf000,  0x1000,
factory,  app,  factory, 0x10000, 0x2F0000,
vfs,      data, fat,     0x300000, 0xD00000,

Using this program (which works with the same display on an ESP32-WROOM with 4MB PSRAM) and disabling the touch for this test:
import espidf as esp
import lvgl as lv
from ili9XXX import ili9341,LANDSCAPE
#from xpt2046 import xpt2046

#init display
disp = ili9341(miso=11, mosi=12, clk=13, cs=14, dc=8, rst=9,
               backlight=-1,power=-1,width=320, height=240,
               rot=LANDSCAPE,double_buffer=True)
# use same SPI as display, init touch
#touch = xpt2046(spihost=esp.HSPI_HOST,cs=2,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)

lv.init()
scr = lv.obj()
btn = lv.btn(scr)
label = lv.label(btn)
label.set_text("Button")
btn.center()
label.center()

results in the following:
Double buffer
ILI9341 initialization completed

and shows this on the screen:

I found the problem,too.
You can try these two ways:
1
change:
disp = ili9341(miso=11, mosi=12, clk=13, cs=14, dc=8, rst=9,
backlight=-1,power=-1,width=320, height=240,
rot=LANDSCAPE,double_buffer=True)
to
disp = ili9341(miso=11, mosi=12, clk=13, cs=14, dc=8, rst=9,
backlight=-1,power=-1,width=320, height=200,
rot=LANDSCAPE,double_buffer=True)
it can show normally
2 modify the drivers ili9XXX.py
156:
self.disp_buf.init(self.buf1, self.buf2, self.buf_size // 10)
it can work normally,too
the problem is about fbbuf
But I can't let xpt2046 work,Can you try it?

@jd3096-mpy You 2nd suggestion works! Thanks for that. This is the result:

As for the touch, it worked just once. The touch sensor shares the SPI of the TFT. I have to check the pin-outs once more.

because the touch shares the SPI I believe there needs to be some work done on the display driver side of things and how it sets up the SPI, The SPI needs to be shared between the 2. I am running into the same kind of an issue with an 8bit parallel screen I have been dinking about with. 2 of the data pins are used for the touch so the pins need to be changed from output pins to input pins in order to read the touch data and then they need to get set back.
I think the best thing to do is possibly read the touch every time a screen write occurs. I am not sure how often the screen is redrawn or the mechanics behind it. Does it only perform a redraw if something on the screen changes? How does LVGL poll for touches being made? Those are things I am looking into.

I have exactly the same configuration with a ESP32-WROOM board with 4MByte of PSRAM. On that board the touch works just fine with this code:
# import libraries
from machine import I2S, Pin
import espidf as esp
import lvgl as lv
from ili9XXX import ili9341,LANDSCAPE
from xpt2046 import xpt2046

#init display
disp = ili9341( miso=12, mosi=13, clk=14, cs=15, dc=23, rst=25, backlight=-1,power=-1,width=320, height=240, rot=LANDSCAPE)
# use same SPI as display, init touch
touch = xpt2046(spihost=esp.HSPI_HOST,cs=26,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)
# enable backlight
l=Pin(2,Pin.OUT)
l.value(1)

def event_handler(evt):
    code = evt.get_code()

    if code == lv.EVENT.CLICKED:
            print("Clicked event seen")
    elif code == lv.EVENT.VALUE_CHANGED:
        print("Value changed seen")

# create a simple button
btn1 = lv.btn(lv.scr_act())

# attach the callback
btn1.add_event_cb(event_handler,lv.EVENT.ALL, None)

btn1.align(lv.ALIGN.CENTER,0,-40)
label=lv.label(btn1)
label.set_text("Button")

# create a toggle button
btn2 = lv.btn(lv.scr_act())

# attach the callback
#btn2.add_event_cb(event_handler,lv.EVENT.VALUE_CHANGED,None)
btn2.add_event_cb(event_handler,lv.EVENT.ALL, None)

btn2.align(lv.ALIGN.CENTER,0,40)
btn2.add_flag(lv.obj.FLAG.CHECKABLE)
#btn2.set_height(lv.SIZE_CONTENT)

label=lv.label(btn2)
label.set_text("Toggle")
label.center()

https://user-images.githubusercontent.com/51531682/210155254-72e513d4-05c1-47be-926e-4ffdea3d4b7f.mp4
PS. you can hear the fireworks going on outside ;)

I have exactly the same configuration with a ESP32-WROOM board with 4MByte of PSRAM. On that board the touch works just fine with the code below. Somehow, on the S3 platform something changed in sharing the SPI.:
# import libraries
from machine import I2S, Pin
import espidf as esp
import lvgl as lv
from ili9XXX import ili9341,LANDSCAPE
from xpt2046 import xpt2046

#init display
disp = ili9341( miso=12, mosi=13, clk=14, cs=15, dc=23, rst=25, backlight=-1,power=-1,width=320, height=240, rot=LANDSCAPE)
# use same SPI as display, init touch
touch = xpt2046(spihost=esp.HSPI_HOST,cs=26,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)
# enable backlight
l=Pin(2,Pin.OUT)
l.value(1)

def event_handler(evt):
    code = evt.get_code()

    if code == lv.EVENT.CLICKED:
            print("Clicked event seen")
    elif code == lv.EVENT.VALUE_CHANGED:
        print("Value changed seen")

# create a simple button
btn1 = lv.btn(lv.scr_act())

# attach the callback
btn1.add_event_cb(event_handler,lv.EVENT.ALL, None)

btn1.align(lv.ALIGN.CENTER,0,-40)
label=lv.label(btn1)
label.set_text("Button")

# create a toggle button
btn2 = lv.btn(lv.scr_act())

# attach the callback
#btn2.add_event_cb(event_handler,lv.EVENT.VALUE_CHANGED,None)
btn2.add_event_cb(event_handler,lv.EVENT.ALL, None)

btn2.align(lv.ALIGN.CENTER,0,40)
btn2.add_flag(lv.obj.FLAG.CHECKABLE)
#btn2.set_height(lv.SIZE_CONTENT)

label=lv.label(btn2)
label.set_text("Toggle")
label.center()

lms_esp32_lvgl.mp4
PS. you can hear the fireworks going on outside ;)

I slove this problem,too.
Just add half_duplex=False for touch init:
touch = xpt2046(spihost=esp.HSPI_HOST,cs=26,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)
touch = xpt2046(half_duplex=False,spihost=esp.HSPI_HOST,cs=26,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)
Just don't work on half_duplex mode!
By the way,Can you tell me how to get ths cal valus for x0 y0 x1 y1?

I have exactly the same configuration with a ESP32-WROOM board with 4MByte of PSRAM. On that board the touch works just fine with the code below. Somehow, on the S3 platform something changed in sharing the SPI.:
# import libraries
from machine import I2S, Pin
import espidf as esp
import lvgl as lv
from ili9XXX import ili9341,LANDSCAPE
from xpt2046 import xpt2046

#init display
disp = ili9341( miso=12, mosi=13, clk=14, cs=15, dc=23, rst=25, backlight=-1,power=-1,width=320, height=240, rot=LANDSCAPE)
# use same SPI as display, init touch
touch = xpt2046(spihost=esp.HSPI_HOST,cs=26,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)
# enable backlight
l=Pin(2,Pin.OUT)
l.value(1)

def event_handler(evt):
    code = evt.get_code()

    if code == lv.EVENT.CLICKED:
            print("Clicked event seen")
    elif code == lv.EVENT.VALUE_CHANGED:
        print("Value changed seen")

# create a simple button
btn1 = lv.btn(lv.scr_act())

# attach the callback
btn1.add_event_cb(event_handler,lv.EVENT.ALL, None)

btn1.align(lv.ALIGN.CENTER,0,-40)
label=lv.label(btn1)
label.set_text("Button")

# create a toggle button
btn2 = lv.btn(lv.scr_act())

# attach the callback
#btn2.add_event_cb(event_handler,lv.EVENT.VALUE_CHANGED,None)
btn2.add_event_cb(event_handler,lv.EVENT.ALL, None)

btn2.align(lv.ALIGN.CENTER,0,40)
btn2.add_flag(lv.obj.FLAG.CHECKABLE)
#btn2.set_height(lv.SIZE_CONTENT)

label=lv.label(btn2)
label.set_text("Toggle")
label.center()

lms_esp32_lvgl.mp4
PS. you can hear the fireworks going on outside ;)

I slove this problem,too.
Just add half_duplex=False for touch init:
touch = xpt2046(spihost=esp.HSPI_HOST,cs=26,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)
touch = xpt2046(half_duplex=False,spihost=esp.HSPI_HOST,cs=26,transpose=False,cal_x0=3865, cal_y0=329, cal_x1=399, cal_y1=3870)
Just don't work on half_duplex mode!
By the way,Can you tell me how to get ths cal valus for x0 y0 x1 y1?

I could have sworn I changed the partition size already. Maybe I didn't commit/push the update.
If you run the following on your ESP
import micropython

micropython.mem_info()

what does it say for total memory?? I am wondering if it is 8mb or only 4mb.

I could have sworn I changed the partition size already. Maybe I didn't commit/push the update.
If you run the following on your ESP
import micropython

micropython.mem_info()

what does it say for total memory?? I am wondering if it is 8mb or only 4mb.

example touch calibration and the calibration gets stored in NVRAM so no need to worry about hard coding the calibration numbers. If the touchscreen has not been calibrated it will launch the calibration process anbd when the calibration process has completed the ESP32 will reboot and the calibrations will get used and the calibration screen will not get seen again.
# import libraries
import time
from machine import Pin
import espidf as esp
import lvgl as lv
from ili9XXX import ili9341, LANDSCAPE
from xpt2046 import xpt2046
import esp32
from micropython import const
import _thread
import machine

lv.init()

# init display
disp = ili9341(
    miso=12,
    mosi=13,
    clk=14,
    cs=15, dc=23,
    rst=25, backlight=-1,
    power=-1,
    width=320,
    height=240,
    rot=LANDSCAPE
)

HRES = lv.scr_act().get_disp().driver.hor_res
VRES = lv.scr_act().get_disp().driver.ver_res

# touch calibrations stored in NVRAM
class TouchCalibration(object):

    def __init__(self):
        self._config = esp32.NVS('touch_cal')

        try:
            self._x0 = self._config.get_i32('x0')
        except OSError:
            self._x0 = 0

        try:
            self._y0 = self._config.get_i32('y0')
        except OSError:
            self._y0 = 0

        try:
            self._x1 = self._config.get_i32('x1')
        except OSError:
            self._x1 = HRES

        try:
            self._y1 = self._config.get_i32('y1')
        except OSError:
            self._y1 = VRES

        self._is_dirty = False

    def save(self):
        if self._is_dirty:
            self._config.commit()

    @property
    def x0(self):
        return self._x0

    @x0.setter
    def x0(self, value):
        self._x0 = value
        self._config.set_i32('x0', value)
        self._is_dirty = True

    @property
    def y0(self):
        return self._y0

    @y0.setter
    def y0(self, value):
        self._y0 = value
        self._config.set_i32('y0', value)
        self._is_dirty = True

    @property
    def x1(self):
        return self._x1

    @x1.setter
    def x1(self, value):
        self._x1 = value
        self._config.set_i32('x1', value)
        self._is_dirty = True

    @property
    def y1(self):
        return self._y1

    @y1.setter
    def y1(self, value):
        self._y1 = value
        self._config.set_i32('y1', value)
        self._is_dirty = True

    @property
    def is_calibrated(self):
        return not (
            self.x0 == 0 and
            self.y0 == 0 and
            self.x1 == HRES and
            self.y1 == VRES
        )

touch_calibration = TouchCalibration()

# use same SPI as display, init touch
touch = xpt2046(
    spihost=esp.HSPI_HOST,
    cs=26,
    transpose=False,
    cal_x0=touch_calibration.x0,
    cal_x1=touch_calibration.x1,
    cal_y0=touch_calibration.y0,
    cal_y1=touch_calibration.y1
)

# enable backlight
backlight = Pin(2, Pin.OUT)
backlight.value(1)

def main():

    def event_handler(evt):
        code = evt.get_code()

        if code == lv.EVENT.CLICKED:
            print("Clicked event seen")
        elif code == lv.EVENT.VALUE_CHANGED:
            print("Value changed seen")

    # create a simple button
    btn1 = lv.btn(lv.scr_act())

    # attach the callback
    btn1.add_event_cb(event_handler, lv.EVENT.ALL, None)

    btn1.align(lv.ALIGN.CENTER, 0, -40)
    label = lv.label(btn1)
    label.set_text("Button")

    # create a toggle button
    btn2 = lv.btn(lv.scr_act())

    # attach the callback
    # btn2.add_event_cb(event_handler,lv.EVENT.VALUE_CHANGED,None)
    btn2.add_event_cb(event_handler, lv.EVENT.ALL, None)

    btn2.align(lv.ALIGN.CENTER, 0, 40)
    btn2.add_flag(lv.obj.FLAG.CHECKABLE)
    # btn2.set_height(lv.SIZE_CONTENT)

    label = lv.label(btn2)
    label.set_text("Toggle")
    label.center()

if touch_calibration.is_calibrated:
    main()
else:
    # Run calibration
    class Tpcal_point:

        def __init__(self, x, y, name):
            self.display_coordinates = lv.point_t({'x': x, 'y': y})
            self.touch_coordinate = None
            self.name = name

        def __repr__(self):
            return "%s: (%d, %d)" % (
                self.name,
                self.touch_coordinate.x,
                self.touch_coordinate.y
            )

    CIRCLE_SIZE = const(20)
    CIRCLE_OFFSET = const(20)
    TP_MAX_VALUE = const(10000)
    LV_COORD_MAX = const((1 << (8 * 2 - 1)) - 1000)
    LV_RADIUS_CIRCLE = const(LV_COORD_MAX)

    class Tpcal:

        def __init__(self, points, calibrate_func, touch_count=5):
            self.points = points
            self.calibrate = calibrate_func
            self.touch_count = touch_count

            # Storage point to calculate median
            self.med = [lv.point_t() for _ in range(0, self.touch_count)]

            self.cur_point = 0
            self.cur_touch = 0

            self.scr = lv.obj(None)
            self.scr.set_size(TP_MAX_VALUE, TP_MAX_VALUE)
            lv.scr_load(self.scr)

            # Create a big transparent button screen to receive clicks
            style_transp = lv.style_t()
            style_transp.init()
            style_transp.set_bg_opa(lv.OPA.TRANSP)
            self.big_btn = lv.btn(lv.scr_act())
            self.big_btn.set_size(TP_MAX_VALUE, TP_MAX_VALUE)
            self.big_btn.add_style(style_transp, lv.PART.MAIN)
            self.big_btn.add_style(style_transp, lv.PART.MAIN)

            self.big_btn.add_event_cb(
                self.calibrate_clicked,
                lv.EVENT.CLICKED,
                None
            )

            # Create the screen, circle and label

            self.label_main = lv.label(lv.scr_act())

            style_circ = lv.style_t()
            style_circ.init()
            style_circ.set_radius(LV_RADIUS_CIRCLE)

            self.circ_area = lv.obj(lv.scr_act())
            self.circ_area.set_size(CIRCLE_SIZE, CIRCLE_SIZE)
            self.circ_area.add_style(style_circ, lv.STATE.DEFAULT)
            self.circ_area.clear_flag(
                lv.obj.FLAG.CLICKABLE
            )

            self.show_circle()

        def show_text(self, txt):
            self.label_main.set_text(txt)
            self.label_main.set_pos(
                (HRES - self.label_main.get_width()) // 2,
                (VRES - self.label_main.get_height()) // 2
            )

        def show_circle(self):
            point = self.points[self.cur_point]
            self.show_text(
                "Click the circle in\n" +
                point.name + "\n" +
                "%d left" % (self.touch_count - self.cur_touch)
            )

            if point.display_coordinates.x < 0:
                point.display_coordinates.x += HRES

            if point.display_coordinates.y < 0:
                point.display_coordinates.y += VRES

            self.circ_area.set_pos(
                point.display_coordinates.x - CIRCLE_SIZE // 2,
                point.display_coordinates.y - CIRCLE_SIZE // 2
            )

        def calibrate_clicked(self, event):
            point = self.points[self.cur_point]
            indev = lv.indev_get_act()
            indev.get_point(self.med[self.cur_touch])
            self.cur_touch += 1

            if self.cur_touch == self.touch_count:
                med_x = sorted([med.x for med in self.med])
                med_y = sorted([med.y for med in self.med])
                x = med_x[len(med_x) // 2]
                y = med_y[len(med_y) // 2]
                point.touch_coordinate = lv.point_t({'x': x, 'y': y})

                self.cur_point += 1
                self.cur_touch = 0

            if self.cur_point == len(self.points):
                self.calibrate(self.points)
                # letting the thread go so it is able to restart the ESP32
                self.show_text("Calibration Complete")
                t_lock.release()

                # self.big_btn.set_event_cb(
                #     self.check,
                #     lv.EVENT.PRESSING,
                #     None
                # )
            else:
                self.show_circle()

        def check(self, event):
            point = lv.point_t()
            indev = lv.indev_get_act()
            indev.get_point(point)
            self.circ_area.set_pos(
                point.x - CIRCLE_SIZE // 2,
                point.y - CIRCLE_SIZE // 2
            )

    # Calculate calibration, and calibrate

    def calibrate(points):
        visual_width = (
                points[1].display_coordinates.x -
                points[0].display_coordinates.x
        )
        visual_height = (
                points[1].display_coordinates.y -
                points[0].display_coordinates.y
        )
        touch_width = points[1].touch_coordinate.x - points[
            0].touch_coordinate.x
        touch_height = points[1].touch_coordinate.y - points[
            0].touch_coordinate.y

        pixel_width = touch_width / visual_width
        pixel_height = touch_height / visual_height

        x0 = (
                points[0].touch_coordinate.x -
                points[0].display_coordinates.x *
                pixel_width
        )
        y0 = (
                points[0].touch_coordinate.y -
                points[0].display_coordinates.y *
                pixel_height
        )

        x1 = (
                points[1].touch_coordinate.x +
                (HRES - points[1].display_coordinates.x) *
                pixel_width
        )
        y1 = (
                points[1].touch_coordinate.y +
                (VRES - points[1].display_coordinates.y) *
                pixel_height
        )

        print(
            "Calibration result: x0=%d, y0=%d, x1=%d, y1=%d" %
            (round(x0), round(y0), round(x1), round(y1))
        )
        touch.calibrate(round(x0), round(y0), round(x1), round(y1))
        touch_calibration.x0 = int(round(x0))
        touch_calibration.y0 = int(round(y0))
        touch_calibration.x1 = int(round(x1))
        touch_calibration.y1 = int(round(y1))
        touch_calibration.save()

    t_lock = _thread.allocate_lock()

    def _run():
        t_lock.acquire()
        tpcal = Tpcal([Tpcal_point(20, 20, "upper left-hand corner"), Tpcal_point(-40, -40, "lower right-hand corner")], calibrate)
        # we do a second acquire to hold the thread from exiting. once the
        # calibration has finished the lock will be released and then the module
        # will get rebooted
        t_lock.acquire()
        # sleep for 3 seconds so the user can see the
        # calibration complete message
        time.sleep_ms(3000)
        machine.reset()

    _thread.start_new_thread(_run, ())

    # let the main thread run off back to a repl prompt. Doing this allows you
    # to upload new code to the board without needing to flash the firmware
    # again. We don't want to use a while statement because that is a
    # "spinning wheels" deal that will consume all of the available processor
    # time. We do not want to use sleep either because there is no way to force
    # the exit of a sleep statement other then supplying a timeout. So better
    # to let the main thread run off and do it's thing and once the calibration
    # is finished we just reboot the ESP which will force a reload of the stored
    # calibrations and the main program will run from that point.

import micropython

micropython.mem_info()

stack: 736 out of 31744
GC: total: 8196480, used: 9152, free: 8187328
 No. of 1-blocks: 186, 2-blocks: 27, max blk sz: 32, max free sz: 511698

I get the full 8MByte of PSRAM.

half_duplex=False,

That did the trick! Touch works fine now. Thanks.

I compiled firmware for my Lilygo T-QT 128x128 module. This module uses GC9107 which seems to be compatible with GC9A01. I can create buttons,etc, on the screen. Only, the text is slipped upside down. it looks like the y-coordinate is flipped. Do you have any idea how, or where in the source code, I can fix this?

Only, the text is slipped upside down. it looks like the y-coordinate is flipped.

Did you try setting rot parameter of gc9a01 to REVERSE_PORTRAIT instead of PORTRAIT?

Only, the text is slipped upside down. it looks like the y-coordinate is flipped.

Did you try setting rot parameter of gc9a01 to REVERSE_PORTRAIT instead of PORTRAIT?

Yes, I tried all the different orientations and reverse. The text is still upside down.

Hi any update on the issue? I would like to build on a ESP32-S2, and I am unsure about what branch should I use.
I currently I am trying to do it from master, and I can build sucessfully BOARD GENERIC, but not GENERIC_S2 or GENERIC_S3.
Some guidence and help would be lovely! Thank you in advance!

Hi any update on the issue? I would like to build on a ESP32-S2, and I am unsure about what branch should I use.

As the maintainer of the Micropython Bindings for LVGL, I would love to see ESP32-S2 support integrated into the official lv_micropython repository. While I would have added this support myself if I were developing for the board, I am relying on the community for assistance.
There have been some community efforts, such as @imliubo fork and @kdschlosser fork. Please note that these forks are not officially maintained by LVGL and may not be up-to-date with the latest LVGL releases. Unfortunately, there have been no attempts to merge them back into lv_micropython.
An open PR exists, but it appears to be abandoned.
To merge ESP32-S2 support into lv_micropython, we need some testing and code cleanup. I would be happy to review any PRs from the community, and encourage anyone interested in contributing to this effort to do so.

I think we should make lvgl a extend module，the driver can use the micropython‘s c to reach. I have done the esp32s3_hal_lcd_i80 link to lvgl(lv_micropython), it also can use the micropython’s spi to do it，I will make the hal_RGB_LCD link the lv_micropython next.
https://github.com/fvstory/lcd_bind_lv_micropython

@kdschlosser here go！

already did that using gen_mpy. it builds it automatically.
I don't have a screen to test with tho so I never brought it up. All I know is it compiles properly.
What I did exposes all of the esp_lcd component. i8080, spi, i2s and rgb.
I also exposed the esp_hid component, usb component and twai

@kdschlosser I have test my work.perfect run，but if use the gen_mpy，you also need to write the c to link the flush_ready，is not ok from MP，I did try

it would be from MP if you use @micropython.viper. You just need to know how to declare the types. I would set up a python callback for the flush and then pass only the needed parameters to a function that uses viper. The viper code emitter turns the function into machine instructions.
You can also set it up so yo write the flush function in C code and pass any additional commands that need to be done while it is flushing as parameters to that callback. Just have a python intermediate callback that calls the function written in c code.

I bought this : https://www.makerfabs.com/sunton-esp32-s3-4-3-inch-ips-with-touch.html
Hoping to program it in micropython and with LVGL
Unfortunately, after fighting for hours, I realised thank's to this ticket that the micropython port of LVGL doesn't support the ESP32S3 yet
I have no idea how to do it, otherwise I would have help :/

you can give this a go. it is an altered version of the binding to work on the S3.
https://github.com/kdschlosser/lv_binding_micropython/tree/esp32-s-c-h_support

I have an esp32-s3-box-lite with a product introduction at https://github.com/espressif/esp-box .
Refer to https://github.com/imliubo/lv_binding_micropython/tree/dev_esp32_s3, modified source code of lv_micropython , and then compiled it as GENERIC_S3_SPIRAM_OCT .
Now I can run the lvgl program.

But there are still some problems:

Sometimes when starting up, it will freeze for a while, and then continue to run.
After running the lvgl program once, stop the program, and then run it again, the following error will appear:

Traceback (most recent call last):
  File "<stdin>", line 29, in <module>
  File "ili9XXX.py", line 586, in __init__
  File "ili9XXX.py", line 161, in __init__
  File "ili9XXX.py", line 240, in disp_spi_init
RuntimeError: Failed initializing SPI bus

           #File "ili9XXX.py", line 240, in disp_spi_init
          if ret != 0: raise RuntimeError("Failed initializing SPI bus")

Even if i use machine.reset() it doesn't work unless I press the Reset button.
The return code of esp.spi_bus_initialize is ESP_ERR_INVALID_STATE(259).

I have an esp32-s3-box-lite with a product introduction at https://github.com/espressif/esp-box .
Refer to https://github.com/imliubo/lv_binding_micropython/tree/dev_esp32_s3, modified source code of lv_micropython , and then compiled it as GENERIC_S3_SPIRAM_OCT .
Now I can run the lvgl program.
But there are still some problems:

Sometimes when starting up, it will freeze for a while, and then continue to run.
After running the lvgl program once, stop the program, and then run it again, the following error will appear:

Traceback (most recent call last):
  File "<stdin>", line 29, in <module>
  File "ili9XXX.py", line 586, in __init__
  File "ili9XXX.py", line 161, in __init__
  File "ili9XXX.py", line 240, in disp_spi_init
RuntimeError: Failed initializing SPI bus

           #File "ili9XXX.py", line 240, in disp_spi_init
          if ret != 0: raise RuntimeError("Failed initializing SPI bus")

Even if i use machine.reset() it doesn't work unless I press the Reset button. The return code of esp.spi_bus_initialize is ESP_ERR_INVALID_STATE(259). 3. Sometimes , the error of 2 is:
Traceback (most recent call last):
  File "<stdin>", line 28, in <module>
  File "ili9XXX.py", line 802, in __init__
  File "ili9XXX.py", line 159, in __init__
RuntimeError: Not enough DMA-able memory to allocate display buffer

import machine;machine.reset()  can't release SPI1.
import machine;machine.WDT(timeout=1000) can release SPI1.

OK where you are having an issue... The ili9XXX display driver that in the binding doesn't have any mechanism in place to specify where the DMA is allocated from. There are several different version of the S3 and without knowing the actual chip model there is no way to know if you have a version that has SPIRAM that has DMA ability.. The absolute very first thing you need to do when the program starts is get that display initialized. This needs to be done first because there is not all that much DMA memory available for the built in RAM. Ideally if possible you want the buffers to get initialized in the built in RAM instead of the SPIRAM. The SPIRAM is slow in comparison to the built in ram even with it being octal SPI.
One of the things you can do is pass factor=8 to the driver. This will decrease the size of the frame buffers, Also make sure to specify double_buffer=True as well.
If you perform a reset this does not flush all of the memory and is the reason why you are getting the SPI error. Pushing the reset button does flush the memory. If you shrink the frame buffer size and get the display initialized first thing those errors will not show up.

Specification

ESP32-S3-Box-Lite: ESP32-S3-WROOM-1-N16R8
DisPlay: ST7789V, 240 * 320

I use the following parameters to configure the display:
#init display
try:
    disp = st7789(
            mhz=4,
            miso=TFT_MISO,
            mosi=TFT_MOSI,
            clk=TFT_SCK,
            cs=TFT_CS,
            dc=TFT_DC,
            rst=TFT_RST,
            backlight=-1,
            power=-1,
            width=320,
            height=240,
            start_x=0,
            start_y=0,
            rot=ILI9341.REVERSE_LANDSCAPE,
            factor=10,
            double_buffer=True
            )
except Exception as e:
    print("Error:", e)
    machine.WDT(timeout=1000) # I added this to automatically restart so I can continue testing

The following parameters will still cause SPI initialization failure:
factor=8, double_buffer=True
# OR
factor=10, double_buffer=True

The error:
Double buffer
esp.spi_bus_initialize ret:  259
Error: Failed initializing SPI bus

what version of LVGL are you using?
 disp = st7789(
            mhz=4, < this is wrong. should be set to 40, maybe even 80
            miso=TFT_MISO,
            mosi=TFT_MOSI,
            clk=TFT_SCK,
            cs=TFT_CS,
            dc=TFT_DC,
            rst=TFT_RST,
            backlight=-1,
            power=-1,
            width=320,
            height=240,
            start_x=0,
            start_y=0,
            rot=ILI9341.REVERSE_LANDSCAPE, < where is this coming from?
            factor=10,  <-- I believe this has to be the result of 2 ^n. so 2^2 (4), 2^3(8), 2^4 (16)... etc
            double_buffer=True
            )

You should have your spihost set to VSPI_HOST. the st7789 class defaults to HSPI_HOST. you may also need to use the actual pins defined for that host.
I just double checked and it is connected to SPI3_HOST which is VSPI_HOST
byte order is BGR
color format is RGB565
clk is GPIO7
mosi is GPIO6
miso is -1
dc is GPIO4
cs is GPIO 5
the mhz is 40
spimode is 0
rst is GPIO48
They are doing almost exactly the same thing that is being done in the binding. I think you might be having an issue because of either one of the above things not being correct or the version of the binding you are using has issues in it.

I can tell you that for the size display you can use a factor of 8 and it will work properly so long as you initialize the display driver first and foremost.

from ili9XXX import LANDSCAPE, st7789
import espidf as esp
import lvgl as lv

disp = st7789(
            mhz=40
            miso=-1,
            mosi=6,
            clk=7,
            cs=5,
            dc=4,
            rst=48,
            backlight=45,
            power=-1,
            width=320,
            height=240,
            start_x=0,
            start_y=0,
            rot=LANDSCAPE,
            spihost=esp.VSPI_HOST,
            spimode=0,
            factor=8,
            double_buffer=True,
            color_format=lv.COLOR_FORMAT.NATIVE_REVERSED
            )

this is what I came up with.

import espidf as esp
import lvgl as lv
import ili9XXX as ILI9341
from ili9XXX import st7789

TFT_MISO = -1
TFT_MOSI = 6
TFT_SCK  = 7
TFT_RST = 48
TFT_CS  = 5
TFT_DC  = 4
TFT_BL  = 45

#gc.collect()
#print(gc.mem_free())

lv_ver = "%d.%d.%d-%s" % (lv.version_major(), lv.version_minor(), lv.version_patch(), lv.version_info())
print(lv_ver)

# enable backlight
l=Pin(TFT_BL,Pin.OUT)
l.value(0)

lv.init()

#init display
try:
    disp = st7789(
            mhz=40,
            miso=TFT_MISO,
            mosi=TFT_MOSI,
            clk=TFT_SCK,
            cs=TFT_CS,
            dc=TFT_DC,
            rst=TFT_RST,
            backlight=-1,
            power=-1,
            width=320,
            height=240,
            start_x=0,
            start_y=0,
            rot=ILI9341.REVERSE_LANDSCAPE,
            factor=8,
            double_buffer=True
            )
except Exception as e:
    print("Error:", e)
    machine.WDT(timeout=1000)
    time.sleep(1)

ILI9341.REVERSE_LANDSCAPE is for correct screen orientation
lv.version_major(), lv.version_minor(), lv.version_patch(), lv.version_info():

9.0.0-dev

l.value(0) to light the LCD.

My lcd already works fine, except for the problem I mentioned above.
    disp = st7789(
            mhz=40,
            miso=TFT_MISO,
            mosi=TFT_MOSI,
            clk=TFT_SCK,
            cs=TFT_CS,
            dc=TFT_DC,
            rst=TFT_RST,
            backlight=-1,
            power=-1,
            width=320,
            height=240,
            start_x=0,
            start_y=0,
            rot=ILI9341.REVERSE_LANDSCAPE,
            factor=8,
            double_buffer=True,
            spihost=esp.VSPI_HOST,
            spimode=0,
            color_format=lv.COLOR_FORMAT.NATIVE_REVERSED
            )

I use the above configuration, and when I run the code for the second time, an error still occurs:
Error: Failed initializing SPI bus
So I use the following code to reset automatically：
try:
    ......
except Exception as e:
    print("Error:", e)
    machine.WDT(timeout=1000)
    time.sleep(1)

color_format=lv.COLOR_FORMAT.NATIVE_REVERSED

On my box's lcd, the colors appear fine.
The color of the picture above is not normal, just because I took the photo at night.

I asked about the ILI9341.REVERSE_LANDSCAPE because i did not know where it was coming from due to the name that was being used at the front of it.
and that is the only code that is running, there is nothing that gets run before it?
so when you plug the ESP32 in and upload the main.py file to it  and then press the reset button you get the SPI initialization failure?
You should not be using the watchdog timer in the manner you are using it.. The WDT also restarts the ESP it does not reset it. restarting leaves a lot of the thing in memory in tact where as a reset is a full reboot which clears everything. Reset is the same as pressing the reset button.
machine.reset()
I have had this issue on occasion if my program went all kinds of sideways and the MCU restarted for whatever reason. a simple press of the reset button usually fixed it. Where I would run into this issue is when I connected to the ESP over serial. sometimes it would reset and sometimes it would restart it was a crap shoot when it would do it. I would simply press the reset button if it happened and it would then load without any issue.
I think the DMA memory has something to do with it and transactions not getting cleared out properly when a restart occurs. There is no  way to handle that other then making sure you clear out the transactions before restarting which is not going to happen because you are not really given any notification of when a watch dog timer fails and forces the restart.

Oh also to let you know. I have been working on a CPython binding and the binding is going to have the MicroPython API available for it. Faster development when you don't have to keep on flashing code changes over and over again. runs right on the desktop (Windows Linux or OSX). I am still hammering out some issues with the MicroPython API portion of it, the C API portion works. it's still an alpha version and it does have some glitches in it but it mostly works without any issues.

import ili9XXX as ILI9341

ILI9341.REVERSE_LANDSCAPE is same to ili9XXX.REVERSE_LANDSCAPE.
PORTRAIT = const(-1)
LANDSCAPE = const(-2)
REVERSE_PORTRAIT = const(-3)
REVERSE_LANDSCAPE = const(-4)

If I don't use this parameter, then my screen display is upside down.
About spi error, my test steps:

Connect esp32-s3-box-lite to my computer with data cable, and then in thonny, run the program which contains lvgl, it can run correctly.
In thonny, click stop button to stop the program.
Click run button, run the program again, an error throws: Error: Failed initializing SPI bus
use import machine; machine.reset(), run the program again, the same error throws: Error: Failed initializing SPI bus

How can it work again?

reconnect it to my computer
or push reset button
or import machine;machine.WDT(timeout=1000);

In thonny, click stop button to stop the program.

have you tried using a serial monitor and not thonny. Thonny connects to the ESP is an odd manner. I would try it just using a serial monitor like Putty.

In thonny, click stop button to stop the program.

have you tried using a serial monitor and not thonny. Thonny connects to the ESP is an odd manner. I would try it just using a serial monitor like Putty.

I didn't expect that thonny would have this problem.
I tested with minicom/picocom:

connect to board with minicom/picocom
run lgvl program
import machine; machine.reset()
reconnect to board with minicom/picocom
run lgvl program again, no error

everything looks good.

Thonny has a weird way of making the connection to MIcroPython. I know this because I had an issue with it as well. specifically when I changed the bitrate of the serial port and setting it to match in Thonny had to be done at the code level and it took me some time to locate where to change it.
I don't know if you know how to change the bitrate of the repl uart in MicroPython or not. I set the port to 921600 bps instead of 115200. I do this to upload scripts to it. I use ampy which I have modified so it doesn't get any errors. It creates an identical directory structure as what is fed into it and it checks any file that is not a python source file to see if it needs to be updated if it already exists.
I have come across the same issue as you when using ampy, sometimes the board doesn't properly reset and I need to manually press the button on the ESP32 after the upload of files. Not a big deal. I have not screwed around with the serial port and setting the RTS / CTS states on the serial port to get the ESP32 to reset. I am sure if I took a look at it I could fix it. I think it's RTS/CTS it could be RTS and DTR I would have to check the schematics for the ESP32 S3 devkit. I don't remember off the top of my head.
I wrote a binding to a kernel mode driver for Windows that would make the ESP32 look like a removable drive to Windows. Never finished up working with that because aat the time the ability to set the speed of UART0 in MicroPython on the ESP32 could not be done.

I wrote a binding to a kernel mode driver for Windows that would make the ESP32 look like a removable drive to Windows. Never finished up working with that because aat the time the ability to set the speed of UART0 in MicroPython on the ESP32 could not be done.

Like tinyuf2?

No. This doesn't get flashed to the MCU. It gets run on the PC connected to the PC. The connection can be over WiFi too. It uses the repl to do the transfers. If the connection is over the USB you can change the bitrate of UART0 to close to a megabit which speeds things up quite a bit.

I put some work into it again today and got it working doing a simple mirror of a local folder. It should be fairly simple to get it working with MicroPython. Currently it is only going to work for Windows.

Hello all,
I would like to tackle the problem "running lv_micropython on recent ESP32 hardware
by having lvgl run as user C module (from what I understood it seems the most future-proof and MCU-agnostic way to do).
I´ve read all your comments and remarks here, but i lack somehow a clear roadmap to achieve it. And for sure i will hit here or there the elastic wall of my own knowledge about C or Micropython, which is indeed to be happily challenged.

Who would be able to provide a synthetic, cleared, and detailed help on how to achieve this ?
Who would be able to join me in a time-limited, coordinated, collective effort to implement LVGL in micropython in the cleanest most elegant way possible ?

Hi @pak-man,
Running LVGL as a user C module does not automatically solve the problem of "running lv_micropython on recent ESP32 hardware". That's mostly because the challenge is fixing display drivers and ESP-IDF differences.
If you look at https://github.com/lvgl/lv_binding_micropython/pull/243, which is a PR by @imliubo for supporting esp32-s3, you'll notice most of the changes there are related to ESP-IDF and driver compatibility.
Unfortunately that PR seems abandoned, I believe it requires relatively small effort additional to fix and test it before it can be merged.  Personally, I'm currently not using esp32-s3 so I'm waiting for some volunteer to step in and complete this work.
There are also some private forks you can try (by @kdschlosser for example), but I'd rather see this merged upstream and maintained in a single location, instead of scattered around GitHub.
If there are any volunteers, I'll be happy to review PRs for "running lv_micropython on recent ESP32 hardware", but I cannot test it on my side for now so someone else would need to actively push this effort.
Regardless, if you are still interested in running LVGL as an external user C module, there's an open PR  (https://github.com/lvgl/lv_binding_micropython/pull/242) which is waiting for aligning to Micropython v1.20 (https://github.com/lvgl/lv_micropython/pull/65) which I'm actively working on.
But as said, I don't think this will help achieving your goal of "running lv_micropython on recent ESP32 hardware".

Thank you for the hints, I will likely start by updating #243  for a recent ESP-IDF version.
But I´m not sure about putting efforts into supporting an old ESP-IDF release that will be abandoned in 2024 https://github.com/micropython/micropython/issues/11078#top
Concerning the display drivers: there are a lot of display drivers around, also several display drivers for the same chipsets, sometimes C and also micropython.
I believe there is a need for a clean C display driver stub with lvgl hooks for micropython, along with -most important- a clear document describing generally how displays work (spi vs i2c protocol, bus speed, signals like reset, backlight, d/c, and concepts like double buffering, RGB/BGR.. encoding)
and some guidelines with a hands-on example how to cleanly implement a new driver:

get the relevant information for the datasheet about registers, signals, features ...
fill the stub with the relevant functions
hook those properly with LVGL

this would make so much easier the writing of new drivers (and a cleaner implementation of the existing ones) while providing a consistent micropython and LVGL integration. A bit like what circuitpython does - but i personally dislike the whole circuitpython fork precisely because of all the forced dependencies to a whole lot of circuitpython libraries .
Concerning ESP32 newest chips: If anybody want to join me in the effort, like @kdschlosser , I would consider sending boards free of charge if it can accelerate the process. I see that there is a program to reward developers, but it does not seem to get much traction, maybe because the people who would consider helping don´t have the right hardware on hand at first. I personally have a wide range of hardware available (most ESP32 version, RP2, STM32, as well as all supported or partially supported TFT displays in various resolutions with or without touchscreen...)

I tried to understand how to work with the custom bindings (kdschlosser or imliubo) for the S3, but I failed...
And I don't know why :/
Here is my complete procedure:

git clone -b v4.4 --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh
source export.sh
git clone https://github.com/lvgl/lv_micropython.git --recursive
cd lv_micropython/lib
rm -rf lv_bindings
git clone -b esp32-s-c-h_support https://github.com/kdschlosser/lv_binding_micropython.git lv_bindings --recursive
(- also tried with git clone -b dev_esp32_s3 https://github.com/imliubo/lv_binding_micropython.git lv_bindings --recursive
(- rm -rf ports/esp32/build-GENERIC)
cd ../
make -C ports/esp32
python3 esptool -p ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32  write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 build-GENERIC/bootloader/bootloader.bin 0x8000 build-GENERIC/partition_table/partition-table.bin 0x10000 build-GENERIC/micropython.bin
screen /dev/ttyUSB0 115200

Everything works fine, until I monitor the serial of the ESP
The error that I got at this point is:
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x10 (RTCWDT_RTC_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3808,len:0xf34
load:0x403c9700,len:0xc44
load:0x00000000,len:0x0
Checksum failure. Calculated 0x57 stored 0x00
ets_main.c 329
Could anyone please help me ?

Sometimes a make -C ports/esp32 (...) erase helps, did you try ?

I believe there is a need for a clean C display driver stub with lvgl hooks for micropython, along with -most important- a clear document describing generally how displays work

In the long term, I think the goal is to have drivers part of LVGL and not part of the bindings.
It makes sense to maintain all LVGL drivers in one place and use them on both C code and Micropython (or any other language with LVGL bindings for that matter).
Some work in that direction has already began: https://github.com/lvgl/lvgl/issues/4011, https://github.com/lvgl/lvgl/issues/2720 and Linux SDL/FB drivers are already part of LVGL and removed from the Micropython bindings.
@kisvegabor Could you comment on the timeline for pushing some display controller drivers (such as ILI9341) to LVGL?
I think that eventually, in the long term, we will only keep the pure Micropython generic drivers which are not architecture specific. These are naturally slower but have the advantage that they should work on any Micropython port.

you are not specifying the board.
make -c /ports/esp32 BOARD=GENERIC_S3_SPIRAM_OCT
make -c /ports/esp32 BOARD=GENERIC_S3_SPIRAM
or
make -c /ports/esp32 BOARD=GENERIC_S3

at this point in the game it is pointless to add or change anything specific for the ESP32 until the devs over at MicroPython finish up with getting the IDF 5.1 to work. The reason why is they are removing support for anything lower than IDF 5.1 so whatever code changes get made are going to end up having to get changed again.
If that PR that @amirgon made would get merged it would make it a whole lot easier for everyone because micropython would not have to be customized in the manner that is seen currently. There are a bunch of PRs that are not stale but are not getting merged and no real reasoning as to why they aren't It's quite frustrating because one of them is CAN interface for the ESP32. I have been waiting 2 years for that to get merged. I do not think that @amirgon 's PR will ever get merged either. it has been sitting there too long and I don't believe the author of MicroPython feels there is enough value in adding it because he is not importing modules have have as many QSTR's in it as this binding does.

Could you comment on the timeline for pushing some display controller drivers (such as ILI9341) to LVGL?

I think in 1 month we can have ILI9341 integrated.

you are not specifying the board.
make -c /ports/esp32 BOARD=GENERIC_S3_SPIRAM_OCT make -c /ports/esp32 BOARD=GENERIC_S3_SPIRAM or make -c /ports/esp32 BOARD=GENERIC_S3

it makes sense... Thanks @kdschlosser
I don't know which one is my ESP32, so I tried with the 3 boards, but none is working :/
S3 : it crashes at the last compilation step :
Error: app partition is too small for binary micropython.bin size 0x1fb650:

Part 'factory' 0/0 @ 0x10000 size 0x1f0000 (overflow 0xb650)
ninja: build stopped: subcommand failed.

S3_SPIRAM:
Compilation and flash work, but when I screen the serial port :
Build:Mar 27 2021
rst:0x7 (TG0WDT_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40043ac8
Invalid chip id. Expected 9 read 0. Bootloader for wrong chip?
ets_main.c 329
S3_SPIRAM_OCT:
doesn't start the cimpilation :
CMake Error at CMakeLists.txt:18 (message):
Invalid MICROPY_BOARD specified: GENERIC_S3_SPIRAM_OCT

ok you need to know which board you have. how much RAM does your board have? if it has 8mb then you need to use the board that has OCT in the name. If it has anything above 1MB or ram then you need to use the board that has SPIRAM without the oct and all others get used for the last board.
The error you are getting at the last step is  because the partition sizes are not set up properly. That is the one that is more than likely going to work once that issue is solved. If you give me a few hours I can make the changes needed to get you running using the one that failed at the last step.

@kdschlosser: Maybe I´m wrong, but I thought quad and oct spiram was related to the speed of the SPI RAM chip, not its capacity. Quad-SPI aka QSPI having respectively four data lines
https://embeddedinventor.com/quad-spi-everything-you-need-to-know/
and 8 data lines
https://www.apmemory.com/wp-content/uploads/APM_PSRAM_OPI_Xccela-APS256XXN-OBRx-v1.0-PKG.pdf
And the relevant compilation flags are used to configure this:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/kconfig.html#config-esptoolpy-oct-flash
Also you write about "8mb" and "1MB" which is basically the same.

It's for the SPI connected to the SPIRAM. 8mb memory uses OCTAL and 4 MB uses QUAD as does 2MB. There are low voltage variations of the MCU where that changes but they are not all that common.

sorry for incorrect capitalization. my bad. I am talking about megabytes. I usually type in mbit for megabit so there is no confusion that way.

Sorry but I'm not sure to understand...
On my module is written ESP32-S3-WROOM-1
Does it mean that I should try to compile with BOARD=GENERIC_S3_SPIRAM_QUAD ?
Because there is no such board description in the boards folder

As I said. You have to know how much memory there is. If it has 8MB of RAM then you use the board that has OCTAL in it. If the board has 2 MB of RAM then you use the one that just says SPIRAM and if the board has less than 2MB of memory then you use the last one.
Here are the choices you have for the  boards and the amount of memory you need to have in order to use that boaard
GENERIC_S3: < 2MB
GENERIC_S3_SPIRAM: 2MB
GENERIC_S3_SPIRAM_OCT: 8MB

I have been trying the last few days to get this thing compiled for an ESP32-C3, but it seems compilation keeps on failing on me. I'm not a c or cpp dev, but it seems something is off on the lv_bindings side since the error looks like pointing to something in there.
These are the steps I am executing (inside WSL, but don't think that matters):

mkdir esp
cd esp/
git clone -b v4.4 --recursive https://github.com/espressif/esp-idf.git
cd esp-idf/
ls
./install.sh
source export.sh
cd esp/esp-idf/
source export.sh
cd ..
git clone https://github.com/lvgl/lv_micropython.git --recursive
cd lv_micropython/lib/
rm -rf lv_bindings
git clone -b esp32-s-c-h_support https://github.com/kdschlosser/lv_binding_micropython.git lv_bindings --recursive
cd ..
make -C ports/esp32  BOARD=GENERIC_S3_SPIRAM_OCT

The result of this can be found in this gist: https://gist.github.com/calmera/1b1217fa96f3c2ef855cf5f976d41a4a
I have no idea what is going on here, but it feels like something off with modrtch.c and some things it is expecting but can't find.

This issue is way too long to fully read & comprehend in human time, so I have to ask: Is the 100$ offer still up, and what exactly still needs to be done, given that it seems kdschlosser has already done all the heavy lifting? I'm currently having trouble getting lv_bindings to compile with micropython 1.21 & idf-5.0-release-branch. I'd like to go bump it to v5.2 even. Any financial motivation would be welcome, but not necessary. Currently I'm trying to compile for the esp32. Afterwards I'll work on the other variants.

This no longer needs to be done because of MicroPython dropping support for all version of the IDF except for version 5 and newer.
what does need to be fixed and I am willing to give you 100 bucks to do it is to get LVGL to compile properly using MicroPython 1.21. The build system has been changed and now it will not compile.

Compiling LVGL with Micropython  for boards other than the ESP32 should be a non issue because LVGL is compiled as a user module. It would be nice if LVGL can be compiled as a user module for all boards and that is really the direction we are trying to go with it. only bus drivers would be supplied with the compilation and those would be compiled as a separate user module.
I have already written the bus drivers for the ESP32. need drivers written for the rest of the boards.

so currently there are difficulties compiling lvgl with micropython as a user C module, if and only if the target is an esp32/s2/s3?

If you separate the ESP_IDF specific stuff from the build I believe that you will have more success with getting it to compile properly as a user module. LVGL it self already compiles without any issues as a user module for other boards, it only has a problem on the ESP32. I think the goal is to compile the ESP specific stuff as a separate user module and remove as much as possible from the micropython build files. I already have the bus drivers compiling properly as as user module. just need to write the python display drivers which should be fairly simple to do.

I don't think the esp32 currently works for lv_binding_micropython, it only works for lv_micropython, w.r.t. esp-idf-v5.x. Is this correct? Right now, I've successfully managed to get lv_binding_micropython to compile for esp32 for micropython v1.22 preview & esp-idf-v5.0.x (release branch), but a simple test to display something to screen meditates at random moments, before the screen is done rendering. Here's a snapshot:

Here's the output from the repl:
MicroPython v1.22.0-preview.65.gbb6d085ee.dirty on 2023-11-18; Generic ESP32 module with ESP32
Type "help()" for more information.
>>> import test
[Info]	(0.000, +0)	 lv_init: begin 	(in lv_obj.c line #122)
[Warn]	(0.000, +0)	 lv_init: Memory integrity checks are enabled via LV_USE_ASSERT_MEM_INTEGRITY which makes LVGL much slower 	(in lv_obj.c line #206)
[Warn]	(0.000, +0)	 lv_init: Object sanity checks are enabled via LV_USE_ASSERT_OBJ which makes LVGL much slower 	(in lv_obj.c line #210)
[Warn]	(0.000, +0)	 lv_init: Style sanity checks are enabled that uses more RAM 	(in lv_obj.c line #214)
Double buffer
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
ILI9341 initialization completed
Enable backlight
[Warn]	(0.000, +0)	 lv_init: lv_init: already inited 	(in lv_obj.c line #118)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.000, +0)	 lv_btn_create: begin 	(in lv_btn.c line #49)
[Info]	(0.000, +0)	 lv_label_create: begin 	(in lv_label.c line #82)
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x400835ee  PS      : 0x00050731  A0      : 0x80084e29  A1      : 0x3ffc2210
A2      : 0x00000040  A3      : 0x00018040  A4      : 0x000637ff  A5      : 0x3ffc21d0
A6      : 0x00000000  A7      : 0x3ffdffa4  A8      : 0x3ffc21d4  A9      : 0x00000000
A10     : 0x00000000  A11     : 0x3ffdfec8  A12     : 0x8023840c  A13     : 0x3ffc21b0
A14     : 0x00000001  A15     : 0x00000001  SAR     : 0x0000001e  EXCCAUSE: 0x0000001c
EXCVADDR: 0x80084e35  LBEG    : 0x401ddc24  LEND    : 0x401ddc2d  LCOUNT  : 0x00000000

Backtrace: 0x400835eb:0x3ffc2210 0x40084e26:0x3ffda500 0x400e9936:0x3ffda540 0x400e96fb:0x3ffda580 0x400e948d:0x3ffda5e0 0x400e90c0:0x3ffda610 0x40132019:0x3ffda660 0x40131ca7:0x3ffda6b0 0x401b8492:0x3ffda6f0 0x401b67fb:0x3ffda710 0x401b7da1:0x3ffda730 0x4019e80d:0x3ffda750 0x4019e8d1:0x3ffda770 0x40085e29:0x3ffda790 0x40197a9c:0x3ffda830 0x4019e80d:0x3ffda860 0x401ed80f:0x3ffda880 0x401ed861:0x3ffda8c0 0x4019e80d:0x3ffda8e0 0x4019e891:0x3ffda900 0x401f0444:0x3ffda930 0x4019f56d:0x3ffda9b0 0x401
b1dd0:0x3ffda9d0 0x401a67dd:0x3ffdaa00 0x40197991:0x3ffdaa20 0x4019e80d:0x3ffdaa40 0x40085d79:0x3ffdaa60 0x40197a9c:0x3ffdab00 0x4019e80d:0x3ffdab30 0x4019e878:0x3ffdab50 0x401de725:0x3ffdab90 0x401dea52:0x3ffdabc0 0x4019e94d:0x3ffdacb0 0x400860c6:0x3ffdacf0 0x40197a9c:0x3ffdad90 0x4019e80d:0x3ffdade0 0x4019e822:0x3ffdae00 0x401f332a:0x3ffdae20 0x401f366c:0x3ffdaeb0 0x401b1a94:0x3ffdaef0 0x4031ce76:0x3ffdaf20

ELF file SHA256: 2aaf5124b292e992

CPU halted.

... another test....
>>> import test
import test
[Info]	(0.000, +0)	 lv_init: begin 	(in lv_obj.c line #122)
[Warn]	(0.000, +0)	 lv_init: Memory integrity checks are enabled via LV_USE_ASSERT_MEM_INTEGRITY which makes LVGL much slower 	(in lv_obj.c line #206)
[Warn]	(0.000, +0)	 lv_init: Object sanity checks are enabled via LV_USE_ASSERT_OBJ which makes LVGL much slower 	(in lv_obj.c line #210)
[Warn]	(0.000, +0)	 lv_init: Style sanity checks are enabled that uses more RAM 	(in lv_obj.c line #214)
Double buffer
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
ILI9341 initialization completed
Enable backlight
[Warn]	(0.000, +0)	 lv_init: lv_init: already inited 	(in lv_obj.c line #118)
[Info]	(0.000, +0)	 lv_obj_create: begin 	(in lv_obj.c line #305)
[Info]	(0.040, +40)	 lv_sysmon_create: begin 	(in lv_sysmon.c line #75)
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

The test code is:
from ili9XXX import ili9341
import lvgl as lv
from espidf import HSPI_HOST,VSPI_HOST
from time import sleep

display=ili9341(miso=15, mosi=27, clk=26, cs=13, dc=14, rst=12, spihost=HSPI_HOST, mhz=20, factor=8, hybrid=False)
lv.init()

scr = lv.obj()
#btn = lv.btn(scr)
#btn.align_to(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
#label = lv.label(btn)
#label.set_text("Hello World!")
#lv.scr_load(scr)
sleep(5)

coredump.txt
lv_conf.h.txt
The top #0 & #1 functions of the currently running task (mp_task), are always identical, and it is always mp_task that is crashing (is the last thread running at moment of crash). The PC address and the prohibited load address (VADDR) are always identical across crashes, although the length of the stack and the exact moment of the crash is non-deterministic.
Just wanted to ask if anyone has an idea off the top of their heads what is going on, to save me some time debugging. At first I thought it was a gc issue, but I've attached lv_conf.h and I'm definately sure this file and this file only is getting picked up. I even changed some defines to rule out kconfig getting chosen, and any changes to lv_conf.h are manifesting themselves correctly, such as turning logging on/off.

As I had stated previously, strip all of the esp specific parts of the LVGL build out and build it as a user c module. Then we can add in the drivers. It would only take me 30 minutes to code a driver for the display you are using.
We don't know if it is something LVGL is doing that is causing the problem or something that the driver is doing.
Try eliminating making a driver. provide an empty flush callback and call lv.flush_ready(disp) from inside of the function. That way you are removing the driver from the equation. see if it still crashes. if it doesn't then we know where the problem is stemming from.

u still didnt answer the qjestion, and it has been over a year since this issue was opened, i think you would have finished the driver by now?

Again if you remove all code that gets generated in the cmake files that is not for LVGL you will no longer have an issue with the ESP32S3 and such as that is where the problems stem from. There is a different driver framework that we are going to be doing that will be a separate thing. Right now the gen_mpy script converts some of the ESP-IDF into Micropython C code and that is where the current compatibility issues stem from.

I didn't try the esp32s3 yet. This is about the esp32 right now. The issue is resolved, see the edited comment.

By you changing the hybrid tells me it is a problem with the driver and not with LVGL.

yeah... I'll look deeper into it later when I have the time... whether it is an esp-idf bug, a compatibility issue due to autogeneration, or a mistake in the python file itself. but I'll be doing the rest of the updating in this repo. I will unsubscribe here. Look there for future updates.

@moefear85
I have gotten the binding to compile with LVGL as a user module using MicroPython 1.21 with ESP-IDF 5.0.4. I am sure it will work with later version of the IDF as well..
It compiles properly for the ESP32 and also Unix. I have not messed about with the other boards yet. Therte is a single python script used as the entry point to compile it. I deep sixed the display drivers that were included before. I wrote a wrapper around the esp_lcd component to expose the API to the interpreter. I only exposed the bus portions of the esp_idf because the display ddriver can be written in Python. I8080, SPI, I2C and RGB busses are exposed.  The bus drivers take care of setting up the frame buffers.
https://github.com/kdschlosser/lv_binding_micropython/tree/MicroPython_1.21.0_Update

bravo good work. I guess you can close this issue then. When you're done we can compare speeds. I'm running on esp32s3 right now using fully native esp drivers and it is FAST (master lvgl/mpy/esp-idf)

i realized how flexible the gen_mpy.py script is and use it directly now to pythonify any api, not just the esp-idf's driver. I don't need to write any boilerplate anymore to get anything in C to show up in mpy. Hence simply bumping the package versions is a piece of cake.

I am not the maintainer of this repo. I am just a lowly user. LOL.
While the gen_mpy script can handle writing the code to make it work in MicroPython it is not going to do it the most efficient way. It is going to add things that might not get used and things of that nature. It is an easy way to get it working but it comes at a cost. That is the reason why I hard coded the drivers for the bus. Working on an MCU means that every byte counts. so the additional bytes used not only in storage but also in RAM can be the tipping point for someone's project working or not. As an example. In order to use the gen_mpy script to expose macros those macros need to be turned into enums and because the enums get used in a global namespace it ends up using up resources. A single boolean parameter to a function can free up many bytes of memory. If a user specifies double buffering then DMA memory is to be used. simple testing if a buffer is valid will tell you if the next step is to place it into PSRAM instead of SRAM. So there ends up being no reason to expose any of the allocation portions of the ESP-IDF.
I went the route that you did close to a year ago.

Easy guys. Everyone is here to work on something interesting and have fun with it. All we need to do is channeling this interest in a constructive way.
I'm not an expert of this topic so I cannot comment on the technical part in a meaningful way, but I can do help to make everyone feel good.
As I scroll back it seems the conversation was quite balanced, however I do understand if @moefear85 has no time to participate at this level. This is fine, however it should be expressed in a respectful way.
@moefear85 please let us know how can you contribute with this update. Participating only with testing and providing feedback is more than welcome too.

@kisvegabor
I don't see what is wrong with anything I said. Why are you taking sides anyways? I really don't need to explain myself. Take it or leave it. Blocking both of you.

You don't have to explain yourself and I'm not taking sides.
If you are busy with something else feel free to comment here if you have free time for this.

About a year ago I experimented with the S3 port that @kdschlosser prepared. With his help, I succeeded in getting my own designed board running with a 2.8" LCD screen. Now, I bought an ESP32S3 board with 16bit parallel LCD There is a port of lvgl in micropython supplied by the vendor, but I would like to test the newest firmware that you are developing in this git repo. So, how should I proceed in building a firmware for this board? I will try to compile the git as is using the esp-idf 5, first, but I will need some help to get the screendriver working, I am afraid.

This is an alpha test version. it is going to have some bugs in it I am sure. If you are willing to go through the steps needed to bug test it I can get you up and running.
https://github.com/kdschlosser/lv_binding_micropython/tree/MicroPython_1.21.0_Update

The board you just bought says it's an RGB interface but when you look at the datasheet for the driver IC and the schematics the board is not using an RGB interface (MIPI-DPI) it is using an I8080 interface (MIPI-DBI type B)

see if you can get MicroPython to compile properly without LVGL involved. I suspect there is something else going on... Did you clone the repository or did you download it? There are specific versions of LVGL and MicroPython that are being used so you have to clone the repository and init the submodules as is described in the directions. You also need to use ESP-IDF versions 5.0.4 as that is what the MicroPython version is set up for.

The display and the touch controller drivers are going to need to be written in Python. It's fairly easy to do and I can do that up for ya... There are no display drivers included in the firmware only the bus drivers.

Built and tested on esp32-c3 and working fine, need ST7789 display driver now, without display is not possible test lvgl

OK I will get you a driver for the ST7789

Those constants cause  warnings not errors. I would not worry about them at all. If you can paste the entire contents of the build output I can see what is going on.

Yes the script corrects the partition sizes in the event of an overflow. I need to also have it adjust the other way around and shrink a partition size if needs be. I have not gotten that far into it yet.

Did you compile the first time around using the following??
make.py esp32 -mpy_cross -submodules -clean BOARD=ESP32_GENERIC_S3 MICROPY_BOARD_VARIANT=SPIRAM_OCTAL

I also recommend adding -clean every time. this way you know you are getting a clean build.

@AndreoBotelho
I believe the ST7789 is the same as the ST7796. you can give this a shot for the display drivers.
st7796_driver.zip
You also need to initialize a bus. Here are some code examples
I8080
import lcd_bus
from micropython import const
import lvgl as lv

_DISPLAY_WIDTH = const(480)
_DISPLAY_HEIGHT = const(320)

bus = lcd_bus.I8080Bus(
    dc=1,
    wr=2,
    cs=3,
    data0=4,
    data1=5,
    data2=6,
    data3=7,
    data4=8,
    data5=9,
    data6=10,
    data7=11,
    # additional data pins here if using 16 lanes
    freq=10 * 1000 * 1000,
    dc_idle_level=False,
    dc_cmd_level=False,
    dc_dummy_level=False,
    dc_data_level=True,
    cmd_bits=8,
    param_bits=8,
    buffer_size=int((_DISPLAY_WIDTH * _DISPLAY_HEIGHT) // 10) * lv.color_t.__SIZE__,
    fb_in_psram=False,
    use_dma=True,
    cs_active_high=False,
    reverse_color_bits=False,
    swap_color_bytes=False,
    pclk_active_neg=False,
    pclk_idle_low=False
)

SPI

import lcd_bus
from micropython import const
import lvgl as lv

_DISPLAY_WIDTH = const(480)
_DISPLAY_HEIGHT = const(320)

bus = lcd_bus.SPIBus(
    dc=1,
    host=1,
    mosi=2,
    miso=3,
    sclk=4,
    cs=5,
    freq=-1,
    wp=-1,
    hd=-1,
    quad_spi=False,
    tx_only=False,
    cmd_bits=8,
    param_bits=8,
    buffer_size=int((_DISPLAY_WIDTH * _DISPLAY_HEIGHT) // 10) * lv.color_t.__SIZE__,
    fb_in_psram=False,
    use_dma=True,
    dc_low_on_data=True,
    sio_mode=False,
    lsb_first=False,
    cs_high_active=False,
    spi_mode=0
)

Thanks for the drivers.
First I need to get the ps_ram running. It seems that during compilation it does not take the octal psram driver, but still uses the quad:
[654/1722] Building C object esp-idf/esp_psram/CMakeFiles/__idf_esp_psram.dir/esp32s3/esp_psram_impl_quad.c.obj

I still get the psram initialization error.
I have included the whole build output.
compile_output.txt

The compilation seems to be good.
do me a favor change your directory to micropython under the binding and key in these commands. I am going to have you build MicroPython without LVGL and see if you still get the error.
make clean -C ports/esp32 BOARD=ESP32_GENERIC_S3 MICROPY_BOARD_VARIANT=SPIRAM_OCTAL
make -C ports/esp32 BOARD=ESP32_GENERIC_S3 MICROPY_BOARD_VARIANT=SPIRAM_OCTAL

My module is ESp32S2 MON16R8, so 16MByte of flash and 8MByte of PSRAM.
Using compile of only micropython as you suggested also results in the psram error.

Hi @martytriska ,
I tried that. Can you elobrate on step 3. If I run idf.py menuconfig I change the settings in the /ports/esp32/build directory and not in the build-ESP32_GENERIC_S3. How can I change the sdkconfig settings and that compile without resetting the sdkconfig to its defaults?

change to IDF version 5.0.2. I was just told that is what Micropython supports. it's not 5.0.4.. I could swear I saw somewhere in their changelog that it is 5.0.4 but I could be mistaken.

It could also be docker causing some kind of an issue, possibly because of the make.py script launching a subprocess?

Thanks @martytriska for mentioning the direct build again. @ste7anste7an must not have seen it when I said to do that.

@ste7anste7an
did you use docker with the compilation that worked?

@kdschlosser
Yes, I use docker and the recipe given by @martytriska  generates a full functioning firmware.
How do I proceed in writing an ili9488 driver as you did for the ST7796 display. It seems that I have to rewrite the example_display_driver.py file for an ILI9488 initialization. By te way, it should be lcd_bus.I80Bus in the example you gave earlier.

Did you use docker when compiling it using make and not make.py??
I need to figure out where the problem is,

@AndreoBotelho
I believe the ST7789 is the same as the ST7796. you can give this a shot for the display drivers.
st7796_driver.zip
You also need to initialize a bus. Here are some code examples
I8080
import lcd_bus
from micropython import const
import lvgl as lv

_DISPLAY_WIDTH = const(480)
_DISPLAY_HEIGHT = const(320)

bus = lcd_bus.I8080Bus(
    dc=1,
    wr=2,
    cs=3,
    data0=4,
    data1=5,
    data2=6,
    data3=7,
    data4=8,
    data5=9,
    data6=10,
    data7=11,
    # additional data pins here if using 16 lanes
    freq=10 * 1000 * 1000,
    dc_idle_level=False,
    dc_cmd_level=False,
    dc_dummy_level=False,
    dc_data_level=True,
    cmd_bits=8,
    param_bits=8,
    buffer_size=int((_DISPLAY_WIDTH * _DISPLAY_HEIGHT) // 10) * lv.color_t.__SIZE__,
    fb_in_psram=False,
    use_dma=True,
    cs_active_high=False,
    reverse_color_bits=False,
    swap_color_bytes=False,
    pclk_active_neg=False,
    pclk_idle_low=False
)

SPI

import lcd_bus
from micropython import const
import lvgl as lv

_DISPLAY_WIDTH = const(480)
_DISPLAY_HEIGHT = const(320)

bus = lcd_bus.SPIBus(
    dc=1,
    host=1,
    mosi=2,
    miso=3,
    sclk=4,
    cs=5,
    freq=-1,
    wp=-1,
    hd=-1,
    quad_spi=False,
    tx_only=False,
    cmd_bits=8,
    param_bits=8,
    buffer_size=int((_DISPLAY_WIDTH * _DISPLAY_HEIGHT) // 10) * lv.color_t.__SIZE__,
    fb_in_psram=False,
    use_dma=True,
    dc_low_on_data=True,
    sio_mode=False,
    lsb_first=False,
    cs_high_active=False,
    spi_mode=0
)

SPI bus is resulting in Core  0 panic'ed (Instruction access fault). Exception was unhandled when acessing the frame buffer pointer returned from  data_bus.get_frame_buffer

I figured that I would have an issue with the frame buffer. I gotta figure out how to return it as an array.array or a memory view object. The latter would be better.

I am working on the problem now. I am trying to find the most elegant way of handling passing the buffer.

It is going to be a little bit longer. I decided to reorganize the source files for the bus drivers. I wanted to reduce the code footprint so I am combining duplicate code into functions that are going to get shared. I am almost done with it. I have to hammer out a compilation error.
I am returning a memory view object for the buffer so I am hoping that the gen_mpy script has written into the binding aa way to handle a memoryview object being passed. I am hoping it does as this would be the best transport mechanism otherwise I will have to return a bytearray which is going to consume more memory. Not a ton more but I am all about keeping the resource use as low as absolutely possible.
I am probably going to split the lcd_bus module into 4 separate modules to reduce the amount of ram used. The flash size may increase by a really small amount but that is less of an issue than available memory. I am really wanting to be able to squeeze larger sized buffers in SRAM than what is able to be done currently especially on the ESP32 which doesn't have a whole lot of DMA memory available to start off with.
Do you guys think that I should automatically try to put the buffers into SRAM and if that fails then place it into SPIRAM? or should I let the user specify where they want it to be placed and if it doesn't work throw an error?

@AndreoBotelho
what you can try in the meantime is changing the fb_in_psram parameter from False to True when constructing the buffer. See if that will work. It might be that there is not enough memory available in SRAM to make the buffers and that is the reason why it is failing. I have not coded in any specific testing of the buffers yet. I do plan on adding that in to make sure the buffers initialized properly just haven't gotten that far yet.

thanks for the work, unfortunately ESP32-C3 doesn't support psram, i´ve tested some ST7789 pure python drivers and they're working fine but to support LVGL the driver need some changes, its possible to code a simple framework with pure python? I know it will be slower but this gives time to work on a c version that we can use when ready

@kdschlosser

Do you guys think that I should automatically try to put the buffers into SRAM and if that fails then place it into SPIRAM? or should I let the user specify where they want it to be placed and if it doesn't work throw an error?

As long as the manual method does not need too many parameters, I would opt for that option.

It adds 2 additional parameters. use_dma and fb_in_psram. buffer_size is an optional parameter and it defaults to -1. if it is -1 at the construction of the bus then the buffers will be automatically made when the display driver calls the init method of the bus. The reason why I did it this way is because of memory allocation into SRAM. If the bus is the first thing that is initialized in the users application and the buffer size is given the first thing the bus driver does is makes the frame buffers. This gives a better chance of being able to get the frame buffers into SRAM instead of the slower PSRAM. The use_dma is defaulted to True and the fb_in_psram is defaulted to False. If use_dma is set to False only a single frame buffer is going to be made. There is no point to using double buffering if DMA memory is not used because the program is going to stall while the data in the buffer is being transmitted so it becomes pointless to have a second buffer. The purpose of double buffering is to be able to send a buffer and while that is taking place be able to fill a second buffer. no DMA means that the buffer being written is a blocking call.

@kdschlosser
I would like to test my ILI9488 display with your new compiled firmware. What would be the steps that I need to take to get it running? The I8080 interface seems to be implemented already. Can I craft a driver for the ILI9488 together based on the example code you provided for the ST7789, where I replace the initialization with that what I find in a regu;ar ILI9488 driver? Or is it wise to wait a little bit until you had time to execute your plans that you described earlier?

I just updated the repository. I believe it will fix some of the issues that were going on. I also reduced the compiled size by a couple thousand bytes. so the firmware is not a couple K smaller. I know it's not a huge amount but every little bit counts especially for the folks wanting to use OTA updates for the firmware.  I think with moving LVGL into a user module it can now also be compiled as as an mpy module so it doesn't have to be shipped built into the firmware. Doing this would help the folks that was to be able to do OTA updates. Downside is additional memory used when loading the module.

I also added in the display driver framework into the firmware also.

ili9488 driver has been added. this is not going to be built into the firmware so you will need to transfer it to your esp like the rest of the code for your app

It is compiling and starting but lv.timer_handler() hangs and display driver framework has a error on line 145, the bus doesn't have frame_buffer_size() method

OK I pushed a commit that should fix the framework error and the get_frame_buffer_size not existing. I am hoping that it won't freeze up now but we will see.
Give it a go and see what happens.

OK there is another change I made. The way it was done before it kept things running in an ISR and then would schedule tasks to run. I satopped it from doing that as ISRs use up a considerable amount of processor time due to states needing to be saved and loaded.
Instead you need to loop your code in an endless fashion.
import time
import lvgl as lv

# setup code here

start_time = time.ticks_ns()

left_over = 0
while True:
    # user_code here
    curr_time = time.ticks_ns()
    new_amount = time.ticks_diff(curr_time, start_time) + left_over
    left_over = new_amount & 0x3E8
    lv.tick_inc(new_amount >> 12)
    lv.task_handler()
    start_time = curr_time

something along those lines.
You also have to call the display drivers  init method after constructing the driver. This will initialize the display.
If your display has a power pin then you need to turn the power on before calling the init method.
display.power = True

If your display has a backlight pin then you will need to turn the backlight on after you have called the init method.
display.backlight = 100

you have the option of setting the display backlight to use PWM if your display has been set up to do this. You have to tell the display driver to use PWM for the backlight pin by setting backlight_on_state to STATE_PWM

The looping code I am using avoids the use of fractional numbers or any division math. Because nanoseconds are 1000th of a millisecond we can use bitwise operations to get milliseconds that have elapsed. Because of the nanosecond resolution I want to add any "leftovers" to the new time measurement so this way it will be as accurate as possible when incrementing the time that has passed in LVGL. I include the amount of time that LVGL takes to do it's thing as well. that time counts also!!!

OooooOOoOO I forgot one other thing. Just like before you need to specify the color depth in the same manner when compiling.
LVFLAGS="LV_COLOR_DEPTH=16"

changing 16 to whatever the color depth is for your display. That needs to be added onto the make.py compile line.
python3 make.py esp32 -mpy_cross -submodules -clean BOARD=ESP32_GENERIC BOARD_VARIANT=SPIRAM LVFLAGS="LV_COLOR_DEPTH=16"

There's some typing errors but after compiling it is stil hanging on task handler, the driver sends the first chunk of data to display and lvgl hangs, display is blank.
*driver/esp32/lcd_bus/src/../include/modlcd_bus.h:96:14: error: 'self' is a pointer; did you mean to use '->'?
*driver/esp32/lcd_bus/src/../include/modlcd_bus.h:98:21: error: 'self' is a pointer; did you mean to use '->'?
*driver/esp32/lcd_bus/src/modlcd_bus.c:23:16: error: 'bus_obj' is a pointer; did you mean to use '->'?

OK i fixed the type errors and committed the changes. So that should be good to go.
Let me see about returning the buffers as an array.array object. Maybe that will correct the problem.

I just pushed a commit. see if that fixes the issue with the buffers. I have not tested the code at all so lemme know how you make out.

Error compiling /include/modlcd_bus.h:173:48: error: 'BYTEARRAY_TYPECODE' undeclared (first use in this function)

Ok I missed an include. I will see if I can get that fixed from where I am. I am not at home

I made a bunch of changes.
I am hoping that this time I have the buffers fixed. It would be nice if it is.
I updated the make.py script. The second go around compiling after changing the partition size is now a whole lot faster, it doesn't compile the entire things again. I also updated it so it resizes up and also down if needs be. I added a command line switch to turn off the resizing, -skip-partition-resize is what you add when you run make.py
I also have the script automatically disabling I2C for the time being. This is due to an upstream bug in MicroPython. It has been reported and hopefully it will  be fixed along with the btree issue in the next release. Fingers crossed there.
A added some additional output to the build that is easily seen so the user will know what is taking place when the build starts over again. Just informative messages is all.
I did test compile before I committed and pushed the changes. So there should be no type errors when compiling.

The code compliled fine bus SPI display still not working, I've made some tests using a upy driver and the problem is that disp_drv.flush_ready() is never called in your code, this hags lgvl waiting the display, there's some problem with SPI transfer. Using soft SPI (without DMA) LVGL is running fine.

OK I will have a look and see what's up with it. So the issue is in the bus driver somewhere.
Just as a question what are the parameters you are passing to the bus driver. I would like to se if maybe I am initializing it incorrectly and if that is the source of the hang.
I am going to dig out my MCU's and displays. I will put together a couple of testing setups. I probably will not do any more updating of the repo until I get everything working properly.

the speed is actually limited to 26.6 mhz. my bad on that one.

I made a couple of small changes. so I would update your code and try it again with the buffer size change

I added the exceptions for memory allocation.

Also, version 9.0 isn't a mess. the API has changed. It works just fine.

the speed is actually limited to 26.6 mhz. my bad on that one.

ESP32-C3/S3/S2 SPI can go up to 80Mhz  using gpio matrix. only original ESP32 have this 26.6Mhz limit but I've tested and could reach 60Mhz on a ESP32 rev3 using SPI through GPIO matrix

says it right here in the documentation
https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/spi_master.html#_CPPv418spi_bus_add_device17spi_host_device_tPK29spi_device_interface_config_tP19spi_device_handle_t

While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz.

so 26.6 mhz is as fast as it will go using full duplex over the GPIO matrix.

says it right here in the documentation
https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/spi_master.html#_CPPv418spi_bus_add_device17spi_host_device_tPK29spi_device_interface_config_tP19spi_device_handle_t

While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz.

so 26.6 mhz is as fast as it will go using full duplex over the GPIO matrix.
scroll to the top and check for yourself. The documentation is set to the ESP32S3.

Yes, this note exists in all ESP32 model docs but only on ESP32 original there's a note about timing linking to it, all othes says
When an SPI Host is set to 80 MHz or lower frequencies, routing SPI pins via the GPIO matrix will behave the same compared to routing them via IOMUX.
on esp32 original there's this note:
`The GPIO matrix introduces flexibility of routing but also brings the following disadvantages:
Increases the input delay of the MISO signal, which makes MISO setup time violations more likely. If SPI needs to operate at high speeds, use dedicated IO_MUX pins.
Allows signals with clock frequencies only up to 40 MHz, as opposed to 80 MHz if IO_MUX pins are used.
Note
For more details about the influence of the MISO input delay on the maximum clock frequency, see Timing Considerations.`
The 26Mhz is only full duplex but I can't much use for full duplex on a display bus

Update: fixed some code and now the LCD BUS using Spi is sending perfect data to display with or without DMA, the only problem is that the transmission needs to be syncronous because the code is unable to call a python function from C, direct calling gives infinite recurssion and sheduled call never gets called on Py VM.

PS: I'm using the code with mpy malloc and works fine, the bus passing a array buffer and sending back with dereference from py

Yes you can create a byte array and pass it  to C code and it will work as a buffer. Problem is no ability to specify where that data is to be stored, DMA SRAM, DMA SPIRAM, SRAM or SPIRAM, It goes into where ever it is going to fit.

I'm using your commit d782fec55fd7e62618239ac18ab18b606025a975 before change the frame buffers, on framework flush_cb need to uncomment the code
        size = (x2 - x1 + 1) * (y2 - y1 + 1)
        data_view = color_p.__dereference__(size * lv.color_t.__SIZE__)  # NOQA

to not get segfault when passing the buffer back to C and include
disp_drv.flush_ready()
after flush_cb code to not hang LVGL on wainting flush loop, this way the LCD_BUS works in sincronous (slow) or unmanaged DMA (a little faster)

I know what is going on with the flush function I am trying to dereference more memory than has been allocated. That is what is causing the segfault/hang.
SIZE can no longer be used to determine the color depth that is being used.
Ot should now read
        data_view = color_p.__dereference__(size * lv.color_format_get_size(disp.get_color_format()))  # NOQA

That should fix the issue in the flush function.

How things are done is when the buffer gets passed to the display driver initially that buffer gets converted into an LVGL CArray. That CArray then gets passed to the flush function and this is the reason why you need to use the dereference. doing that converts the object into a MicroPython MemoryView object I have to change the C code to handle collecting the pointer from that memoryview object to pass it to the driver as an actual C pointer.
I just figurred all of this out in the last couple of days.

I know what is going on with the flush function I am trying to dereference more memory than has been allocated. That is what is causing the segfault/hang.
SIZE can no longer be used to determine the color depth that is being used.
It should now read
        data_view = color_p.__dereference__(size * lv.color_format_get_size(disp.get_color_format()))  # NOQA

That should fix the issue in the flush function.

The hang is due to mp_sched_schedule never beeing called on python code ( maybe the lvgl wait flush never returns the control to mpy) and if you change to mp_call_function get recursion error

After spending countless hours/days/weeks trying to get a mix of MicroPython 1.22, IDF 5.1.2 and LVGL 9.1 working as a USER_C_MODULE I could directly use from my MicroPython build using any and all resources I could find I finally caved and gave up trying to adapt existing solutions.
I crafted a custom repository that is specialized for my use case but still worth sharing in case others find it useful and perhaps it is useful to get this issue, PR https://github.com/lvgl/lv_binding_micropython/pull/242 or PR https://github.com/lvgl/lv_binding_micropython/pull/341 moving.
You can find the repository here: https://github.com/MathyV/lvgl_esp32_mpy
If you have an ESP32 connected to an ST7789 display over SPI, this solution will probably work out-of-the-box for you.
Finally, a small movie that shows it's working:
https://github.com/lvgl/lv_binding_micropython/assets/6393603/116b9a7e-0ece-4a5a-8ce4-8f664d7004b2

Thank you the countless  hours/days/weeks you put into it and for sharing the result! :+1:
@kdschlosser is into approaching it from a new perspective too and he also made good progress, but I'm not sure what is the exact status on his end.