lvgl-micropython / lvgl_micropython

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

RGBDisplay frame buffer allocation failure on ESP32-S3 #20

Closed bland328 closed 4 months ago

bland328 commented 5 months ago

I have a Sunton ESP32-8048S043 board with ESP32-S3 (16MB QIO flash / 8MB OPI SPIRAM), 800×480 parallel IPS display, and GT911 capacitive touch digitizer.

lvgl_micropython is building, installing and fundamentally working, but I'm running into a problem allocating the RGBDisplay frame buffer.

Here's how I'm building the firmware under macOS Sonoma: python3 make.py esp32 clean mpy_cross BOARD=ESP32_GENERIC_S3 BOARD_VARIANT=SPIRAM_OCT DISPLAY=rgb_display INDEV=GT911

Here's my main.py:

import micropython
micropython.mem_info()

import lcd_bus
display_bus = lcd_bus.RGBBus(
    hsync = 39,
    vsync = 41,
    de = 40,
    disp = -1,
    pclk = (12 * 1000 * 1000),
    data0 = 8, data1 = 3, data2 = 46, data3 = 9, data4 = 1,  # B
    data5 = 5, data6 = 6, data7 = 7, data8 = 15, data9 = 16, data10 = 4,  # G
    data11 = 45, data12 = 48, data13 = 47, data14 = 21, data15 = 14,  # R
    hsync_front_porch = 8,
    hsync_back_porch = 8,
    hsync_pulse_width = 4,
    hsync_idle_low = True,
    vsync_front_porch = 8,
    vsync_back_porch = 8,
    vsync_pulse_width = 4,
    vsync_idle_low = True,
    de_idle_high = False,
    pclk_idle_high = False,
    pclk_active_low = True,
    disp_active_low = False,
)

import rgb_display
import lvgl as lv
display = rgb_display.RGBDisplay(
    data_bus = display_bus,
    display_width = 800,
    display_height = 480,
    color_byte_order = rgb_display.BYTE_ORDER_BGR,
    color_space = lv.COLOR_FORMAT.RGB565,
)

And here's the resulting output:

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0xf8c
load:0x403c9700,len:0xb3c
load:0x403cc700,len:0x2dd4
entry 0x403c989c
stack: 656 out of 15360
GC: total: 64000, used: 3120, free: 60880, max new split: 8257536
 No. of 1-blocks: 20, 2-blocks: 6, max blk sz: 30, max free sz: 3704
E (5974) lcd_panel.rgb: lcd_rgb_panel_alloc_frame_buffers(156): no mem for frame buffer
E (5974) lcd_panel.rgb: esp_lcd_new_rgb_panel(285): alloc frame buffers failed
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x420bb3ac  PS      : 0x00060030  A0      : 0x820bbf8e  A1      : 0x3fced740
A2      : 0x3fcac9a0  A3      : 0x3c1f7a5c  A4      : 0x3c1f7e3c  A5      : 0x00001756
A6      : 0x3c1f7a5c  A7      : 0x3c1f7f74  A8      : 0x00000000  A9      : 0x7fffffff
A10     : 0x0000005a  A11     : 0x3fcedefc  A12     : 0x3fced720  A13     : 0x0000000c
A14     : 0x3c1f7a5c  A15     : 0x00000008  SAR     : 0x00000004  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000  LBEG    : 0x400556d5  LEND    : 0x400556e5  LCOUNT  : 0xfffffffa

Backtrace: 0x420bb3a9:0x3fced740 0x420bbf8b:0x3fced760 0x420034bd:0x3fced7f0 0x42001cc1:0x3fced850 0x4200164b:0x3fced8a0 0x420c295d:0x3fced8f0 0x420c9719:0x3fced920 0x420c97dd:0x3fced940 0x4037a7e1:0x3fced960 0x420c28fc:0x3fceda00 0x420c9719:0x3fceda30 0x420c97dd:0x3fceda50 0x420c83b8:0x3fceda70 0x420c81ed:0x3fcedad0 0x420c9719:0x3fcedaf0 0x420c97dd:0x3fcedb10 0x4037a7e1:0x3fcedb30 0x420c28fc:0x3fcedbd0 0x420c9719:0x3fcedc00 0x420c972e:0x3fcedc20 0x420d5cfa:0x3fcedc40 0x420d609d:0x3fcedcd0 0x420dd713:0x3fcedd00

