diff --git a/README.md b/README.md index 6d583687..3f9bcad3 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ _____________________________________________ ### Supported Touch IC's * CST816S + * CST820 * FT5x06 * FT5x16 * FT5x26 diff --git a/api_drivers/common_api_drivers/indev/cst816s.py b/api_drivers/common_api_drivers/indev/cst816s.py index 146bdae9..15b50655 100644 --- a/api_drivers/common_api_drivers/indev/cst816s.py +++ b/api_drivers/common_api_drivers/indev/cst816s.py @@ -206,7 +206,7 @@ def __init__( print('FW Version:', hex(self._rx_buf[0])) if chip_id != _ChipIDValue: - raise RuntimeError(f'Incorrect chip id ({hex(_ChipIDValue)})') + raise RuntimeError(f'Incorrect chip id ({hex(chip_id)} expected: {hex(_ChipIDValue)})') self._write_reg(_IrqCtl, _EnTouch | _EnChange) diff --git a/api_drivers/common_api_drivers/indev/cst820.py b/api_drivers/common_api_drivers/indev/cst820.py new file mode 100644 index 00000000..afb6e514 --- /dev/null +++ b/api_drivers/common_api_drivers/indev/cst820.py @@ -0,0 +1,306 @@ +# Based on cst816s, Copyright (c) 2024 - 2025 Kevin G. Schlosser + +from micropython import const # NOQA +import pointer_framework +import time +import machine # NOQA + + +I2C_ADDR = 0x15 +BITS = 8 + +# 0x00: No gesture +# 0x01: Swipe up +# 0x02: Swipe down +# 0x03: Swipe left +# 0x04: Swipe right +# 0x05: Single click +# 0x0B: Double click +# 0x0C: Long press +_GestureID = const(0x01) + +# 0: No finger +# 1: 1 finger +_FingerNum = const(0x02) + +# & 0xF << 8 +_XposH = const(0x03) +_XposL = const(0x04) + +# & 0xF << 8 +_YposH = const(0x05) +_YposL = const(0x06) + +_RegisterVersion = const(0x15) + +_BPC0H = const(0xB0) +_BPC0L = const(0xB1) + +_BPC1H = const(0xB2) +_BPC1L = const(0xB3) + +_ChipID = const(0xA7) +_ChipIDValue = const(0xB7) # 0xB5=cst816s, 0xB7=cst820 + +_ProjID = const(0xA8) +_FwVersion = const(0xA9) + + +# =============================== +_MotionMask = const(0xEC) + +# Enables continuous left and right sliding +_EnConLR = const(0x04) +# Enables continuous up and down sliding +_EnConUD = const(0x02) +# Enable double-click action +_EnDClick = const(0x01) +# =============================== + +# Interrupt low pulse output width. +# Unit 0.1ms, optional value: 1~200. The default value is 10. +_IrqPluseWidth = const(0xED) + +# Normal fast detection cycle. +# This value affects LpAutoWakeTime and AutoSleepTime. +# Unit 10ms, optional value: 1~30. The default value is 1. +_NorScanPer = const(0xEE) + +# Gesture detection sliding partition angle control. Angle=tan(c)*10 +# c is the angle based on the positive direction of the x-axis. +_MotionSlAngle = const(0xEF) + +_LpScanRaw1H = const(0xF0) +_LpScanRaw1L = const(0xF1) +_LpScanRaw2H = const(0xF2) +_LpScanRaw2L = const(0xF3) + +# Automatic recalibration period in low power consumption. +# Unit: 1 minute, optional value: 1 to 5. The default value is 5. +_LpAutoWakeTime = const(0xF4) + + +# Low power scan wake-up threshold. The smaller the value, +# the more sensitive it is. +# Optional values: 1 to 255. The default value is 48. +_LpScanTH = const(0xF5) + +# Low power scan range. The larger the value, the more sensitive it is, +# and the higher the power consumption is. +# Optional values: 0, 1, 2, 3. The default value is 3. +_LpScanWin = const(0xF6) + +# Low power scan frequency. The smaller the value, the more sensitive it is. +# Optional values: 1 to 255. The default value is 7. +_LpScanFreq = const(0xF7) + +# Low power scan current. The smaller the value, the more sensitive it is. +# Optional values: 1 to 255. +_LpScanIdac = const(0xF8) + + +# Automatically enters low power mode when there is no touch within x seconds. +# Unit: 1S, default value: 2S. +_AutoSleepTime = const(0xF9) + +# =============================== +_IrqCtl = const(0xFA) +# Interrupt pin test, automatically sends low pulses periodically after enabling +_EnTest = const(0x80) +# Sends low pulses periodically when touch is detected. +_EnTouch = const(0x40) +# Sends low pulses when touch state changes are detected. +_EnChange = const(0x20) +# Sends low pulses when gestures are detected. +_EnMotion = const(0x10) +# Long press gesture only sends one low pulse signal. +_OnceWLP = const(0x01) +# =============================== + + +# Automatically reset when there is touch but no valid gesture within x seconds. +# Unit: 1S. This function is not enabled when it is 0. The default value is 5. +_AutoReset = const(0xFB) + +# Automatically reset after long pressing for x seconds. +# Unit: 1S. This function is not enabled when it is 0. The default value is 10. +_LongPressTime = const(0xFC) + +# =============================== +_IOCtl = const(0xFD) + +# The master controller realizes the soft reset function +# of the touch screen by pulling down the IRQ pin. +# 0: Disable soft reset. +# 1: Enable soft reset. +_SOFT_RST = const(0x04) + +# IIC pin drive mode, the default is resistor pull-up. +# 0: Resistor pull-up +# 1: OD +_IIC_OD = const(0x02) + +# IIC and IRQ pin level selection, the default is VDD level. +# 0: VDD +# 1: 1.8V +_En1v8 = const(0x01) +# =============================== + +# The default value is 0, enabling automatic entry into low power mode. +# When the value is non-zero, automatic entry into low power mode is disabled. +# 0: enabled +# 1: disabled +_DisAutoSleep = const(0xFE) + + +class CST820(pointer_framework.PointerDriver): + + 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]) + + def __init__( + self, + device, + reset_pin=None, + touch_cal=None, + startup_rotation=pointer_framework.lv.DISPLAY_ROTATION._0, # NOQA + debug=False + ): + self._tx_buf = bytearray(2) + self._tx_mv = memoryview(self._tx_buf) + self._rx_buf = bytearray(1) + self._rx_mv = memoryview(self._rx_buf) + + self._device = device + + if not isinstance(reset_pin, int): + self._reset_pin = reset_pin + else: + self._reset_pin = machine.Pin(reset_pin, machine.Pin.OUT) + + if self._reset_pin: + self._reset_pin.value(1) + + self.hw_reset() + self.auto_sleep = False + + self._read_reg(_ChipID) + print('Chip ID:', hex(self._rx_buf[0])) + chip_id = self._rx_buf[0] + + self._read_reg(_RegisterVersion) + print('Touch version:', self._rx_buf[0]) + + self._read_reg(_ProjID) + print('Proj ID:', hex(self._rx_buf[0])) + + self._read_reg(_FwVersion) + print('FW Version:', hex(self._rx_buf[0])) + + if chip_id != _ChipIDValue: + raise RuntimeError(f'Incorrect chip id ({hex(chip_id)} expected: {hex(_ChipIDValue)})') + + self._write_reg(_IrqCtl, _EnTouch | _EnChange) + + super().__init__( + touch_cal=touch_cal, startup_rotation=startup_rotation, debug=debug + ) + + @property + def wake_up_threshold(self): + self._read_reg(_LpScanTH) + return 256 - self._rx_buf[0] + + @wake_up_threshold.setter + def wake_up_threshold(self, value): + if value < 1: + value = 1 + elif value > 255: + value = 255 + + self._write_reg(_LpScanTH, 256 - value) + + @property + def wake_up_scan_frequency(self): + self._read_reg(_LpScanFreq) + return 256 - self._rx_buf[0] + + @wake_up_scan_frequency.setter + def wake_up_scan_frequency(self, value): + if value < 1: + value = 1 + elif value > 255: + value = 255 + + self._write_reg(_LpScanFreq, 256 - value) + + @property + def auto_sleep_timeout(self): + self._read_reg(_AutoSleepTime) + return self._rx_buf[0] + + @auto_sleep_timeout.setter + def auto_sleep_timeout(self, value): + if value < 1: + value = 1 + elif value > 255: + value = 255 + + self._write_reg(_AutoSleepTime, value) + + def wake_up(self): + auto_sleep = self.auto_sleep + + self._write_reg(_DisAutoSleep, 0x00) + time.sleep_ms(10) # NOQA + self._write_reg(_DisAutoSleep, 0x01) + time.sleep_ms(50) # NOQA + self._write_reg(_DisAutoSleep, 0x01) + time.sleep_ms(50) # NOQA + self._write_reg(_DisAutoSleep, int(not auto_sleep)) + + @property + def auto_sleep(self): + self._read_reg(_DisAutoSleep) + return self._rx_buf[0] == 0x00 + + @auto_sleep.setter + def auto_sleep(self, en): + if en: + self._write_reg(_DisAutoSleep, 0x00) + else: + self._write_reg(_DisAutoSleep, 0x01) + + def hw_reset(self): + if self._reset_pin is None: + return + + self._reset_pin(0) + time.sleep_ms(1) # NOQA + self._reset_pin(1) + time.sleep_ms(50) # NOQA + + def _get_coords(self): + self._read_reg(_FingerNum) + if self._rx_buf[0] == 0: + return None + + self._read_reg(_XposH) + x = (self._rx_buf[0] & 0x0F) << 8 + self._read_reg(_XposL) + x |= self._rx_buf[0] + + self._read_reg(_YposH) + y = (self._rx_buf[0] & 0x0F) << 8 + self._read_reg(_YposL) + y |= self._rx_buf[0] + + return self.PRESSED, x, y diff --git a/api_drivers/common_api_drivers/indev/xpt2046.py b/api_drivers/common_api_drivers/indev/xpt2046.py index 782f5229..54a56253 100644 --- a/api_drivers/common_api_drivers/indev/xpt2046.py +++ b/api_drivers/common_api_drivers/indev/xpt2046.py @@ -7,8 +7,8 @@ import time -_CMD_X_READ = const(0xD0) # 12 bit resolution -_CMD_Y_READ = const(0x90) # 12 bit resolution +#_CMD_X_READ = 0xD0 # 12 bit resolution +#_CMD_Y_READ = 0x90 # 12 bit resolution _CMD_Z1_READ = const(0xB0) _CMD_Z2_READ = const(0xC0) _MIN_RAW_COORD = const(10) @@ -40,6 +40,7 @@ def __init__( device, touch_cal=None, startup_rotation=pointer_framework.lv.DISPLAY_ROTATION._0, # NOQA + swapxy=False, debug=False ): self._device = device @@ -55,6 +56,12 @@ def __init__( margin = max(min(self.margin, 100), 1) self.__margin = margin * margin + if swapxy: # some very popular/prolific esp32_2432S028R boards require this + self._cmd_x_read = 0x90 + self._cmd_y_read = 0xD0 + else: + self._cmd_x_read = 0xD0 + self._cmd_y_read = 0x90 super().__init__( touch_cal=touch_cal, startup_rotation=startup_rotation, debug=debug @@ -112,8 +119,8 @@ def _normalize(self, x, y): return x, y def _get_raw(self): - x = self._read_reg(_CMD_X_READ, 3) - y = self._read_reg(_CMD_Y_READ, 3) + x = self._read_reg(self._cmd_x_read, 3) + y = self._read_reg(self._cmd_y_read, 3) if x > _MIN_RAW_COORD and y < _MAX_RAW_COORD: # touch pressed? return x, y else: