Merge branch 'feature/touch_driver_ng_on_p4_v5.3' into 'release/v5.3'

feat(touch_sensor): touch driver ng on p4 (v5.3)

See merge request espressif/esp-idf!31624
This commit is contained in:
Jiang Jiang Jian
2024-07-26 11:42:27 +08:00
81 changed files with 4288 additions and 402 deletions

View File

@@ -433,6 +433,16 @@ examples/peripherals/touch_sensor/touch_sensor_v2:
disable:
- if: SOC_TOUCH_SENSOR_VERSION != 2
examples/peripherals/touch_sensor/touch_sensor_v3:
disable:
- if: SOC_TOUCH_SENSOR_VERSION != 3
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: the runners do not support the pins for touch sensor
depends_components:
- esp_driver_touch_sens
examples/peripherals/twai/twai_alert_and_recovery:
disable:
- if: SOC_TWAI_SUPPORTED != 1

View File

@@ -2,3 +2,4 @@
| ------- | ----------------- |
| V1 | ESP32 |
| V2 | ESP32S2, ESP32S3 |
| V3 | ESP32P4 |

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(touch_sens_example)

View File

@@ -0,0 +1,125 @@
| Supported Targets | ESP32-P4 |
| ----------------- | -------- |
# Capacity Touch Sensor Example (for hardware version 3)
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example is going to demonstrate how to register the touch channels and read the data.
## How to Use Example
### Hardware Required
* A development board with any supported Espressif SOC chip (see `Supported Targets` table above)
* A USB cable for power supply and programming
* (Optional) Touch board with touch buttons on it.
- If you don't have a touch board, you can connect the touch pins with male jump wires and touch it directly for testing.
### Configure the Project
You can determine the touch channel number by ``EXAMPLE_TOUCH_CHANNEL_NUM`` in the example. And adjust the active threshold by ``s_thresh2bm_ratio``.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT build flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
You can see the following output in the monitor if the example runs successfully:
```
W (461) touch: [sample_cfg_id 0] clock precision loss, expect 4000000 hz, got 4006725 hz
W (461) touch: [sample_cfg_id 1] clock precision loss, expect 8000000 hz, got 8013450 hz
W (461) touch: [sample_cfg_id 2] clock precision loss, expect 16000000 hz, got 16026900 hz
Initial benchmark and new threshold are:
[CH 0] 0: 4114, 411 1: 2057, 205 2: 1028, 102
[CH 1] 0: 4643, 464 1: 2322, 232 2: 1160, 116
[CH 2] 0: 4848, 484 1: 2424, 242 2: 1211, 121
[CH 3] 0: 4340, 434 1: 2170, 217 2: 1085, 108
=================================
benchmark [CH 0]: 4115 2056 1028
chan_data [CH 0]: 4115 2056 1028
benchmark [CH 1]: 4644 2322 1160
chan_data [CH 1]: 4644 2322 1160
benchmark [CH 2]: 4848 2423 1211
chan_data [CH 2]: 4848 2423 1211
benchmark [CH 3]: 4337 2168 1084
chan_data [CH 3]: 4337 2168 1084
=================================
benchmark [CH 0]: 4109 2054 1027
chan_data [CH 0]: 4109 2054 1027
benchmark [CH 1]: 4638 2318 1158
chan_data [CH 1]: 4638 2318 1158
benchmark [CH 2]: 4843 2421 1210
chan_data [CH 2]: 4845 2421 1210
benchmark [CH 3]: 4334 2167 1084
chan_data [CH 3]: 4334 2167 1083
...
```
And if you touch and release a button, you will see the following output:
```
...
I (1321) touch_callback: [CH 1] active
=================================
benchmark [CH 0]: 4111 2055 1027
chan_data [CH 0]: 4111 2055 1027
benchmark [CH 1]: 4676 2339 1168
chan_data [CH 1]: 17701 8798 4399
benchmark [CH 2]: 4870 2434 1217
chan_data [CH 2]: 4867 2433 1217
benchmark [CH 3]: 4333 2165 1082
chan_data [CH 3]: 4333 2165 1082
=================================
benchmark [CH 0]: 4109 2053 1027
chan_data [CH 0]: 4108 2053 1027
benchmark [CH 1]: 4676 2339 1168
chan_data [CH 1]: 11256 8817 4363
benchmark [CH 2]: 4868 2434 1217
chan_data [CH 2]: 4862 2429 1214
benchmark [CH 3]: 4332 2165 1082
chan_data [CH 3]: 4330 2164 1081
I (1931) touch_callback: [CH 1] inactive
=================================
benchmark [CH 0]: 4106 2052 1026
chan_data [CH 0]: 4106 2052 1026
benchmark [CH 1]: 4649 2323 1161
chan_data [CH 1]: 4650 2323 1161
benchmark [CH 2]: 4847 2422 1211
chan_data [CH 2]: 4846 2422 1211
benchmark [CH 3]: 4329 2163 1082
chan_data [CH 3]: 4329 2164 1082
...
```
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