Any thoughts on what I'm getting wrong, or what I might try next?

kdschlosser commented 5 months ago

I need to make a change to the code to handle that issue. This is due to how the RGB driver works.

In the meantime here is what you can do.

import micropython
micropython.mem_info()

import lcd_bus
display_bus = lcd_bus.RGBBus(
    hsync = 39,
    vsync = 41,
    de = 40,
    disp = -1,
    pclk = (12 * 1000 * 1000),
    data0 = 8, data1 = 3, data2 = 46, data3 = 9, data4 = 1,  # B
    data5 = 5, data6 = 6, data7 = 7, data8 = 15, data9 = 16, data10 = 4,  # G
    data11 = 45, data12 = 48, data13 = 47, data14 = 21, data15 = 14,  # R
    hsync_front_porch = 8,
    hsync_back_porch = 8,
    hsync_pulse_width = 4,
    hsync_idle_low = True,
    vsync_front_porch = 8,
    vsync_back_porch = 8,
    vsync_pulse_width = 4,
    vsync_idle_low = True,
    de_idle_high = False,
    pclk_idle_high = False,
    pclk_active_low = True,
    disp_active_low = False,
)

buf1 = display_bus.allocate_framebuffer(800 * 480 * 2, lcd_bus.MEMORY_SPIRAM)
buf2 = display_bus.allocate_framebuffer(800 * 480 * 2, lcd_bus.MEMORY_SPIRAM)

import rgb_display
import lvgl as lv
display = rgb_display.RGBDisplay(
    data_bus = display_bus,
    display_width = 800,
    display_height = 480,
    frame_buffer1=buf1,
    frame_buffer2=buf2,
    color_byte_order = rgb_display.BYTE_ORDER_BGR,
    color_space = lv.COLOR_FORMAT.RGB565,
)
kdschlosser commented 5 months ago

I updated the code so clone it again and give it a try the problem should be fixed without you needing to manually create the buffers like in my last post.

bland328 commented 5 months ago

Thanks very much for that, @kdschlosser!

Sadly, either way I do it (manually or the newly-updated way), I get this failure immediately after the rgb_display.RGBDisplay() call:

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x420bbe78  PS      : 0x00060030  A0      : 0x8200356c  A1      : 0x3fced760
A2      : 0x3c251b38  A3      : 0x3fcac9a0  A4      : 0x00000000  A5      : 0x00000000
A6      : 0x60009050  A7      : 0x00000000  A8      : 0x820bbe4d  A9      : 0x3c1f5540
A10     : 0x00b71b00  A11     : 0x0000001f  A12     : 0x00000000  A13     : 0x00000000
A14     : 0xffffffc0  A15     : 0x3c3d7b0c  SAR     : 0x00000017  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0x00000000

Backtrace: 0x420bbe75:0x3fced760 0x42003569:0x3fced7f0 0x42001ccd:0x3fced850 0x42001657:0x3fced8a0 0x420c2a09:0x3fced8f0 0x420c97c5:0x3fced920 0x420c9889:0x3fced940 0x4037a7e1:0x3fced960 0x420c29a8:0x3fceda00 0x420c97c5:0x3fceda30 0x420c9889:0x3fceda50 0x420c8464:0x3fceda70 0x420c8299:0x3fcedad0 0x420c97c5:0x3fcedaf0 0x420c9889:0x3fcedb10 0x4037a7e1:0x3fcedb30 0x420c29a8:0x3fcedbd0 0x420c97c5:0x3fcedc00 0x420c97da:0x3fcedc20 0x420d5da6:0x3fcedc40 0x420d6149:0x3fcedcd0 0x420dd7bf:0x3fcedd00

