274 lines
9.2 KiB
C
274 lines
9.2 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;
|
|
}
|
|
// 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
|
|
//ISR setup moved to __touchChannelInit
|
|
#endif
|
|
|
|
initialized = true;
|
|
return;
|
|
err:
|
|
log_e(" Touch sensor initialization error.");
|
|
initialized = false;
|
|
return;
|
|
}
|
|
|
|
static void __touchChannelInit(int pad)
|
|
{
|
|
static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = { false };
|
|
if(channels_initialized[pad]){
|
|
return;
|
|
}
|
|
|
|
#if SOC_TOUCH_VERSION_1 // ESP32
|
|
// Initial no Threshold and setup
|
|
__touchInterruptHandlers[pad].fn = NULL;
|
|
touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK
|
|
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
|
|
// Initial no Threshold and setup
|
|
__touchInterruptHandlers[pad].fn = NULL;
|
|
touch_pad_config(pad); // returns ESP_OK
|
|
// keep ISR activated - it can run all together (ISR + touchRead())
|
|
esp_err_t err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE);
|
|
if (err != ESP_OK) {
|
|
log_e(" Touch sensor initialization error.");
|
|
return;
|
|
}
|
|
touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK
|
|
#endif
|
|
|
|
channels_initialized[pad] = true;
|
|
delay(20); //delay needed before reading from touch channel after config
|
|
}
|
|
|
|
static touch_value_t __touchRead(uint8_t pin)
|
|
{
|
|
int8_t pad = digitalPinToTouchChannel(pin);
|
|
if(pad < 0){
|
|
return 0;
|
|
}
|
|
|
|
__touchInit();
|
|
__touchChannelInit(pad);
|
|
|
|
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();
|
|
__touchChannelInit(pad);
|
|
__touchInterruptHandlers[pad].fn = userFunc;
|
|
__touchInterruptHandlers[pad].callWithArgs = callWithArgs;
|
|
__touchInterruptHandlers[pad].arg = Args;
|
|
}
|
|
|
|
touch_pad_set_thresh(pad, threshold);
|
|
}
|
|
|
|
// 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
|