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