1
+ // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ #include "soc/soc_caps.h"
15
+
16
+ #if SOC_TOUCH_SENSOR_SUPPORTED
17
+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL (5 , 5 , 0 ) && SOC_TOUCH_SENSOR_VERSION <= 2 // ESP32, ESP32S2, ESP32S3
18
+
19
+ #include "driver/touch_sensor.h"
20
+ #include "esp32-hal-touch.h"
21
+ #include "esp32-hal-periman.h"
22
+
23
+ /*
24
+ Internal Private Touch Data Structure and Functions
25
+ */
26
+
27
+ #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32
28
+ static uint16_t __touchSleepCycles = 0x1000 ;
29
+ static uint16_t __touchMeasureCycles = 0x1000 ;
30
+ #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3
31
+ static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT ;
32
+ static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT ;
33
+ #endif
34
+
35
+ typedef void (* voidFuncPtr )(void );
36
+ typedef void (* voidArgFuncPtr )(void * );
37
+
38
+ typedef struct {
39
+ voidFuncPtr fn ;
40
+ bool callWithArgs ;
41
+ void * arg ;
42
+ #if SOC_TOUCH_SENSOR_VERSION == 2 // Only for ESP32S2 and ESP32S3
43
+ bool lastStatusIsPressed ;
44
+ #endif
45
+ } TouchInterruptHandle_t ;
46
+
47
+ static TouchInterruptHandle_t __touchInterruptHandlers [SOC_TOUCH_SENSOR_NUM ] = {
48
+ 0 ,
49
+ };
50
+
51
+ static uint8_t used_pads = 0 ;
52
+ static bool initialized = false;
53
+ static bool channels_initialized [SOC_TOUCH_SENSOR_NUM ] = {false};
54
+
55
+ static void ARDUINO_ISR_ATTR __touchISR (void * arg ) {
56
+ #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32
57
+ uint32_t pad_intr = touch_pad_get_status ();
58
+ //clear interrupt
59
+ touch_pad_clear_status ();
60
+ // call Pad ISR User callback
61
+ for (int i = 0 ; i < SOC_TOUCH_SENSOR_NUM ; i ++ ) {
62
+ if ((pad_intr >> i ) & 0x01 ) {
63
+ if (__touchInterruptHandlers [i ].fn ) {
64
+ // keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)"
65
+ if (__touchInterruptHandlers [i ].callWithArgs ) {
66
+ ((voidArgFuncPtr )__touchInterruptHandlers [i ].fn )(__touchInterruptHandlers [i ].arg );
67
+ } else {
68
+ __touchInterruptHandlers [i ].fn ();
69
+ }
70
+ }
71
+ }
72
+ }
73
+ #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3
74
+ touch_pad_intr_mask_t evt = touch_pad_read_intr_status_mask ();
75
+ uint8_t pad_num = touch_pad_get_current_meas_channel ();
76
+ if (evt & TOUCH_PAD_INTR_MASK_ACTIVE ) {
77
+ // touch has been pressed / touched
78
+ __touchInterruptHandlers [pad_num ].lastStatusIsPressed = true;
79
+ }
80
+ if (evt & TOUCH_PAD_INTR_MASK_INACTIVE ) {
81
+ // touch has been released / untouched
82
+ __touchInterruptHandlers [pad_num ].lastStatusIsPressed = false;
83
+ }
84
+ if (__touchInterruptHandlers [pad_num ].fn ) {
85
+ // keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)"
86
+ if (__touchInterruptHandlers [pad_num ].callWithArgs ) {
87
+ ((voidArgFuncPtr )__touchInterruptHandlers [pad_num ].fn )(__touchInterruptHandlers [pad_num ].arg );
88
+ } else {
89
+ __touchInterruptHandlers [pad_num ].fn ();
90
+ }
91
+ }
92
+ #endif
93
+ }
94
+
95
+ static void __touchSetCycles (uint16_t measure , uint16_t sleep ) {
96
+ __touchSleepCycles = sleep ;
97
+ __touchMeasureCycles = measure ;
98
+ #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32
99
+ touch_pad_set_measurement_clock_cycles (measure );
100
+ #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3
101
+ touch_pad_set_charge_discharge_times (measure );
102
+ #endif
103
+ touch_pad_set_measurement_interval (sleep );
104
+ }
105
+
106
+ static bool touchDetachBus (void * pin ) {
107
+ int8_t pad = digitalPinToTouchChannel ((int )(pin - 1 ));
108
+ channels_initialized [pad ] = false;
109
+ used_pads -- ;
110
+ if (used_pads == 0 ) {
111
+ if (touch_pad_deinit () != ESP_OK ) //deinit touch module, as no pads are used
112
+ {
113
+ log_e ("Touch module deinit failed!" );
114
+ return false;
115
+ }
116
+ initialized = false;
117
+ }
118
+ return true;
119
+ }
120
+
121
+ static void __touchInit () {
122
+ if (initialized ) {
123
+ return ;
124
+ }
125
+
126
+ esp_err_t err = ESP_OK ;
127
+
128
+ #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32
129
+ err = touch_pad_init ();
130
+ if (err != ESP_OK ) {
131
+ goto err ;
132
+ }
133
+ // the next two lines will drive the touch reading values -- both will return ESP_OK
134
+ touch_pad_set_voltage (TOUCH_HVOLT_2V7 , TOUCH_LVOLT_0V5 , TOUCH_HVOLT_ATTEN_0V );
135
+ touch_pad_set_measurement_clock_cycles (__touchMeasureCycles );
136
+ touch_pad_set_measurement_interval (__touchSleepCycles );
137
+ // Touch Sensor Timer initiated
138
+ touch_pad_set_fsm_mode (TOUCH_FSM_MODE_TIMER ); // returns ESP_OK
139
+ err = touch_pad_filter_start (10 );
140
+ if (err != ESP_OK ) {
141
+ goto err ;
142
+ }
143
+ // keep ISR activated - it can run all together (ISR + touchRead())
144
+ err = touch_pad_isr_register (__touchISR , NULL );
145
+ if (err != ESP_OK ) {
146
+ goto err ;
147
+ }
148
+ touch_pad_intr_enable (); // returns ESP_OK
149
+ #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3
150
+ err = touch_pad_init ();
151
+ if (err != ESP_OK ) {
152
+ goto err ;
153
+ }
154
+ // the next lines will drive the touch reading values -- all os them return ESP_OK
155
+ touch_pad_set_charge_discharge_times (__touchMeasureCycles );
156
+ touch_pad_set_measurement_interval (__touchSleepCycles );
157
+ touch_pad_set_voltage (TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD , TOUCH_PAD_LOW_VOLTAGE_THRESHOLD , TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD );
158
+ touch_pad_set_idle_channel_connect (TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT );
159
+ touch_pad_denoise_t denoise = {
160
+ .grade = TOUCH_PAD_DENOISE_BIT4 ,
161
+ .cap_level = TOUCH_PAD_DENOISE_CAP_L4 ,
162
+ };
163
+ touch_pad_denoise_set_config (& denoise );
164
+ touch_pad_denoise_enable ();
165
+ // Touch Sensor Timer initiated
166
+ touch_pad_set_fsm_mode (TOUCH_FSM_MODE_TIMER ); // returns ESP_OK
167
+ touch_pad_fsm_start (); // returns ESP_OK
168
+ //ISR setup moved to __touchChannelInit
169
+ #endif
170
+ initialized = true;
171
+ return ;
172
+ err :
173
+ log_e (" Touch sensor initialization error." );
174
+ initialized = false;
175
+ return ;
176
+ }
177
+
178
+ static void __touchChannelInit (int pad ) {
179
+ if (channels_initialized [pad ]) {
180
+ return ;
181
+ }
182
+
183
+ #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32
184
+ // Initial no Threshold and setup
185
+ __touchInterruptHandlers [pad ].fn = NULL ;
186
+ touch_pad_config (pad , TOUCH_PAD_THRESHOLD_MAX ); // returns ESP_OK
187
+ #elif SOC_TOUCH_SENSOR_VERSION == 2 // ESP32S2, ESP32S3
188
+ // Initial no Threshold and setup
189
+ __touchInterruptHandlers [pad ].fn = NULL ;
190
+ touch_pad_config (pad ); // returns ESP_OK
191
+ // keep ISR activated - it can run all together (ISR + touchRead())
192
+ esp_err_t err = touch_pad_isr_register (__touchISR , NULL , TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE );
193
+ if (err != ESP_OK ) {
194
+ log_e (" Touch sensor initialization error." );
195
+ return ;
196
+ }
197
+ touch_pad_intr_enable (TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE ); // returns ESP_OK
198
+ #endif
199
+
200
+ channels_initialized [pad ] = true;
201
+ used_pads ++ ;
202
+ delay (20 ); //delay needed before reading from touch channel after config
203
+ }
204
+
205
+ static touch_value_t __touchRead (uint8_t pin ) {
206
+ int8_t pad = digitalPinToTouchChannel (pin );
207
+ if (pad < 0 ) {
208
+ log_e (" No touch pad on selected pin!" );
209
+ return 0 ;
210
+ }
211
+
212
+ if (perimanGetPinBus (pin , ESP32_BUS_TYPE_TOUCH ) == NULL ) {
213
+ perimanSetBusDeinit (ESP32_BUS_TYPE_TOUCH , touchDetachBus );
214
+ if (!perimanClearPinBus (pin )) {
215
+ return 0 ;
216
+ }
217
+ __touchInit ();
218
+ __touchChannelInit (pad );
219
+
220
+ if (!perimanSetPinBus (pin , ESP32_BUS_TYPE_TOUCH , (void * )(pin + 1 ), -1 , pad )) {
221
+ touchDetachBus ((void * )(pin + 1 ));
222
+ return 0 ;
223
+ }
224
+ }
225
+
226
+ touch_value_t touch_value ;
227
+ touch_pad_read_raw_data (pad , & touch_value );
228
+
229
+ return touch_value ;
230
+ }
231
+
232
+ static void __touchConfigInterrupt (uint8_t pin , void (* userFunc )(void ), void * Args , touch_value_t threshold , bool callWithArgs ) {
233
+ int8_t pad = digitalPinToTouchChannel (pin );
234
+ if (pad < 0 ) {
235
+ log_e (" No touch pad on selected pin!" );
236
+ return ;
237
+ }
238
+
239
+ if (userFunc == NULL ) {
240
+ // detach ISR User Call
241
+ __touchInterruptHandlers [pad ].fn = NULL ;
242
+ threshold = TOUCH_PAD_THRESHOLD_MAX ; // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX
243
+ } else {
244
+ // attach ISR User Call
245
+ __touchInit ();
246
+ __touchChannelInit (pad );
247
+ __touchInterruptHandlers [pad ].fn = userFunc ;
248
+ __touchInterruptHandlers [pad ].callWithArgs = callWithArgs ;
249
+ __touchInterruptHandlers [pad ].arg = Args ;
250
+ }
251
+
252
+ touch_pad_set_thresh (pad , threshold );
253
+ }
254
+
255
+ // it keeps backwards compatibility
256
+ static void __touchAttachInterrupt (uint8_t pin , void (* userFunc )(void ), touch_value_t threshold ) {
257
+ __touchConfigInterrupt (pin , userFunc , NULL , threshold , false);
258
+ }
259
+
260
+ // new additional version of the API with User Args
261
+ static void __touchAttachArgsInterrupt (uint8_t pin , void (* userFunc )(void ), void * args , touch_value_t threshold ) {
262
+ __touchConfigInterrupt (pin , userFunc , args , threshold , true);
263
+ }
264
+
265
+ // new additional API to detach touch ISR
266
+ static void __touchDettachInterrupt (uint8_t pin ) {
267
+ __touchConfigInterrupt (pin , NULL , NULL , 0 , false); // userFunc as NULL acts as detaching
268
+ }
269
+
270
+ /*
271
+ External Public Touch API Functions
272
+ */
273
+
274
+ #if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC
275
+ void touchInterruptSetThresholdDirection (bool mustbeLower ) {
276
+ if (mustbeLower ) {
277
+ touch_pad_set_trigger_mode (TOUCH_TRIGGER_BELOW );
278
+ } else {
279
+ touch_pad_set_trigger_mode (TOUCH_TRIGGER_ABOVE );
280
+ }
281
+ }
282
+ #elif SOC_TOUCH_SENSOR_VERSION == 2 // Only for ESP32S2 and ESP32S3
283
+ // returns true if touch pad has been and continues pressed and false otherwise
284
+ bool touchInterruptGetLastStatus (uint8_t pin ) {
285
+ int8_t pad = digitalPinToTouchChannel (pin );
286
+ if (pad < 0 ) {
287
+ return false;
288
+ }
289
+
290
+ return __touchInterruptHandlers [pad ].lastStatusIsPressed ;
291
+ }
292
+ #endif
293
+
294
+ void touchSleepWakeUpEnable (uint8_t pin , touch_value_t threshold ) {
295
+ int8_t pad = digitalPinToTouchChannel (pin );
296
+ if (pad < 0 ) {
297
+ log_e (" No touch pad on selected pin!" );
298
+ return ;
299
+ }
300
+
301
+ if (perimanGetPinBus (pin , ESP32_BUS_TYPE_TOUCH ) == NULL ) {
302
+ perimanSetBusDeinit (ESP32_BUS_TYPE_TOUCH , touchDetachBus );
303
+ __touchInit ();
304
+ __touchChannelInit (pad );
305
+ if (!perimanSetPinBus (pin , ESP32_BUS_TYPE_TOUCH , (void * )(pin + 1 ), -1 , pad )) {
306
+ log_e ("Failed to set bus to Peripheral manager" );
307
+ touchDetachBus ((void * )(pin + 1 ));
308
+ return ;
309
+ }
310
+ }
311
+ #if SOC_TOUCH_SENSOR_VERSION == 1 // Only for ESP32 SoC
312
+ touch_pad_set_thresh (pad , threshold );
313
+
314
+ #elif SOC_TOUCH_SENSOR_VERSION == 2
315
+ touch_pad_sleep_channel_enable (pad , true);
316
+ touch_pad_sleep_set_threshold (pad , threshold );
317
+
318
+ #endif
319
+ esp_sleep_enable_touchpad_wakeup ();
320
+ }
321
+
322
+ extern touch_value_t touchRead (uint8_t ) __attribute__((weak , alias ("__touchRead" )));
323
+ extern void touchAttachInterrupt (uint8_t , voidFuncPtr , touch_value_t ) __attribute__((weak , alias ("__touchAttachInterrupt" )));
324
+ extern void touchAttachInterruptArg (uint8_t , voidArgFuncPtr , void * , touch_value_t ) __attribute__((weak , alias ("__touchAttachArgsInterrupt" )));
325
+ extern void touchDetachInterrupt (uint8_t ) __attribute__((weak , alias ("__touchDettachInterrupt" )));
326
+ extern void touchSetCycles (uint16_t , uint16_t ) __attribute__((weak , alias ("__touchSetCycles" )));
327
+
328
+ #endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 5, 0) && SOC_TOUCH_SENSOR_VERSION <= 2 */
329
+ #endif /* SOC_TOUCH_SENSOR_SUPPORTED */
0 commit comments