Initial Version
// 12th of Sept 2025
// SDKv: 5.5
// source:
// https://docs.espressif.com/projects/esp-idf/en/release-v5.5/esp32/api-reference/peripherals/cap_touch_sens.html
// https://github.com/espressif/esp-idf/tree/129cd0d2/examples/peripherals/touch_sensor/touch_sens_basic
// https://docs.espressif.com/projects/esp-idf/en/release-v5.5/esp32/api-reference/system/freertos_additions.html
#include "ESP.h"
#include <driver/touch_sens.h>
#include <esp_check.h>
#define TCH_PAD_1 TOUCH_PAD_NUM8
#define TCH_PAD_2 TOUCH_PAD_NUM9
#define EXAMPLE_SAMPLE_CFG() { TOUCH_SENSOR_V1_DEFAULT_SAMPLE_CONFIG(1, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_1V7) }
#define EXAMPLE_TOUCH_CHAN_CFG_DEFAULT() { \
.abs_active_thresh = {1000}, \
.charge_speed = TOUCH_CHARGE_SPEED_7, \
.init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, \
.group = TOUCH_CHAN_TRIG_GROUP_BOTH, \
}
touch_sensor_handle_t sens_handle = NULL;
touch_channel_handle_t chan_handle_1 = NULL;
touch_channel_handle_t chan_handle_2 = NULL;
void start_info();
void setup() {
Serial.begin(115200);
while (!Serial);
start_info();
delay(3000);
// config touch sensor
touch_sensor_sample_config_t sample_config[1] = EXAMPLE_SAMPLE_CFG();
touch_sensor_filter_config_t filter_config = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG();
touch_sensor_config_t sens_config = {
.power_on_wait_us = 100, // uint32
.intr_trig_mode = TOUCH_INTR_TRIG_ON_BELOW_THRESH, // touch_intr_trig_mode_t
.intr_trig_group = TOUCH_INTR_TRIG_GROUP_BOTH, // touch_intr_trig_group_t
.sample_cfg_num = 1, // uint32
.sample_cfg = sample_config // touch_sensor_sample_config_t *
};
// creating a new touch sensor controller
ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_config, &sens_handle));
// setting filter_config for a touch controller
ESP_ERROR_CHECK(touch_sensor_config_filter(sens_handle, &filter_config));
// config touch channel
touch_channel_config_t chan_config = EXAMPLE_TOUCH_CHAN_CFG_DEFAULT();
// creating 2 new touch channels linked to a controller
ESP_ERROR_CHECK(touch_sensor_new_channel(sens_handle, TCH_PAD_1, &chan_config, &chan_handle_1));
ESP_ERROR_CHECK(touch_sensor_new_channel(sens_handle, TCH_PAD_2, &chan_config, &chan_handle_2));
// printing channels' info
touch_chan_info_t chan_info = {};
ESP_ERROR_CHECK(touch_sensor_get_channel_info(chan_handle_1, &chan_info));
Serial.printf("Touch [CH %d] enabled on GPIO%d\n", TCH_PAD_1, chan_info.chan_gpio);
ESP_ERROR_CHECK(touch_sensor_get_channel_info(chan_handle_2, &chan_info));
Serial.printf("Touch [CH %d] enabled on GPIO%d\n", TCH_PAD_2, chan_info.chan_gpio);
// 'warming up' touch sensor
ESP_ERROR_CHECK(touch_sensor_enable(sens_handle));
ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 2000));
ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 2000));
ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 2000));
ESP_ERROR_CHECK(touch_sensor_disable(sens_handle));
// start continuous reading for all channels within a touch controller
ESP_ERROR_CHECK(touch_sensor_enable(sens_handle));
ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(sens_handle));
}
void loop() {
uint32_t val_1[1] = { 0 };
uint32_t val_2[1] = { 0 };
ESP_ERROR_CHECK(touch_channel_read_data(chan_handle_1, TOUCH_CHAN_DATA_TYPE_SMOOTH, val_1));
Serial.print("val_1: ");
Serial.print(val_1[0]);
Serial.println();
ESP_ERROR_CHECK(touch_channel_read_data(
chan_handle_2, TOUCH_CHAN_DATA_TYPE_SMOOTH, val_2));
Serial.print("val_2: ");
Serial.print(val_2[0]);
Serial.println();
delay(10);
}
void start_info() {
multi_heap_info_t heap_info;
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
Serial.printf("ChipRev: %lu", (unsigned long)ESP.getChipRevision());
Serial.println();
Serial.printf("CpuFreqMHz(): %lu", (unsigned long)ESP.getCpuFreqMHz());
Serial.println();
Serial.printf("SdkVersion: %s", ESP.getSdkVersion());
Serial.println();
Serial.printf("FlashChipSize: %lu", (unsigned long)ESP.getFlashChipSize());
Serial.println();
}
Task Based Version
// 12th of Sept 2025
// SDKv: 5.5
// source:
// https://docs.espressif.com/projects/esp-idf/en/release-v5.5/esp32/api-reference/peripherals/cap_touch_sens.html
// https://github.com/espressif/esp-idf/tree/129cd0d2/examples/peripherals/touch_sensor/touch_sens_basic
// https://docs.espressif.com/projects/esp-idf/en/release-v5.5/esp32/api-reference/system/freertos_additions.html
#include "ESP.h"
#include <driver/touch_sens.h>
#include <esp_check.h>
#define TCH_PAD_1 TOUCH_PAD_NUM8
#define TCH_PAD_2 TOUCH_PAD_NUM9
#define EXAMPLE_SAMPLE_CFG() { TOUCH_SENSOR_V1_DEFAULT_SAMPLE_CONFIG(1, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_1V7) }
#define EXAMPLE_TOUCH_CHAN_CFG_DEFAULT() { \
.abs_active_thresh = {1000}, \
.charge_speed = TOUCH_CHARGE_SPEED_7, \
.init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, \
.group = TOUCH_CHAN_TRIG_GROUP_BOTH, \
}
#define TASK_STACK_SIZE 8192
#define TASK_PRIORITY 1
#define TASK_CORE_ID 0
touch_sensor_handle_t sens_handle = NULL;
touch_channel_handle_t chan_handle_1 = NULL;
touch_channel_handle_t chan_handle_2 = NULL;
TaskHandle_t task_1 = NULL, task_2 = NULL;
void xTask(void *xTaskParam);
void start_info();
void setup() {
Serial.begin(115200);
while (!Serial);
start_info();
delay(1000);
// config touch sensor
touch_sensor_sample_config_t sample_config[1] = EXAMPLE_SAMPLE_CFG();
touch_sensor_filter_config_t filter_config = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG();
touch_sensor_config_t sens_config = {
.power_on_wait_us = 100, // uint32
.intr_trig_mode = TOUCH_INTR_TRIG_ON_BELOW_THRESH, // touch_intr_trig_mode_t
.intr_trig_group = TOUCH_INTR_TRIG_GROUP_BOTH, // touch_intr_trig_group_t
.sample_cfg_num = 1, // uint32
.sample_cfg = sample_config // touch_sensor_sample_config_t *
};
// creating a new touch sensor controller
ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_config, &sens_handle));
// setting filter_config for a touch controller
ESP_ERROR_CHECK(touch_sensor_config_filter(sens_handle, &filter_config));
// config touch channel
touch_channel_config_t chan_config = EXAMPLE_TOUCH_CHAN_CFG_DEFAULT();
// creating 2 new touch channels linked to a controller
ESP_ERROR_CHECK(touch_sensor_new_channel(sens_handle, TCH_PAD_1, &chan_config, &chan_handle_1));
ESP_ERROR_CHECK(touch_sensor_new_channel(sens_handle, TCH_PAD_2, &chan_config, &chan_handle_2));
// printing channels' info
touch_chan_info_t chan_info = {};
ESP_ERROR_CHECK(touch_sensor_get_channel_info(chan_handle_1, &chan_info));
Serial.printf("Touch [CH %d] enabled on GPIO%d\n", TCH_PAD_1, chan_info.chan_gpio);
ESP_ERROR_CHECK(touch_sensor_get_channel_info(chan_handle_2, &chan_info));
Serial.printf("Touch [CH %d] enabled on GPIO%d\n", TCH_PAD_2, chan_info.chan_gpio);
// 'warming up' touch sensor
ESP_ERROR_CHECK(touch_sensor_enable(sens_handle));
ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 2000));
ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 2000));
ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 2000));
ESP_ERROR_CHECK(touch_sensor_disable(sens_handle));
// start continuous reading for all channels within a touch controller
ESP_ERROR_CHECK(touch_sensor_enable(sens_handle));
ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(sens_handle));
if (xTaskCreatePinnedToCore(xTask, "TCH_CHAN_1", TASK_STACK_SIZE, (void *)chan_handle_1, TASK_PRIORITY, &task_1, TASK_CORE_ID) != pdPASS)
Serial.println("err creating task_1");
if (xTaskCreatePinnedToCore(xTask, "TCH_CHAN_2", TASK_STACK_SIZE, (void *)chan_handle_2, TASK_PRIORITY, &task_2, TASK_CORE_ID) != pdPASS)
Serial.println("err creating task_2");
}
void loop() {
// - e -
// - m -
// - p -
// - t -
// - y -
}
void xTask(void *xTaskParam) {
uint32_t val_1[1] = { 0 };
touch_channel_handle_t channel = (touch_channel_handle_t)xTaskParam;
while (1) {
ESP_ERROR_CHECK(touch_channel_read_data(channel, TOUCH_CHAN_DATA_TYPE_SMOOTH, val_1));
Serial.print("val_1: ");
Serial.print(val_1[0]);
Serial.println();
vTaskDelay(10);
}
// should never reach here,
// but if you wish to terminate
// the function from within, then use:
vTaskDelete(NULL);
}
void start_info() {
multi_heap_info_t heap_info;
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
Serial.printf("ChipRev: %lu", (unsigned long)ESP.getChipRevision());
Serial.println();
Serial.printf("CpuFreqMHz(): %lu", (unsigned long)ESP.getCpuFreqMHz());
Serial.println();
Serial.printf("SdkVersion: %s", ESP.getSdkVersion());
Serial.println();
Serial.printf("FlashChipSize: %lu", (unsigned long)ESP.getFlashChipSize());
Serial.println();
}