View File

@@ -0,0 +1,3 @@
idf_component_register(SRCS "touch_sens_v3_example_main.c"
REQUIRES esp_driver_touch_sens
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,168 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/touch_sens.h"
#include "esp_check.h"
// Touch version 3 supports multiple sample configurations
#define EXAMPLE_TOUCH_SAMPLE_CFG_NUM 1 // Up to 'TOUCH_SAMPLE_CFG_NUM'
#define EXAMPLE_TOUCH_CHANNEL_NUM 4
#define EXAMPLE_TOUCH_CHAN_INIT_SCAN_TIMES 3
static touch_sensor_handle_t s_sens_handle = NULL;
static touch_channel_handle_t s_chan_handle[EXAMPLE_TOUCH_CHANNEL_NUM] = {};
// Active threshold to benchmark ratio. (i.e., touch will be activated when data >= benchmark * (1 + ratio))
static float s_thresh2bm_ratio[EXAMPLE_TOUCH_CHANNEL_NUM] = {
[0 ... EXAMPLE_TOUCH_CHANNEL_NUM - 1] = 0.015f, // 1.5%
};
bool example_touch_on_active_callback(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx)
{
ESP_EARLY_LOGI("touch_callback", "[CH %d] active", (int)event->chan_id);
return false;
}
bool example_touch_on_inactive_callback(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx)
{
ESP_EARLY_LOGI("touch_callback", "[CH %d] inactive", (int)event->chan_id);
return false;
}
static void example_touch_do_initial_scanning(void)
{
/* Enable the touch sensor to do the initial scanning, so that to initialize the channel data */
ESP_ERROR_CHECK(touch_sensor_enable(s_sens_handle));
/* Scan the enabled touch channels for several times, to make sure the initial channel data is stable */
for (int i = 0; i < EXAMPLE_TOUCH_CHAN_INIT_SCAN_TIMES; i++) {
ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(s_sens_handle, 2000));
}
/* Disable the touch channel to rollback the state */
ESP_ERROR_CHECK(touch_sensor_disable(s_sens_handle));
/* (Optional) Read the initial channel benchmark and reconfig the channel active threshold accordingly */
printf("Initial benchmark and new threshold are:\n");
for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) {
/* Read the initial benchmark of the touch channel */
uint32_t benchmark[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {};
ESP_ERROR_CHECK(touch_channel_read_data(s_chan_handle[i], TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark));
/* Calculate the proper active thresholds regarding the initial benchmark */
printf("[CH %d]", i);
touch_channel_config_t chan_cfg = {};
for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) {
chan_cfg.active_thresh[j] = (uint32_t)(benchmark[j] * s_thresh2bm_ratio[i]);
printf(" %d: %"PRIu32", %"PRIu32"\t", j, benchmark[j], chan_cfg.active_thresh[j]);
}
printf("\n");
/* Update the channel configuration */
ESP_ERROR_CHECK(touch_sensor_reconfig_channel(s_chan_handle[i], &chan_cfg));
}
}
void app_main(void)
{
/* Use the default sample configurations */
touch_sensor_sample_config_t sample_cfg[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {
TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(1, 1, 1),
#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 1
TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(2, 1, 1),
#endif
#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 2
TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(4, 1, 1),
#endif
};
/* Allocate new touch controller handle */
touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(EXAMPLE_TOUCH_SAMPLE_CFG_NUM, sample_cfg);
ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_cfg, &s_sens_handle));
/* Configure the touch sensor filter */
touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG();
ESP_ERROR_CHECK(touch_sensor_config_filter(s_sens_handle, &filter_cfg));
/* Allocate new touch channel on the touch controller */
touch_channel_config_t chan_cfg = {
/** Set the touch channel active threshold of each sample configuration.
*
* @How to Determine:
* As the actual threshold is affected by various factors in real application,
* we need to run the touch app first to get the `benchmark` and the `smooth_data` that being touched.
*
* @Formula:
* threshold = benchmark * coeff, (coeff for example, 0.1%~20%)
* Please adjust the coeff to guarantee the threshold < smooth_data - benchmark
*
* @Typical Practice:
* Normally, we can't determine a fixed threshold at the beginning,
* but we can give them estimated values first and update them after an initial scanning (like this example),
* Step1: set an estimated value for each sample configuration first. (i.e., here)
* Step2: then reconfig the threshold after the initial scanning.(see `example_touch_do_initial_scanning`)
* Step3: adjust the `s_thresh2bm_ratio` to a proper value to trigger the active callback
*/
.active_thresh = {
1000, // estimated active threshold of sample configuration 0
#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 1
2500, // estimated active threshold of sample configuration 1
#endif
#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 2
5000, // estimated active threshold of sample configuration 2
#endif
},
};
for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) {
ESP_ERROR_CHECK(touch_sensor_new_channel(s_sens_handle, i, &chan_cfg, &s_chan_handle[i]));
}
/* Do the initial scanning to initialize the touch channel data
* Without this step, the channel data in the first read will be invalid
*/
example_touch_do_initial_scanning();
/* Register the touch sensor callbacks, here only take `active` and `deactivate` event for example */
touch_event_callbacks_t callbacks = {
.on_active = example_touch_on_active_callback,
.on_inactive = example_touch_on_inactive_callback,
.on_measure_done = NULL,
.on_scan_done = NULL,
.on_timeout = NULL,
.on_proximity_meas_done = NULL,
};
ESP_ERROR_CHECK(touch_sensor_register_callbacks(s_sens_handle, &callbacks, NULL));
/* Enable the touch sensor */
ESP_ERROR_CHECK(touch_sensor_enable(s_sens_handle));
/* Start continuous scanning, you can also trigger oneshot scanning manually */
ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(s_sens_handle));
uint32_t benchmark[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {};
uint32_t chan_data[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {};
while (1) {
printf("=================================\n");
for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) {
/* Read and print the benchmark of each sample configuration */
ESP_ERROR_CHECK(touch_channel_read_data(s_chan_handle[i], TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark));
printf("benchmark [CH %d]:", i);
for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) {
printf(" %"PRIu32, benchmark[j]);
}
printf("\n");
/* Read and print the channel data of each sample configuration */
ESP_ERROR_CHECK(touch_channel_read_data(s_chan_handle[i], TOUCH_CHAN_DATA_TYPE_SMOOTH, chan_data));
printf("chan_data [CH %d]:", i);
for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) {
printf(" %"PRIu32, chan_data[j]);
}
printf("\n\n");
}
/* Read and display the data every 300 ms */
vTaskDelay(pdMS_TO_TICKS(300));
}
}

View File

@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32p4
@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 runners do not support touch pins')
@pytest.mark.generic
def test_touch_sens_v3(dut: Dut) -> None:
dut.expect_exact('Initial benchmark and new threshold are:')
dut.expect(r'\[CH [0-9]+\] 0: [0-9]+, [0-9]+')
dut.expect(r'benchmark \[CH [0-9]+\]: [0-9]+')
dut.expect(r'chan_data \[CH [0-9]+\]: [0-9]+')