From f54c66354817a9f5dce56b27bb2a2b58a90d55a1 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 5 Oct 2023 14:53:47 +0200 Subject: [PATCH] scripts/libraries: Add GT911 controller driver. --- scripts/libraries/gt911.py | 138 +++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 scripts/libraries/gt911.py diff --git a/scripts/libraries/gt911.py b/scripts/libraries/gt911.py new file mode 100644 index 000000000..6f20bc078 --- /dev/null +++ b/scripts/libraries/gt911.py @@ -0,0 +1,138 @@ +""" +This file is part of the OpenMV project. + +Copyright (c) 2023 Ibrahim Abdelkader +Copyright (c) 2023 Kwabena W. Agyeman + +This work is licensed under the MIT license, see the file LICENSE for details. + +GT911 5-Point Capacitive Touch Controller driver for MicroPython. + +Basic polling mode example usage: + +import time +from gt911 import GT911 +from machine import I2C + +# Note use pin numbers or names not Pin objects because the +# driver needs to change pin directions to reset the controller. +touch = GT911(I2C(1, freq=400_000), reset_pin="P1", irq_pin="P2", touch_points=5) + +while True: + n, points = touch.read_points() + for i in range(0, n): + print(f"id {points[i][3]} x {points[i][0]} y {points[i][1]} size {points[i][2]}") + time.sleep_ms(100) +""" + +from time import sleep_ms +from array import array +from machine import Pin + +_DEFAULT_ADDR = const(0x5D) + +_COMMAND = const(0x8040) +_REFRESH_RATE = const(0x8056) +_RESOLUTION_X = const(0x8048) +_RESOLUTION_Y = const(0x804A) +_TOUCH_POINTS = const(0x804C) +_MODULE_SWITCH1 = const(0x804D) +_CONFIG_CHKSUM = const(0x80FF) +_CONFIG_FRESH = const(0x8100) +_POINT_DATA_START = const(0x8150) +_DATA_BUFFER = const(0x814E) + + +class GT911: + def __init__( + self, + bus, + reset_pin, + irq_pin, + address=_DEFAULT_ADDR, + width=800, + height=480, + touch_points=1, + reverse_x=False, + reverse_y=False, + reverse_axis=True, + sito=True, + refresh_rate=240, + touch_callback=None, + ): + self.bus = bus + self.address = address + self.touch_callback = touch_callback + self.rst_pin = Pin(reset_pin, Pin.OUT_PP, value=0) + self.irq_pin = None + self.irq_pin_label = irq_pin + + # Reset the touch panel controller. + self.reset() + + # Write and update the config. + self._write_reg(_RESOLUTION_X, width, 2) + self._write_reg(_RESOLUTION_Y, height, 2) + self._write_reg(_TOUCH_POINTS, touch_points) + self._write_reg( + _MODULE_SWITCH1, + (int(reverse_y) << 7) + | (int(reverse_x) << 6) + | (int(reverse_axis) << 3) + | (int(sito) << 2) + | 0x01, + ) + self._write_reg(_REFRESH_RATE, (1000 * 1000) // (refresh_rate * 250)) + self._write_reg(_COMMAND, 0x00) + self._update_config() + + # Allocate scratch buffer. + self.points_data = [array("H", [0, 0, 0, 0]) for x in range(5)] + + def _read_reg(self, reg, size=1, buf=None): + if buf is not None: + self.bus.readfrom_mem_into(self.address, reg, buf, addrsize=16) + else: + return self.bus.readfrom_mem(self.address, reg, size, addrsize=16) + + def _write_reg(self, reg, val, size=1): + buf = bytes([val & 0xFF]) if size == 1 else bytes([val & 0xFF, val >> 8]) + self.bus.writeto_mem(self.address, reg, buf, addrsize=16) + + def _update_config(self): + # Read current config + chksum = ~sum(self._read_reg(0x8047, 184)) + 1 + # Calculate checksum + self._write_reg(_CONFIG_CHKSUM, chksum) + # Update the config + self._write_reg(_CONFIG_FRESH, 0x01) + + def read_id(self): + return self._read_reg(0x8140, 4) + + def read_points(self): + status = self._read_reg(_DATA_BUFFER)[0] + n_points = status & 0x0F + if status & 0x80: + for i in range(0, n_points): + self._read_reg(_POINT_DATA_START + i * 8, buf=self.points_data[i]) + # We read an extra reserved byte, shift track ID to fix it. + self.points_data[i][-1] = self.points_data[i][-1] >> 8 + self._write_reg(_DATA_BUFFER, 0) + return n_points, self.points_data + + def reset(self): + if self.irq_pin is not None: + self.irq_pin.irq(handler=None) + self.rst_pin(0) + sleep_ms(10) + self.irq_pin = Pin(self.irq_pin_label, Pin.OUT_PP, value=0) + sleep_ms(50) + self.rst_pin(1) + # Note must wait for at least 50ms before switching the IRQ pin to input. + sleep_ms(100) + self.irq_pin = Pin(self.irq_pin_label, Pin.IN, Pin.PULL_UP) + if self.touch_callback is not None: + self.irq_pin.irq( + handler=self.touch_callback, trigger=Pin.IRQ_FALLING, hard=False + )