Skip to main content

Touch Screen

Endpoint supports capacitive and resistive touchscreens through the GHIElectronics.Endpoint.Devices.Touch package. The Touch class is abstract: you write a small subclass for your touch chip (SPI chips like XPT2046, I2C chips like FT5xx6 or GT911, or a resistive panel driven by the on-board ADC), reading the chip through the standard System.Device.Spi / System.Device.I2c / System.Device.Gpio APIs. The subclass raises its touch event whenever a finger goes down, moves, or lifts.

The Widget library consumes those events through a tiny bridge, TouchBridge.Feed(x, y, pressed), so touches drive Clicked / ValueChanged on the widgets automatically.

Writing a touch driver​

A minimal driver fits in one small class. The pattern is: configure the chip (I2C/SPI + reset + IRQ) in the constructor, read the chip from the IRQ handler, and call RaiseChanged with the fingers currently on screen.

using System.Device.Gpio;
using System.Device.I2c;
using GHIElectronics.Endpoint.Devices.Touch;

public sealed class FT5xx6 : Touch {
private readonly I2cDevice _i2c;
private readonly GpioController _gpio;
private readonly int _irqPin;

public override int Width => 480;
public override int Height => 272;
public override bool Connected => true;

public FT5xx6(I2cDevice i2c, GpioController gpio, int resetPin, int irqPin) {
this._i2c = i2c;
this._gpio = gpio;
this._irqPin = irqPin;

// reset the chip
gpio.OpenPin(resetPin, PinMode.Output);
gpio.Write(resetPin, PinValue.Low);
Thread.Sleep(10);
gpio.Write(resetPin, PinValue.High);

// wake up on IRQ
gpio.OpenPin(irqPin, PinMode.InputPullUp);
gpio.RegisterCallbackForPinValueChangedEvent(irqPin, PinEventTypes.Falling, OnIrq);
}

private void OnIrq(object sender, PinValueChangedEventArgs e) {
// read the FT5xx6 touch registers, build the point array
var buffer = new byte[32];
this._i2c.WriteRead(new byte[] { 0x00 }, buffer);
int count = buffer[2] & 0x0F;

var points = new TouchPoint[count];
for (int i = 0; i < count; i++) {
int x = ((buffer[3 + i * 6] & 0x0F) << 8) | buffer[4 + i * 6];
int y = ((buffer[5 + i * 6] & 0x0F) << 8) | buffer[6 + i * 6];
int id = buffer[5 + i * 6] >> 4;
points[i] = new TouchPoint(id, x, y);
}

var type = count == 0 ? TouchEventType.Released : TouchEventType.Moved;
RaiseChanged(new TouchEventArgs(type, points));
}

public override void Dispose() {
this._gpio.UnregisterCallbackForPinValueChangedEvent(this._irqPin, OnIrq);
this._i2c.Dispose();
}
}

TouchPoint.Id is stable per finger across moves within one gesture, so use it to track multi-touch.

Feeding touches into the UI​

If you use the Widget library, wire your driver's events into TouchBridge.Feed and the UI does the rest. The right widget gets a Clicked or ValueChanged event.

On Endpoint Domino24, the touch chip on the display connector is on I2C5, with reset on PF2 and interrupt on PB11 (see the display pinout). The FT5xx6 answers at I2C address 0x38.

using System.Device.Gpio;
using System.Device.I2c;
using GHIElectronics.Endpoint.Core;
using GHIElectronics.Endpoint.Devices.Touch;
using GHIElectronics.Endpoint.UI;

UI.Initialize(); // after DisplayController.Enable()
TouchBridge.Attach();

// Touch chip on the display connector: I2C5, reset PF2, interrupt PB11
I2cController.Initialize(EPDomino24.I2c.I2c5);
var i2c = I2cDevice.Create(new I2cConnectionSettings(EPDomino24.I2c.I2c5, 0x38));
using var gpio = new GpioController(new EPDomino24.Gpio.Driver());
using var touch = new FT5xx6(i2c, gpio, resetPin: EPDomino24.Gpio.Pin.PF2, irqPin: EPDomino24.Gpio.Pin.PB11);

touch.OnChangedEvent += (sender, e) => {
if (e.Points.Length > 0)
TouchBridge.Feed(e.Points[0].X, e.Points[0].Y, pressed: e.EventType != TouchEventType.Released);
else
TouchBridge.Feed(0, 0, pressed: false);
};

UI.Run(); // blocks on the UI thread

Coordinates​

Event coordinates are in display pixels (0 at the top-left), so no scaling is needed as long as the touchscreen matches the display resolution. If the chip reports its own coordinate space, convert inside your driver before calling RaiseChanged.

Full FT5xx6 driver​

The snippets above are a condensed version of the driver to keep the example short. The complete, tested FT5xx6 driver is published on GitHub at GHIElectronics.Endpoint.Drivers.FocalTech.FT5xx6 and is also available as a NuGet package. Use it directly in production instead of copying the tutorial.