lvgl-micropython / lvgl_micropython

LVGL module for MicroPython
MIT License
91 stars 28 forks source link

Please help me initialize my ILI9488 display with XPT2046 on ESP32S2 Lolin S2 Mini Board #199

Open tetopik opened 2 days ago

tetopik commented 2 days ago

I'm struggling to find any valid documentation on how to create a config to initialize my setup. I've been trying a couple code from this issues tab but nothing's really works. One yelled 'Bus' object has no attribute 'init'.

  File "display_driver_framework.py", line 212, in __init__
  File "display_driver_framework.py", line 217, in _init_bus
AttributeError: 'Bus' object has no attribute 'init'

Please help!

My code provided below

tetopik commented 2 days ago
import lcd_bus
import machine 
from micropython import const 

spi_bus = machine.SPI.Bus(
    host=1,
    mosi=11,
    miso=9,
    sck=7
)

display_bus = lcd_bus.SPIBus(
    spi_bus=spi_bus,
    dc=5,
    cs=12,
    freq=40000000
)

import ili9488  
import lvgl as lv 

fb1 = display_bus.allocate_framebuffer(480*320*2/10, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA)
fb2 = display_bus.allocate_framebuffer(480*320*2/10, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA)

display = ili9488.ILI9488(
    data_bus=spi_bus,
    display_width=480,
    display_height=320,
    frame_buffer1 = fb1,
    frame_buffer2 = fb2,
    reset_pin=1,
    reset_state=ili9488.STATE_LOW,
    power_on_state=ili9488.STATE_HIGH,
    backlight_pin=3,
    offset_x=0,
    offset_y=0,
    color_space=lv.COLOR_FORMAT.RGB888,
    color_byte_order=ili9488.BYTE_ORDER_BGR,
    rgb565_byte_swap=True
)

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

import task_handler
th = task_handler.TaskHandler()
kdschlosser commented 2 days ago

you are passing the wrong "Bus" to the display driver. You need to be passing the lcd_bus.SPIBus instance to the display driver not the SPI.Bus instance.

tetopik commented 2 days ago

Working great now, thank you.

But now how to properly calibrate the display? Because calling the indev.calibrate() seems laggy and still invalid touch detected. I'm using the same SPI bus as the display.

import lcd_bus
import machine 
from micropython import const 
import ili9488  
import lvgl as lv 
import task_handler
import xpt2046

spi_bus = machine.SPI.Bus(host=1, mosi=11, miso=9, sck=7)
display_bus = lcd_bus.SPIBus(spi_bus=spi_bus, dc=5, cs=12, freq=40000000)

display = ili9488.ILI9488(
    data_bus=display_bus,
    display_width=320,
    display_height=480,
    reset_pin=1,
    reset_state=ili9488.STATE_LOW,
    backlight_pin=3,
    backlight_on_state=ili9488.STATE_PWM,
    color_space=lv.COLOR_FORMAT.RGB888,
    color_byte_order=ili9488.BYTE_ORDER_RGB,
    rgb565_byte_swap=True
)

display.init()
display.set_backlight(50)
display.set_rotation(lv.DISPLAY_ROTATION._90)

touch_dev = machine.SPI.Device(spi_bus=spi_bus, freq=10_000_000, cs=18)
indev = xpt2046.XPT2046(touch_dev, startup_rotation=lv.DISPLAY_ROTATION._90, debug=True)

th = task_handler.TaskHandler()

Same thing also happen using my ili9341 display, anything I missed? I also noticed that by default the touch y point is mirrored, is there any way to just flip it away?

kdschlosser commented 1 day ago

reduce the color depth to 16 bit by changing color_space=lv.COLOR_FORMAT.RGB888 to color_space=lv.COLOR_FORMAT.RGB565 That will help with the speeds. I have some work I need to do with the touch calibration as it has some issues in it. I will be working on that today at some point.

tetopik commented 1 day ago

What an effort you put on this repo.

Just a little suggestion if it's really possible to have a choice to attach the touch IRQ pin instead of just periodically polling the screen since we are using a very slow frameworks.

kdschlosser commented 1 day ago

LVGL is not written to be able to inject touch input. It is only able to poll for touch input. Well... Not easily anyway, I would have to code in a work around. The functions that process input in LVGL are not exposed in any header files, so they are not public, In order to make it work I would have to make a copy of the functions which would cause an increase in the program size. MCU's have very limited resources. I did provide a function that does allow the polling to work better.

indev.enable_input_priority()

This bypasses the normal mechanics of

task_handler -> update display if 33 milliseconds has passed -> read indev if 33 milliseconds has passed -> process input if any -> exit task handler -> user code main loop -> task_handler -> update display if 33 milliseconds has passed.

