Files
arduino-esp32/cores/esp32/esp32-hal-touch.c
Rodrigo Garcia 0ea485e518 Touch Sensor IDF Refactoring (#6194)
Summary

Touch Sensor refactoring to be based on IDF 4.4.
Adds support to ESP32S2 and future ESP32S3.

Adds some new APIs:

For all chips:

void touchAttachInterruptArg(uint8_t pin, void (*userFunc)(void*), void *arg, uint32_t threshold);
This function allows the user to add and pass a void* parameter to the ISR user callback.

void touchDetachInterrupt(uint8_t pin);
This function detaches ISR call back for the touch pad pin.

Only ESP32 chip

void touchInterruptSetThresholdDirection(bool mustbeLower);
This function allows the user to set if the ISR callback will be activated when the touch sensor readings are lower or higher than the threshold defined. See example TouchButton.ino.

Only ESP32-S2 and ESP32-S3 chips

bool touchInterruptGetLastStatus(uint8_t pin);
This function reports if the touch pad pin is touched or untouched. It can be used with ISR to identify when it is touched and untouched (released). See example TouchButtonV2.ino.

Impact

None. ll original APIs and examples now run on ESP32 and ESP32-S2.

Related links

Fix #6095
Fix #6034
Fix #5799
Fix #5745
Fix #5527
Fix #5493
Fix #4321
Fix #4044
Fix #2722
Fix #2625
2022-02-03 19:06:12 +02:00

263 lines
9.0 KiB
C

// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "soc/soc_caps.h"
#if SOC_TOUCH_SENSOR_NUM > 0
#include "driver/touch_sensor.h"
#include "esp32-hal-touch.h"
/*
Internal Private Touch Data Structure and Functions
*/
#if SOC_TOUCH_VERSION_1 // ESP32
static uint16_t __touchSleepCycles = 0x1000;
static uint16_t __touchMeasureCycles = 0x1000;
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT;
static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT;
#endif
typedef void (*voidFuncPtr)(void);
typedef void (*voidArgFuncPtr)(void *);
typedef struct {
voidFuncPtr fn;
bool callWithArgs;
void* arg;
#if SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3
bool lastStatusIsPressed;
#endif
} TouchInterruptHandle_t;
static TouchInterruptHandle_t __touchInterruptHandlers[SOC_TOUCH_SENSOR_NUM] = {0,};
static void ARDUINO_ISR_ATTR __touchISR(void * arg)
{
#if SOC_TOUCH_VERSION_1 // ESP32
uint32_t pad_intr = touch_pad_get_status();
//clear interrupt
touch_pad_clear_status();
// call Pad ISR User callback
for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) {
if ((pad_intr >> i) & 0x01) {
if(__touchInterruptHandlers[i].fn){
// keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)"
if (__touchInterruptHandlers[i].callWithArgs) {
((voidArgFuncPtr)__touchInterruptHandlers[i].fn)(__touchInterruptHandlers[i].arg);
} else {
__touchInterruptHandlers[i].fn();
}
}
}
}
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
touch_pad_intr_mask_t evt = touch_pad_read_intr_status_mask();
uint8_t pad_num = touch_pad_get_current_meas_channel();
if (evt & TOUCH_PAD_INTR_MASK_ACTIVE) {
// touch has been pressed / touched
__touchInterruptHandlers[pad_num].lastStatusIsPressed = true;
}
if (evt & TOUCH_PAD_INTR_MASK_INACTIVE) {
// touch has been released / untouched
__touchInterruptHandlers[pad_num].lastStatusIsPressed = false;
}
if(__touchInterruptHandlers[pad_num].fn){
// keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)"
if (__touchInterruptHandlers[pad_num].callWithArgs) {
((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg);
} else {
__touchInterruptHandlers[pad_num].fn();
}
}
#endif
}
static void __touchSetCycles(uint16_t measure, uint16_t sleep)
{
__touchSleepCycles = sleep;
__touchMeasureCycles = measure;
touch_pad_set_meas_time(sleep, measure);
}
static void __touchInit()
{
static bool initialized = false;
if(initialized){
return;
}
esp_err_t err = ESP_OK;
#if SOC_TOUCH_VERSION_1 // ESP32
err = touch_pad_init();
if (err != ESP_OK) {
goto err;
}
// the next two lines will drive the touch reading values -- both will return ESP_OK
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V);
touch_pad_set_meas_time(__touchMeasureCycles, __touchSleepCycles);
// Touch Sensor Timer initiated
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK
err = touch_pad_filter_start(10);
if (err != ESP_OK) {
goto err;
}
// Initial no Threshold and setup
for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) {
__touchInterruptHandlers[i].fn = NULL;
touch_pad_config(i, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK
}
// keep ISR activated - it can run all together (ISR + touchRead())
err = touch_pad_isr_register(__touchISR, NULL);
if (err != ESP_OK) {
goto err;
}
touch_pad_intr_enable(); // returns ESP_OK
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
err = touch_pad_init();
if (err != ESP_OK) {
goto err;
}
// the next lines will drive the touch reading values -- all os them return ESP_OK
touch_pad_set_meas_time(__touchSleepCycles, __touchMeasureCycles);
touch_pad_set_voltage(TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD, TOUCH_PAD_LOW_VOLTAGE_THRESHOLD, TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD);
touch_pad_set_idle_channel_connect(TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT);
touch_pad_denoise_t denoise = {
.grade = TOUCH_PAD_DENOISE_BIT4,
.cap_level = TOUCH_PAD_DENOISE_CAP_L4,
};
touch_pad_denoise_set_config(&denoise);
touch_pad_denoise_enable();
// Touch Sensor Timer initiated
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK
touch_pad_fsm_start(); // returns ESP_OK
// Initial no Threshold and setup - TOUCH0 is internal denoise channel
for (int i = 1; i < SOC_TOUCH_SENSOR_NUM; i++) {
__touchInterruptHandlers[i].fn = NULL;
touch_pad_config(i); // returns ESP_OK
}
// keep ISR activated - it can run all together (ISR + touchRead())
err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE);
if (err != ESP_OK) {
goto err;
}
touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK
#endif
initialized = true;
return;
err:
log_e(" Touch sensor initialization error.");
initialized = false;
return;
}
static touch_value_t __touchRead(uint8_t pin)
{
int8_t pad = digitalPinToTouchChannel(pin);
if(pad < 0){
return 0;
}
__touchInit();
touch_value_t touch_value;
touch_pad_read_raw_data(pad, &touch_value);
return touch_value;
}
static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Args, touch_value_t threshold, bool callWithArgs)
{
int8_t pad = digitalPinToTouchChannel(pin);
if(pad < 0){
return;
}
if (userFunc == NULL) {
// dettach ISR User Call
__touchInterruptHandlers[pad].fn = NULL;
threshold = SOC_TOUCH_PAD_THRESHOLD_MAX; // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX
} else {
// attach ISR User Call
__touchInit();
__touchInterruptHandlers[pad].fn = userFunc;
__touchInterruptHandlers[pad].callWithArgs = callWithArgs;
__touchInterruptHandlers[pad].arg = Args;
}
#if SOC_TOUCH_VERSION_1 // ESP32
touch_pad_config(pad, threshold);
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
touch_pad_set_thresh(pad, threshold);
#endif
}
// it keeps backwards compatibility
static void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold)
{
__touchConfigInterrupt(pin, userFunc, NULL, threshold, false);
}
// new additional version of the API with User Args
static void __touchAttachArgsInterrupt(uint8_t pin, void (*userFunc)(void), void *args, touch_value_t threshold)
{
__touchConfigInterrupt(pin, userFunc, args, threshold, true);
}
// new additional API to dettach touch ISR
static void __touchDettachInterrupt(uint8_t pin)
{
__touchConfigInterrupt(pin, NULL, NULL, 0, false); // userFunc as NULL acts as dettaching
}
/*
External Public Touch API Functions
*/
#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC
void touchInterruptSetThresholdDirection(bool mustbeLower) {
if (mustbeLower) {
touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW);
} else {
touch_pad_set_trigger_mode(TOUCH_TRIGGER_ABOVE);
}
}
#elif SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3
// returns true if touch pad has been and continues pressed and false otherwise
bool touchInterruptGetLastStatus(uint8_t pin) {
int8_t pad = digitalPinToTouchChannel(pin);
if(pad < 0){
return false;
}
return __touchInterruptHandlers[pad].lastStatusIsPressed;
}
#endif
extern touch_value_t touchRead(uint8_t) __attribute__ ((weak, alias("__touchRead")));
extern void touchAttachInterrupt(uint8_t, voidFuncPtr, touch_value_t) __attribute__ ((weak, alias("__touchAttachInterrupt")));
extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value_t) __attribute__ ((weak, alias("__touchAttachArgsInterrupt")));
extern void touchDetachInterrupt(uint8_t) __attribute__ ((weak, alias("__touchDettachInterrupt")));
extern void touchSetCycles(uint16_t, uint16_t) __attribute__ ((weak, alias("__touchSetCycles")));
#endif // #if SOC_TOUCH_SENSOR_NUM > 0