It appears this may be a result of accessing an illegal memory location; unfortunately, I'm not yet quite ESP32-savvy enough to determine if this might be my fault somehow, or beyond my control.

kdschlosser commented 5 months ago

Lets decode the backtrace.

~/.espressif/tools/xtensa-esp32s3-elf/esp-2022r1-11.2.0/xtensa-esp32s3-elf/bin/xtensa-esp32-elf-addr2line -e /lib/micropython/ports/esp32/build-ESP32_GENERIC_S3-SPIRAM_OCT/micropython.elf 0x420bbe75:0x3fced760 0x42003569:0x3fced7f0 0x42001ccd:0x3fced850 0x42001657:0x3fced8a0 0x420c2a09:0x3fced8f0 0x420c97c5:0x3fced920 0x420c9889:0x3fced940 0x4037a7e1:0x3fced960 0x420c29a8:0x3fceda00 0x420c97c5:0x3fceda30 0x420c9889:0x3fceda50 0x420c8464:0x3fceda70 0x420c8299:0x3fcedad0 0x420c97c5:0x3fcedaf0 0x420c9889:0x3fcedb10 0x4037a7e1:0x3fcedb30 0x420c29a8:0x3fcedbd0 0x420c97c5:0x3fcedc00 0x420c97da:0x3fcedc20 0x420d5da6:0x3fcedc40 0x420d6149:0x3fcedcd0 0x420dd7bf:0x3fcedd00

You may have to adjust the path to xtensa-esp32-elf-addr2line. I am not sure where it gets put on MACOS

kdschlosser commented 5 months ago

download the attached file and unzip it. The upload it to your MCU. When the driver framework loads it will use this one ionstead of the one that is baked into the firmware automatically.

display_driver_framework.zip

I added a bunch of print statements to see where it is tanking. The backtrace stuff isn't going to give any insight into location for the python code so this will help locate the function call that is tanking it.

bland328 commented 5 months ago

Here's the output from your alternate display_driver_framework.zip:

stack: 656 out of 15360
GC: total: 64000, used: 3472, free: 60528, max new split: 8257536
 No. of 1-blocks: 24, 2-blocks: 12, max blk sz: 30, max free sz: 3666
START
if not lv.is_initialized
DONE
databus is not None
self._disp_drv = lv.display_create
DONE
self._disp_drv.set_color_format
DONE
self._disp_drv.set_driver_data
DONE
framebuffer is None
allocating buffers
2056
1032
DONE
checking framebuffer 2
data_bus.init
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x420bbe78  PS      : 0x00060030  A0      : 0x8200356c  A1      : 0x3fced760
A2      : 0x3c251b38  A3      : 0x3fcac9a0  A4      : 0x00000000  A5      : 0x00000000
A6      : 0x60009050  A7      : 0x00000000  A8      : 0x820bbe4d  A9      : 0x3c1f5540
A10     : 0x00b71b00  A11     : 0x0000001f  A12     : 0x00000000  A13     : 0x00000000
A14     : 0xffffffc0  A15     : 0x3c3d7b0c  SAR     : 0x00000017  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0x00000000

Backtrace: 0x420bbe75:0x3fced760 0x42003569:0x3fced7f0 0x42001ccd:0x3fced850 0x42001657:0x3fced8a0 0x420c2a09:0x3fced8f0 0x420c97c5:0x3fced920 0x420c9889:0x3fced940 0x4037a7e1:0x3fced960 0x420c29a8:0x3fceda00 0x420c97c5:0x3fceda30 0x420c9889:0x3fceda50 0x420c8464:0x3fceda70 0x420c8299:0x3fcedad0 0x420c97c5:0x3fcedaf0 0x420c9889:0x3fcedb10 0x4037a7e1:0x3fcedb30 0x420c29a8:0x3fcedbd0 0x420c97c5:0x3fcedc00 0x420c97da:0x3fcedc20 0x420d5da6:0x3fcedc40 0x420d6149:0x3fcedcd0 0x420dd7bf:0x3fcedd00
bland328 commented 5 months ago

