From 83f86d168383db2832ffb50fa358217a92645268 Mon Sep 17 00:00:00 2001 From: Liz Date: Tue, 5 Dec 2023 19:21:01 -0500 Subject: [PATCH 1/9] initial library file --- adafruit_ft5336.py | 96 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/adafruit_ft5336.py b/adafruit_ft5336.py index ca6a6c1..dd08d5e 100644 --- a/adafruit_ft5336.py +++ b/adafruit_ft5336.py @@ -1,4 +1,3 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # SPDX-FileCopyrightText: Copyright (c) 2023 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT @@ -27,11 +26,100 @@ .. todo:: Uncomment or remove the Bus Device and/or the Register library dependencies based on the library's use of either. -# * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice -# * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register +* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice +* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register """ -# imports +from adafruit_register.i2c_bits import ROBits +from adafruit_bus_device.i2c_device import I2CDevice +from micropython import const +try: + from typing import List +except ImportError: + pass __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_FT5336.git" + +_DEFAULT_ADDR = const(0x38) +_REG_VENDID = const(0xA3) +_REG_CHIPID = const(0xA8) +_VENDID = const(0x11) +_CHIPID = const(0x79) +_REG_NUMTOUCHES = const(0x02) +_TD_STATUS = const(0x02) +_TOUCH1_XH = const(0x03) +_TOUCH1_XL = const(0x04) +_TOUCH1_YH = const(0x05) +_TOUCH1_YL = const(0x06) + +class Adafruit_FT5336: + # Define read-only register bits for vendor ID, chip ID, and number of touches. + _vend_id = ROBits(8, _REG_VENDID, 0) # 8-bit read-only register for vendor ID + _chip_id = ROBits(8, _REG_CHIPID, 0) # 8-bit read-only register for chip ID + _num_touches = ROBits(8, _REG_NUMTOUCHES, 0) # 8-bit read-only register for number of touches + + def __init__(self, i2c, i2c_addr: int = _DEFAULT_ADDR, max_touches: int = 5): + """ + Initializes the FT5336 touchscreen driver. + + Args: + i2c: The I2C bus object. + i2c_addr (int): The I2C address of the device. Defaults to _DEFAULT_ADDR. + max_touches (int): Maximum number of touch points to track. Defaults to 5. + + Raises: + ValueError: If the detected vendor ID or chip ID does not match the expected values. + """ + self.i2c_device = I2CDevice(i2c, i2c_addr) # I2C device instance + self.i2c_addr = i2c_addr # Store the I2C address + self._touches = 0 # Number of current touches + self.max_touches = max_touches # Maximum number of touches to track + + # Initialize touch point arrays + self._touchX: List[int] = [0] * self.max_touches + self._touchY: List[int] = [0] * self.max_touches + self._touchID: List[int] = [0] * self.max_touches + + # Verify device identity by checking the vendor and chip IDs + if self._vend_id != _VENDID: + raise ValueError("Incorrect vendor ID") + if self._chip_id != _CHIPID: + raise ValueError("Incorrect chip ID") + + @property + def touched(self): + n = self._num_touches + return 0 if n > 5 else n + + def _read_data(self): + buffer = bytearray(32) + with self.i2c_device as i2c: + i2c.write_then_readinto(bytearray([0]), buffer, in_end=32) + + self._touches = buffer[_TD_STATUS] + if self._touches > 5 or self._touches == 0: + self._touches = 0 + + for i in range(self._touches): + self._touchX[i] = (buffer[_TOUCH1_XH + i * 6] & 0x0F) << 8 | buffer[_TOUCH1_XL + i * 6] + self._touchY[i] = (buffer[_TOUCH1_YH + i * 6] & 0x0F) << 8 | buffer[_TOUCH1_YL + i * 6] + self._touchID[i] = buffer[_TOUCH1_YH + i * 6] >> 4 + + @property + def points(self): + self._read_data() + + points = [] + for i in range(min(self._touches, self.max_touches)): + point = (self._touchX[i], self._touchY[i], 1) # 1 indicates touch is active + points.append(point) + + return points + + def point(self, point_index: int): + self._read_data() + if self._touches == 0 or point_index >= self._touches: + return (0, 0, 0) + else: + return (self._touchX[point_index], self._touchY[point_index], 1) From e972374117497ecb3c27ca261d280a35f7f99696 Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 10:17:15 -0500 Subject: [PATCH 2/9] docs --- README.rst | 14 ++------------ docs/conf.py | 11 ++++++----- docs/index.rst | 6 ++---- requirements.txt | 2 -- 4 files changed, 10 insertions(+), 23 deletions(-) diff --git a/README.rst b/README.rst index 82c0382..31e0c92 100644 --- a/README.rst +++ b/README.rst @@ -21,7 +21,7 @@ Introduction :target: https://github.com/psf/black :alt: Code Style: Black -Touchscreen driver for the FT5336 touch controller +CircuitPython driver for the FT5336 touch controller Dependencies @@ -38,19 +38,10 @@ This is easily achieved by downloading or individual libraries can be installed using `circup `_. - - -.. todo:: Describe the Adafruit product this library works with. For PCBs, you can also add the -image from the assets folder in the PCB's GitHub repo. - `Purchase one from the Adafruit shop `_ Installing from PyPI ===================== -.. note:: This library is not available on PyPI yet. Install documentation is included - as a standard element. Stay tuned for PyPI availability! - -.. todo:: Remove the above note if PyPI version is/will be available at time of release. On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from PyPI `_. @@ -101,8 +92,7 @@ Or the following command to update an existing version: Usage Example ============= -.. todo:: Add a quick, simple example. It and other examples should live in the -examples folder and be included in docs/examples.rst. +.. code-block:: python Documentation ============= diff --git a/docs/conf.py b/docs/conf.py index d68f1a4..4d497ea 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,11 +23,12 @@ "sphinx.ext.todo", ] -# TODO: Please Read! -# Uncomment the below if you use native CircuitPython modules such as -# digitalio, micropython and busio. List the modules you use. Without it, the -# autodoc module docs will fail to generate with a warning. -# autodoc_mock_imports = ["digitalio", "busio"] +autodoc_mock_imports = [ + "micropython", + "busio", + "adafruit_bus_device", + "adafruit_register", +] autodoc_preserve_defaults = True diff --git a/docs/index.rst b/docs/index.rst index b250d8d..ec33a0a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -24,14 +24,12 @@ Table of Contents .. toctree:: :caption: Tutorials -.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave - the toctree above for use later. + Adafruit 3.5" 320x480 Color TFT Touchscreen Breakout Learn Guide .. toctree:: :caption: Related Products -.. todo:: Add any product links here. If there are none, then simply delete this todo and leave - the toctree above for use later. + Adafruit 3.5" TFT 320x480 with Capacitive Touch Breakout Board - EYESPI .. toctree:: :caption: Other Links diff --git a/requirements.txt b/requirements.txt index a1b2e6c..da6830f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # SPDX-FileCopyrightText: Copyright (c) 2023 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT @@ -6,4 +5,3 @@ Adafruit-Blinka adafruit-circuitpython-busdevice adafruit-circuitpython-register -n From 8168409738ce0b8624f76e22518338d72bd89b46 Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 10:43:07 -0500 Subject: [PATCH 3/9] Update adafruit_ft5336.py --- adafruit_ft5336.py | 60 +++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/adafruit_ft5336.py b/adafruit_ft5336.py index dd08d5e..c74fa38 100644 --- a/adafruit_ft5336.py +++ b/adafruit_ft5336.py @@ -5,7 +5,7 @@ `adafruit_ft5336` ================================================================================ -Touchscreen driver for the FT5336 touch controller +CircuitPython driver for the FT5336 touch screen controller * Author(s): Liz Clark @@ -15,17 +15,13 @@ **Hardware:** -.. todo:: Add links to any specific hardware product page(s), or category page(s). - Use unordered list & hyperlink rST inline format: "* `Link Text `_" +* `Adafruit 3.5" TFT 320x480 with Capacitive Touch Breakout: `_ **Software and Dependencies:** * Adafruit CircuitPython firmware for the supported boards: https://circuitpython.org/downloads -.. todo:: Uncomment or remove the Bus Device and/or the Register library dependencies - based on the library's use of either. - * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register """ @@ -34,7 +30,7 @@ from adafruit_bus_device.i2c_device import I2CDevice from micropython import const try: - from typing import List + from typing import List, Tuple except ImportError: pass @@ -54,22 +50,17 @@ _TOUCH1_YL = const(0x06) class Adafruit_FT5336: + """Adafruit FT5336 touch screen driver""" # Define read-only register bits for vendor ID, chip ID, and number of touches. _vend_id = ROBits(8, _REG_VENDID, 0) # 8-bit read-only register for vendor ID _chip_id = ROBits(8, _REG_CHIPID, 0) # 8-bit read-only register for chip ID _num_touches = ROBits(8, _REG_NUMTOUCHES, 0) # 8-bit read-only register for number of touches - def __init__(self, i2c, i2c_addr: int = _DEFAULT_ADDR, max_touches: int = 5): - """ - Initializes the FT5336 touchscreen driver. + def __init__(self, i2c, i2c_addr: int = _DEFAULT_ADDR, max_touches: int = 5) -> None: + """Initialization over I2C - Args: - i2c: The I2C bus object. - i2c_addr (int): The I2C address of the device. Defaults to _DEFAULT_ADDR. - max_touches (int): Maximum number of touch points to track. Defaults to 5. - - Raises: - ValueError: If the detected vendor ID or chip ID does not match the expected values. + :param int i2c_addr: I2C address (default 0x38) + :param int max_touches: Maximum number of touch points to track. Defaults to 5. """ self.i2c_device = I2CDevice(i2c, i2c_addr) # I2C device instance self.i2c_addr = i2c_addr # Store the I2C address @@ -87,37 +78,52 @@ def __init__(self, i2c, i2c_addr: int = _DEFAULT_ADDR, max_touches: int = 5): if self._chip_id != _CHIPID: raise ValueError("Incorrect chip ID") - @property - def touched(self): - n = self._num_touches - return 0 if n > 5 else n - def _read_data(self): buffer = bytearray(32) with self.i2c_device as i2c: i2c.write_then_readinto(bytearray([0]), buffer, in_end=32) self._touches = buffer[_TD_STATUS] - if self._touches > 5 or self._touches == 0: + if self._touches > self.max_touches or self._touches == 0: self._touches = 0 for i in range(self._touches): self._touchX[i] = (buffer[_TOUCH1_XH + i * 6] & 0x0F) << 8 | buffer[_TOUCH1_XL + i * 6] self._touchY[i] = (buffer[_TOUCH1_YH + i * 6] & 0x0F) << 8 | buffer[_TOUCH1_YL + i * 6] self._touchID[i] = buffer[_TOUCH1_YH + i * 6] >> 4 + + @property + def touched(self) -> int: + """Count of touch inputs detected + + :return: Count of touch inputs detected (0-max_touches) + :rtype: int + """ + n = self._num_touches + return 0 if n > self.max_touches else n @property - def points(self): + def points(self) -> List: + """X, Y and Z values from each available touch input + + :return: X, Y and Z values in a list + :rtype: List + """ self._read_data() - points = [] for i in range(min(self._touches, self.max_touches)): - point = (self._touchX[i], self._touchY[i], 1) # 1 indicates touch is active + point = (self._touchX[i], self._touchY[i], 1) points.append(point) return points - def point(self, point_index: int): + def point(self, point_index: int) -> Tuple: + """X, Y and Z value from a specified touch input + + :param int point_index: Touch input to read (0 - max_touches) + :return: X, Y and Z values + :rtype: Tuple + """ self._read_data() if self._touches == 0 or point_index >= self._touches: return (0, 0, 0) From 1f87c8fc9352d03859c30df028d44f1d663df8b7 Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 11:14:18 -0500 Subject: [PATCH 4/9] lint --- adafruit_ft5336.py | 42 ++++++++++++++++++++++------------- docs/conf.py | 3 ++- examples/ft5336_simpletest.py | 22 ++++++++++++++---- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/adafruit_ft5336.py b/adafruit_ft5336.py index c74fa38..aa7bbff 100644 --- a/adafruit_ft5336.py +++ b/adafruit_ft5336.py @@ -29,6 +29,7 @@ from adafruit_register.i2c_bits import ROBits from adafruit_bus_device.i2c_device import I2CDevice from micropython import const + try: from typing import List, Tuple except ImportError: @@ -49,14 +50,20 @@ _TOUCH1_YH = const(0x05) _TOUCH1_YL = const(0x06) + class Adafruit_FT5336: """Adafruit FT5336 touch screen driver""" + # Define read-only register bits for vendor ID, chip ID, and number of touches. _vend_id = ROBits(8, _REG_VENDID, 0) # 8-bit read-only register for vendor ID _chip_id = ROBits(8, _REG_CHIPID, 0) # 8-bit read-only register for chip ID - _num_touches = ROBits(8, _REG_NUMTOUCHES, 0) # 8-bit read-only register for number of touches + _num_touches = ROBits( + 8, _REG_NUMTOUCHES, 0 + ) # 8-bit read-only register for number of touches - def __init__(self, i2c, i2c_addr: int = _DEFAULT_ADDR, max_touches: int = 5) -> None: + def __init__( + self, i2c, i2c_addr: int = _DEFAULT_ADDR, max_touches: int = 5 + ) -> None: """Initialization over I2C :param int i2c_addr: I2C address (default 0x38) @@ -68,9 +75,9 @@ def __init__(self, i2c, i2c_addr: int = _DEFAULT_ADDR, max_touches: int = 5) -> self.max_touches = max_touches # Maximum number of touches to track # Initialize touch point arrays - self._touchX: List[int] = [0] * self.max_touches - self._touchY: List[int] = [0] * self.max_touches - self._touchID: List[int] = [0] * self.max_touches + self._touch_x: List[int] = [0] * self.max_touches + self._touch_y: List[int] = [0] * self.max_touches + self._touch_id: List[int] = [0] * self.max_touches # Verify device identity by checking the vendor and chip IDs if self._vend_id != _VENDID: @@ -88,44 +95,49 @@ def _read_data(self): self._touches = 0 for i in range(self._touches): - self._touchX[i] = (buffer[_TOUCH1_XH + i * 6] & 0x0F) << 8 | buffer[_TOUCH1_XL + i * 6] - self._touchY[i] = (buffer[_TOUCH1_YH + i * 6] & 0x0F) << 8 | buffer[_TOUCH1_YL + i * 6] - self._touchID[i] = buffer[_TOUCH1_YH + i * 6] >> 4 + self._touch_x[i] = (buffer[_TOUCH1_XH + i * 6] & 0x0F) << 8 | buffer[ + _TOUCH1_XL + i * 6 + ] + self._touch_y[i] = (buffer[_TOUCH1_YH + i * 6] & 0x0F) << 8 | buffer[ + _TOUCH1_YL + i * 6 + ] + self._touch_id[i] = buffer[_TOUCH1_YH + i * 6] >> 4 @property def touched(self) -> int: """Count of touch inputs detected - + :return: Count of touch inputs detected (0-max_touches) :rtype: int """ n = self._num_touches return 0 if n > self.max_touches else n - + @property def points(self) -> List: """X, Y and Z values from each available touch input - + :return: X, Y and Z values in a list :rtype: List """ self._read_data() points = [] for i in range(min(self._touches, self.max_touches)): - point = (self._touchX[i], self._touchY[i], 1) + point = (self._touch_x[i], self._touch_y[i], 1) points.append(point) return points def point(self, point_index: int) -> Tuple: """X, Y and Z value from a specified touch input - + :param int point_index: Touch input to read (0 - max_touches) :return: X, Y and Z values :rtype: Tuple """ self._read_data() if self._touches == 0 or point_index >= self._touches: - return (0, 0, 0) + value = (0, 0, 0) else: - return (self._touchX[point_index], self._touchY[point_index], 1) + value = (self._touch_x[point_index], self._touch_y[point_index], 1) + return value diff --git a/docs/conf.py b/docs/conf.py index 4d497ea..a989d12 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,7 +34,8 @@ intersphinx_mapping = { - "python": ("https://docs.python.org/3", None),"BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None), + "python": ("https://docs.python.org/3", None), + "BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None), "Register": ("https://docs.circuitpython.org/projects/register/en/latest/", None), "CircuitPython": ("https://docs.circuitpython.org/en/latest/", None), } diff --git a/examples/ft5336_simpletest.py b/examples/ft5336_simpletest.py index 9ed95d2..5bd0db5 100644 --- a/examples/ft5336_simpletest.py +++ b/examples/ft5336_simpletest.py @@ -1,4 +1,18 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# SPDX-FileCopyrightText: Copyright (c) 2023 Liz Clark for Adafruit Industries -# -# SPDX-License-Identifier: Unlicense +# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +Demo for the FT5336. Reads all available touch input coordinates. +""" + +import time +import board +import adafruit_ft5336 + +i2c = board.I2C() +touch = adafruit_ft5336.Adafruit_FT5336(i2c) + +while True: + t = touch.points + print(t) + time.sleep(0.1) From d6c8a294ff874bd5d08ea7305b74afd45c664f8a Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 11:17:45 -0500 Subject: [PATCH 5/9] readme example --- README.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.rst b/README.rst index 31e0c92..06a0450 100644 --- a/README.rst +++ b/README.rst @@ -94,6 +94,18 @@ Usage Example .. code-block:: python + import time + import board + import adafruit_ft5336 + + i2c = board.I2C() + touch = adafruit_ft5336.Adafruit_FT5336(i2c) + + while True: + t = touch.points + print(t) + time.sleep(0.1) + Documentation ============= API documentation for this library can be found on `Read the Docs `_. From 5fa2af061a41c1c7b68d40fa847cb53377b8dd74 Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 11:42:11 -0500 Subject: [PATCH 6/9] Update conf.py --- docs/conf.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a989d12..0e64b08 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,8 +26,6 @@ autodoc_mock_imports = [ "micropython", "busio", - "adafruit_bus_device", - "adafruit_register", ] autodoc_preserve_defaults = True From 69cfd150f5819742f619c7c57d629445a3852a34 Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 11:44:45 -0500 Subject: [PATCH 7/9] lint --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 0e64b08..bc1f2a9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -30,7 +30,6 @@ autodoc_preserve_defaults = True - intersphinx_mapping = { "python": ("https://docs.python.org/3", None), "BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None), From 6b1820b1e5ba7bca30768a4ca93f4b3e95d8e6cf Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 11:47:34 -0500 Subject: [PATCH 8/9] CI test --- docs/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index bc1f2a9..a989d12 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,10 +26,13 @@ autodoc_mock_imports = [ "micropython", "busio", + "adafruit_bus_device", + "adafruit_register", ] autodoc_preserve_defaults = True + intersphinx_mapping = { "python": ("https://docs.python.org/3", None), "BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None), From 3b07e32843ad61ecce3917d31ed52f6324c84af4 Mon Sep 17 00:00:00 2001 From: BlitzCityDIY Date: Wed, 6 Dec 2023 11:57:23 -0500 Subject: [PATCH 9/9] Update conf.py --- docs/conf.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a989d12..fc39709 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,12 +23,12 @@ "sphinx.ext.todo", ] -autodoc_mock_imports = [ - "micropython", - "busio", - "adafruit_bus_device", - "adafruit_register", -] +# autodoc_mock_imports = [ +# "micropython", +# "busio", +# "adafruit_bus_device", +# "adafruit_register", +# ] autodoc_preserve_defaults = True