Skip to content

Commit 6c8195c

Browse files
committed
adds spd2010 touch driver
1 parent d234569 commit 6c8195c

File tree

1 file changed

+318
-0
lines changed

1 file changed

+318
-0
lines changed
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
2+
# Copyright (c) 2024 - 2025 Kevin G. Schlosser
3+
4+
# this driver uses a special i2c bus implimentation I have written.
5+
# This implimentation takes into consideration the ESP32 and it having
6+
# threading available. It also has some convience methods built into it
7+
# that figure out what is wanting to be done automatically.
8+
# read more about it's use in the stub files.
9+
10+
from micropython import const # NOQA
11+
import pointer_framework
12+
import machine # NOQA
13+
import time
14+
15+
I2C_ADDR = 0x53
16+
BITS = 8
17+
18+
19+
class _tp_status_high_t:
20+
21+
def __init__(self):
22+
self.none0 = 0
23+
self.none1 = 0
24+
self.none2 = 0
25+
self.cpu_run = 0
26+
self.tint_low = 0
27+
self.tic_in_cpu = 0
28+
self.tic_in_bios = 0
29+
self.tic_busy = 0
30+
31+
32+
class _tp_status_low_t:
33+
def __init__(self):
34+
self.pt_exist = 0
35+
self.gesture = 0
36+
self.key = 0
37+
self.aux = 0
38+
self.keep = 0
39+
self.raw_or_pt = 0
40+
self.none6 = 0
41+
self.none7 = 0
42+
43+
44+
class _tp_status_t:
45+
def __init__(self):
46+
self.status_low = _tp_status_low_t()
47+
self.status_high = _tp_status_high_t()
48+
self.read_len = 0
49+
50+
51+
class _tp_report_t:
52+
def __init__(self):
53+
self.id = 0
54+
self.x = 0
55+
self.y = 0
56+
self.weight = 0
57+
58+
59+
class _tp_touch_t:
60+
def __init__(self):
61+
self.rpt = [_tp_report_t() for _ in range(10)]
62+
self.touch_num = 0
63+
self.pack_code = 0
64+
self.down = 0
65+
self.up = 0
66+
self.gesture = 0
67+
self.down_x = 0
68+
self.down_y = 0
69+
self.up_x = 0
70+
self.up_y = 0
71+
72+
73+
class _tp_hdp_status_t:
74+
def __init__(self):
75+
self.status = 0
76+
self.next_packet_len = 0
77+
78+
79+
class SPD2010(pointer_framework.PointerDriver):
80+
81+
def __init__(
82+
self,
83+
device,
84+
reset_pin=None,
85+
touch_cal=None,
86+
startup_rotation=pointer_framework.lv.DISPLAY_ROTATION._0, # NOQA
87+
debug=False
88+
):
89+
self._tx_buf = bytearray(4)
90+
self._tx_mv = memoryview(self._tx_buf)
91+
self._rx_buf = bytearray(64)
92+
self._rx_mv = memoryview(self._rx_buf)
93+
94+
self._device = device
95+
96+
self.__x = 0
97+
self.__y = 0
98+
self.__last_state = self.RELEASED
99+
100+
if isinstance(reset_pin, int):
101+
reset_pin = machine.Pin(reset_pin, machine.Pin.OUT)
102+
103+
self._reset_pin = reset_pin
104+
105+
self.hw_reset()
106+
107+
super().__init__(
108+
touch_cal=touch_cal, startup_rotation=startup_rotation, debug=debug
109+
)
110+
111+
def hw_reset(self):
112+
if self._reset_pin:
113+
self._reset_pin(1)
114+
time.sleep_ms(2) # NOQA
115+
self._reset_pin(0)
116+
time.sleep_ms(22) # NOQA
117+
118+
def __write_tp_point_mode_cmd(self):
119+
self._tx_buf[:4] = bytearray([0x50, 0x00, 0x00, 0x00])
120+
121+
self._device.write(self._tx_mv[:4])
122+
time.sleep_us(200) # NOQA
123+
124+
def __write_tp_start_cmd(self):
125+
self._tx_buf[:4] = bytearray([0x46, 0x00, 0x00, 0x00])
126+
127+
self._device.write(self._tx_mv[:4])
128+
time.sleep_us(200) # NOQA
129+
130+
def __write_tp_cpu_start_cmd(self):
131+
self._tx_buf[:4] = bytearray([0x04, 0x00, 0x01, 0x00])
132+
133+
self._device.write(self._tx_mv[:4])
134+
time.sleep_us(200) # NOQA
135+
136+
def __write_tp_clear_int_cmd(self):
137+
self._tx_buf[:4] = bytearray([0x02, 0x00, 0x01, 0x00])
138+
139+
self._device.write(self._tx_mv[:4])
140+
time.sleep_us(200) # NOQA
141+
142+
def __read_tp_status_length(self):
143+
tp_status = _tp_status_t()
144+
145+
self._tx_buf[:2] = bytearray([0x20, 0x00])
146+
147+
self._device.write(self._tx_mv[:2])
148+
time.sleep_us(200) # NOQA
149+
150+
self._device.read_into(self._rx_mv[:4])
151+
time.sleep_us(200) # NOQA
152+
153+
rx_buf = self._rx_buf
154+
155+
tp_status.status_low.pt_exist = rx_buf[0] & 0x01
156+
tp_status.status_low.gesture = rx_buf[0] & 0x02
157+
tp_status.status_high.tic_busy = (rx_buf[1] & 0x80) >> 7
158+
tp_status.status_high.tic_in_bios = (rx_buf[1] & 0x40) >> 6
159+
tp_status.status_high.tic_in_cpu = (rx_buf[1] & 0x20) >> 5
160+
tp_status.status_high.tint_low = (rx_buf[1] & 0x10) >> 4
161+
tp_status.status_high.cpu_run = (rx_buf[1] & 0x08) >> 3
162+
tp_status.status_low.aux = rx_buf[0] & 0x08 # aux, cytang
163+
tp_status.read_len = (rx_buf[3] << 8) | rx_buf[2]
164+
165+
return tp_status
166+
167+
def __read_tp_hdp(self, tp_status, touch):
168+
self._tx_buf[:2] = bytearray([0x00, 0x03])
169+
self._device.write(self._tx_mv[:2])
170+
time.sleep_us(200) # NOQA
171+
172+
self._device.read_into(self._rx_mv[:tp_status.read_len])
173+
time.sleep_us(200) # NOQA
174+
175+
rx_buf = self._rx_buf
176+
177+
check_id = rx_buf[4]
178+
179+
if check_id <= 0x0A and tp_status.status_low.pt_exist:
180+
touch.touch_num = int((tp_status.read_len - 4) / 6)
181+
touch.gesture = 0x00
182+
183+
for i in range(touch.touch_num):
184+
offset = i * 6
185+
touch.rpt[i].id = rx_buf[4 + offset]
186+
touch.rpt[i].x = ((rx_buf[7 + offset] & 0xF0) << 4) | rx_buf[5 + offset]
187+
touch.rpt[i].y = ((rx_buf[7 + offset] & 0x0F) << 8) | rx_buf[6 + offset]
188+
touch.rpt[i].weight = rx_buf[8 + offset]
189+
190+
# For slide gesture recognize */
191+
if touch.rpt[0].weight != 0 and touch.down != 1:
192+
touch.down = 1
193+
touch.up = 0
194+
touch.down_x = touch.rpt[0].x
195+
touch.down_y = touch.rpt[0].y
196+
elif touch.rpt[0].weight == 0 and touch.down == 1:
197+
touch.up = 1
198+
touch.down = 0
199+
touch.up_x = touch.rpt[0].x
200+
touch.up_y = touch.rpt[0].y
201+
202+
elif check_id == 0xF6 and tp_status.status_low.gesture:
203+
touch.touch_num = 0x00
204+
touch.up = 0
205+
touch.down = 0
206+
touch.gesture = rx_buf[6] & 0x07
207+
else:
208+
touch.touch_num = 0x00
209+
touch.gesture = 0x00
210+
211+
def __read_tp_hdp_status(self):
212+
tp_hdp_status = _tp_hdp_status_t()
213+
214+
self._tx_buf[:2] = bytearray([0xFC, 0x02])
215+
self._device.write(self._tx_mv[:2])
216+
time.sleep_us(200) # NOQA
217+
218+
self._device.read_into(self._rx_mv[:8])
219+
time.sleep_us(200) # NOQA
220+
221+
rx_buf = self._rx_buf
222+
tp_hdp_status.status = rx_buf[5]
223+
tp_hdp_status.next_packet_len = rx_buf[2] | (rx_buf[3] << 8)
224+
225+
return tp_hdp_status
226+
227+
def __Read_HDP_REMAIN_DATA(self, tp_hdp_status):
228+
self._tx_buf[:2] = bytearray([0x00, 0x03])
229+
self._device.write(self._tx_mv[:2])
230+
time.sleep_us(200) # NOQA
231+
232+
self._device.read_into(self._rx_mv[:tp_hdp_status.next_packet_len])
233+
time.sleep_us(200) # NOQA
234+
235+
def __read_fw_version(self):
236+
self._tx_buf[:2] = bytearray([0x26, 0x00])
237+
self._device.write(self._tx_mv[:2])
238+
time.sleep_us(200) # NOQA
239+
240+
self._device.read_into(self._rx_mv[:18])
241+
time.sleep_us(200) # NOQA
242+
243+
rx_buf = self._rx_buf
244+
245+
Dummy = (rx_buf[0] << 24) | (rx_buf[1] << 16) | (rx_buf[3] << 8) | rx_buf[0]
246+
DVer = (rx_buf[5] << 8) | rx_buf[4]
247+
PID = (rx_buf[9] << 24) | (rx_buf[8] << 16) | (rx_buf[7] << 8) | rx_buf[6]
248+
ICName_L = (rx_buf[13] << 24) | (rx_buf[12] << 16) | (rx_buf[11] << 8) | rx_buf[10] # "2010"
249+
ICName_H = (rx_buf[17] << 24) | (rx_buf[16] << 16) | (rx_buf[15] << 8) | rx_buf[14] # "SPD"
250+
251+
print(Dummy, DVer, PID, ICName_H, ICName_L)
252+
253+
def __tp_read_data(self):
254+
touch = _tp_touch_t()
255+
256+
tp_status = self.__read_tp_status_length()
257+
258+
if tp_status.status_high.tic_in_bios:
259+
# Write Clear TINT Command
260+
self.__write_tp_clear_int_cmd()
261+
262+
# Write CPU Start Command
263+
self.__write_tp_cpu_start_cmd()
264+
265+
elif tp_status.status_high.tic_in_cpu:
266+
# Write Touch Change Command
267+
self.__write_tp_point_mode_cmd()
268+
269+
# Write Touch Start Command
270+
self.__write_tp_start_cmd()
271+
272+
# Write Clear TINT Command
273+
self.__write_tp_clear_int_cmd()
274+
275+
elif tp_status.status_high.cpu_run and tp_status.read_len == 0:
276+
self.__write_tp_clear_int_cmd()
277+
elif tp_status.status_low.pt_exist or tp_status.status_low.gesture:
278+
# Read HDP
279+
self.__read_tp_hdp(tp_status, touch)
280+
281+
def hdp_done_check():
282+
# Read HDP Status
283+
tp_hdp_status = self.__read_tp_hdp_status()
284+
285+
if tp_hdp_status.status == 0x82:
286+
# Clear INT
287+
self.__write_tp_clear_int_cmd()
288+
elif tp_hdp_status.status == 0x00:
289+
# Read HDP Remain Data
290+
self.__Read_HDP_REMAIN_DATA(tp_hdp_status)
291+
hdp_done_check()
292+
293+
hdp_done_check()
294+
295+
elif tp_status.status_high.cpu_run and tp_status.status_low.aux:
296+
self.__write_tp_clear_int_cmd()
297+
298+
return touch
299+
300+
def _get_coords(self):
301+
touch = self.__tp_read_data()
302+
303+
# Expect Number of touched points */
304+
touch_cnt = touch.touch_num
305+
306+
if touch_cnt:
307+
coords = touch.rpt[0]
308+
self.__x = coords.x
309+
self.__y = coords.y
310+
if coords.weight:
311+
self.__last_state = self.PRESSED
312+
else:
313+
self.__last_state = self.RELEASED
314+
315+
else:
316+
self.__last_state = self.RELEASED
317+
318+
return self.__last_state, self.__x, self.__y

0 commit comments

Comments
 (0)