I just realized that this line from my main.py:

pclk = (12 * 1000 * 1000),

was written under the assumption that pclk is a frequency, but now I'm realizing it should likely be the number of the GPIO pin which runs to the DCLK line of the display. Does this sound right?

kdschlosser commented 5 months ago

Yup I just saw that too.

kdschlosser commented 5 months ago

I mean JUST now I saw that... LOL..

kdschlosser commented 5 months ago

pclk you set to 42 and freq you set to 12000000

kdschlosser commented 5 months ago

Everything else looks to be correct.

kdschlosser commented 5 months ago

You might have to dink about with the freq setting a bit if your display image is not centered.. You might be able to push it up to a higher clock frequency than 12mhz. you have to test it to find out.

I have a waveshare display here that in the docs it says 16mhz but 13mhz is what works with the image centered correctly and not scrolling horizontally when the display redraws

kdschlosser commented 5 months ago

It will work like it should once you make those changes.

bland328 commented 5 months ago

The crash is gone, and the output with your alternate display_driver_framework.py still installed is this:

START
if not lv.is_initialized
DONE
databus is not None
self._disp_drv = lv.display_create
DONE
self._disp_drv.set_color_format
DONE
self._disp_drv.set_driver_data
DONE
framebuffer is None
allocating buffers
2056
1032
DONE
checking framebuffer 2
data_bus.init
DONE
self._disp_drv.set_flush_cb
DONE
self._disp_drv.set_buffers
DONE
data_bus.register_callback
INIT DONE

I added display.init() to the end of main.py, hoping I'd at least see the backlight come on, but no luck so far.

It's very late for me here, so I'll tackle this again after I've slept. Thanks very much for your help to this point!

kdschlosser commented 5 months ago
display = rgb_display.RGBDisplay(
    data_bus = display_bus,
    display_width = 800,
    display_height = 480,
    backlight_pin = 2,
    color_byte_order = rgb_display.BYTE_ORDER_BGR,
    color_space = lv.COLOR_FORMAT.RGB565,
)

display.init()
display.set_backlight(100)

scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)

slider = lv.slider(scrn)
slider.set_size(200, 50)
slider.center()

import time

while True:
    time.sleep_ms(1)
    lv.tick_inc(1)
    lv.task_handler()

That will get you rolling.

bland328 commented 5 months ago

Thanks so much, @kdschlosser, both for your time creating lvgl_micropython and for your generous assistance.

At this point, the backlight is on and I have a white screen, but nothing renders.

Would you guess I'm up against a problem in my definition of either lcd_bus.RGBBus or rgb_display.RGBDisplay?

Or is it more likely I'm mishandling lvgl itself somehow?

Here's main.py as it stands now:

import time, micropython
micropython.mem_info()

import lcd_bus
display_bus = lcd_bus.RGBBus(
    hsync = 39,
    vsync = 41,
    de = 40,
    disp = -1,
    pclk = 42,  # to TFT DCLK
    data0  = 8,  data1  = 3,  data2  = 46, data3  = 9,  data4  = 1,  # B
    data5  = 5,  data6  = 6,  data7  = 7,  data8  = 15, data9  = 16, data10 = 4,  # G
    data11 = 45, data12 = 48, data13 = 47, data14 = 21, data15 = 14,  # R
    freq = 12000000,
    hsync_front_porch = 8,
    hsync_back_porch = 8,
    hsync_pulse_width = 4,
    hsync_idle_low = True,
    vsync_front_porch = 8,
    vsync_back_porch = 8,
    vsync_pulse_width = 4,
    vsync_idle_low = True,
    de_idle_high = False,
    pclk_idle_high = False,
    pclk_active_low = True,
    disp_active_low = False,
)

