driver(touchpad): improve touchpad filter mode and update examples.

This commit is contained in:
Wangjialin 2018-05-18 15:56:45 +08:00 committed by fuzhibo
parent 993b8b7bf6
commit 09181b7d94
6 changed files with 221 additions and 131 deletions

View file

@ -103,14 +103,17 @@ typedef enum {
typedef intr_handle_t touch_isr_handle_t;
#define TOUCH_PAD_SLEEP_CYCLE_DEFAULT (0x1000) /*!<The timer frequency is RTC_SLOW_CLK (can be 150k or 32k depending on the options), max value is 0xffff */
#define TOUCH_PAD_MEASURE_CYCLE_DEFAULT (0xffff) /*!<The timer frequency is 8Mhz, the max value is 0xffff */
#define TOUCH_FSM_MODE_DEFAULT (TOUCH_FSM_MODE_TIMER) /*!<The touch FSM my be started by the software or timer */
#define TOUCH_PAD_MEASURE_CYCLE_DEFAULT (0x7fff) /*!<The timer frequency is 8Mhz, the max value is 0x7fff */
#define TOUCH_PAD_MEASURE_WAIT_DEFAULT (0xFF) /*!<The timer frequency is 8Mhz, the max value is 0xff */
#define TOUCH_FSM_MODE_DEFAULT (TOUCH_FSM_MODE_SW) /*!<The touch FSM my be started by the software or timer */
#define TOUCH_TRIGGER_MODE_DEFAULT (TOUCH_TRIGGER_BELOW) /*!<Interrupts can be triggered if sensor value gets below or above threshold */
#define TOUCH_TRIGGER_SOURCE_DEFAULT (TOUCH_TRIGGER_SOURCE_SET1) /*!<The wakeup trigger source can be SET1 or both SET1 and SET2 */
#define TOUCH_PAD_BIT_MASK_MAX (0x3ff)
/**
* @brief Initialize touch module.
* @note The default FSM mode is 'TOUCH_FSM_MODE_SW'. If you want to use interrupt trigger mode,
* then set it using function 'touch_pad_set_fsm_mode' to 'TOUCH_FSM_MODE_TIMER' after calling 'touch_pad_init'.
* @return
* - ESP_OK Success
* - ESP_FAIL Touch pad init error
@ -138,11 +141,11 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold);
/**
* @brief get touch sensor counter value.
* Each touch sensor has a counter to count the number of charge/discharge cycles.
* When the pad is not 'touched', we can get a number of the counter.
* When the pad is 'touched', the value in counter will get smaller because of the larger equivalent capacitance.
* User can use this function to determine the interrupt trigger threshold.
*
* Each touch sensor has a counter to count the number of charge/discharge cycles.
* When the pad is not 'touched', we can get a number of the counter.
* When the pad is 'touched', the value in counter will get smaller because of the larger equivalent capacitance.
* @note This API requests hardware measurement once. If IIR filter mode is enabled,,
* please use 'touch_pad_read_raw_data' interface instead.
* @param touch_num touch pad index
* @param touch_value pointer to accept touch sensor value
* @return
@ -162,10 +165,51 @@ esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value);
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Touch pad error
* - ESP_ERR_INVALID_STATE Touch pad not initialized
* - ESP_FAIL Touch pad not initialized
*/
esp_err_t touch_pad_read_filtered(touch_pad_t touch_num, uint16_t *touch_value);
/**
* @brief get raw data (touch sensor counter value) from IIR filter process.
* Need not request hardware measurements.
* @note touch_pad_filter_start has to be called before calling touch_pad_read_raw_data.
* This function can be called from ISR
*
* @param touch_num touch pad index
* @param touch_value pointer to accept touch sensor value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Touch pad error
* - ESP_ERR_INVALID_STATE Touch pad not initialized
* - ESP_FAIL Touch pad not initialized
*/
esp_err_t touch_pad_read_raw_data(touch_pad_t touch_num, uint16_t *touch_value);
/**
* @brief Callback function that is called after each IIR filter calculation.
* @note This callback is called in timer task in each filtering cycle.
* @note This callback should not be blocked.
* @param raw_value The latest raw data(touch sensor counter value) that
* points to all channels(raw_value[0..TOUCH_PAD_MAX-1]).
* @param filtered_value The latest IIR filtered data(calculated from raw data) that
* points to all channels(filtered_value[0..TOUCH_PAD_MAX-1]).
*
*/
typedef void (* filter_cb_t)(uint16_t *raw_value, uint16_t *filtered_value);
/**
* @brief Register the callback function that is called after each IIR filter calculation.
* @note The 'read_cb' callback is called in timer task in each filtering cycle.
* @param read_cb Pointer to filtered callback function.
* If the argument passed in is NULL, the callback will stop.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG set error
*/
esp_err_t touch_pad_set_filter_read_cb(filter_cb_t read_cb);
/**
* @brief Register touch-pad ISR,
* @note Deprecated function, users should replace this with touch_pad_isr_register,
@ -177,6 +221,7 @@ esp_err_t touch_pad_read_filtered(touch_pad_t touch_num, uint16_t *touch_value);
* @return
* - ESP_OK Success ;
* - ESP_ERR_INVALID_ARG GPIO error
* - ESP_ERR_NO_MEM No memory
*/
esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int unused, intr_handle_t *handle_unused) __attribute__ ((deprecated));
@ -188,6 +233,7 @@ esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int unuse
* @return
* - ESP_OK Success ;
* - ESP_ERR_INVALID_ARG GPIO error
* - ESP_ERR_NO_MEM No memory
*/
esp_err_t touch_pad_isr_register(intr_handler_t fn, void* arg);

