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();
}