import rgb_display
import lvgl as lv
display = rgb_display.RGBDisplay(
    data_bus = display_bus,
    display_width = 800,
    display_height = 480,
    backlight_pin = 2,
    color_byte_order = rgb_display.BYTE_ORDER_BGR,
    color_space = lv.COLOR_FORMAT.RGB565,
)

display.init()
display.set_backlight(100)

scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)

slider = lv.slider(scrn)
slider.set_size(200, 50)
slider.center()

while True:
    time.sleep_ms(1)
    lv.tick_inc(1)
    lv.task_handler()
kdschlosser commented 5 months ago

By looking at the specs for the display I am going to say this is what you need to be running..

import time, micropython
micropython.mem_info()

import lcd_bus
display_bus = lcd_bus.RGBBus(
    hsync = 39,
    vsync = 41,
    de = 40,
    disp = -1,
    pclk = 42,  # to TFT DCLK
    data0  = 8,  data1  = 3,  data2  = 46, data3  = 9,  data4  = 1,  # B
    data5  = 5,  data6  = 6,  data7  = 7,  data8  = 15, data9  = 16, data10 = 4,  # G
    data11 = 45, data12 = 48, data13 = 47, data14 = 21, data15 = 14,  # R
    freq = 12000000,
    hsync_front_porch = 8,
    hsync_back_porch = 8,
    hsync_pulse_width = 4,
    hsync_idle_low = True,
    vsync_front_porch = 8,
    vsync_back_porch = 8,
    vsync_pulse_width = 4,
    vsync_idle_low = True,
    de_idle_high = False,
    pclk_idle_high = False,
    pclk_active_low = True,
    disp_active_low = False,
)

import rgb_display
import lvgl as lv
display = rgb_display.RGBDisplay(
    data_bus = display_bus,
    display_width = 800,
    display_height = 480,
    backlight_pin = 2,
    color_space = lv.COLOR_FORMAT.RGB565,
    rgb565_byte_swap=True
)

display.init()
display.set_backlight(100)

scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)

slider = lv.slider(scrn)
slider.set_size(200, 50)
slider.center()

while True:
    time.sleep_ms(1)
    lv.tick_inc(1)
    lv.task_handler()
kdschlosser commented 5 months ago

I know it works. it's just a matter of dialing in the right settings for your display. Unfortunately the information is just published to a datasheet somewhere. we have to go digging through the code examples that are used in order to get it to display properly.

The code example I just gave you is only as a test. if it works then we will change some other stuff around so we don't have to iterate over the buffer to move bytes around. This will give you better performance.

kdschlosser commented 5 months ago

I just updated the code to deal with using rgb565_byte_swap in a different manner. It will increase the performance by about 30%.

bland328 commented 5 months ago

~I'm now running precisely the code you provided, but I'm still getting just a blank white display.~

I'll do more digging for display specs.

FYI, a couple sources assert that this is the screen being used, and at first glance it certainly appears consistent with what's mounted on the board.

EDIT: Also, this page appears to be a dumping ground for technical data on this specific ESP32-8048S043 board.

EDIT 2: Based on the sample LovyanGFX configuration code from that page, I bumped the freq up to 16000000, and now I'm seeing a slider, though it occasionally changes position horizontally, sometimes wrapping around from the right edge to the left edge of the screen.

Also, zones across the top and bottom of the screen are flickering at a high frequency.

This progress is inspirational! I'll continue to experiment.

kdschlosser commented 5 months ago

turn the freq down to 14mhz or even 13mhz and that will fix the slider moving. I ran into this very same problem with the waveshare display I have.

kdschlosser commented 5 months ago

I believe the flickering will go away once you get the frequency dialed in

EDIT

I am going to double check your vsync and hsync settings just to make sure they are right.

bland328 commented 5 months ago

I believe the flickering will go away once you get the frequency dialed in

And so it did! 13mhz appears solid. Very exciting, thank you.