and turns it into

task_handler -> read indev if 33 milliseconds has passed -> if input then process -> update display -> read indev ->  if input then process -> update display -> continue this loop as long as there is input. once input stops then exit the loop and continue the normal task_handler cycle 

You can see where the problem is with the first one. You can end up with a really long time from when input occurs until it gets realized on the display. it can be at least 33 milliseconds later, usually it is longer and depending on how long it takes the user code in the main loop to run you could see a much higher latency.

That function bypassed the typical mechanics and keeps reading the indev in a continuous loop so long as there is active input. This places user interaction with the GUI above all other thing in terms of priority.

tetopik commented 1 day ago

I think that indev.enable_input_priority() function should be the default setup, but in my case I feel noting's difference after I put it after indev init and before the task handler. At least for now.

And also, my board didn't update the display when I switched the setup to color_space=lv.COLOR_FORMAT.RGB565 as you mentioned above.

Anyway, what is the proper spi freq to use for this xpt2046 driver? I've used this driver before with vanilla micropython and the driver from https://github.com/rdagger/micropython-ili9341/blob/master/xpt2046.py and it working great on 1MHz freq, but on this one is it really need 10Mhz?

Oh ya, once more, is it possible to do the calibration using arduino eSPI touch calibrate function instead, and than just put the result into the cal-data in the indev init?

kdschlosser commented 1 day ago

, is it possible to do the calibration using arduino eSPI touch calibrate function instead

You cannot use the same calibration numbers from eSPI. They are calculated differently I believe.

and it working great on 1MHz freq, but on this one is it really need 10Mhz?

I believe that 1 mhz is the speed you need to use for the touch panel. You would need to read the datasheet to find out if that is the case.

but in my case I feel noting's difference after I put it after indev init and before the task handler. At least for now.

not sure what you mean by this.

And also, my board didn't update the display when I switched the setup to color_space=lv.COLOR_FORMAT.RGB565 as you mentioned above.

I would have to check and see if this color depth is supported by your display. It may not be. Give me a few minutes to check on that.

kdschlosser commented 1 day ago

OK so your display only supports RGB888 when using an SPI Bus. That is quite a bit of additional work that needs to be done with that added byte to not a huge amount of perceived color difference due to the size of the display.

kdschlosser commented 1 day ago

If you have a mess of widgets and some of those widgets are outside of the viewable area on the display that will activate scrolling. When you scroll the display is when you will really notice a difference with the touch set to high priority vs not having it set.

tetopik commented 1 day ago

I noticed that calling this indev.enable_input_priority() function allow me to initialize the touch driver with 1Mhz freq instead of 10Mhz. But still didn't manage to finish the calibration.

kdschlosser commented 1 day ago

OK the touch calibration should now be fixed.

tetopik commented 1 day ago

OK the touch calibration should now be fixed.

I can confirm that touch calibration is working pretty well right now, but the touch orientation seem flipped here and there. On rotation._0 , the y is mirrored On rotation._90, the x,y is flipped and than the x is mirrored, and y seems random.

Even after the calibration succeed, indev.is_calibrated keeps returning False.

display.init()
display.set_backlight(100)
display.set_rotation(lv.DISPLAY_ROTATION._90)

touch_dev = machine.SPI.Device(spi_bus=spi_bus, freq=1_000_000, cs=18)

indev = xpt2046.XPT2046(touch_dev, startup_rotation=lv.DISPLAY_ROTATION._90, debug=True)
indev.enable_input_priority()

th = task_handler.TaskHandler()

if not indev.is_calibrated: indev.calibrate()

I'll try using my ILI9341 board later to see if ithe touch also got messy, I'm a little bit busy right now, gotta post here after getting the test result.

kdschlosser commented 1 day ago

If you flash your ESP32 at all that is going to erase the stored calibration settings.

I will check to see what could be causing the values to not be saved. If the values are working after you calibrate the only way they could work is if they have been saved. The indev driver reads the calibration values from NV memory. the calibration saves the values to the NV memory.

I will look into it later on today. It is 4:00 am where I am at so I am going to lay down for a few hours.

tetopik commented 4 hours ago

Using ILI9341 my touch now working perfectly fine. Didn't tested on ILI9488 yet, will come back later.

Here is the catch:

display.init(1)
indev = XPT2046(tch_bus)
indev.enable_input_priority()
th = TaskHandler()
if not indev.is_calibrated: indev.calibrate()
display.set_rotation(lv.DISPLAY_ROTATION._90)

Untitled

tetopik commented 1 hour ago

Didn't tested on ILI9488 yet, will come back later.

I can peacefully say that same thing happen with my ILI9488 display, it's fully working now. One thing left is the calibration data isn't automatically being saved after the calibration.