lvgl-micropython / lvgl_micropython

LVGL module for MicroPython
MIT License
80 stars 25 forks source link

Adapt XPT2046 driver for custom SPI #47

Closed demitrix closed 5 months ago

demitrix commented 5 months ago

Due to work done under https://github.com/kdschlosser/lvgl_micropython/issues/42 XPT2046 driver needs to be adapted to use new custom SPI implementation. Creating this issue as a place to track that progress.

kdschlosser commented 5 months ago

Yup, that's what it is. LVGL is handling the rotation internally. I removed the transforming of the pointer coordinates due to LVGL handling this internally.

kdschlosser commented 5 months ago

I think that should finish this driver up.

If you still get phantom touches at all you can change the threshold value for the Z axis. it is defaulted to 400 and you can up that number if you want to filter out any random touches if they occur. You can set the threshold per instance or globally across all XPT2046 indevs.

To set it at the instance level..


indev1 = xpt2046.XPT2046(...)
indev1.touch_threshold= 600

indev2 = xpt2046.XPT2046(...)
indev2.touch_threshold= 800

and to set it globally.


xpt2046.XPT2046.touch_threshold = 600
indev1 = xpt2046.XPT2046(...)
indev2 = xpt2046.XPT2046(...)
kdschlosser commented 5 months ago

Also I wanted to say thanks for adding the expandable/collapsible code blocks. It makes it a lot nicer when scrolling through an issue.

I like to use those when dealing with large code blocks or pasting logging data. 👍 for doing that.

demitrix commented 5 months ago

Yeah realized things were getting lengthy and wanted to clean it up haha. I'll give this a shot tomorrow and see what happens 🤞

demitrix commented 5 months ago

Think everything looks good here. Closing this issue.

kdschlosser commented 5 months ago

rotation is working properly?

demitrix commented 5 months ago

Sure is. I think everything is solid. While there may be improvements down the road, everything is in working order as of now.

ikkesia commented 5 months ago

Can someone tell me how to set the parameters for touch calibration ?

With the old touch driver I used : touch = xpt2046(cs=32 ,cal_x0=3840, cal_x1 = 393, cal_y1=220, cal_y0 = 3719)

kdschlosser commented 5 months ago

the calibration program has not had all of the kinks ironed out with it yet. I am going to be working on that soon.

ikkesia commented 5 months ago

So, if I understand well, I can't enter the calibration values manually ?

I'm doing some tests and like @demitrix I confirm that it works fine. Unfortunately I detect a misalignment between the graphic position and the touch pointer, which effectively makes it unusable.

kdschlosser commented 5 months ago

You can enter them manually but they don't use the typical calibration coordinates that you have seen in the past. I went for an easier approach. which is recording the left, right top and bottom boundaries. It is very rudimentary as it doesn't handle if the touch panel has been rotated at all. to handle the rotation of the display I needed to have the ability to store floats into the NVS on the esp32. I did add that ability but have not gotten to updating the calibration so it is more complete.

if you wanted to pass the left, right top and bottom boundaries that can be done by doing the following.

class TouchCal:

    def __init__(self),

        left = 0
        right = 0
        top = 0
        bottom = 0

    def save():
        pass

cal = TouchCal()

import xpt2046

xpt2046.XPT2046(spi_bus, touch_cal=cal)

you change the values in the __init__ to what you need and pass an instance of that class to the touch driver as seen above. It's very basic at the moment but at least it is something. I have been focusing on getting the bus drivers working properly and fixing some things in MicroPython that caused serious limitations on being able to use things like the touch, display and an SD card being on the same SPI bus... I still have to fix the SDCard driver that is built into MicroPython to get this to work properly..

I also want to update the SPI display bus driver so it can take an instance of the SPI driver from MicroPython. Being able to do that is going to take a little bit more work.

kdschlosser commented 5 months ago

@ikkesia

I updated the calibration routine. The new design uses a more complex way of handling the touch panel to screen alignment. I never looked at the xpt2046 driver code in the official binding so I do not know what their calibration was all about. I can tell you that what is being used is not something that is considered typical.

My design doesn't not require any hard coding of the calibration numbers either. The calibration data gets stored in non volatile memory so it is persistent between power cycles and restarts. This is a better design for a production environment where the user is able to calibrate the display without needing to change and flash any source code.

It is easy to launch the screen calibration

# display driver and display bus code
import machine
import xpt2046
import task_handler

spi_bus = machine.SPI(...)
indev = xpt2046.XPT2046(spi_bus)

th = task_handler.TaskHandler()

if not indev.is_calibrated:
    indev.calibrate()

You have to make sure that the task handler has been started prior to running the calibration.

I do have to make some tweaks to it still and I am going to mess about with that now.

ikkesia commented 5 months ago

@kdschlosser

I would have worked with the manual setting as you suggested, but having a calibration routine is great. Thank you very much for this update.

Unfortunately I can't try it quickly because my development kit broke. I'm waiting for a new one at the beginning of the week.

ste7anste7an commented 5 months ago

For m the calibration is not working:

indev.calibrate()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pointer_framework.py", line 45, in calibrate
  File "touch_calibrate.py", line 275, in __init__
  File "touch_calibrate.py", line 117, in build_crosshair