Your work on this is well-conceived, nicely executed, and incredibly appreciated--is there a link I can use to buy you a coffee, beer or microcontroller? :)

kdschlosser commented 5 months ago

The settings look right with what is in the examples for the display so it should just be a matter of dialing in the pixel clock.

I want to let you know what the last few code changes I made actually do.

The very last one combines the 3 bin files into a single binary for easier flashing of the firmware. The change before that is for the rgb565_byte_swap. the byte order for each pixel when using RGB565 sometimes needs to be flip flopped. Typically that means the frame buffer needs to be iterated over and the bytes changed for each pixel. While this is not a big deal to do, when you are doing it for something like an 800x480 display that is a lot of pixels that need to have this done. That is going to take some time. This could be the cause of the flicker you are seeing.

In the second to last code change what I did was add code that checks to see if rgb565 byte swapping is wanted, if it is then I check to make sure the color depth is 16bpp and if 16 lanes are being used. If all 3 of those conditions are met then I change the order of the pins instead of iterating the frame buffer moving bytes around. Same effect just much faster, about 30% faster.

so give the new code a shot and lower that pixel clock and that should do the trick for ya.

bland328 commented 5 months ago

I pulled your changes and tried to build, but eventually got this failure:

/opt/homebrew/Cellar/python@3.12/3.12.2_1/Frameworks/Python.framework/Versions/3.12/Resources/Python.app/Contents/MacOS/Python: can't open file '/Users/bland328/code/esp-idf/lvgl_micropython/lib/esp-idf/components/esptool_py/esptool/esptool.py,': [Errno 2] No such file or directory

Note the comma trailing esptool.py. Perhaps just a typo?

kdschlosser commented 5 months ago

Quit drinking over a decade ago so beer is not something I would use. Coffee is not something I buy, I will make it at home and I only drink 1/2 a cup in the morning. So that's probably not ideal either.

An MCU would be nice. can never have too many of those.

https://www.paypal.com/ncp/payment/4NZXTMZD25PMJ

kdschlosser commented 5 months ago

yup that's a fat finger. lemme fix it.

kdschlosser commented 5 months ago

all fixed

kdschlosser commented 5 months ago

I am super happy we got you up and running. I knew the RGB bus driver worked but you having issues with it exposed the memory issue which is now fixed and it also exposed a better way of handling the RGB565 byte swap that should be a HUGE improvement in performance.

I still have to tell you how to get the gt911 driver working...

you need to change the INDEV=GT911 in your build command to INDEV=gt911 I know it wouldn't matter on windows because file names are not case sensitive and I cannot remember if I added code to make the filename all lower case or not. so just to make sure I would make it all lowercase.

Now I added a special way of dealing with I2C in MicroPython. it actually makes it easier to use and it will deal with using I2C from more than one thread. The ESP32 supports threading and if you have any attached I2C devices you are able to collect or send data to those devices in a thread.

so this is how the gt911 driver works

import i2c
import gt911

i2c_bus = i2c.I2CBus(scl=10, sda=11, freq=4000000, host=None, use_pullups=False, use_locks=False)

touch_driver = gt911.GT911(i2c_bus=i2c_bus, reset_pin=None, interrupt_pin=None, touch_cal=None)

You can change the host if you like and you can specify to use built in pullups if you like. The use_locks you set to True if you are going to use threading.

The reset_pin you can use. The interrupt_pin doesn't get used as an interrupt, it is required in order to perform a hardware reset of the touch driver IC.

touch_cal is something I have to finish up making. I wrote into the firmware the ability to calibrate the touch display. On the ESP32 the calibration data gets saved to NVRAM. This is nice because it would give you the ability to calibrate the touch at runtime and not have to hard code the calibration data. It allows for real time calibrations to take place for the touch screen while the MCU is running and you will not need to perform a reboot in order for the settings to take effect.

bland328 commented 5 months ago

Works fine now, thanks! And I've sent a gift your way 🎁

