Closed demitrix closed 5 months ago
OK cool. I am working on it now. I am updating the lcd_bus driver so instead of passing pin numbers to it you are going to pass an spi.Bus instance to it. I am also going to do the same thing for any touch drivers that use SPI. I have to figure out a way to stall the main loop until a response is gotten form the SPI. I am thinking a lock object will do the trick but the issue there is that ends up being ESP specific python code. I have to figure out what MCU's support the threading module.
Quite a bit of low level protocol is over my head, but I have noticed that CircuitPython has a try_lock() method of their SPI class. Might be able to lend you some insight.
I have pushed some code changes is you want to give it a try. I am sure there is bound to be errors and I will fix those as we come across them. It is compiling as per the CI.
Firmware builds. Screen is working and xpt2046 seems to init okay. Need to dig in on how to test further. Calling indev.calibrate crashes with
OverflowError: overflow converting long int to machine word
which I believe is related to https://github.com/kdschlosser/lvgl_micropython/discussions/43
calibrate was actually preventing me from getting to the crash. Adding
from xpt2046 import XPT2046
indev = XPT2046(spi_bus, cs=5)
Just before task handler causes a crash
D (3600) nvs: nvs_open_from_partition XPT2046_2 1
D (3600) nvs: nvs_get left 4
D (3600) nvs: nvs_get right 4
D (3600) nvs: nvs_get top 4
D (3600) nvs: nvs_get bottom 4
D (3600) spi_hal: eff: 1000, limit: 80000k(/0), 0 dummy, -1 delay
D (3610) spi_master: SPI2: New device added to CS1, effective clock: 1000kHz
D (3650) intr_alloc: Connected src 50 to int 13 (cpu 1)
main(): drop to repl
MicroPython v1.22.2-dirty on 2024-05-31; Generic ESP32S3 module with Octal-SPIRAM with ESP32S3
Type "help()" for more information.
>>> Guru Meditation Error: Core 1 panic'ed (IntegerDivideByZero). Exception was unhandled.
Core 1 register dump:
PC : 0x420adc48 PS : 0x00060e30 A0 : 0x820c9b50 A1 : 0x3fced3f0
A2 : 0x00000000 A3 : 0x00000010 A4 : 0x3fced4a0 A5 : 0x00000000
A6 : 0x3c265ce4 A7 : 0x3fced3f0 A8 : 0x820adc3d A9 : 0x3fced3c0
A10 : 0x00000006 A11 : 0x00000002 A12 : 0x00000002 A13 : 0x00000008
A14 : 0x00000001 A15 : 0x3fced3c0 SAR : 0x0000001a EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x40056f5c LEND : 0x40056f72 LCOUNT : 0xffffffff
Backtrace: 0x420adc45:0x3fced3f0 0x420c9b4d:0x3fced4a0 0x420d0909:0x3fced4d0 0x420d09cd:0x3fced4f0 0x4037b0a9:0x3fced510 0x420c9aec:0x3fced5b0 0x420d0909:0x3fced5e0 0x420d09cd:0x3fced600 0x4037b0a9:0x3fced620 0x420c9aec:0x3fced6c0 0x420d0909:0x3fced6f0 0x420d09cd:0x3fced710 0x4037b0a9:0x3fced730 0x420c9aec:0x3fced7d0 0x420d0909:0x3fced800 0x420fc6ab:0x3fced820 0x420fc6fd:0x3fced860 0x420d0909:0x3fced880 0x420270a1:0x3fced8a0 0x42051a6b:0x3fced8e0 0x42051aca:0x3fced910 0x42051a81:0x3fced960 0x420839f1:0x3fced990 0x420835e1:0x3fced9d0 0x42006bdd:0x3fceda10 0x42027f2d:0x3fceda30 0x42006d13:0x3fceda70 0x420d0909:0x3fcedab0 0x420d09cd:0x3fcedad0 0x4037b0a9:0x3fcedaf0 0x420c9aec:0x3fcedb90 0x420d0909:0x3fcedbc0 0x420fc6ab:0x3fcedbe0 0x420fc6fd:0x3fcedc20 0x420d0909:0x3fcedc40 0x420d098d:0x3fcedc60 0x420d1530:0x3fcedc90 0x420d16a5:0x3fcedd10 0x420e4c04:0x3fcedd30 0x421044ed:0x3fcedd50 0x420dd143:0x3fcedd70 0x420e4924:0x3fceddb0
ELF file SHA256: ca0687b2ae1b32a8
Rebooting...
OoOO you have backtrace data. That's good. Lets decode that and see what it says.
~/.espressif/tools/xtensa-esp32s3-elf/esp-2022r1-11.2.0/xtensa-esp32s3-elf/bin/xtensa-esp32s3-elf-addr2line -fe lib/micropython/ports/esp32/build-ESP32_GENERIC_S3-SPIRAM_OCT/micropython.elf 0x420adc45:0x3fced3f0 0x420c9b4d:0x3fced4a0 0x420d0909:0x3fced4d0 0x420d09cd:0x3fced4f0 0x4037b0a9:0x3fced510 0x420c9aec:0x3fced5b0 0x420d0909:0x3fced5e0 0x420d09cd:0x3fced600 0x4037b0a9:0x3fced620 0x420c9aec:0x3fced6c0 0x420d0909:0x3fced6f0 0x420d09cd:0x3fced710 0x4037b0a9:0x3fced730 0x420c9aec:0x3fced7d0 0x420d0909:0x3fced800 0x420fc6ab:0x3fced820 0x420fc6fd:0x3fced860 0x420d0909:0x3fced880 0x420270a1:0x3fced8a0 0x42051a6b:0x3fced8e0 0x42051aca:0x3fced910 0x42051a81:0x3fced960 0x420839f1:0x3fced990 0x420835e1:0x3fced9d0 0x42006bdd:0x3fceda10 0x42027f2d:0x3fceda30 0x42006d13:0x3fceda70 0x420d0909:0x3fcedab0 0x420d09cd:0x3fcedad0 0x4037b0a9:0x3fcedaf0 0x420c9aec:0x3fcedb90 0x420d0909:0x3fcedbc0 0x420fc6ab:0x3fcedbe0 0x420fc6fd:0x3fcedc20 0x420d0909:0x3fcedc40 0x420d098d:0x3fcedc60 0x420d1530:0x3fcedc90 0x420d16a5:0x3fcedd10 0x420e4c04:0x3fcedd30 0x421044ed:0x3fcedd50 0x420dd143:0x3fcedd70 0x420e4924:0x3fceddb0
copy and paste the above line to the shell prompt. This needs to be done from the root directory of the repo. Then paste the output to me and lets see what it says.
esp32_hw_spi_dev_comm
??:?
fun_builtin_var_call
/home/demitrix/lvgl_micropython/lib/micropython/py/objfun.c:114
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
mp_call_method_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:729
mp_execute_bytecode
/home/demitrix/lvgl_micropython/lib/micropython/py/vm.c:1042
fun_bc_call
/home/demitrix/lvgl_micropython/lib/micropython/py/objfun.c:273
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
mp_call_method_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:729
mp_execute_bytecode
/home/demitrix/lvgl_micropython/lib/micropython/py/vm.c:1042
fun_bc_call
/home/demitrix/lvgl_micropython/lib/micropython/py/objfun.c:273
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
mp_call_method_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:729
mp_execute_bytecode
/home/demitrix/lvgl_micropython/lib/micropython/py/vm.c:1042
fun_bc_call
/home/demitrix/lvgl_micropython/lib/micropython/py/objfun.c:273
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
mp_call_method_self_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/objboundmeth.c:70
bound_meth_call
/home/demitrix/lvgl_micropython/lib/micropython/py/objboundmeth.c:83
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
lv_indev_t_read_cb_callback
lv_mp.c:?
indev_read_core
lv_indev.c:?
lv_indev_read
??:?
lv_indev_read_timer_cb
??:?
lv_timer_exec
lv_timer.c:?
lv_timer_handler
??:?
lv_task_handler
lv_mp.c:?
mp_lv_task_handler
lv_mp.c:?
lv_fun_builtin_var_call
lv_mp.c:?
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
mp_call_method_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:729
mp_execute_bytecode
/home/demitrix/lvgl_micropython/lib/micropython/py/vm.c:1042
fun_bc_call
/home/demitrix/lvgl_micropython/lib/micropython/py/objfun.c:273
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
mp_call_method_self_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/objboundmeth.c:70
bound_meth_call
/home/demitrix/lvgl_micropython/lib/micropython/py/objboundmeth.c:83
mp_call_function_n_kw
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:713
mp_call_function_1
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime.c:691
mp_call_function_1_protected
/home/demitrix/lvgl_micropython/lib/micropython/py/runtime_utils.c:33
mp_sched_run_pending
/home/demitrix/lvgl_micropython/lib/micropython/py/scheduler.c:111
mp_hal_stdin_rx_chr
/home/demitrix/lvgl_micropython/lib/micropython/ports/esp32/mphalport.c:124
readline
/home/demitrix/lvgl_micropython/lib/micropython/shared/readline/readline.c:560
pyexec_friendly_repl
/home/demitrix/lvgl_micropython/lib/micropython/shared/runtime/pyexec.c:610
mp_task
/home/demitrix/lvgl_micropython/lib/micropython/ports/esp32/main.c:159
OK so the error is happening in the esp32_hw_spi_dev_comm function.
hey, I made some changes to how things work. I am attempting to work around the issues with the SPI. I believe this should work.
Here is some example code. Things need to be done in this exact order so don't move anything around at all. You need to set the CS and the interrupt pins for the touch IC, if applicable.
from micropython import const # NOQA
import machine # NOQA
_WIDTH = const(320)
_HEIGHT = const(240)
_TP_FREQ = const(1_000_000)
_TP_CS = const(-1) # CHANGE THIS TO THE CS PIN FOR THE TOUCH PANEL
_TP_INT = const(-1) # CHANGE THIS TO THE INTERRUPT PIN FOR THE TOUCH PANEL
_SPI_HOST = const(1)
_DC_PIN = const(7)
_MOSI_PIN = const(11)
_MISO_PIN = const(13)
_SCLK_PIN = const(12)
_CS_PIN = const(10)
_RESET_PIN = const(6)
_BACKLIGHT_PIN = const(5)
_FREQ = const(40_000_000)
import lcd_bus # NOQA
spi_bus = machine.SPI(
_SPI_HOST,
_TP_FREQ,
miso=_MISO_PIN,
mosi=_MOSI_PIN,
sck=_SCLK_PIN,
)
display_bus = lcd_bus.SPIBus(
dc=_DC_PIN,
host=_SPI_HOST,
sclk=_SCLK_PIN,
freq=_FREQ,
mosi=_MOSI_PIN,
miso=_MISO_PIN,
cs=_CS_PIN,
)
import ili9341 # NOQA
display = ili9341.ILI9341(
data_bus=display_bus,
display_width=_WIDTH,
display_height=_HEIGHT,
reset_pin=_RESET_PIN,
backlight_pin=_BACKLIGHT_PIN,
backlight_on_state=ili9341.STATE_HIGH,
)
display.init()
display.set_backlight(100)
import xpt2046 # NOQA
indev = xpt2046.XPT2046(spi_bus, _TP_CS, _TP_INT)
import lvgl as lv # NOQA
scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)
slider = lv.slider(scrn)
slider.set_size(_WIDTH - 50, 50)
slider.center()
import task_handler # NOQA
th = task_handler.TaskHandler()
Everything runs, but I can't tell if touch is doing anything, There is no console output when touching the screen. I assume at the least I should see some SPI debug output for devices locking and releasing the bus.
D (7320) gdma: new group (0) at 0x3c270ac0
D (7320) gdma: new pair (0,0) at 0x3c270b04
D (7320) gdma: new tx channel (0,0) at 0x3c270a90
D (7320) gdma: new rx channel (0,0) at 0x3c270b24
D (7320) spi: SPI2 use iomux pins.
D (7330) intr_alloc: Connected src 21 to int 12 (cpu 1)
D (7330) spi_hal: eff: 1000, limit: 80000k(/0), 0 dummy, -1 delay
D (7340) spi_master: SPI2: New device added to CS5, effective clock: 1000kHz
host=1
sclk_io_num=12
mosi_io_num=11
miso_io_num=13
quadwp_io_num=-1
quadhd_io_num=-1
cs_gpio_num=10
dc_gpio_num=7
spi_mode=0
pclk_hz=40000000
lcd_cmd_bits=8
lcd_param_bits=8
dc_low_on_data=0
sio_mode=0
lsb_first=0
cs_high_active=0
octal_mode=0
DisplayDriver: __init__
DisplayDriver: if not lv.is_initialized()
DisplayDriver: if not lv.init()
DisplayDriver: data_bus is not None
DisplayDriver: self._reset_pin = machine.Pin(reset_pin, machine.Pin.OUT)
DisplayDriver: self._backlight_pin = machine.Pin(backlight_pin, machine.Pin.OUT)
DisplayDriver: self._disp_drv = lv.display_create(display_width, display_height)
DisplayDriver: self._disp_drv.set_color_format(color_space)
DisplayDriver: self._disp_drv.set_driver_data(self)
DisplayDriver: frame_buffer1 is None
DisplayDriver: frame_buffer1 = data_bus.allocate_framebuffer(buf_size, flags)
lcd_panel_io_allocate_framebuffer(self, size=15360, caps=2056)
DisplayDriver: frame_buffer2 = data_bus.allocate_framebuffer(buf_size, flags)
lcd_panel_io_allocate_framebuffer(self, size=15360, caps=2056)
DisplayDriver: data_bus.init()
spi_init(self, width=240, height=320, bpp=16, buffer_size=15360, rgb565_byte_swap=1)
rgb565_byte_swap=1
trans_queue_depth=10
max_transfer_sz=15360
dma_chan=3
E (7520) spi: spi_bus_initialize(758): SPI bus already initialized.
D (7530) spi_hal: eff: 40000, limit: 80000k(/0), 0 dummy, -1 delay
D (7530) spi_master: SPI2: New device added to CS0, effective clock: 40000kHz
I (7540) gpio: GPIO[7]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
D (7550) lcd_panel.io.spi: new spi lcd panel io @0x3fcee95c, max_trans_bytes: 4092
DisplayDriver: self._disp_drv.set_flush_cb(self._flush_cb)
DisplayDriver: self._disp_drv.set_buffers()
DisplayDriver: data_bus.register_callback(self._flush_ready_cb)
DisplayDriver: self.set_default()
DisplayDriver: self._disp_drv.add_event_cb(self._on_size_change, lv.EVENT.RESOLUTION_CHANGED, None)
lcd_panel_io_tx_param(self, lcd_cmd=239, param, param_size=3)
D (7590) spi_master: device0 locked the bus
D (7590) spi_master: Allocate TX buffer for DMA
D (7600) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=207, param, param_size=3)
D (7610) spi_master: device0 locked the bus
D (7610) spi_master: Allocate TX buffer for DMA
D (7620) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=237, param, param_size=4)
D (7630) spi_master: device0 locked the bus
D (7630) spi_master: Allocate TX buffer for DMA
D (7640) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=232, param, param_size=3)
D (7650) spi_master: device0 locked the bus
D (7650) spi_master: Allocate TX buffer for DMA
D (7650) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=203, param, param_size=5)
D (7660) spi_master: device0 locked the bus
D (7670) spi_master: Allocate TX buffer for DMA
D (7670) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=247, param, param_size=1)
D (7680) spi_master: device0 locked the bus
D (7690) spi_master: Allocate TX buffer for DMA
D (7690) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=234, param, param_size=2)
D (7700) spi_master: device0 locked the bus
D (7700) spi_master: Allocate TX buffer for DMA
D (7710) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=192, param, param_size=1)
D (7720) spi_master: device0 locked the bus
D (7720) spi_master: Allocate TX buffer for DMA
D (7730) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=193, param, param_size=1)
D (7740) spi_master: device0 locked the bus
D (7740) spi_master: Allocate TX buffer for DMA
D (7750) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=197, param, param_size=2)
D (7760) spi_master: device0 locked the bus
D (7760) spi_master: Allocate TX buffer for DMA
D (7760) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=199, param, param_size=1)
D (7770) spi_master: device0 locked the bus
D (7780) spi_master: Allocate TX buffer for DMA
D (7780) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=54, param, param_size=1)
D (7790) spi_master: device0 locked the bus
D (7800) spi_master: Allocate TX buffer for DMA
D (7800) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=58, param, param_size=1)
D (7810) spi_master: device0 locked the bus
D (7810) spi_master: Allocate TX buffer for DMA
D (7820) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=177, param, param_size=2)
D (7830) spi_master: device0 locked the bus
D (7830) spi_master: Allocate TX buffer for DMA
D (7840) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=182, param, param_size=3)
D (7850) spi_master: device0 locked the bus
D (7850) spi_master: Allocate TX buffer for DMA
D (7860) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=242, param, param_size=1)
D (7870) spi_master: device0 locked the bus
D (7870) spi_master: Allocate TX buffer for DMA
D (7870) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=38, param, param_size=1)
D (7880) spi_master: device0 locked the bus
D (7890) spi_master: Allocate TX buffer for DMA
D (7890) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=224, param, param_size=15)
D (7900) spi_master: device0 locked the bus
D (7910) spi_master: Allocate TX buffer for DMA
D (7910) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=225, param, param_size=15)
D (7920) spi_master: device0 locked the bus
D (7920) spi_master: Allocate TX buffer for DMA
D (7930) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=17, param, param_size=0)
D (7940) spi_master: device0 locked the bus
D (7940) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=41, param, param_size=0)
D (8070) spi_master: device0 locked the bus
D (8070) spi_master: device0 release bus
D (8180) nvs: nvs_open_from_partition XPT2046_2 1
D (8180) nvs: nvs_get left 4
D (8180) nvs: nvs_get right 4
D (8180) nvs: nvs_get top 4
D (8180) nvs: nvs_get bottom 4
lcd_panel_io_tx_param(self, lcd_cmd=54, param, param_size=1)
D (8190) spi_master: device0 locked the bus
D (8200) spi_master: Allocate TX buffer for DMA
D (8200) spi_master: device0 release bus
D (8250) intr_alloc: Connected src 50 to int 13 (cpu 1)
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8300) spi_master: device0 locked the bus
D (8300) spi_master: Allocate TX buffer for DMA
D (8310) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8320) spi_master: device0 locked the bus
D (8320) spi_master: Allocate TX buffer for DMA
D (8320) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8330) spi_master: device0 locked the bus
D (8340) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8350) spi_master: device0 locked the bus
D (8350) spi_master: Allocate TX buffer for DMA
D (8360) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8370) spi_master: device0 locked the bus
D (8370) spi_master: Allocate TX buffer for DMA
D (8380) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8380) spi_master: device0 locked the bus
D (8390) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8400) spi_master: device0 locked the bus
D (8400) spi_master: Allocate TX buffer for DMA
D (8410) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8420) spi_master: device0 locked the bus
D (8420) spi_master: Allocate TX buffer for DMA
D (8430) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8440) spi_master: device0 locked the bus
D (8440) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8450) spi_master: device0 locked the bus
D (8450) spi_master: Allocate TX buffer for DMA
D (8460) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8470) spi_master: device0 locked the bus
D (8470) spi_master: Allocate TX buffer for DMA
D (8480) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8490) spi_master: device0 locked the bus
D (8490) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8500) spi_master: device0 locked the bus
D (8500) spi_master: Allocate TX buffer for DMA
D (8510) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8520) spi_master: device0 locked the bus
D (8520) spi_master: Allocate TX buffer for DMA
D (8530) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8540) spi_master: device0 locked the bus
D (8540) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8550) spi_master: device0 locked the bus
D (8550) spi_master: Allocate TX buffer for DMA
D (8560) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8570) spi_master: device0 locked the bus
D (8570) spi_master: Allocate TX buffer for DMA
D (8580) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8590) spi_master: device0 locked the bus
D (8590) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8600) spi_master: device0 locked the bus
D (8600) spi_master: Allocate TX buffer for DMA
D (8610) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8620) spi_master: device0 locked the bus
D (8620) spi_master: Allocate TX buffer for DMA
D (8630) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8640) spi_master: device0 locked the bus
D (8640) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8650) spi_master: device0 locked the bus
D (8650) spi_master: Allocate TX buffer for DMA
D (8660) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8670) spi_master: device0 locked the bus
D (8670) spi_master: Allocate TX buffer for DMA
D (8680) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8690) spi_master: device0 locked the bus
D (8690) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8700) spi_master: device0 locked the bus
D (8710) spi_master: Allocate TX buffer for DMA
D (8710) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8720) spi_master: device0 locked the bus
D (8720) spi_master: Allocate TX buffer for DMA
D (8730) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8740) spi_master: device0 locked the bus
D (8740) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=42, param, param_size=4)
D (8750) spi_master: device0 locked the bus
D (8760) spi_master: Allocate TX buffer for DMA
D (8760) spi_master: device0 release bus
lcd_panel_io_tx_param(self, lcd_cmd=43, param, param_size=4)
D (8770) spi_master: device0 locked the bus
D (8770) spi_master: Allocate TX buffer for DMA
D (8780) spi_master: device0 release bus
lcd_panel_io_tx_color(self, lcd_cmd=44, color, color_size=15360)
D (8790) spi_master: device0 locked the bus
D (8790) spi_master: device0 release bus
Please copy and paste the code you are running into a post here.
and are you getting anything on the display? can you see the slider being displayed when running the code?
Yeah slider loads on the screen. I'm using the code you posted above, only I swapped height and width and added rotation.
Just tested everything with TFT_eSPI through Arduino and hardware is all good.
don't add any rotation at all.
is the height and width correct if you don't change the rotation
the slider might not be working because of a glitch in the rotation end of things. I just want to know at this point is the touch is working or not. I will deal with the rotation later on.
I have no doubt the hardware works fine. I am working through bugs in the binding. Things are handled differently in this binding then using something like the Arduino IDE. That's because there is no DMA memory use and the espiodf port for the arduino IDE is an antique so the esp_lcd component is not being used. A lot of the code in the tft_espi library is not going to offer the best performance wise.
This is the result with no changes to code.
Flipping width and height, no rotation applied.
Touch still seems to do nothing. No console output, no response on screen.
OK then that is what the native width and height are with the rotation set to 0 degrees. That is what your code should be always when you start the display.
Now.. There is still no touch inputs taking place. Are you using the interrupt pin?
Yes, I tried with interrupt defined and set to -1. I haven't looked to see if theres any logging around the interrupt function, so I'm not sure its being caught. Tested that the pin value is flipping with a simple while loop to print pin value to insure that the pin wasn't misbehaving. Can see the pin pulled to gnd when screen it touched. Also added a print line to _on_interrupt in xpt2046.py and the function is never called.
OK we are going to mess around with the driver some.
run this code to test if we get anything on the touch. The display will be blank but you should still be able to get touch input
"""XPT2046 Touch module."""
from time import sleep
from micropython import const
_WIDTH = const(240)
_HEIGHT = const(320)
_TP_FREQ = const(1_000_000)
_TP_CS = const(-1) # CHANGE THIS TO THE CS PIN FOR THE TOUCH PANEL
_TP_INT = const(-1) # CHANGE THIS TO THE INTERRUPT PIN FOR THE TOUCH PANEL
_SPI_HOST = const(1)
_MOSI_PIN = const(11)
_MISO_PIN = const(13)
_SCLK_PIN = const(12)
class Touch(object):
"""Serial interface for XPT2046 Touch Screen Controller."""
# Command constants from ILI9341 datasheet
GET_X = const(0xD0) # X position
GET_Y = const(0x90) # Y position
GET_Z1 = const(0xB0) # Z1 position
GET_Z2 = const(0xC0) # Z2 position
GET_TEMP0 = const(0x80) # Temperature 0
GET_TEMP1 = const(0xF0) # Temperature 1
GET_BATTERY = const(0xA0) # Battery monitor
GET_AUX = const(0xE0) # Auxiliary input to ADC
def __init__(self, spi, cs, int_pin=None, int_handler=None,
width=240, height=320,
x_min=100, x_max=1962, y_min=100, y_max=1900):
"""Initialize touch screen controller.
Args:
spi (Class Spi): SPI interface for OLED
cs (Class Pin): Chip select pin
int_pin (Class Pin): Touch controller interrupt pin
int_handler (function): Handler for screen interrupt
width (int): Width of LCD screen
height (int): Height of LCD screen
x_min (int): Minimum x coordinate
x_max (int): Maximum x coordinate
y_min (int): Minimum Y coordinate
y_max (int): Maximum Y coordinate
"""
self.spi = spi
self.cs = cs
self.cs.init(self.cs.OUT, value=1)
self.rx_buf = bytearray(3) # Receive buffer
self.tx_buf = bytearray(3) # Transmit buffer
self.width = width
self.height = height
# Set calibration
self.x_min = x_min
self.x_max = x_max
self.y_min = y_min
self.y_max = y_max
self.x_multiplier = width / (x_max - x_min)
self.x_add = x_min * -self.x_multiplier
self.y_multiplier = height / (y_max - y_min)
self.y_add = y_min * -self.y_multiplier
if int_pin is not None:
self.int_pin = int_pin
self.int_pin.init(int_pin.IN)
self.int_handler = int_handler
self.int_locked = False
int_pin.irq(trigger=int_pin.IRQ_FALLING | int_pin.IRQ_RISING,
handler=self.int_press)
def get_touch(self):
"""Take multiple samples to get accurate touch reading."""
timeout = 2 # set timeout to 2 seconds
confidence = 5
buff = [[0, 0] for x in range(confidence)]
buf_length = confidence # Require a confidence of 5 good samples
buffptr = 0 # Track current buffer position
nsamples = 0 # Count samples
while timeout > 0:
if nsamples == buf_length:
meanx = sum([c[0] for c in buff]) // buf_length
meany = sum([c[1] for c in buff]) // buf_length
dev = sum([(c[0] - meanx)**2 +
(c[1] - meany)**2 for c in buff]) / buf_length
if dev <= 50: # Deviation should be under margin of 50
return self.normalize(meanx, meany)
# get a new value
sample = self.raw_touch() # get a touch
if sample is None:
nsamples = 0 # Invalidate buff
else:
buff[buffptr] = sample # put in buff
buffptr = (buffptr + 1) % buf_length # Incr, until rollover
nsamples = min(nsamples + 1, buf_length) # Incr. until max
sleep(.05)
timeout -= .05
return None
def int_press(self, pin):
"""Send X,Y values to passed interrupt handler."""
if not pin.value() and not self.int_locked:
self.int_locked = True # Lock Interrupt
buff = self.raw_touch()
if buff is not None:
x, y = self.normalize(*buff)
self.int_handler(x, y)
sleep(.1) # Debounce falling edge
elif pin.value() and self.int_locked:
sleep(.1) # Debounce rising edge
self.int_locked = False # Unlock interrupt
def normalize(self, x, y):
"""Normalize mean X,Y values to match LCD screen."""
x = int(self.x_multiplier * x + self.x_add)
y = int(self.y_multiplier * y + self.y_add)
return x, y
def raw_touch(self):
"""Read raw X,Y touch values.
Returns:
tuple(int, int): X, Y
"""
x = self.send_command(self.GET_X)
y = self.send_command(self.GET_Y)
if self.x_min <= x <= self.x_max and self.y_min <= y <= self.y_max:
return (x, y)
else:
return None
def send_command(self, command):
"""Write command to XT2046 (MicroPython).
Args:
command (byte): XT2046 command code.
Returns:
int: 12 bit response
"""
self.tx_buf[0] = command
self.cs(0)
self.spi.write_readinto(self.tx_buf, self.rx_buf)
self.cs(1)
return (self.rx_buf[1] << 4) | (self.rx_buf[2] >> 4)
import machine
if _TP_INT != -1:
i_pin = machine.Pin(_TP_INT, machine.Pin.IN)
else:
i_pin = None
if _TP_CS != -1:
cs_pin = machine.Pin(_TP_CS, machine.Pin.OUT)
cs_pin.value(1)
else:
cs_pin = None
def callback(x, y):
print(x, y)
spi_bus = machine.SPI(_SPI_HOST, _TP_FREQ, miso=_MISO_PIN, mosi=_MOSI_PIN, sck=_SCLK_PIN)
tp = Touch(spi_bus, cs_pin, i_pin, callback, width=_WIDTH, height=_HEIGHT)
Nothing other than the init function is called.
I lied. Possibly a bad connection or something. While it was running I reseated the int wire and that test code is working now.
Popping the original example back in to see if thats all it was.
In the original example, if I reseat the interrupt pin the event fires, no coordinates are returned but it fires. Touching the screen after results in no events.
Something weird is going on, if I upload the code with the display as main.py and reset. Interrupt is dead. If I reseat the wire, the interrupt fires, but the screen doesn't fire it. If I then upload the touch example as main.py and reset, the int doesn't work via the screen. If I reseat the wire, the int fires, and then works from the screen as well. I can even reset and not touch the wire, and the int via screen keeps working. Same behavior when choosing other pins.
does your touch screen have a reset pin?
No, its just the generic red ili9341/xpt2046 combo http://www.lcdwiki.com/2.8inch_SPI_Module_ILI9341_SKU:MSP2807
ok I updates the repo again. clone it and recompile and then run it again using the code below and see if it works
from micropython import const # NOQA
import machine # NOQA
_WIDTH = const(240)
_HEIGHT = const(320)
_TP_FREQ = const(1_000_000)
_TP_CS = const(-1) # CHANGE THIS TO THE CS PIN FOR THE TOUCH PANEL
_SPI_HOST = const(1)
_DC_PIN = const(7)
_MOSI_PIN = const(11)
_MISO_PIN = const(13)
_SCLK_PIN = const(12)
_CS_PIN = const(10)
_RESET_PIN = const(6)
_BACKLIGHT_PIN = const(5)
_FREQ = const(40_000_000)
import lcd_bus # NOQA
spi_bus = machine.SPI(
_SPI_HOST,
_TP_FREQ,
miso=_MISO_PIN,
mosi=_MOSI_PIN,
sck=_SCLK_PIN,
cs=_TP_CS
)
display_bus = lcd_bus.SPIBus(
dc=_DC_PIN,
host=_SPI_HOST,
sclk=_SCLK_PIN,
freq=_FREQ,
mosi=_MOSI_PIN,
miso=_MISO_PIN,
cs=_CS_PIN,
)
import ili9341 # NOQA
display = ili9341.ILI9341(
data_bus=display_bus,
display_width=_WIDTH,
display_height=_HEIGHT,
reset_pin=_RESET_PIN,
backlight_pin=_BACKLIGHT_PIN,
backlight_on_state=ili9341.STATE_HIGH,
)
display.init()
display.set_backlight(100)
import xpt2046 # NOQA
indev = xpt2046.XPT2046(spi_bus)
import lvgl as lv # NOQA
scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)
slider = lv.slider(scrn)
slider.set_size(_WIDTH - 50, 50)
slider.center()
import task_handler # NOQA
th = task_handler.TaskHandler()
I changed the code to use polling instead of interrupt based. The interrupt adds a layer of complexity that is hard to work around. So lets give this a try and see if it works.
Small typo on line 252 of micropy_updates/esp32/machine_hw_spi.c, you have : at the end.
No-go on that. The xpt device is locking the SPI and not releasing it.
D (3148) spi_master: device0 locked the bus
Is the last console line, nothing gets drawn on the screen and console is unresponsive.
ahh ok I forgot to free the bus.
ok I just pushed a commit that should fix those issues.
I uploaded this latest commit and ran the code above. I get the following error
Traceback (most recent call last):
File "task_handler.py", line 135, in _task_handler
File "pointer_framework.py", line 63, in _read
File "xpt2046.py", line 54, in _get_coords
AttributeError: 'module' object has no attribute 'ticks_ns'
Same issues here. I changed out for ticks.us() and set time to the equivalent 5000. Everything runs, I added logging to get_coords, and it is returning coords. Can't interact with the slider though, not sure if its a calibration issue, screen update issue, or something else. Might try to replcae the slider with a button and see if even a simple click registers.
So you are seeing the driver respond to touches now? Correct?
If yes that is a step in the right direction and the problem isn't going to be specific to that driver anymore. I should be able to test locally now and see what is going on and if the problem is happening with other drivers.
You aren't rotating the screen are you? I know that the rotation is not working properly at the moment and that does need fixing I am trying to just get the touch working and then I will mess with why it's breaking when rotating.
Yeah I had to throw in a print line in get_coords to catch it, but its sending back values and not Nones so its working. No rotation set, wasn't really expecting touch interactivity to work anyhow, theres calibration and other other issues at play. I need to put together a trial to make sure the screen can still update while touch is working.
I am curious to know what is being recorded as the touch coordinates. Do you have an example of that?
print(self.PRESSED, x, y)
return self.PRESSED, x, y
Just added the print statement to see under the hood. Using my displays "native" orientation | Position | Approximate X | Approximate Y |
---|---|---|---|
TL | 20 | 295 | |
TR | 210 | 295 | |
BR | 210 | 40 | |
BL | 20 | 40 |
Each touch returns quite a set of value no matter how quickly I try to tap.
1 22 40
1 22 40
1 21 40
1 21 40
1 20 40
1 20 40
1 21 40
1 21 40
1 21 40
It's not supposed to be returning values if you are not touching the display. So that's an issue I need to figure out why it is doing it.
It has to be something with setting up the touch panel. I have to dig through the data sheet for the touch IC to see how to turn off interrupt mode or how to check to see if there is touch that is actually taking place.
It's not sending anything without touches. It seems to be working just fine.
Just to confirm. When you touch the display you don't get any coordinates?
Show me the output from you moving your finger across the screen horizontally. I want to see what the coordinates are and if they are being calculated properly.
I did update the driver so now it will check to see if there is a Z axis. If there is no Z axis above a certain threshold then it will not register as a touch input.
As far as a string of coordinates being generated that is fine to have happen. What happens is LVGL loops checking the touch panel and updating the display on each loop. It doesn't redraw the display on each loop it will only read the input and change values for widgets etc... I can tell it not to do this but I want to see how it performs the way that it is now. If the touch input is kind of crappy then I will tell it to exit the loop.
I tried to build the latest clean repo this morning using this command:
python3 make.py esp32 submodules clean mpy_cross BOARD=ESP32_GENERIC BOARD_VARIANT=SPIRAM DISPLAY=ili9341 INDEV=xpt2046
and I get this error:
MPY pointer_framework.py
error compiling pointer_framework.py:
Traceback (most recent call last):
File "pointer_framework.py", line 12, in _remap
ViperTypeError: binary op not implemented
Any suggestions what could be wrong?
You need to pull the latest updates. I have fixed that issue not too long ago..
Error with last commit and the usual "slider" test code
Traceback (most recent call last):
File "<stdin>", line 66, in <module>
File "xpt2046.py", line 4, in <module>
File "pointer_framework.py", line 4, in <module>
ImportError: no module named 'lcd_utils'
So the new xpt2046 module doesn't work for me at all. I added a line to print coords got nothing, so I added a line to print the z value before comparing it to the threshold. That ran once and then everything hangs. I rolled xpt2046.py back to https://github.com/kdschlosser/lvgl_micropython/blob/e10678cb7feb975712e3813a18af0f368253f9a4/api_drivers/common_api_drivers/indev/xpt2046.py and ran the demo and now the slider is working.
These are the coords that I dumped for sliding the slider back and forth once.
@demitrix didn't you have a run time error on 'lcd utils'?
@demitrix didn't you have a run time error on 'lcd utils'?
I did not. Make sure you have a clean pull, or delete and reclone the repo.
OK I rolled the driver back to that PR and fixed the ticks_ns problem.
Let me know if the slider now works properly.
If the slider is working then try adding the rotate to it. You have to do this after the touch driver has been created. I am trying to set the rotation up so it is something that can be done real time. so if someone wanted to add a mems sensor to detect orientation they could and it would rotate the screen based on the device position.
display.init()
display.set_backlight(100)
import xpt2046 # NOQA
indev = xpt2046.XPT2046(spi_bus)
import lvgl as lv # NOQA
display.set_rotation(lv.DISPLAY_ROTATION._90)
scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)
slider = lv.slider(scrn)
slider.set_size(_WIDTH - 50, 50)
slider.center()
import task_handler # NOQA
th = task_handler.TaskHandler()
Touch is working but is not rotated. I can move the slider by sliding where it was before rotation. Also I was incorrect, the previous version of xpt2046 is reporting phantom touches. While I was typing up this reply and not touching anything. It is incredibly sporadic and I can't find anything that influences it.
1 240 0
1 466 4
1 29 1
1 180 24
1 481 0
1 2 0
1 481 0
1 481 80
1 481 0
1 119 39
1 6 0
1 119 0
1 481 310
1 25 0
1 79 4
1 320 1
1 160 39
1 5 0
1 481 0
1 0 310
1 481 0
1 119 106
1 481 0
1 3 0
1 361 19
1 29 12
1 481 0
1 129 39
1 19 0
1 1 0
1 1 0
1 4 0
1 360 0
OK I updated the driver again. I added in the z axis but I used different registers and hopefully that will do the trick. I also added to it debugging output so to enable that add debug=True
to the arguments when constructing the driver instance. This is going to print out the RAW data received by the driver as well as the data after it has been normalized to the display resolution and it will also include the data after rotation has been applied as well. This is going to stream a lot of data out including when the display is not touched at all.
If you can give me a copy of that data so I can check it out without any rotation being applied and also when rotation is applied that would be really helpful. I would like to see data when touching and when not touching with and without rotation,
Phantom touches are resolved for sure. Rotation behavior remains the same. No rotation works as expected. Rotation applied and the slider responds to where it is when not rotated.
However, rotation seems like it should be working.
No rotation touching what is the native Top Right corner of the screen XPT2046(raw_x=214, raw_y=294, x=214, y=294, state=PRESSED) With rotation touching the same corner XPT2046(raw_x=215, raw_y=298, x=22, y=215, state=PRESSED)
So the coords are being transposed.
Here are dumps from both states.
rotated what degree?
from what I am seeing is you have rotated the display 90° and the numbers are aligning properly.. if you have a native resolution of 240 x 320 and you touch the display at position 20, 200 that would translate to position 120, 20 when rotating the display 90°
What I am wondering is if LVGL is handling the change to the indev. I have to look at the code in LVGL to see what it is doing with respect to the indev drivers.
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.