ValueError: need more than 2 values to unpack
kdschlosser commented 5 months ago

give it a try. I think it should be fixed now.

ikkesia commented 4 months ago
/lvgl_micropython/ext_mod/lcd_bus/esp32_src/spi_bus.c: In function 'spi_init':
/esp/lvgl_micropython/ext_mod/lcd_bus/esp32_src/spi_bus.c:181:5: error: 'ret' undeclared (first use in this function)
kdschlosser commented 4 months ago

Yeah I know there are going to be some errors now from me working on getting the SDCard to play nice and share the SPI bus with other things.

You have to give me a day to get them all sorted out.

ikkesia commented 4 months ago

Now that everything seems a bit more stable, I resume the touch screen calibration tests. I see that the parameters for manually setting the calibration parameters have changed, if I use

class TouchCal:

    def __init__(self),

        left = 0
        right = 0
        top = 0
        bottom = 0

    def save():
        pass

cal = TouchCal()

import xpt2046

xpt2046.XPT2046(spi_bus, touch_cal=cal)

I get an error. I will study the new drivers to understand which new parameters to use and how to calculate them.


I also tried running the new calibration code according to the example above and I get an error

Traceback (most recent call last):
  File "<stdin>", line 93, in <module>
  File "xpt2046.py", line 43, in __init__
  File "pointer_framework.py", line 16, in __init__
  File "_indev_base.py", line 23, in __init__
RuntimeError: the display driver must be initilized before the pointer driver

Then I initialize the display driver and get this screen

tempImageDNCQkm

Touch screen is responsive (debug=True), but calibration does not proceed.

Any suggestions ?

kdschlosser commented 4 months ago

The calibration program still needs some work done to it. I am working on getting my display up and running to be able to work on the calibration program.

You must call the init() method for the display driver prior to initializing the touch driver. This is due to the touch driver collecting the width and the height of the display from the display driver.

paste me the code you are using...

kdschlosser commented 4 months ago

Here is the code that is run for the touch screen data.

https://github.com/kdschlosser/lvgl_micropython/blob/9a04833e8f4295ebc6eb307b7bb78e3a9af05d7c/api_drivers/py_api_drivers/frozen/indev/touch_calibration/touch_calibrate.py#L436

That file is the calibration screen and the link is the function where the calculations are done.

I suspect it is getting stuck because you have not started the task handler prior to running the calibration.

ikkesia commented 4 months ago

This is my code

from micropython import const
from machine import SPI
import time
import sys
import lcd_bus

#Display settings
_WIDTH = const(240)
_HEIGHT = const(320)

# Display SPI bus settings
_LCD_SPI_HOST = const(1)
_LCD_SPI_FREQ = const(40_000_000)
_LCD_MOSI_PIN = const(23)
_LCD_MISO_PIN = const(25)
_LCD_SCLK_PIN = const(19)
_LCD_CS_PIN = const(22)
# display additional pins
_LCD_RST_PIN = const(18)
_LCD_DC_PIN = const(21)
_LCD_BKL_PIN = const(5)
_LCD_PWR_PIN = None

# touch panel SPI settings
_TP_SPI_HOST = const(1)
_TP_SPI_FREQ = const(1_000_000)
_TP_CS_PIN = const(32)
_TP_INT_PIN = const(-1)

#cal_x0=3840, cal_x1 = 393, cal_y1=220, cal_y0 = 3719,
class TouchCal:

    def __init__(self):

#         self.left = 3840
#         self.right = 393
#         self.top = 3719
#         self.bottom = 220

        self.left = 0
        self.right = 0
        self.top = 0
        self.bottom = 0

    def save():
        pass

# create the SPI bus for the display
spi_bus = SPI(
    _LCD_SPI_HOST,
    _TP_SPI_FREQ,
    miso=_LCD_MISO_PIN,
    mosi=_LCD_MOSI_PIN,
    sck=_LCD_SCLK_PIN,
    cs=_TP_CS_PIN
)

display_bus = lcd_bus.SPIBus(
    spi_bus=spi_bus,
    dc=_LCD_DC_PIN,
    freq=_LCD_SPI_FREQ,
    cs=_LCD_CS_PIN
)

import ili9341
import lvgl as lv

display = ili9341.ILI9341(
    data_bus=display_bus,
    display_width=_WIDTH,
    display_height=_HEIGHT,
    reset_pin=_LCD_RST_PIN,
    reset_state=ili9341.STATE_LOW,
    power_pin=_LCD_PWR_PIN,
    backlight_pin=_LCD_BKL_PIN,
    backlight_on_state=ili9341.STATE_HIGH,
    color_space=lv.COLOR_FORMAT.RGB565,
#    color_byte_order=ili9341.BYTE_ORDER_BGR,
    rgb565_byte_swap=False
)

# start the display driver
display.init()
display.invert_colors()
#display.set_rotation(lv.DISPLAY_ROTATION._90)

#cal = TouchCal()
import xpt2046

indev = xpt2046.XPT2046(spi_bus, touch_cal=None, debug=True)
print('is_calibrate is', indev.is_calibrated)

import task_handler

th = task_handler.TaskHandler()

time.sleep_ms(1000)

if not indev.is_calibrated:
    indev.calibrate()