rgrizzell / CircuitPython_GT911

CircuitPython driver for GT911-based touchscreens.
MIT License
5 stars 0 forks source link

Blinka compatibility (Raspberry Pi) #5

Closed leonard-voss closed 4 months ago

leonard-voss commented 4 months ago

I think that this library is not compatible with Adafruit Blinka boards yet. I would like to use this library on a Raspberry Pi. It looks like there are some major issues with the compatibility to this library.

(The TFT LCD works without any problems with the Adafruit_CircuitPython_RGB_Display library)

Here you can see the steps i tried to get this library running:

  1. Download the gt911.py and move it to my work directory
  2. Modified the example so it should work on my hardware - This is the code i used:
    
    import time
    import board
    import gt911
    import digitalio

Pin declaration

interrupt_pin = digitalio.DigitalInOut(board.D17) reset_pin = digitalio.DigitalInOut(board.D27)

i2c = board.I2C()

gt = gt911.GT911(i2c, int_pin=interrupt_pin, rst_pin=reset_pin)

while True:

Wait for a touch on the display

for i, touch in enumerate(gt.touches):
    x, y, a = touch
    print(f"[{i+1}]({x},{y}) size:{a}")
time.sleep(1)

And by executing, i get the following error message:

%Run touchtest.py Traceback (most recent call last): File "/home/pi/Desktop/touchtest.py", line 11, in gt = gt911.GT911(i2c, int_pin=interrupt_pin, rst_pin=reset_pin) File "/home/pi/Desktop/gt911.py", line 82, in init self._reset() File "/home/pi/Desktop/gt911.py", line 135, in _reset self.int_pin.switch_to_output( File "/usr/local/lib/python3.11/dist-packages/digitalio.py", line 199, in switch_to_output self.drive_mode = drive_mode File "/usr/local/lib/python3.11/dist-packages/digitalio.py", line 278, in drive_mode self._pin.init(mode=Pin.OPEN_DRAIN) AttributeError: type object 'Pin' has no attribute 'OPEN_DRAIN'

So after posting this error in the Adafruit Tech Support Forum here it seems like the Raspberry Pi does not have the Open Drain feature. I tried to fix this error by replacing the self._reset() command with a pass-statement in the init-function of the gt911.py. As a continued, i got the following error message as an output:

>>> %Run touchtest.py
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/adafruit_bus_device/i2c_device.py", line 175, in __probe_for_device
    self.i2c.writeto(self.device_address, b"")
  File "/usr/local/lib/python3.11/dist-packages/busio.py", line 213, in writeto
    return self._i2c.writeto(address, buffer, stop=True)
  File "/usr/local/lib/python3.11/dist-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 60, in writeto
    self._i2c_bus.write_bytes(address, buffer[start:end])
  File "/usr/local/lib/python3.11/dist-packages/Adafruit_PureIO/smbus.py", line 303, in write_bytes
    self._device.write(buf)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/adafruit_bus_device/i2c_device.py", line 181, in __probe_for_device
    self.i2c.readfrom_into(self.device_address, result)
  File "/usr/local/lib/python3.11/dist-packages/busio.py", line 203, in readfrom_into
    return self._i2c.readfrom_into(address, buffer, stop=True)
  File "/usr/local/lib/python3.11/dist-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 67, in readfrom_into
    readin = self._i2c_bus.read_bytes(address, end - start)
  File "/usr/local/lib/python3.11/dist-packages/Adafruit_PureIO/smbus.py", line 170, in read_bytes
    return self._device.read(number)
OSError: [Errno 5] Input/output error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/Desktop/touchtest.py", line 11, in <module>
    gt = gt911.GT911(i2c, int_pin=interrupt_pin, rst_pin=reset_pin)
  File "/home/pi/Desktop/gt911.py", line 94, in __init__
    self.i2c_device = I2CDevice(i2c, self._i2c_addr)
  File "/usr/local/lib/python3.11/dist-packages/adafruit_bus_device/i2c_device.py", line 62, in __init__
    self.__probe_for_device()
  File "/usr/local/lib/python3.11/dist-packages/adafruit_bus_device/i2c_device.py", line 184, in __probe_for_device
    raise ValueError("No I2C device at address: 0x%x" % self.device_address)
ValueError: No I2C device at address: 0x14

So because the I2C device was not recognized, i tried to execute the i2cdetect, which successfully detected a device on the address 5d. I changed the variable _GT_DEFAULT_I2C_ADDR to 0x14 and _GT_SECONDARY_I2C_ADDR to 0x5d and executed again. This time, the error message was much smaller, but the OSError / I/O error remains.

>>> %Run touchtest.py
Traceback (most recent call last):
  File "/home/pi/Desktop/touchtest.py", line 15, in <module>
    for i, touch in enumerate(gt.touches):
  File "/home/pi/Desktop/gt911.py", line 110, in touches
    data = self._read(_GT_POINT_START + i * 8, 8)
  File "/home/pi/Desktop/gt911.py", line 150, in _read
    i2c.write_then_readinto(payload, result)
  File "/usr/local/lib/python3.11/dist-packages/adafruit_bus_device/i2c_device.py", line 140, in write_then_readinto
    self.i2c.writeto_then_readfrom(
  File "/usr/local/lib/python3.11/dist-packages/busio.py", line 230, in writeto_then_readfrom
    return self._i2c.writeto_then_readfrom(
  File "/usr/local/lib/python3.11/dist-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 98, in writeto_then_readfrom
    readin = self._i2c_bus.read_i2c_block_data(
  File "/usr/local/lib/python3.11/dist-packages/Adafruit_PureIO/smbus.py", line 264, in read_i2c_block_data
    ioctl(self._device.fileno(), I2C_RDWR, request)
OSError: [Errno 5] Input/output error

At this point, I have absolutely no idea how to continue or to verify if the stuff i tried even works correctly. An native support for Adafruit Blinka would be pretty cool.

rgrizzell commented 4 months ago

I don't have another GT911 screen to test with, but there shouldn't be any reason why this couldn't also work for Blinka.

If the Raspberry Pi doesn't support the OPEN_DRAIN mode, then leaving out the interrupt pin might be necessary. The I2C address can also be manually passed if the default doesn't work. In your case it would look like: gt = gt911.GT911(i2c, i2c_address=0x5d, rst_pin=reset_pin)

If that's not an issue and you continue to receive the Input/output errors from CircuitPython, then it might be worth checking to see if another I2C device will work. Alternative you can try to read the register manually using Adafruit BusDevice library. I suspect the problem might be Linux-related, but don't know for certain. The results of those tests would help.

leonard-voss commented 4 months ago

If the Raspberry Pi doesn't support the OPEN_DRAIN mode, then leaving out the interrupt pin might be necessary. The I2C address can also be manually passed if the default doesn't work. In your case it would look like: gt = gt911.GT911(i2c, i2c_address=0x5d, rst_pin=reset_pin)

Adjusting the I2C address as a parameter sounds good, I'll try that out. However, I don't think simply omitting the INT and possibly the RST function is a good solution to the problem. This could possibly waste a lot of computing time and does not guarantee that the display is in a defined initial state. I'll try it out and get back to you...

rgrizzell commented 4 months ago

However, I don't think simply omitting the INT and possibly the RST function is a good solution to the problem.

On the GT911, the INT pin is an optional feature. It's used to control the addressing of the device. Depending on the state of the pin, the address is either 0x14 or 0x5d. Once the chip is initialized the pin is then used to signal when a touch is available. If memory is correct, it essentially requires the GPIO input pin to act as a ground, hence the OPEN_DRAIN mode.

Most microcontrollers have issues with handling those interrupts in software, and some board makers haven't bothered to wire it up. On some of those boards, the RST pin is also just wired up to power.

In order to allow this driver to work on those boards, the INT and RST pins needed to be optional. In your case it might even help get you up and running. You can keep the RST pin, but try initializing without the INT pin.

If that works for you, I'll patch in an extra parameter that'll disable the touch interrupt support (disable OPEN_DRAIN) and we can go from there.

rgrizzell commented 4 months ago

If memory is correct, it essentially requires the GPIO input pin to act as a ground, hence the OPEN_DRAIN mode.

I'll be real here, I think this is where I messed up. It might work if it's in a PUSH_PULL drive mode with the line pulled Down.

leonard-voss commented 4 months ago

I'll try it out and get back to you...

Alright, so I downloaded the gt911.py again to ensure all changes I previously made were undone.

Afterwards I checked my wiring and guess what: I found an wiring issue. So i fixed my wiring and also changed the call of the GT911 object (removing rst_pin, adding i2c_address).

I executed the code and it now works fine!

Here is my final working code:

import time
import board
import gt911
import digitalio

interrupt_pin = digitalio.DigitalInOut(board.D24)

i2c = board.I2C()

gt = gt911.GT911(i2c=i2c, int_pin=interrupt_pin, i2c_address=0x5d)

while True:
    # Wait for a touch on the display
    for i, touch in enumerate(gt.touches):
        x, y, a = touch
        print(f"[{i+1}]({x},{y}) size:{a}")
    time.sleep(0.2)

Display I used: Phoenix Contact BC 107,6 DKL R D2,4 TCG KMGY VPE1 - Housing cover with touch display

And here you can see my wiring:

SDA (Display) - GPIO2 (Pin3) Raspberry Pi SCL (Display) - GPIO3 (Pin5) Raspberry Pi INT (Display) - GPIO24 (Pin18) Raspberry Pi

I also wired the RST pin, but not used it in the code, so you can remove it: RST (Display - GPIO23 (Pin16) Raspberry Pi)

Thank for your great and fast support! :)