3
3
import machine # NOQA
4
4
import pointer_framework
5
5
import time
6
- import array
7
6
8
7
9
- _INT_ON_PD0_BIT = const (0x01 )
10
- _INT_OFF_PD0_BIT = const (0x00 )
8
+ _CMD_X_READ = const (0xD0 ) # 12 bit resolution
9
+ _CMD_Y_READ = const (0x90 ) # 12 bit resolution
11
10
12
- _VREF_ON_PD1_BIT = const (0x02 )
13
- _VREF_OFF_PD1_BIT = const (0x00 )
14
-
15
- _CMD_X_READ = const (0xD0 )
16
- _CMD_Y_READ = const (0x90 )
17
11
_MIN_RAW_COORD = const (10 )
18
12
_MAX_RAW_COORD = const (4090 )
19
13
20
- _Z_VALUE_1 = const (0xB0 )
21
- _Z_VALUE_2 = const (0xC0 )
22
- _Y_POSITION = const (0x90 )
23
- _X_POSITION = const (0xD0 )
24
- _BATTERY = const (0xA6 )
25
- _AUX_IN = const (0xE6 )
26
- _TEMP0 = const (0x86 )
27
- _TEMP1 = const (0xF6 )
28
-
29
14
30
15
class XPT2046 (pointer_framework .PointerDriver ):
31
16
17
+ confidence = 5
18
+ margin = 50
19
+
32
20
def __init__ (
33
21
self ,
34
22
spi_bus ,
35
23
cs = None ,
36
- interrupt = None ,
37
- vref_on = False ,
38
- press_threshold = 400 ,
39
24
touch_cal = None
40
25
):
41
26
super ().__init__ (touch_cal = touch_cal )
42
- self ._trans_buf = bytearray (2 )
27
+ self ._trans_buf = bytearray (3 )
43
28
self ._trans_mv = memoryview (self ._trans_buf )
44
29
45
- self ._recv_buf = bytearray (2 )
30
+ self ._recv_buf = bytearray (3 )
46
31
self ._recv_mv = memoryview (self ._recv_buf )
47
32
48
- self ._press_threshold = press_threshold
49
- self .__read_last = False
50
- self .__int_running = False
51
-
52
- if interrupt not in (- 1 , None ):
53
- self ._on_schedule_ref = self ._on_schedule
54
- self .__last_coords = array .array ('i' , [- 1 , 0 , 0 ])
33
+ self .__confidence = max (min (self .confidence , 25 ), 3 )
34
+ self .__points = [[0 , 0 ] for _ in range (self .__confidence )]
55
35
56
- PD0_BIT = _INT_ON_PD0_BIT
57
- self ._interrupt = machine . Pin ( interrupt , machine . Pin . IN )
36
+ margin = max ( min ( self . margin , 100 ), 1 )
37
+ self .__margin = margin * margin
58
38
59
- self ._interrupt .irq (
60
- trigger = machine .Pin .IRQ_FALLING ,
61
- handler = self ._on_interrupt
62
- )
63
-
64
- self ._set_mode_event ()
65
- else :
66
- PD0_BIT = _INT_OFF_PD0_BIT
67
- self ._interrupt = None
39
+ self ._spi = spi_bus
68
40
69
- if vref_on :
70
- PD1_BIT = _VREF_ON_PD1_BIT
41
+ if cs in ( - 1 , None ) :
42
+ self . __cs = None
71
43
else :
72
- PD1_BIT = _VREF_OFF_PD1_BIT
73
-
74
- PD_BITS = PD1_BIT | PD0_BIT
75
-
76
- self ._Z_VALUE_1 = _Z_VALUE_1 | PD_BITS
77
- self ._Z_VALUE_2 = _Z_VALUE_2 | PD_BITS
78
- self ._Y_POSITION = _Y_POSITION | PD_BITS
79
- self ._X_POSITION = _X_POSITION | PD_BITS
80
- # self._BATTERY = const(0xA6)
81
- # self._AUX_IN = const(0xE6)
82
- # self._TEMP0 = const(0x86)
83
- # self._TEMP1 = const(0xF6)
84
- self ._spi = spi_bus
85
- if cs not in (- 1 , None ):
86
44
self .__cs = machine .Pin (cs , machine .Pin .OUT )
87
45
self .__cs .value (1 )
88
- else :
89
- self .__cs = None
90
46
91
47
def _read_reg (self , reg ):
92
48
self ._trans_buf [0 ] = reg
@@ -101,76 +57,47 @@ def _read_reg(self, reg):
101
57
if self .__cs is not None :
102
58
self .__cs .value (1 )
103
59
104
- return (self ._recv_buf [0 ] << 8 ) | self ._recv_buf [1 ]
105
-
106
- def _on_schedule (self , * _ ):
107
- self .__read_last = True
108
- self .read ()
109
-
110
- def _on_interrupt (self , pin ):
111
- if not pin .value () and not self .__int_running :
112
- self .__int_running = True
113
-
114
- coords = self ._get_coords ()
115
- if coords is not None :
116
- (
117
- self .__last_coords [0 ],
118
- self .__last_coords [1 ],
119
- self .__last_coords [2 ]
120
- ) = coords
121
- micropython .schedule (self ._on_schedule_ref , None )
122
-
123
- time .sleep_ms (100 )
124
- elif pin .value () and self .__int_running :
125
- time .sleep_ms (100 ) # Debounce rising edge
126
- self .__int_running = False # Unlock interrupt
60
+ return ((self ._recv_buf [0 ] << 8 ) | self ._recv_buf [1 ]) >> 3
127
61
128
62
def _get_coords (self ):
129
- if self .__read_last and not self .__int_running :
130
- self .__read_last = False
131
- if self .__last_coords [0 ] == - 1 :
132
- return None
133
-
134
- state = self .__last_coords [0 ]
135
- x = self .__last_coords [1 ]
136
- y = self .__last_coords [2 ]
137
-
138
- self .__last_coords [0 ] = - 1
63
+ points = self .__points
64
+ count = 0
65
+ timeout = 5000000
66
+ start_time = time .ticks_ns ()
67
+ while timeout > 0 :
68
+ if count == self .__confidence :
69
+ break
70
+
71
+ sample = self ._get_raw () # get a touch
72
+ if sample is not None :
73
+ points [count ][0 ], points [count ][1 ] = sample # put in buff
74
+ count += 1
75
+
76
+ end_time = time .ticks_ns ()
77
+ timeout -= time .ticks_diff (end_time , start_time )
78
+ start_time = end_time
79
+
80
+ if count :
81
+ meanx = sum ([points [i ][0 ] for i in range (count )]) // count
82
+ meany = sum ([points [i ][1 ] for i in range (count )]) // count
83
+ dev = sum ([(points [i ][0 ] - meanx ) ** 2 + (points [i ][1 ] - meany ) ** 2 for i in range (count )]) / count
84
+
85
+ if dev <= self .__margin :
86
+ x , y = self ._normalize (meanx , meany )
87
+ return self .PRESSED , x , y
88
+
89
+ return None
90
+
91
+ def _normalize (self , x , y ):
92
+ x = pointer_framework ._remap (x , _MIN_RAW_COORD , _MAX_RAW_COORD , 0 , self ._orig_width )
93
+ y = pointer_framework ._remap (y , _MIN_RAW_COORD , _MAX_RAW_COORD , 0 , self ._orig_height )
94
+
95
+ return x , y
96
+
97
+ def _get_raw (self ):
98
+ x = self ._read_reg (_CMD_X_READ )
99
+ y = self ._read_reg (_CMD_Y_READ )
100
+ if x > _MIN_RAW_COORD and y < _MAX_RAW_COORD : # touch pressed?
101
+ return x , y
139
102
else :
140
- z1 = self ._read_reg (self ._Z_VALUE_1 )
141
- z2 = self ._read_reg (self ._Z_VALUE_2 )
142
-
143
- z = (z1 >> 3 ) + (_MAX_RAW_COORD - (z2 >> 3 ))
144
-
145
- if z < self ._press_threshold :
146
- return None
147
-
148
- # dump first reading
149
- self ._read_reg (self ._X_POSITION )
150
-
151
- x_points = []
152
- y_points = []
153
-
154
- for _ in range (3 ):
155
- x = self ._read_reg (self ._X_POSITION ) >> 3
156
- y = self ._read_reg (self ._Y_POSITION ) >> 3
157
-
158
- if (
159
- (_MIN_RAW_COORD <= x <= _MAX_RAW_COORD ) or
160
- (_MIN_RAW_COORD <= y <= _MAX_RAW_COORD )
161
- ):
162
- x = int ((x / float (_MAX_RAW_COORD )) * self ._orig_width )
163
- y = int ((y / float (_MAX_RAW_COORD )) * self ._orig_height )
164
-
165
- x_points .append (x )
166
- y_points .append (y )
167
-
168
- if x_points and y_points :
169
- x = int (sum (x_points ) / len (x_points ))
170
- y = int (sum (y_points ) / len (y_points ))
171
-
172
- state = self .PRESSED
173
- else :
174
- return None
175
-
176
- return state , x , y
103
+ return None
0 commit comments