Skip to content

Commit

Permalink
XPT2046 Touch driver
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven Pearson committed Dec 11, 2021
1 parent 114e248 commit f71cb78
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ DRIVERS = $(wildcard */)
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 xpt2046
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))

unit-test:
Expand Down
43 changes: 43 additions & 0 deletions examples/xpt2046/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"machine"
"time"

"tinygo.org/x/drivers/xpt2046"
)

func main() {

clk := machine.GPIO0
cs := machine.GPIO1
din := machine.GPIO2
dout := machine.GPIO3
irq := machine.GPIO4
precision := uint8(10) //Maximum number of samples for a single ReadTouchPoint to improve accuracy.

touchScreen := xpt2046.New(clk, cs, din, dout, irq, precision)

touchScreen.Configure()

for {

//Wait for a touch
for !touchScreen.Touched() {
time.Sleep(50 * time.Millisecond)
}

touch := touchScreen.ReadTouchPoint()
//X and Y are 12 bit (0-4096) and need to be scaled for the display size
//Z is 24 bit and is typically > 2000 for a touch
println("touch:", touch.X, touch.Y, touch.Z)
//Example of scaling for a 240x320 display
println("screen:", (touch.X*240)>>12, (touch.Y*320)>>12)

//Wait for touch to end
for touchScreen.Touched() {
time.Sleep(50 * time.Millisecond)
}

}
}
175 changes: 175 additions & 0 deletions xpt2046/xpt2046.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Package xpt2046 implements a driver for the XPT2046 resistive touch controller as packaged on the TFT_320QVT board
//
// Datasheet: http://grobotronics.com/images/datasheets/xpt2046-datasheed.pdf
package xpt2046

import (
"machine"
"time"

"tinygo.org/x/drivers/touch"
)

type Device struct {
t_clk machine.Pin
t_cs machine.Pin
t_din machine.Pin
t_dout machine.Pin
t_irq machine.Pin

precision uint8
}

func New(t_clk, t_cs, t_din, t_dout, t_irq machine.Pin, precision uint8) Device {
return Device{
precision: precision,

t_clk: t_clk,
t_cs: t_cs,
t_din: t_din,
t_dout: t_dout,
t_irq: t_irq,
}
}

func (d *Device) Configure() {
d.t_clk.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.t_cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.t_din.Configure(machine.PinConfig{Mode: machine.PinOutput})

d.t_dout.Configure(machine.PinConfig{Mode: machine.PinInput})
d.t_irq.Configure(machine.PinConfig{Mode: machine.PinInput})

d.t_clk.Low()
d.t_cs.High()
d.t_din.Low()

d.readRaw() //Set Powerdown mode to enable T_IRQ
}

func busSleep() {
time.Sleep(5 * time.Nanosecond)
}

func pulseHigh(p machine.Pin) {
p.High()
busSleep()
p.Low()
busSleep()
}

func (d *Device) writeCommand(data uint8) {

for count := uint8(0); count < 8; count++ {
d.t_din.Set((data & 0x80) != 0)
data <<= 1
pulseHigh(d.t_clk)
}

}

func (d *Device) readData() uint16 {

data := uint16(0)

for count := uint8(0); count < 12; count++ {
data <<= 1
pulseHigh(d.t_clk)
if d.t_dout.Get() {
data |= 1
}
}
pulseHigh(d.t_clk) //13
pulseHigh(d.t_clk) //14
pulseHigh(d.t_clk) //15
pulseHigh(d.t_clk) //16

return data
}

func (d *Device) ReadTouchPoint() touch.Point {

tx := uint32(0)
ty := uint32(0)
tz := uint32(0)
sampleCount := uint8(0)

d.t_cs.Low()

for ; sampleCount < d.precision && d.Touched(); sampleCount++ {
rx, ry, rz := d.readRaw()
tx += uint32(rx)
ty += uint32(ry)
tz += uint32(rz)
}
d.t_cs.High()

if sampleCount > 0 {
x := int(tx / uint32(sampleCount))
y := int(ty / uint32(sampleCount))
z := int(tz / uint32(sampleCount))
return touch.Point{
X: x,
Y: y,
Z: z,
}
} else {
return touch.Point{
X: 0,
Y: 0,
Z: 0,
}
}
}

func (d *Device) Touched() bool {
avail := !d.t_irq.Get()
return avail
}

func (d *Device) readRaw() (int32, int32, int32) {

d.t_cs.Low()

//S = 1 --> Required Control bit
//A2-A0 = 001 --> Y-Position
//MODE = 0 --> 12 bit conversion
//SER/DFR = 0 --> Differential preferred for X,Y position
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
d.writeCommand(0x90)
ty := d.readData()

//S = 1 --> Required Control bit
//A2-A0 = 101 --> X-Position
//MODE = 0 --> 12 bit conversion
//SER/DFR = 0 --> Differential preferred for X,Y position
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
d.writeCommand(0xD0)
tx := d.readData()

//S = 1 --> Required Control bit
//A2-A0 = 011 --> Z1-position (pressure)
//MODE = 0 --> 12 bit conversion
//SER/DFR = 0 --> Differential preferred for pressure
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
d.writeCommand(0xB0)
tz1 := int32(d.readData())

//S = 1 --> Required Control bit
//A2-A0 = 100 --> Z2-position (pressure)
//MODE = 0 --> 12 bit conversion
//SER/DFR = 0 --> Differential preferred for pressure
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
d.writeCommand(0xC0)
tz2 := int32(d.readData())

tz := int32(0)
if tz1 != 0 {
//Touch pressure is proportional to the ratio of z2 to z1 and the x position.
tz = int32(tx) * ((tz2 << 12) / (tz1 << 12))
}

d.t_cs.High()

return int32(tx), int32(4096 - ty), tz
}

0 comments on commit f71cb78

Please sign in to comment.