-
Notifications
You must be signed in to change notification settings - Fork 2
/
xpt2046.py
135 lines (119 loc) · 4.91 KB
/
xpt2046.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""XPT2046 Touch module."""
from time import sleep
class Touch(object):
"""Serial interface for XPT2046 Touch Screen Controller."""
# Command constants from ILI9341 datasheet
GET_X = const(0b11010000) # X position
GET_Y = const(0b10010000) # Y position
GET_Z1 = const(0b10110000) # Z1 position
GET_Z2 = const(0b11000000) # Z2 position
GET_TEMP0 = const(0b10000000) # Temperature 0
GET_TEMP1 = const(0b11110000) # Temperature 1
GET_BATTERY = const(0b10100000) # Battery monitor
GET_AUX = const(0b11100000) # Auxiliary input to ADC
def __init__(self, spi, cs, int_pin=None, int_handler=None,
width=240, height=320,
x_min=100, x_max=1962, y_min=100, y_max=1900):
"""Initialize touch screen controller.
Args:
spi (Class Spi): SPI interface for OLED
cs (Class Pin): Chip select pin
int_pin (Class Pin): Touch controller interrupt pin
int_handler (function): Handler for screen interrupt
width (int): Width of LCD screen
height (int): Height of LCD screen
x_min (int): Minimum x coordinate
x_max (int): Maximum x coordinate
y_min (int): Minimum Y coordinate
y_max (int): Maximum Y coordinate
"""
self.spi = spi
self.cs = cs
self.cs.init(self.cs.OUT, value=1)
self.rx_buf = bytearray(3) # Receive buffer
self.tx_buf = bytearray(3) # Transmit buffer
self.width = width
self.height = height
# Set calibration
self.x_min = x_min
self.x_max = x_max
self.y_min = y_min
self.y_max = y_max
self.x_multiplier = width / (x_max - x_min)
self.x_add = x_min * -self.x_multiplier
self.y_multiplier = height / (y_max - y_min)
self.y_add = y_min * -self.y_multiplier
if int_pin is not None:
self.int_pin = int_pin
self.int_pin.init(int_pin.IN)
self.int_handler = int_handler
self.int_locked = False
int_pin.irq(trigger=int_pin.IRQ_FALLING | int_pin.IRQ_RISING,
handler=self.int_press)
def get_touch(self):
"""Take multiple samples to get accurate touch reading."""
timeout = 2 # set timeout to 2 seconds
confidence = 5
buff = [[0, 0] for x in range(confidence)]
buf_length = confidence # Require a confidence of 5 good samples
buffptr = 0 # Track current buffer position
nsamples = 0 # Count samples
while timeout > 0:
if nsamples == buf_length:
meanx = sum([c[0] for c in buff]) // buf_length
meany = sum([c[1] for c in buff]) // buf_length
dev = sum([(c[0] - meanx)**2 +
(c[1] - meany)**2 for c in buff]) / buf_length
if dev <= 50: # Deviation should be under margin of 50
return self.normalize(meanx, meany)
# get a new value
sample = self.raw_touch() # get a touch
if sample is None:
nsamples = 0 # Invalidate buff
else:
buff[buffptr] = sample # put in buff
buffptr = (buffptr + 1) % buf_length # Incr, until rollover
nsamples = min(nsamples + 1, buf_length) # Incr. until max
sleep(.05)
timeout -= .05
return None
def int_press(self, pin):
"""Send X,Y values to passed interrupt handler."""
if not pin.value() and not self.int_locked:
self.int_locked = True # Lock Interrupt
buff = self.raw_touch()
if buff is not None:
x, y = self.normalize(*buff)
self.int_handler(x, y)
sleep(.1) # Debounce falling edge
elif pin.value() and self.int_locked:
sleep(.1) # Debounce rising edge
self.int_locked = False # Unlock interrupt
def normalize(self, x, y):
"""Normalize mean X,Y values to match LCD screen."""
x = int(self.x_multiplier * x + self.x_add)
y = int(self.y_multiplier * y + self.y_add)
return x, y
def raw_touch(self):
"""Read raw X,Y touch values.
Returns:
tuple(int, int): X, Y
"""
x = self.send_command(self.GET_X)
y = self.send_command(self.GET_Y)
if self.x_min <= x <= self.x_max and self.y_min <= y <= self.y_max:
return (x, y)
else:
return None
def send_command(self, command):
"""Write command to XT2046 (MicroPython).
Args:
command (byte): XT2046 command code.
Returns:
int: 12 bit response
"""
self.tx_buf[0] = command
self.cs(0)
self.spi.write_readinto(self.tx_buf, self.rx_buf)
self.cs(1)
return (self.rx_buf[1] << 4) | (self.rx_buf[2] >> 4)