Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XPT2046 Touch driver #350

Merged
merged 1 commit into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,14 @@ endif
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
@md5sum ./build/test.hex
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/xpt2046/main.go
@md5sum ./build/test.uf2

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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ The following 74 devices are supported.
| [Waveshare 2.13" e-paper display](https://www.waveshare.com/w/upload/e/e6/2.13inch_e-Paper_Datasheet.pdf) | SPI |
| [Waveshare 4.2" e-paper B/W display](https://www.waveshare.com/w/upload/6/6a/4.2inch-e-paper-specification.pdf) | SPI |
| [WS2812 RGB LED](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf) | GPIO |
| [XPT2046 touch controller](http://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf) | GPIO |

## Contributing

Expand Down
44 changes: 44 additions & 0 deletions examples/xpt2046/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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

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

touchScreen.Configure(&xpt2046.Config{
Precision: 10, //Maximum number of samples for a single ReadTouchPoint to improve accuracy.
})

for {

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

touch := touchScreen.ReadTouchPoint()
//X and Y are 16 bit with 12 bit resolution 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)>>16, (touch.Y*320)>>16)

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

}
}
188 changes: 188 additions & 0 deletions xpt2046/xpt2046.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// 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-datasheet.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
}

type Config struct {
Precision uint8
}

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

func (d *Device) Configure(config *Config) error {

if config.Precision == 0 {
d.precision = 10
} else {
d.precision = config.Precision
}

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

return nil
}

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++ {
sago35 marked this conversation as resolved.
Show resolved Hide resolved
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,
}
sago35 marked this conversation as resolved.
Show resolved Hide resolved
} 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()

//Scale X&Y to 16 bit for consistency across touch drivers
return int32(tx) << 4, int32(4096-ty) << 4, tz
}