From f492278b992c918aba9ecfc263deeb0fab2c5bf7 Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Sun, 1 Mar 2026 22:45:30 +0100 Subject: [PATCH] Improve lilygo_t_watch_s3_plus --- .../lib/drivers/indev/__init__.py | 10 ++ .../lib/drivers/indev/focaltech_touch.py | 124 ++++++++++++++++++ .../lib/drivers/indev/ft6x36.py | 37 ++++++ .../lib/mpos/board/lilygo_t_watch_s3_plus.py | 20 ++- .../board/waveshare_esp32_s3_touch_lcd_2.py | 3 +- internal_filesystem/lib/mpos/main.py | 9 +- 6 files changed, 185 insertions(+), 18 deletions(-) create mode 100644 internal_filesystem/lib/drivers/indev/__init__.py create mode 100644 internal_filesystem/lib/drivers/indev/focaltech_touch.py create mode 100644 internal_filesystem/lib/drivers/indev/ft6x36.py diff --git a/internal_filesystem/lib/drivers/indev/__init__.py b/internal_filesystem/lib/drivers/indev/__init__.py new file mode 100644 index 00000000..b51d2f04 --- /dev/null +++ b/internal_filesystem/lib/drivers/indev/__init__.py @@ -0,0 +1,10 @@ +"""Input device drivers package helpers.""" + +try: + import sys + from . import focaltech_touch as _focaltech_touch + + if "focaltech_touch" not in sys.modules: + sys.modules["focaltech_touch"] = _focaltech_touch +except Exception: + pass diff --git a/internal_filesystem/lib/drivers/indev/focaltech_touch.py b/internal_filesystem/lib/drivers/indev/focaltech_touch.py new file mode 100644 index 00000000..5e0f6d1a --- /dev/null +++ b/internal_filesystem/lib/drivers/indev/focaltech_touch.py @@ -0,0 +1,124 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +from micropython import const # NOQA +import pointer_framework +import machine # NOQA + + +# Register of the current mode +_DEV_MODE_REG = const(0x00) + +# ** Possible modes as of FT6X36_DEV_MODE_REG ** +_DEV_MODE_WORKING = const(0x00) +_CTRL = const(0x86) + + +# Status register: stores number of active touch points (0, 1, 2) +_TD_STAT_REG = const(0x02) +_P1_XH = const(0x03) +_P1_XL = const(0x04) + +_P1_YH = const(0x05) +_P1_YL = const(0x06) + +_MSB_MASK = const(0x0F) +_LSB_MASK = const(0xFF) + +# Report rate in Active mode +_PERIOD_ACTIVE_REG = const(0x88) + + +_VENDID = const(0x11) +_CHIPID_REG = const(0xA3) + +_FIRMWARE_ID_REG = const(0xA6) +_RELEASECODE_REG = const(0xAF) +_PANEL_ID_REG = const(0xA8) + +_G_MODE = const(0xA4) + + +class FocalTechTouch(pointer_framework.PointerDriver): + + def __init__( + self, + device, + touch_cal, + startup_rotation, # NOQA + debug, + factors, + *chip_ids + ): # NOQA + self._tx_buf = bytearray(5) + self._tx_mv = memoryview(self._tx_buf) + self._rx_buf = bytearray(5) + self._rx_mv = memoryview(self._rx_buf) + + self._device = device + self._factors = factors + + self._read_reg(_PANEL_ID_REG) + print("Touch Device ID: 0x%02x" % self._rx_buf[0]) + ven_id = self._rx_buf[0] # NOQA + + self._read_reg(_CHIPID_REG) + print("Touch Chip ID: 0x%02x" % self._rx_buf[0]) + chip_id = self._rx_buf[0] + + self._read_reg(_DEV_MODE_REG) + print("Touch Device mode: 0x%02x" % self._rx_buf[0]) + + self._read_reg(_FIRMWARE_ID_REG) + print("Touch Firmware ID: 0x%02x" % self._rx_buf[0]) + + self._read_reg(_RELEASECODE_REG) + print("Touch Release code: 0x%02x" % self._rx_buf[0]) + + if chip_id not in chip_ids: + raise RuntimeError( + f'IC is not compatable with the {self.__class__.__name__} driver' # NOQA + ) + + self._write_reg(_DEV_MODE_REG, _DEV_MODE_WORKING) + self._write_reg(_PERIOD_ACTIVE_REG, 0x0E) + self._write_reg(_G_MODE, 0x00) + + # This is needed so the TS doesn't go to sleep + self._write_reg(_CTRL, 0x00) + + super().__init__( + touch_cal=touch_cal, startup_rotation=startup_rotation, debug=debug + ) + + def _get_coords(self): + self._tx_buf[0] = _TD_STAT_REG + try: + self._device.write_readinto(self._tx_mv, self._rx_mv) + except OSError: + return None + + buf = self._rx_buf + + touch_pnt_cnt = buf[0] + if touch_pnt_cnt != 1: + return None + + x = ((buf[1] & _MSB_MASK) << 8) | buf[2] + y = ((buf[3] & _MSB_MASK) << 8) | buf[4] + + if self._factors is not None: + x = round(x / self._factors[0]) + y = round(y / self._factors[1]) + + return self.PRESSED, x, y + + def _read_reg(self, reg): + self._tx_buf[0] = reg + self._rx_buf[0] = 0x00 + + self._device.write_readinto(self._tx_mv[:1], self._rx_mv[:1]) + + def _write_reg(self, reg, value): + self._tx_buf[0] = reg + self._tx_buf[1] = value + self._device.write(self._tx_mv[:2]) diff --git a/internal_filesystem/lib/drivers/indev/ft6x36.py b/internal_filesystem/lib/drivers/indev/ft6x36.py new file mode 100644 index 00000000..b85c8ae2 --- /dev/null +++ b/internal_filesystem/lib/drivers/indev/ft6x36.py @@ -0,0 +1,37 @@ +# Copyright (c) 2024 - 2025 Kevin G. Schlosser + +# FT6236/FT6336/FT6436/FT6436L + +from micropython import const # NOQA +import focaltech_touch +import pointer_framework + + +I2C_ADDR = const(0x38) +BITS = 8 + +_FT6x36_CHIPID_1 = const(0x36) +_FT6x36_CHIPID_2 = const(0x64) +_FT6x36_CHIPID_3 = const(0xCD) + + +class FT6x36(focaltech_touch.FocalTechTouch): + + def __init__( + self, + device, + touch_cal=None, + startup_rotation=pointer_framework.lv.DISPLAY_ROTATION._0, # NOQA + debug=False + ): # NOQA + + super().__init__( + device, + touch_cal, + startup_rotation, + debug, + None, + _FT6x36_CHIPID_1, + _FT6x36_CHIPID_2, + _FT6x36_CHIPID_3 + ) diff --git a/internal_filesystem/lib/mpos/board/lilygo_t_watch_s3_plus.py b/internal_filesystem/lib/mpos/board/lilygo_t_watch_s3_plus.py index a11db159..65cec32f 100644 --- a/internal_filesystem/lib/mpos/board/lilygo_t_watch_s3_plus.py +++ b/internal_filesystem/lib/mpos/board/lilygo_t_watch_s3_plus.py @@ -2,13 +2,10 @@ print("lilygo_t_watch_s3_plus.py initialization") # Manufacturer's website at https://lilygo.cc/products/t-watch-s3-plus import lcd_bus import machine -import i2c import lvgl as lv import task_handler -import drivers.display.st7789 as st7789 - import mpos.ui spi_bus = machine.SPI.Bus( @@ -27,6 +24,7 @@ _BUFFER_SIZE = const(28800) fb1 = display_bus.allocate_framebuffer(_BUFFER_SIZE, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA) fb2 = display_bus.allocate_framebuffer(_BUFFER_SIZE, lcd_bus.MEMORY_INTERNAL | lcd_bus.MEMORY_DMA) +import drivers.display.st7789 as st7789 mpos.ui.main_display = st7789.ST7789( data_bus=display_bus, frame_buffer1=fb1, @@ -38,19 +36,17 @@ mpos.ui.main_display = st7789.ST7789( rgb565_byte_swap=True, backlight_pin=45, backlight_on_state=st7789.STATE_PWM, -) +) # triggers lv.init() mpos.ui.main_display.init() mpos.ui.main_display.set_power(True) mpos.ui.main_display.set_backlight(100) -# TODO: -# Touch handling: -#import drivers.indev.cst816s as cst816s -#i2c_bus = i2c.I2C.Bus(host=0, scl=40, sda=39, freq=400000, use_locks=False) -#touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=0x15, reg_bits=8) -#indev=cst816s.CST816S(touch_dev) - -lv.init() +import i2c +import drivers.indev.ft6x36 as ft6x36 +i2c_bus = i2c.I2C.Bus(host=0, sda=39, scl=40, freq=400000, use_locks=False) +touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=ft6x36.I2C_ADDR, reg_bits=ft6x36.BITS) +import pointer_framework +indev=ft6x36.FT6x36(touch_dev, startup_rotation=pointer_framework.lv.DISPLAY_ROTATION._180) # TODO: # - battery diff --git a/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py b/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py index 5422523b..32a6f26d 100644 --- a/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py +++ b/internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py @@ -72,7 +72,7 @@ mpos.ui.main_display = st7789.ST7789( rgb565_byte_swap=True, backlight_pin=LCD_BL, backlight_on_state=st7789.STATE_PWM, -) +) # triggers lv.init() mpos.ui.main_display.init() mpos.ui.main_display.set_power(True) mpos.ui.main_display.set_backlight(100) @@ -82,7 +82,6 @@ i2c_bus = i2c.I2C.Bus(host=I2C_BUS, scl=TP_SCL, sda=TP_SDA, freq=I2C_FREQ, use_l touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=TP_ADDR, reg_bits=TP_REGBITS) indev=cst816s.CST816S(touch_dev,startup_rotation=lv.DISPLAY_ROTATION._180) # button in top left, good -lv.init() mpos.ui.main_display.set_rotation(lv.DISPLAY_ROTATION._90) # must be done after initializing display and creating the touch drivers, to ensure proper handling # Battery voltage ADC measuring diff --git a/internal_filesystem/lib/mpos/main.py b/internal_filesystem/lib/mpos/main.py index 66e20cd8..14a65a95 100644 --- a/internal_filesystem/lib/mpos/main.py +++ b/internal_filesystem/lib/mpos/main.py @@ -105,6 +105,11 @@ def detect_board(): # or: if single_address_i2c_scan(i2c0, 0x6A): # IMU currently not installed on prototype board return "fri3d_2026" + print("lilygo_t_watch_s3_plus ?") + if i2c0 := fail_save_i2c(sda=10, scl=11): + if single_address_i2c_scan(i2c0, 0x19): # IMU on 32? but scan shows: [25, 52, 81, 90] + return "lilygo_t_watch_s3_plus" # example MAC address: D0:CF:13:33:36:306 + # Then do I2C-based board detection print("matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660 ?") if i2c0 := fail_save_i2c(sda=39, scl=38): @@ -127,10 +132,6 @@ def detect_board(): if single_address_i2c_scan(i2c0, 0x6B): # IMU (plus possibly the Communicator's LANA TNY at 0x38) return "fri3d_2024" - print("lilygo_t_watch_s3_plus ?") - if i2c0 := fail_save_i2c(sda=10, scl=11): - if single_address_i2c_scan(i2c0, 0x20): # IMU - return "lilygo_t_watch_s3_plus" # example MAC address: D0:CF:13:33:36:306 print("Unknown board: couldn't detect known I2C devices or unique_id prefix")