View file

@ -51,8 +51,9 @@
#define ADC_MEAS_NUM_LIM_DEFAULT (1)
#define SAR_ADC_CLK_DIV_DEFUALT (2)
#define ADC_PATT_LEN_MAX (16)
#define TOUCH_PAD_FILTER_FACTOR_DEFAULT (16)
#define TOUCH_PAD_SHIFT_DEFAULT (4)
#define TOUCH_PAD_FILTER_FACTOR_DEFAULT (4) // IIR filter coefficient.
#define TOUCH_PAD_SHIFT_DEFAULT (4) // Increase computing accuracy.
#define TOUCH_PAD_SHIFT_ROUND_DEFAULT (8) // ROUND = 2^(n-1); rounding off for fractional.
#define DAC_ERR_STR_CHANNEL_ERROR "DAC channel error"
static const char *RTC_MODULE_TAG = "RTC_MODULE";
@ -105,12 +106,16 @@ static _lock_t adc1_i2s_lock = NULL;
typedef struct {
TimerHandle_t timer;
uint32_t filtered_val[TOUCH_PAD_MAX];
uint16_t filtered_val[TOUCH_PAD_MAX];
uint16_t raw_val[TOUCH_PAD_MAX];
uint32_t filter_period;
uint32_t period;
bool enable;
} touch_pad_filter_t;
static touch_pad_filter_t *s_touch_pad_filter = NULL;
// check if touch pad be inited.
static uint16_t s_touch_pad_init_bit = 0x0000;
static filter_cb_t s_filter_cb = NULL;
//Reg,Mux,Fun,IE,Up,Down,Rtc_number
const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
@ -425,6 +430,7 @@ void rtc_gpio_force_hold_dis_all()
//Some register bits of touch sensor 8 and 9 are mismatched, we need to swap the bits.
#define BITSWAP(data, n, m) (((data >> n) & 0x1) == ((data >> m) & 0x1) ? (data) : ((data) ^ ((0x1 <<n) | (0x1 << m))))
#define TOUCH_BITS_SWAP(v) BITSWAP(v, TOUCH_PAD_NUM8, TOUCH_PAD_NUM9)
static esp_err_t _touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value, touch_fsm_mode_t mode);
//Some registers of touch sensor 8 and 9 are mismatched, we need to swap register index
inline static touch_pad_t touch_pad_num_wrap(touch_pad_t touch_num)
@ -503,18 +509,38 @@ static uint32_t _touch_filter_iir(uint32_t in_now, uint32_t out_last, uint32_t k
}
}
esp_err_t touch_pad_set_filter_read_cb(filter_cb_t read_cb)
{
s_filter_cb = read_cb;
return ESP_OK;
}
static void touch_pad_filter_cb(void *arg)
{
static uint32_t s_filtered_temp[TOUCH_PAD_MAX] = {0};
if (s_touch_pad_filter == NULL) {
return;
}
uint16_t val = 0;
touch_fsm_mode_t mode;
xSemaphoreTake(rtc_touch_mux, portMAX_DELAY);
touch_pad_get_fsm_mode(&mode);
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
(void) touch_pad_read(i, &val);
// if touch_pad_read fails then the previous value of val is used
s_touch_pad_filter->filtered_val[i] = s_touch_pad_filter->filtered_val[i] == 0 ? (val << TOUCH_PAD_SHIFT_DEFAULT) : s_touch_pad_filter->filtered_val[i];
s_touch_pad_filter->filtered_val[i] = _touch_filter_iir((val << TOUCH_PAD_SHIFT_DEFAULT),
s_touch_pad_filter->filtered_val[i], TOUCH_PAD_FILTER_FACTOR_DEFAULT);
if ((s_touch_pad_init_bit >> i) & 0x1) {
_touch_pad_read(i, &val, mode);
s_touch_pad_filter->raw_val[i] = val;
s_filtered_temp[i] = s_filtered_temp[i] == 0 ? ((uint32_t)val << TOUCH_PAD_SHIFT_DEFAULT) : s_filtered_temp[i];
s_filtered_temp[i] = _touch_filter_iir((val << TOUCH_PAD_SHIFT_DEFAULT),
s_filtered_temp[i], TOUCH_PAD_FILTER_FACTOR_DEFAULT);
s_touch_pad_filter->filtered_val[i] = (s_filtered_temp[i] + TOUCH_PAD_SHIFT_ROUND_DEFAULT) >> TOUCH_PAD_SHIFT_DEFAULT;
}
}
xTimerReset(s_touch_pad_filter->timer, portMAX_DELAY);
xSemaphoreGive(rtc_touch_mux);
if(s_filter_cb != NULL) {
//return the raw data and filtered data.
s_filter_cb(s_touch_pad_filter->raw_val, s_touch_pad_filter->filtered_val);
}
}
@ -526,6 +552,8 @@ esp_err_t touch_pad_set_meas_time(uint16_t sleep_cycle, uint16_t meas_cycle)
SENS.sar_touch_ctrl2.touch_sleep_cycles = sleep_cycle;
//touch sensor measure time= meas_cycle / 8Mhz
SENS.sar_touch_ctrl1.touch_meas_delay = meas_cycle;
//the waiting cycles (in 8MHz) between TOUCH_START and TOUCH_XPD
SENS.sar_touch_ctrl1.touch_xpd_wait = TOUCH_PAD_MEASURE_WAIT_DEFAULT;
portEXIT_CRITICAL(&rtc_spinlock);
xSemaphoreGive(rtc_touch_mux);
return ESP_OK;
@ -792,10 +820,19 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold)
{
RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL);
RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG);
s_touch_pad_init_bit |= (1 << touch_num);
touch_pad_set_thresh(touch_num, threshold);
touch_pad_io_init(touch_num);
touch_pad_set_cnt_mode(touch_num, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_HIGH);
touch_pad_set_group_mask((1 << touch_num), (1 << touch_num), (1 << touch_num));
touch_pad_set_cnt_mode(touch_num, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_LOW);
touch_fsm_mode_t mode;
touch_pad_get_fsm_mode(&mode);
if (TOUCH_FSM_MODE_SW == mode) {
touch_pad_clear_group_mask((1 << touch_num), (1 << touch_num), (1 << touch_num));
} else if (TOUCH_FSM_MODE_TIMER == mode){
touch_pad_set_group_mask((1 << touch_num), (1 << touch_num), (1 << touch_num));
} else {
return ESP_FAIL;
}
return ESP_OK;
}
@ -822,6 +859,7 @@ esp_err_t touch_pad_deinit()
if (rtc_touch_mux == NULL) {
return ESP_FAIL;
}
s_touch_pad_init_bit = 0x0000;
touch_pad_filter_delete();
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_SW);
touch_pad_clear_status();
@ -831,19 +869,52 @@ esp_err_t touch_pad_deinit()
return ESP_OK;
}
static esp_err_t _touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value, touch_fsm_mode_t mode)
{
esp_err_t res = ESP_OK;
touch_pad_t tp_wrap = touch_pad_num_wrap(touch_num);
if (TOUCH_FSM_MODE_SW == mode) {
touch_pad_set_group_mask((1 << touch_num), (1 << touch_num), (1 << touch_num));
touch_pad_sw_start();
while (SENS.sar_touch_ctrl2.touch_meas_done == 0) {};
*touch_value = (tp_wrap & 0x1) ? \
SENS.touch_meas[tp_wrap / 2].l_val: \
SENS.touch_meas[tp_wrap / 2].h_val;
touch_pad_clear_group_mask((1 << touch_num), (1 << touch_num), (1 << touch_num));
} else if (TOUCH_FSM_MODE_TIMER == mode) {
while (SENS.sar_touch_ctrl2.touch_meas_done == 0) {};
*touch_value = (tp_wrap & 0x1) ? \
SENS.touch_meas[tp_wrap / 2].l_val: \
SENS.touch_meas[tp_wrap / 2].h_val;
} else {
res = ESP_FAIL;
}
return res;
}
esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value)
{
RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(touch_value != NULL, "touch_value", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL);
touch_pad_t tp_wrap = touch_pad_num_wrap(touch_num);
esp_err_t res = ESP_OK;
touch_fsm_mode_t mode;
touch_pad_get_fsm_mode(&mode);
xSemaphoreTake(rtc_touch_mux, portMAX_DELAY);
while (SENS.sar_touch_ctrl2.touch_meas_done == 0) {};
*touch_value = (tp_wrap & 0x1) ? \
SENS.touch_meas[tp_wrap / 2].l_val: \
SENS.touch_meas[tp_wrap / 2].h_val;
res = _touch_pad_read(touch_num, touch_value, mode);
xSemaphoreGive(rtc_touch_mux);
return res;
}
IRAM_ATTR esp_err_t touch_pad_read_raw_data(touch_pad_t touch_num, uint16_t *touch_value)
{
RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL);
RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(touch_value != NULL, "touch_value", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE);
*touch_value = s_touch_pad_filter->raw_val[touch_num];
return ESP_OK;
}
@ -853,7 +924,7 @@ IRAM_ATTR esp_err_t touch_pad_read_filtered(touch_pad_t touch_num, uint16_t *tou
RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(touch_value != NULL, "touch_value", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE);
*touch_value = (s_touch_pad_filter->filtered_val[touch_num] >> TOUCH_PAD_SHIFT_DEFAULT);
*touch_value = (s_touch_pad_filter->filtered_val[touch_num]);
return ESP_OK;
}
@ -908,13 +979,12 @@ esp_err_t touch_pad_filter_start(uint32_t filter_period_ms)
}
}
if (s_touch_pad_filter->timer == NULL) {
s_touch_pad_filter->timer = xTimerCreate("filter_tmr", filter_period_ms / portTICK_PERIOD_MS, pdTRUE,
s_touch_pad_filter->timer = xTimerCreate("filter_tmr", filter_period_ms / portTICK_PERIOD_MS, pdFALSE,
NULL, touch_pad_filter_cb);
if (s_touch_pad_filter->timer == NULL) {
ret = ESP_ERR_NO_MEM;
}
xTimerStart(s_touch_pad_filter->timer, portMAX_DELAY);
s_touch_pad_filter->enable = true;
} else {
xTimerChangePeriod(s_touch_pad_filter->timer, filter_period_ms / portTICK_PERIOD_MS, portMAX_DELAY);
s_touch_pad_filter->period = filter_period_ms;
@ -932,7 +1002,6 @@ esp_err_t touch_pad_filter_stop()
xSemaphoreTake(rtc_touch_mux, portMAX_DELAY);
if (s_touch_pad_filter != NULL) {
xTimerStop(s_touch_pad_filter->timer, portMAX_DELAY);
s_touch_pad_filter->enable = false;
} else {
ESP_LOGE(RTC_MODULE_TAG, "Touch pad filter deleted");
ret = ESP_ERR_INVALID_STATE;

View file

@ -1,12 +1,16 @@
# Touch Pad Interrupt Example
Demonstrates how to set up ESP32's capacitive touch pad peripheral to trigger interrupt when a pad is touched. It also shows how to detect the touch event by the software for sensor designs when greater touch detection sensitivity is required.
Demonstrates how to set up ESP32's capacitive touch pad peripheral to trigger interrupt when a pad is touched.
ESP32 supports touch detection by configuring hardware registers. The hardware periodically detects the pulse counts. If the number of pulse counts exceeds the set threshold, a hardware interrupt will be generated to notify the application layer that a certain touch sensor channel may be triggered.
Application has been developed and tested using [ESP32 Demo Board V2](https://dl.espressif.com/dl/schematics/ESP32-Demo-Board-V2_sch.pdf) that has ten capacitive sensor pads T0 to T9 exposed.
For the sensor designs when the pad is covered a glass or plastic, the difference caused by a 'touch' action could be very small. In such a case we are using software pooling and algorithms to reduce noise to still be able to detect small changes of the pulse counts. In certain cases we may need to use additional routines to adjust the threshold level dynamically as it may change depending on environment conditions.
![alt text](https://dl.espressif.com/dl/schematics/pictures/esp32-demo-board-v2.jpg "ESP32 Demo Board V2")
Comparison of the two modes:
The following output is shown when a pad is touched:
- The hardware interrupt mode occupies less CPU resources, but only a single threshold can be set and cannot support various software algorithms.
- The continuous pooling is flexible and supports various software algorithms. However, it also costs CPU overhead
The application is cycling between the interrupt mode and the pooling mode with a filter, to compare performance of the touch sensor system in both scenarios:
```
I (6303) Touch pad: Waiting for any pad being touched...
@ -23,8 +27,10 @@ I (17903) Touch pad: Waiting for any pad being touched...
I (22903) Touch pad: Waiting for any pad being touched...
```
Note: Sensing threshold is set up automatically at start up by performing simple calibration. Application is reading current value for each pad and assuming half of this value as the sensing threshold. Do not touch pads on application start up, otherwise sensing may not work correctly.
Note: Sensing threshold is set up automatically at start up by performing simple calibration. Application is reading current value for each pad and assuming two thirds of this value as the sensing threshold. Do not touch pads on application start up, otherwise sensing may not work correctly.
For a simpler example how to configure and read capacitive touch pads, please refer to [touch_pad_read](../touch_pad_read).
For a simpler example how to configure and read capacitive touch pads, please refer to [touch_pad_read](../touch_pad_read).
Design and implementation of the touch sensor system is a complex process. The [Touch Sensor Application Note](https://github.com/espressif/esp-iot-solution/blob/master/documents/touch_pad_solution/touch_sensor_design_en.md) contains several ESP32 specific notes and comments to optimize the design and get the best out of the application with sensors controlled with the ESP32.
See the README.md file in the upper level 'examples' directory for more information about examples.

View file

@ -17,12 +17,12 @@
static const char* TAG = "Touch pad";
#define TOUCH_THRESH_NO_USE (0)
#define TOUCH_THRESH_PERCENT (99)
#define TOUCH_THRESH_PERCENT (80)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)
static bool s_pad_activated[TOUCH_PAD_MAX];
static uint32_t s_pad_init_val[TOUCH_PAD_MAX];
/*
Read values sensed at all available touch pads.
Use 2 / 3 of read value as the threshold
@ -42,7 +42,7 @@ static void tp_example_set_thresholds(void)
//read filtered value
touch_pad_read_filtered(i, &touch_value);
s_pad_init_val[i] = touch_value;
ESP_LOGI(TAG, "test init touch val: %d\n", touch_value);
ESP_LOGI(TAG, "test init touch val: %d", touch_value);
//set interrupt threshold.
ESP_ERROR_CHECK(touch_pad_set_thresh(i, touch_value * 2 / 3));
@ -58,7 +58,7 @@ static void tp_example_set_thresholds(void)
In interrupt mode, the table is updated in touch ISR.
In filter mode, we will compare the current filtered value with the initial one.
If the current filtered value is less than 99% of the initial value, we can
If the current filtered value is less than 80% of the initial value, we can
regard it as a 'touched' event.
When calling touch_pad_init, a timer will be started to run the filter.
This mode is designed for the situation that the pad is covered
@ -90,12 +90,13 @@ static void tp_example_read_task(void *pvParameter)
} else {
//filter mode, disable touch interrupt
touch_pad_intr_disable();
touch_pad_clear_status();
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
uint16_t value = 0;
touch_pad_read_filtered(i, &value);
if (value < s_pad_init_val[i] * TOUCH_THRESH_PERCENT / 100) {
ESP_LOGI(TAG, "T%d activated!", i);
ESP_LOGI(TAG, "value: %d; init val: %d\n", value, s_pad_init_val[i]);
ESP_LOGI(TAG, "value: %d; init val: %d", value, s_pad_init_val[i]);
vTaskDelay(200 / portTICK_PERIOD_MS);
// Reset the counter to stop changing mode.
change_mode = 1;
@ -115,7 +116,7 @@ static void tp_example_read_task(void *pvParameter)
// We can compare the two different mode.
if (change_mode++ % 2000 == 0) {
filter_mode = !filter_mode;
ESP_LOGI(TAG, "Change mode...%s\n", filter_mode == 0? "interrupt mode": "filter mode");
ESP_LOGW(TAG, "Change mode...%s", filter_mode == 0? "interrupt mode": "filter mode");
}
}
}
@ -152,26 +153,20 @@ void app_main()
// Initialize touch pad peripheral, it will start a timer to run a filter
ESP_LOGI(TAG, "Initializing touch pad");
touch_pad_init();
// If use interrupt trigger mode, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'.
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
// Set reference voltage for charging/discharging
// For most usage scenarios, we recommend using the following combination:
// the high reference valtage will be 2.7V - 1V = 1.7V, The low reference voltage will be 0.5V.
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
// Initialize and start a software filter to detect slight change of capacitance.
touch_pad_filter_start(10);
// Set measuring time and sleep time
// In this case, measurement will sustain 0xffff / 8Mhz = 8.19ms
// Meanwhile, sleep time between two measurement will be 0x1000 / 150Khz = 27.3 ms
touch_pad_set_meas_time(0x1000, 0xffff);
//set reference voltage for charging/discharging
// In this case, the high reference valtage will be 2.4V - 1.5V = 0.9V
// The low reference voltage will be 0.8V, so that the procedure of charging
// and discharging would be very fast.
touch_pad_set_voltage(TOUCH_HVOLT_2V4, TOUCH_LVOLT_0V8, TOUCH_HVOLT_ATTEN_1V5);
touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
// Init touch pad IO
tp_example_touch_pad_init();
// Set thresh hold
tp_example_set_thresholds();
// Register touch interrupt ISR
touch_pad_isr_register(tp_example_rtc_intr, NULL);
// Start a task to show what pads have been touched
xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL);
}

View file

@ -1,24 +1,23 @@
# Touch Pad Read Example
Read and display raw values from capacitive touch pad sensors.
Once configured, ESP32 is continuously measuring capacitance of touch pad sensors. Measurement is reflected as numeric value inversely related to sensor's capacitance. The capacitance is bigger when sensor is touched with a finger and the measured value smaller. In opposite situation, when finger is released, capacitance is smaller and the measured value bigger.
To detect when a sensor is touched and when not, each particular design should be calibrated by obtaining both measurements for each individual sensor. Then a threshold between both values should be established. Using specific threshold, API is then able to distinguish whether specific sensor is touched or released.
ESP32 supports reading up to ten capacitive touch pad sensors T0 - T9, connected to specific GPIO pins. For information on available pins please refer to [Technical Reference Manual](https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf). Application initializes all ten sensor pads. Then in a loop reads sensors T0 - T9 and displays obtained values (after a colon) on a serial terminal:
```
T0: 486 T1: 1 T2: 559 T3: 567 T4: 871 T5: 522 T6:1174 T7:1531 T8:1508 T9:1640
T0: 485 T1: 1 T2: 559 T3: 568 T4: 871 T5: 521 T6:1176 T7:1536 T8:1509 T9:1635
T0: 485 T1: 1 T2: 559 T3: 568 T4: 871 T5: 521 T6:1172 T7:1536 T8:1507 T9:1640
T0: 11 T1: 1 T2: 558 T3: 568 T4: 871 T5: 522 T6:1172 T7:1535 T8:1507 T9:1638
```
Above log is prepared using [ESP32 Demo Board V2](https://dl.espressif.com/dl/schematics/ESP32-Demo-Board-V2_sch.pdf) that has all ten pad sensors exposed. Values will be different depending on layout of pads on particular board.
![alt text](https://dl.espressif.com/dl/schematics/pictures/esp32-demo-board-v2.jpg "ESP32 Demo Board V2")
There is another similar example that demonstrates how to perform simple calibration and trigger an interrupt when a pat is touched - see [touch_pad_interrupt](../touch_pad_interrupt).
See the README.md file in the upper level 'examples' directory for more information about examples.
# Touch Pad Read Example
Read and display raw values or IIR filtered values from capacitive touch pad sensors.
Once configured, ESP32 is continuously measuring capacitance of touch pad sensors. Measurement is reflected as numeric value inversely related to sensor's capacitance. The capacitance is bigger when sensor is touched with a finger and the measured value smaller. In opposite situation, when finger is released, capacitance is smaller and the measured value bigger.
To detect when a sensor is touched and when not, each particular design should be calibrated by obtaining both measurements for each individual sensor. Then a threshold between both values should be established. Using specific threshold, API is then able to distinguish whether specific sensor is touched or released.
ESP32 supports reading up to ten capacitive touch pad sensors T0 - T9, connected to specific GPIO pins. For information on available pins please refer to [Technical Reference Manual](https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf). Application initializes all ten sensor pads. Then in a loop reads sensors T0 - T9 and displays obtained values (after a colon) on a serial terminal:
```
Touch Sensor filter mode read, the output format is:
Touchpad num:[raw data, filtered data]
T0:[1072,1071] T1:[ 475, 475] T2:[1004,1003] T3:[1232,1231] T4:[1675,1676] T5:[1146,1146] T6:[1607,1607] T7:[1118,1118] T8:[1695,1695] T9:[1223,1222]
T0:[1072,1071] T1:[ 475, 475] T2:[1003,1003] T3:[1231,1231] T4:[1676,1676] T5:[1146,1146] T6:[1607,1607] T7:[1118,1118] T8:[1694,1694] T9:[1222,1221]
T0:[1071,1071] T1:[ 475, 475] T2:[1004,1004] T3:[1231,1231] T4:[1678,1677] T5:[1147,1146] T6:[1607,1607] T7:[1118,1118] T8:[1694,1694] T9:[1222,1221]
```
For hardware and firmware design guidelines on ESP32 touch sensor system, please refer to [Touch Sensor Application Note](https://github.com/espressif/esp-iot-solution/blob/master/documents/touch_pad_solution/touch_sensor_design_en.md), where you may find comprehensive information on how to design and implement touch sensing applications, such as linear slider, wheel slider, matrix buttons and spring buttons.
There is another similar example that demonstrates how to perform simple calibration and trigger an interrupt when a pat is touched - see [touch_pad_interrupt](../touch_pad_interrupt).
See the README.md file in the upper level 'examples' directory for more information about examples.

View file

@ -11,69 +11,37 @@
#include "freertos/task.h"
#include "driver/touch_pad.h"
#define TOUCH_TEST_LOOP_NUM (10)
#define TOUCH_PAD_NO_CHANGE (-1)
#define TOUCH_THRESH_NO_USE (0)
#define TOUCH_FILTER_MODE_EN (1)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)
/*
Read values sensed at all available touch pads.
Print out values in a loop on a serial monitor.
*/
static void tp_example_read_task(void *pvParameter)
{
uint16_t touch_value;
uint16_t touch_filter_value;
#if TOUCH_FILTER_MODE_EN
printf("Touch Sensor filter mode read, the output format is: \nTouchpad num:[raw data, filtered data]\n\n");
#else
printf("Touch Sensor normal mode read, the output format is: \nTouchpad num:[raw data]\n\n");
#endif
while (1) {
uint16_t touch_value;
//set reference voltage for charging/discharging
// In this case, the high reference valtage will be 2.7V - 0V = 2.7V
// The low reference voltage will be 0.5
// So the charing/discharging time would be longer, so the counter value would be smaller.
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V);
vTaskDelay(100 / portTICK_PERIOD_MS);
printf("Case[1], set default measure time\n");
for (int j = 0; j < TOUCH_TEST_LOOP_NUM; j++) {
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
ESP_ERROR_CHECK(touch_pad_read(i, &touch_value));
printf("T%d:%5d ", i, touch_value);
}
printf("\n");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
printf("Case[2], set max measure time\n");
//set reference voltage for charging/discharging
// In this case, the high reference valtage will be 2.4V - 1.5V = 0.9V
// The low reference voltage will be 0.8
// So the charing/discharging time would be shorter, so the counter value would be larger.
touch_pad_set_voltage(TOUCH_HVOLT_2V4, TOUCH_LVOLT_0V8, TOUCH_HVOLT_ATTEN_1V5);
vTaskDelay(100 / portTICK_PERIOD_MS);
for (int j = 0; j < TOUCH_TEST_LOOP_NUM; j++) {
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
ESP_ERROR_CHECK(touch_pad_read(i, &touch_value));
printf("T%d:%5d ", i, touch_value);
}
printf("\n");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V);
vTaskDelay(100/portTICK_PERIOD_MS);
printf("Case[3], set differen slope for each channel\n");
for (int i = 0;i<TOUCH_PAD_MAX;i++) {
touch_pad_set_cnt_mode(i, (i % TOUCH_PAD_SLOPE_7) + 1, TOUCH_PAD_TIE_OPT_HIGH);
}
for (int j = 0; j < TOUCH_TEST_LOOP_NUM; j++) {
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
ESP_ERROR_CHECK(touch_pad_read(i, &touch_value));
printf("T%d:%5d ", i, touch_value);
}
printf("\n");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
for (int i = 0;i<TOUCH_PAD_MAX;i++) {
touch_pad_set_cnt_mode(i, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_HIGH);
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
#if TOUCH_FILTER_MODE_EN
// If open the filter mode, please use this API to get the touch pad count.
ESP_ERROR_CHECK(touch_pad_read_raw_data(i, &touch_value));
ESP_ERROR_CHECK(touch_pad_read_filtered(i, &touch_filter_value));
printf("T%d:[%4d,%4d] ", i, touch_value, touch_filter_value);
#else
ESP_ERROR_CHECK(touch_pad_read(i, &touch_value));
printf("T%d:[%4d] ", i, touch_value);
#endif
}
printf("\n");
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
@ -86,11 +54,18 @@ static void tp_example_touch_pad_init()
void app_main()
{
// Initialize touch pad peripheral
// Initialize touch pad peripheral.
// The default fsm mode is software trigger mode.
touch_pad_init();
// Set reference voltage for charging/discharging
// In this case, the high reference valtage will be 2.7V - 1V = 1.7V
// The low reference voltage will be 0.5
// The larger the range, the larger the pulse count value.
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
#if TOUCH_FILTER_MODE_EN
touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
#endif
tp_example_touch_pad_init();
// Start task to read values sensed by pads
xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL);
}