Two quick notes:

  1. In the To flash firmware: instructions that appear after building, the esptool.py, trailing comma fat-fingering appears again.

  2. Also, FWIW, the suggested erase_flash command specifies a speed of 460800, whereas the write_flash command specifies a speed of 921600. Perhaps that's correct in many cases, but for me, I'm only able to successfully write flash if I decrease the speed to 460800.

bland328 commented 5 months ago

I still have to tell you how to get the gt911 driver working...

Wow...that's really above and beyond. Thanks so very much--I'll give it a try in the next 30 mins or so!

kdschlosser commented 5 months ago

That's because of the UART chip that is built into the board. That is your limiting thing. The devkits bought from espressif are able to do the higher speed which is why the higher speed is there.

The speed for erasing the flash doesn't mean a hill of beans because it is a command that gets sent to the ESP32 to do this and that command is not that large, a couple of bytes.

I will fix the other comma I missed as well. Thanks.

bland328 commented 5 months ago

After eliminating one error by dropping one of the zeros in i2c.I2CBus(...freq=4000000,..., I then get this error (line 57 being your unaltered touch_driver =... line):

Traceback (most recent call last):
  File "main.py", line 57, in <module>
  File "gt911.py", line 91, in __init__
  File "pointer_framework.py", line 58, in __init__
AttributeError: 'lv_indev_t' object has no attribute 'init'

I'm digging into it, but wanted to bounce it off you in case you immediately know what the problem might be.

kdschlosser commented 5 months ago

I just updated the code, give it s shot now.

kdschlosser commented 5 months ago

I am not sure if the gt911 uses a 4mhz frequency or a 1mhz frequency. You might have to adjust that if there is an issue like it is not able to read from the device.

bland328 commented 5 months ago

I found in this datasheet some GT911 details suggesting the I2C interface transmission rate should be between 200Kbps and 400Kbps:

GT911 interfaces with the host via 6 pins: VDD, GND, SCL, SDA, INT and RESET. The INT pin of the host can be rising/falling-edge Triggered. In addition, when INT is in input state, the host should set INT to be floating, with no internal pull-up or pull-down; the host controls the RESET pin of the GT911 by outputting high or low level. To ensure reliable reset, it is recommended that RESET pin outputs low for longer than 100μs.

GT911 communicates with the host via standard I2C interface, with a maximum transmission rate of 400K bps. When the host communicates at rates exceeding 200K bps, it is required to pay special attention to the resistance of the external pull-up resistor of I2C interface to ensure the edges of SCL and SDA are steep enough. GT911 invariably serves as slave device in communication and its I2C device address consists of 7 device address bits and 1 Read/Write control bit. The high 7 bits are device address while bit 0 is Read/Write control bit. GT911 supports two slave device addresses which are shown below...

Is this applicable to the i2c.I2CBus(...freq=...) parameter? Or do I misunderstand that parameter?

I've tried 200000, 300000 and 400000 as values for the freq param, but in every case I end up with this error:

Traceback (most recent call last):
  File "main.py", line 59, in <module>
  File "gt911.py", line 106, in __init__
  File "i2c.py", line 146, in write
  File "i2c.py", line 88, in writeto
OSError: [Errno 19] ENODEV

EDIT: A sample LovyanGFX configuration on this page appears to use 400000, assuming I'm comparing apples to apples.

kdschlosser commented 5 months ago

It says it right here...

GT911 communicates with the host via standard I2C interface, with a maximum transmission rate of 400K bps.

so 400000 is what you need to set the freq to it would appear.

kdschlosser commented 5 months ago

after the I2C bus is set up but before you set up the driver add this line of code.

print(i2c_bus.scan())

That will print out all of the device ID's that are attached to the bus.

paste trhat for me so I can check and make sure I am using the right device id's

bland328 commented 5 months ago

I've been chasing this for hours, but no luck.

We're agreed that freq should be 400000. Plus, after examining both the board layout and other projects compatible with this board, I'm 99.9% confident scl should be 20 and sda should be 19. Also, it looks like reset_pin should be 38, and interrupt_pin should be None (because the interrupt trace appears to be interrupted by an open pad, for reasons that are a mystery to me).

However, this code...

i2c_bus = i2c.I2CBus(scl=20, sda=19, freq=400000, host=None, use_pullups=False, use_locks=False)
print(i2c_bus.scan())

never returns from i2c_bus.scan().

FWIW, I've also experimented with machine.I2C() and machine.SoftI2C(), and get unexpected results in every case--that is, either scan() never returns, or returns an empty list.

If I didn't know better, I'd say the board has a hardware issue. But I do know better, because the original demo firmware that shipped on the board works fine.

So, I'm utterly stuck at the moment, sadly.

kdschlosser commented 5 months ago

set the frequency to 1mhz and see what happens

kdschlosser commented 5 months ago

what are you using for a host? If it's not set, set it to 1.

kdschlosser commented 5 months ago

What is the model number of the display you have? Does it end in a "C". If it doesn't then we are using the wrong touch driver and that could be the problem... There are 2 different touch IC's that are used with this display. The "C" means Capacitive which is the GT911 and without the "C" is the resistive touch and that is the XPT2046 IC. completely different driver.

kdschlosser commented 5 months ago

It actually appears like they may have used 3 different drivers. the other one is the FT6x36 IC

bland328 commented 5 months ago

What is the model number of the display you have? Does it end in a "C"

I certainly ordered the capacitive version, and though the board isn't literally marked "-C", running to the TFT there is a flexible flat cable with a visible GT911 chip mounted on it, as seen in this marked-up photo.

EDIT: I'm not 100% certain on this, but I don't immediately find solid evidence that Sunton makes the 4.3" version of this board with anything other than capacitive touch. So, despite the weirdness of I2C scans not working properly at the moment, I'm as convinced as I can be that this display has a GT911 capacitive touch digitizer (especially since I can see the chip marked "Goodix GT911.")

bland328 commented 5 months ago

what are you using for a host? If it's not set, set it to 1.

I was originally using None for the host value, but did switch to 1 along the way, after some research suggested that was appropriate.

bland328 commented 5 months ago

set the frequency to 1mhz and see what happens

I made a boot.py file containing only this:

import i2c
i2c_bus = i2c.I2CBus(scl=20, sda=19, freq=1000000, host=1, use_pullups=False, use_locks=False)
print(i2c_bus.scan())

It hangs on the scan for about 1m50s, then prints an empty list. FWIW, using pullup resistors makes no difference.

kdschlosser commented 5 months ago

I will mess about with the I2C driver on my end and see if I am able to get the gt911 driver to run. I have a display here that has that IC.

kdschlosser commented 5 months ago

Ya know what it could be...

I think I know what it is. There is a bug in MicroPython with I2S and I wonder if there is something with that bug and this problem...

hmmm..... I can't remember if 1.19 had support for the S3 MCU. I think it did. I know it used espidf 4.something.. The I2S issue came about with idf 5.0.x support being added to micropython.

I will compile a binary file of 1.19 for ya just to test and see if I2C is working. If it is and you get a list of device ids when performing a scan then we know the problem is upstream and it needs to be fixed... If we get the same result then your board is going to be no good.

kdschlosser commented 5 months ago

on a happier note, I added generating a stub file for lvgl. so now things like autocomplete and type hinting will work in an IDE.. IDK if you use something like VSCode or PyCharm, if you do then the stub file will make things a whole lot easier when coding.

bland328 commented 5 months ago

I think I know what it is. There is a bug in MicroPython...

That's very interesting! This certainly does feel like "that sort of a problem," because again, the touch screen does work with the demo firmware.

Thanks very offering to provide that build!

on a happier note, I added generating a stub file for lvgl...

Oh! I love that. I do use VSCode with Pylance, so I will certainly make good use of the stub file.