diff --git a/components/esp_driver_touch_sens/CMakeLists.txt b/components/esp_driver_touch_sens/CMakeLists.txt index e2a0c6040f..d7f47492ad 100644 --- a/components/esp_driver_touch_sens/CMakeLists.txt +++ b/components/esp_driver_touch_sens/CMakeLists.txt @@ -8,10 +8,11 @@ set(srcs) set(public_inc) if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED) - if(CONFIG_SOC_TOUCH_SENSOR_VERSION EQUAL 3) - list(APPEND srcs "hw_ver3/touch_version_specific.c" - "common/touch_sens_common.c") - list(APPEND public_inc "include" "hw_ver3/include") + set(version_folder "hw_ver${CONFIG_SOC_TOUCH_SENSOR_VERSION}") + if(CONFIG_SOC_TOUCH_SENSOR_VERSION GREATER 1) + list(APPEND srcs "common/touch_sens_common.c" + "${version_folder}/touch_version_specific.c") + list(APPEND public_inc "include" "${version_folder}/include") endif() endif() diff --git a/components/esp_driver_touch_sens/common/touch_sens_common.c b/components/esp_driver_touch_sens/common/touch_sens_common.c index f5119c7237..a89f6b05ac 100644 --- a/components/esp_driver_touch_sens/common/touch_sens_common.c +++ b/components/esp_driver_touch_sens/common/touch_sens_common.c @@ -21,6 +21,7 @@ #include "soc/interrupts.h" #include "esp_intr_alloc.h" #endif +#include "esp_private/touch_sens_helper.h" #if CONFIG_TOUCH_ENABLE_DEBUG_LOG // The local log level must be defined before including esp_log.h @@ -112,7 +113,7 @@ esp_err_t touch_sensor_del_controller(touch_sensor_handle_t sens_handle) ESP_GOTO_ON_ERROR(esp_intr_free(sens_handle->intr_handle), err, TAG, "Failed to deregister the interrupt handler"); #endif TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); - touch_ll_intr_disable(TOUCH_LL_INTR_MASK_ALL); + touch_ll_interrupt_disable(TOUCH_LL_INTR_MASK_ALL); touch_ll_clear_active_channel_status(); TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); @@ -133,6 +134,7 @@ esp_err_t touch_sensor_new_channel(touch_sensor_handle_t sens_handle, int chan_i TOUCH_NULL_POINTER_CHECK(chan_cfg); TOUCH_NULL_POINTER_CHECK(ret_chan_handle); TOUCH_CHANNEL_CHECK(chan_id); + ESP_RETURN_ON_FALSE(g_touch == sens_handle, ESP_ERR_INVALID_ARG, TAG, "The input touch sensor handle is unmatched"); esp_err_t ret = ESP_OK; @@ -145,18 +147,18 @@ esp_err_t touch_sensor_new_channel(touch_sensor_handle_t sens_handle, int chan_i ESP_GOTO_ON_FALSE(sens_handle->ch[chan_id], ESP_ERR_NO_MEM, err2, TAG, "No memory for touch channel"); sens_handle->ch[chan_id]->id = chan_id; sens_handle->ch[chan_id]->base = sens_handle; - sens_handle->ch[chan_id]->is_prox_chan = false; + sens_handle->ch[chan_id]->prox_id = 0; /* Init the channel */ ESP_GOTO_ON_ERROR(touch_priv_config_channel(sens_handle->ch[chan_id], chan_cfg), err1, TAG, "Failed to configure the touch channel %d", chan_id); touch_channel_pin_init(chan_id); + + touch_chan_benchmark_config_t bm_cfg = {.do_reset = true}; TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); -#if SOC_TOUCH_SENSOR_VERSION == 2 - touch_ll_reset_chan_benchmark(1 << chan_id); -#endif sens_handle->chan_mask |= 1 << chan_id; - touch_ll_set_channel_mask(sens_handle->chan_mask); + /* Reset the benchmark to overwrite the legacy benchmark during the deep sleep */ + touch_priv_config_benchmark(sens_handle->ch[chan_id], &bm_cfg); TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); *ret_chan_handle = sens_handle->ch[chan_id]; @@ -180,18 +182,32 @@ esp_err_t touch_sensor_del_channel(touch_channel_handle_t chan_handle) xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); -#if SOC_TOUCH_SENSOR_VERSION == 2 - if (sens_handle->guard_chan == chan_handle || (BIT(chan_handle->id) & sens_handle->shield_chan_mask)) { +#if SOC_TOUCH_SUPPORT_WATERPROOF + if (sens_handle->shield_chan == chan_handle) { ESP_GOTO_ON_ERROR(touch_sensor_config_waterproof(sens_handle, NULL), err, TAG, "Failed to disable waterproof on this channel"); + } else if (sens_handle->guard_chan == chan_handle) { + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_waterproof_set_guard_chan(TOUCH_LL_NULL_CHANNEL); + sens_handle->guard_chan = NULL; + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); } - if (sens_handle->sleep_chan == chan_handle) { - ESP_GOTO_ON_ERROR(touch_sensor_config_sleep_channel(sens_handle, NULL), err, TAG, "Failed to disable sleep function on this channel"); +#endif // SOC_TOUCH_SUPPORT_WATERPROOF +#if SOC_TOUCH_SUPPORT_SLEEP_WAKEUP + if (sens_handle->deep_slp_chan == chan_handle) { + ESP_GOTO_ON_ERROR(touch_sensor_config_sleep_wakeup(sens_handle, NULL), err, TAG, "Failed to disable sleep function on this channel"); + } +#endif +#if SOC_TOUCH_SUPPORT_PROX_SENSING + if (chan_handle->prox_id > 0) { + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + chan_handle->prox_id = 0; + touch_ll_set_proximity_sensing_channel(chan_handle->prox_id - 1, TOUCH_LL_NULL_CHANNEL); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); } #endif int id = chan_handle->id; TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); sens_handle->chan_mask &= ~(1UL << id); - touch_ll_set_channel_mask(sens_handle->chan_mask); TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); free(g_touch->ch[id]); @@ -230,13 +246,14 @@ esp_err_t touch_sensor_enable(touch_sensor_handle_t sens_handle) sens_handle->is_enabled = true; TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); - touch_ll_intr_clear(TOUCH_LL_INTR_MASK_ALL); - touch_ll_intr_enable(TOUCH_LL_INTR_MASK_ALL); + touch_ll_enable_channel_mask(sens_handle->chan_mask); + touch_ll_interrupt_clear(TOUCH_LL_INTR_MASK_ALL); + touch_ll_interrupt_enable(TOUCH_LL_INTR_MASK_ALL); TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); #if SOC_TOUCH_SUPPORT_PROX_SENSING /* Reset the cached data of proximity channel */ FOR_EACH_TOUCH_CHANNEL(i) { - if (sens_handle->ch[i] && sens_handle->ch[i]->is_prox_chan) { + if (sens_handle->ch[i] && sens_handle->ch[i]->prox_id > 0) { sens_handle->ch[i]->prox_cnt = 0; memset(sens_handle->ch[i]->prox_val, 0, sizeof(sens_handle->ch[i]->prox_val[0]) * TOUCH_SAMPLE_CFG_NUM); } @@ -257,7 +274,8 @@ esp_err_t touch_sensor_disable(touch_sensor_handle_t sens_handle) ESP_GOTO_ON_FALSE(sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Touch sensor has not enabled"); TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); - touch_ll_intr_disable(TOUCH_LL_INTR_MASK_ALL); + touch_ll_interrupt_disable(TOUCH_LL_INTR_MASK_ALL); + touch_ll_enable_channel_mask(0); TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); sens_handle->is_enabled = false; @@ -294,13 +312,8 @@ esp_err_t touch_sensor_start_continuous_scanning(touch_sensor_handle_t sens_hand TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); sens_handle->is_started = true; -#if SOC_TOUCH_SENSOR_VERSION <= 2 - touch_ll_set_fsm_mode(TOUCH_FSM_MODE_TIMER); - touch_ll_start_fsm(); -#else touch_ll_enable_fsm_timer(true); - touch_ll_start_fsm_repeated_timer(false); -#endif + touch_ll_start_fsm_repeated_timer(); TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); err: @@ -316,13 +329,8 @@ esp_err_t touch_sensor_stop_continuous_scanning(touch_sensor_handle_t sens_handl ESP_GOTO_ON_FALSE_ISR(sens_handle->is_started, ESP_ERR_INVALID_STATE, err, TAG, "Continuous scanning not started yet"); TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); -#if SOC_TOUCH_SENSOR_VERSION <= 2 - touch_ll_stop_fsm(); - touch_ll_set_fsm_mode(TOUCH_FSM_MODE_SW); -#else - touch_ll_stop_fsm_repeated_timer(false); + touch_ll_stop_fsm_repeated_timer(); touch_ll_enable_fsm_timer(false); -#endif sens_handle->is_started = false; TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); @@ -351,7 +359,6 @@ esp_err_t touch_sensor_trigger_oneshot_scanning(touch_sensor_handle_t sens_handl } xSemaphoreTake(sens_handle->mutex, ticks); TickType_t end_tick = xTaskGetTickCount() + ticks; - // TODO: extract the following implementation into version specific source file when supporting other targets TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); touch_ll_enable_fsm_timer(false); TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); @@ -426,3 +433,21 @@ esp_err_t touch_channel_config_benchmark(touch_channel_handle_t chan_handle, con touch_priv_config_benchmark(chan_handle, benchmark_cfg); return ESP_OK; } + +/******************************************************************************/ +/* Scope: Private APIs */ +/******************************************************************************/ +esp_err_t touch_sensor_get_channel_info(touch_channel_handle_t chan_handle, touch_chan_info_t *chan_info) +{ + TOUCH_NULL_POINTER_CHECK(chan_handle); + TOUCH_NULL_POINTER_CHECK(chan_info); + xSemaphoreTake(chan_handle->base->mutex, portMAX_DELAY); + chan_info->chan_id = chan_handle->id; + chan_info->chan_gpio = touch_sensor_channel_io_map[chan_handle->id]; + chan_info->flags.is_dp_slp = chan_handle == chan_handle->base->deep_slp_chan; + chan_info->flags.is_proxi = chan_handle->prox_id > 0; + chan_info->flags.is_guard = chan_handle == chan_handle->base->guard_chan; + chan_info->flags.is_shield = chan_handle == chan_handle->base->shield_chan; + xSemaphoreGive(chan_handle->base->mutex); + return ESP_OK; +} diff --git a/components/esp_driver_touch_sens/common/touch_sens_private.h b/components/esp_driver_touch_sens/common/touch_sens_private.h index 325acb775e..5b0ce8b2c8 100644 --- a/components/esp_driver_touch_sens/common/touch_sens_private.h +++ b/components/esp_driver_touch_sens/common/touch_sens_private.h @@ -14,7 +14,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "soc/soc_caps.h" -#include "hal/touch_sensor_hal.h" +#include "hal/touch_sens_hal.h" #include "driver/touch_sens_types.h" #include "esp_memory_utils.h" #include "esp_check.h" @@ -85,6 +85,7 @@ struct touch_sensor_s { bool immersion_proof; /*!< Flag to indicate whether to disable scanning when the guard ring is triggered */ bool proximity_en; /*!< Flag to indicate whether the proximity sensing feature is enabled */ bool timeout_en; /*!< Flag to indicate whether the measurement timeout feature (hardware timeout) is enabled */ + bool denoise_en; /*!< Flag to indicate whether the denoise channel feature is enabled */ }; /** @@ -94,7 +95,7 @@ struct touch_sensor_s { struct touch_channel_s { touch_sensor_handle_t base; /*!< The touch sensor controller handle */ int id; /*!< Touch channel id, the range is target-specific */ - bool is_prox_chan; /*!< Flag to indicate whether this is a proximity channel */ + int prox_id; /*!< The proximity channel id + 1. It is 0 if not a proximity channel */ uint32_t prox_cnt; /*!< Cache the proximity measurement count, only takes effect when the channel is a proximity channel. * When this count reaches `touch_proximity_config_t::scan_times`, * this field will be cleared and call the `on_proximity_meas_done` callback. diff --git a/components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h b/components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h index 3eb0d2167e..a57587f7e0 100644 --- a/components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h +++ b/components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h @@ -9,4 +9,375 @@ * Version 2 includes ESP32-S2 and ESP32-S3 */ -#error "'esp_driver_touch_sens' does not support for ESP32-S2 and ESP32-S3 yet" +#pragma once + +#include "soc/soc_caps.h" +#include "driver/touch_sens_types.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TOUCH_MIN_CHAN_ID 1 /*!< The minimum available channel id of the touch pad */ +#define TOUCH_MAX_CHAN_ID 14 /*!< The maximum available channel id of the touch pad */ + +#define TOUCH_SHIELD_CHAN_ID 14 /*!< The touch channel that can be used as the shield channel */ + +/** + * @brief Helper macro to the default configurations of the touch sensor controller + * + * @param[in] sample_cfg_number The number of the sample configurations, which can only be 1 here because there is only one sample configuration + * @param[in] sample_cfg_ptr The pointer to the sample configurations + */ +#define TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(sample_cfg_number, sample_cfg_ptr) { \ + .power_on_wait_us = 256, \ + .meas_interval_us = 32.0, \ + .max_meas_time_us = 0, \ + .sample_cfg_num = sample_cfg_number, \ + .sample_cfg = sample_cfg_ptr, \ +} + +/** + * @brief Helper macro to the default sample configurations + * @note This default configuration uses `sample frequency = clock frequency / 1` + * + * @param[in] chg_times The charge times of the touch channel + * @param[in] volt_low The low voltage limit of the touch channel + * @param[in] volt_high The high voltage limit of the touch channel + */ +#define TOUCH_SENSOR_V2_DEFAULT_SAMPLE_CONFIG(chg_times, volt_low, volt_high) { \ + .charge_times = chg_times, \ + .charge_volt_lim_h = volt_high, \ + .charge_volt_lim_l = volt_low, \ + .idle_conn = TOUCH_IDLE_CONN_GND, \ + .bias_type = TOUCH_BIAS_TYPE_SELF, \ +} + +/** + * @brief Helper macro to the default filter configurations + * + */ +#define TOUCH_SENSOR_DEFAULT_FILTER_CONFIG() { \ + .benchmark = { \ + .filter_mode = TOUCH_BM_IIR_FILTER_4, \ + .jitter_step = 4, \ + .denoise_lvl = 1, \ + }, \ + .data = { \ + .smooth_filter = TOUCH_SMOOTH_IIR_FILTER_2, \ + .active_hysteresis = 2, \ + .debounce_cnt = 2, \ + }, \ +} + +/** + * @brief The data type of the touch channel + * + */ +typedef enum { + TOUCH_CHAN_DATA_TYPE_RAW, /*!< The raw data of the touch channel */ + TOUCH_CHAN_DATA_TYPE_SMOOTH, /*!< The smooth data of the touch channel */ + TOUCH_CHAN_DATA_TYPE_BENCHMARK, /*!< The benchmark of the touch channel */ + TOUCH_CHAN_DATA_TYPE_PROXIMITY, /*!< The proximity data of the proximity channel */ +} touch_chan_data_type_t; + +/** + * @brief Sample configurations of the touch sensor + * + */ +typedef struct { + uint32_t charge_times; /*!< The charge and discharge times of this sample configuration, the read data are positive correlation to the charge_times */ + touch_volt_lim_h_t charge_volt_lim_h; /*!< The upper voltage limit while charging a touch pad */ + touch_volt_lim_l_t charge_volt_lim_l; /*!< The lower voltage limit while charging a touch pad */ + touch_idle_conn_t idle_conn; /*!< The connection of the idle touch channels. + * The idle touch channel is a channel which is enabled but not under measuring. + */ + touch_bias_type_t bias_type; /*!< The type of the touch sensor bias */ +} touch_sensor_sample_config_t; + +/** + * @brief Configurations of the touch sensor controller + * + */ +typedef struct { + uint32_t power_on_wait_us; /*!< The waiting time between the channels power on and able to measure, to ensure the data stability */ + float meas_interval_us; /*!< Measurement interval of each channels */ + uint32_t max_meas_time_us; /*!< The maximum time of measuring one channel, if the time exceeds this value, the timeout interrupt will be triggered. + * Set to '0' to ignore the measurement time limitation, otherwise please set a proper time considering the configurations + * of this sample configurations below. + */ + /* Touch sensor sample configuration */ + uint32_t sample_cfg_num; /*!< The sample configuration number that used for sampling, CANNOT exceed TOUCH_SAMPLE_CFG_NUM */ + touch_sensor_sample_config_t *sample_cfg; /*!< The array of this sample configuration configurations, the length should be specified in `touch_sensor_config_t::sample_cfg_num` */ +} touch_sensor_config_t; + +/** + * @brief Configurations of the touch sensor channel + * + */ +typedef struct { + uint32_t active_thresh[TOUCH_SAMPLE_CFG_NUM]; /*!< The active threshold of each sample configuration, + * while the touch channel smooth value minus benchmark value exceed this threshold, + * will be regarded as activated + */ + touch_charge_speed_t charge_speed; /*!< The speed of charging and discharging the touch pad, the higher the speed, the faster charging and discharging */ + touch_init_charge_volt_t init_charge_volt; /*!< The initial voltage before charging/discharging a touch pad */ +} touch_channel_config_t; + +/** + * @brief Configurations of the touch sensor filter + * + */ +typedef struct { + /** + * @brief Benchmark configuration + */ + struct { + touch_benchmark_filter_mode_t filter_mode; /*!< Benchmark filter mode. IIR filter and Jitter filter can be selected, + * TOUCH_BM_IIR_FILTER_16 is recommended + */ + uint32_t jitter_step; /*!< Jitter filter step size, only takes effect when the `filter_mode` is TOUCH_BM_JITTER_FILTER. Range: [0 ~ 15] */ + int denoise_lvl; /*!< The denoise level, which determines the noise bouncing range that won't trigger benchmark update. + * Range: [0 ~ 4]. The greater the denoise_lvl is, more noise resistance will be. Specially, `0` stands for no denoise + * Typically, recommend to set this field to 1. + */ + } benchmark; /*!< Benchmark filter */ + /** + * @brief Data configuration + */ + struct { + touch_smooth_filter_mode_t smooth_filter; /*!< Smooth data IIR filter mode */ + uint32_t active_hysteresis; /*!< The hysteresis threshold to judge whether the touch channel is active + * If the channel data exceed the 'touch_channel_config_t::active_thresh + active_hysteresis' + * The channel will be activated. If the channel data is below to + * 'touch_channel_config_t::active_thresh - active_hysteresis' the channel will be inactivated. + */ + uint32_t debounce_cnt; /*!< The debounce count of the touch channel. + * Only when the channel data exceed the `touch_channel_config_t::active_thresh + active_hysteresis` for `debounce_cnt` times + * The channel will be activated. And only if the channel data is below to the `touch_channel_config_t::active_thresh - active_hysteresis` + * for `debounce_cnt` times, the channel will be inactivated. + * (The unit of `debounce_cnt` is the tick of the slow clock source) + */ + } data; /*!< Channel data filter */ +} touch_sensor_filter_config_t; + +/** + * @brief Touch sensor configuration during the deep sleep + * @note Currently it is the same as the normal controller configuration. + * The deep sleep configuration only takes effect when the chip entered sleep, + * so that to update a more power efficient configuration. + * + */ +typedef touch_sensor_config_t touch_sensor_config_dslp_t; + +/** + * @brief Configuration of the touch sensor sleep function + * + */ +typedef struct { + touch_sleep_wakeup_level_t slp_wakeup_lvl; /*!< The sleep level that can be woke up by touch sensor. */ + touch_channel_handle_t deep_slp_chan; /*!< The touch channel handle that supposed to work in the deep sleep. It can wake up the chip + * from deep sleep when this channel is activated. + * Only effective when the `touch_sleep_config_t::slp_wakeup_lvl` is `TOUCH_DEEP_SLEEP_WAKEUP` + */ + uint32_t deep_slp_thresh[TOUCH_SAMPLE_CFG_NUM]; /*!< The active threshold of the deep sleep channel during deep sleep, + * while the sleep channel exceed this threshold, it will be regarded as activated + * Only effective when the `touch_sleep_config_t::slp_wakeup_lvl` is `TOUCH_DEEP_SLEEP_WAKEUP` + */ + touch_sensor_config_dslp_t *deep_slp_sens_cfg; /*!< Specify the touch sensor configuration during the deep sleep. + * Note that these configurations will no take effect immediately, + * they will be set automatically while the chip prepare to enter sleep. + * Set NULL to not change the configurations before entering sleep. + * The sleep configuration mainly aims at lower down the charging and measuring times, + * so that to save power consumption during the sleep. + * Only effective when the `touch_sleep_config_t::slp_wakeup_lvl` is `TOUCH_DEEP_SLEEP_WAKEUP` + */ +} touch_sleep_config_t; + +/** + * @brief Configuration of the touch sensor waterproof function + * + */ +typedef struct { + touch_channel_handle_t guard_chan; /*!< The guard channel of that used for immersion detect. Set NULL if you don't need the guard channel. + * Typically, the guard channel is a ring that surrounds the touch panels, + * it is used to detect the large area that covered by water. + * While large area of water covers the touch panel, the guard channel will be activated. + */ + touch_channel_handle_t shield_chan; /*!< The shield channel that used for water droplets shield, can't be NULL. + * The shield channel can only be the No.14 channel on touch version 2. + * Typically, the shield channel uses grid layout which covers the touch area, + * it is used to shield the influence of water droplets covering both the touch panel and the shield channel. + * The shield channel will be paralleled to the current measuring channel (except the guard channel) to reduce the influence of water droplets. + */ + uint32_t shield_drv; /*!< The shield channel driver, which controls the drive capability of shield channel, range: 0 ~ 7 + * The larger the parasitic capacitance on the shielding channel, the higher the drive capability needs to be set. + */ + struct { + uint32_t immersion_proof: 1; /*!< Enable to protect the touch sensor pad when immersion detected. + * It will temporary disable the touch scanning if the guard channel triggered, and enable again if guard channel released. + * So that to avoid the fake touch when the touch panel is immersed in water. + */ + } flags; /*!< Flags of the water proof function */ +} touch_waterproof_config_t; + +/** + * @brief Configuration of the touch sensor proximity function + * + */ +typedef struct { + touch_channel_handle_t proximity_chan[TOUCH_PROXIMITY_CHAN_NUM]; /*!< The touch channel handles that will be configured as proximity sensing channels */ + uint32_t scan_times; /*!< The total scan times of EACH sample configuration, all sample configurations share a same `scan_times`. + * The measurement result of each scanning will be accumulated together to get the final result. + */ +} touch_proximity_config_t; + +/** + * @brief Configuration of denoise channel + * + */ +typedef struct { + touch_charge_speed_t charge_speed; /*!< The speed of charging and discharging the denoise touch channel, the higher the speed, the faster charging and discharging */ + touch_init_charge_volt_t init_charge_volt; /*!< The initial voltage before starting charging/discharging the denoise channel */ + touch_denoise_chan_cap_t ref_cap; /*!< The reference capacitance of the denoise channel. */ + touch_denoise_chan_res_t resolution; /*!< The noise suppression resolution of the denoise channel. + * The higher the resolution, the better the suppression effect, + * but at the same time, the attenuation of other touch channel sampling values also increases. + */ +} touch_denoise_chan_config_t; + +/** + * @brief Base event structure used in touch event queue + */ +typedef struct { + touch_channel_handle_t chan; /*!< the current triggered touch channel handle */ + int chan_id; /*!< the current triggered touch channel number */ + uint32_t status_mask; /*!< the current channel triggered status. + * For the bits in the status mask, + * if the bit is set, the corresponding channel is active + * if the bit is cleared, the corresponding channel is inactive + */ +} touch_base_event_data_t; + +/** + * @brief Measure done event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_meas_done_event_data_t; + +/** + * @brief Scan done event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_scan_done_event_data_t; + +/** + * @brief Active event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_active_event_data_t; + +/** + * @brief Inactive event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_inactive_event_data_t; + +/** + * @brief Proximity sensing measure done event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_prox_done_event_data_t; + +/** + * @brief Timeout event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_timeout_event_data_t; + +/** + * @brief Touch sensor callbacks + * @note Set NULL for the used callbacks. + * + */ +typedef struct { + /** + * @brief Touch sensor on active event callback. + * Callback when any touch channel is activated. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor active event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_active)(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on inactive event callback. + * Callback when any touch channel is inactivated. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor inactive event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_inactive)(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on measure done event callback. + * Callback when the measurement of all the sample configurations on the current touch channel is done. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor measure done event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_measure_done)(touch_sensor_handle_t sens_handle, const touch_meas_done_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on scan done event callback. + * Callback when finished scanning all the registered touch channels. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor scan done event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_scan_done)(touch_sensor_handle_t sens_handle, const touch_scan_done_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on measurement timeout event callback. + * Callback when measure the current touch channel timeout. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor timeout event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_timeout)(touch_sensor_handle_t sens_handle, const touch_timeout_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on proximity sensing measurement done event callback. + * Callback when proximity sensing measurement of the current channel is done. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor proximity sensing measure done event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_proximity_meas_done)(touch_sensor_handle_t sens_handle, const touch_prox_done_event_data_t *event, void *user_ctx); +} touch_event_callbacks_t; + +/** + * @brief Touch sensor benchmark configurations, to set or reset the benchmark of the channel + * + */ +typedef struct { + bool do_reset; /*!< Whether to reset the benchmark to the channel's latest smooth data */ +} touch_chan_benchmark_config_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_touch_sens/hw_ver2/touch_version_specific.c b/components/esp_driver_touch_sens/hw_ver2/touch_version_specific.c new file mode 100644 index 0000000000..27af1aa834 --- /dev/null +++ b/components/esp_driver_touch_sens/hw_ver2/touch_version_specific.c @@ -0,0 +1,470 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief This file is only applicable to the touch hardware version2 + * Version 2 includes ESP32-S2 and ESP32-S3 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "soc/soc_caps.h" +#include "soc/clk_tree_defs.h" +#include "soc/touch_sensor_periph.h" +#include "soc/rtc.h" +#include "hal/hal_utils.h" +#include "driver/touch_sens.h" +#include "esp_private/rtc_ctrl.h" +#include "esp_private/periph_ctrl.h" +#include "esp_clk_tree.h" +#include "esp_sleep.h" +#include "../../common/touch_sens_private.h" +#if CONFIG_TOUCH_ENABLE_DEBUG_LOG +// The local log level must be defined before including esp_log.h +// Set the maximum log level for this source file +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#endif +#include "esp_check.h" + +#define TOUCH_DENOISE_CHAN_ID 0 /*!< The touch channel that can be used as the denoise channel */ + +static const char *TAG = "touch"; + +portMUX_TYPE g_touch_spinlock = portMUX_INITIALIZER_UNLOCKED; + +/****************************************************************************** + * Scope: touch driver private * + ******************************************************************************/ + +void touch_priv_enable_module(bool enable) +{ + TOUCH_ENTER_CRITICAL(TOUCH_RTC_LOCK); + touch_ll_enable_clock_gate(enable); + // Reset the benchmark after finished the scanning + touch_ll_reset_chan_benchmark(TOUCH_LL_FULL_CHANNEL_MASK); + TOUCH_EXIT_CRITICAL(TOUCH_RTC_LOCK); +} + +void IRAM_ATTR touch_priv_default_intr_handler(void *arg) +{ + /* If the touch controller object has not been allocated, return directly */ + if (!g_touch) { + return; + } + bool need_yield = false; + uint32_t status = touch_ll_get_intr_status_mask(); + g_touch->is_meas_timeout = false; + touch_ll_interrupt_clear(status); + touch_base_event_data_t data; + touch_ll_get_active_channel_mask(&data.status_mask); + data.chan = g_touch->ch[touch_ll_get_current_meas_channel()]; + /* If the channel is not registered, return directly */ + if (!data.chan) { + return; + } + data.chan_id = data.chan->id; + + if (status & TOUCH_LL_INTR_MASK_DONE) { +#if !SOC_TOUCH_PROXIMITY_MEAS_DONE_SUPPORTED + /* For the target like ESP32-S2 that don't support proximity done interrupt, + Simulate the interrupt by software by judge the scan times. */ + if (data.chan->prox_id > 0 && + touch_ll_proximity_get_total_scan_times() == touch_ll_proximity_get_curr_scan_cnt(data.chan_id)) { + /* Set the proximity scan done flag to simulate a proximity done interrupt */ + status |= TOUCH_LL_INTR_MASK_PROX_DONE; + } +#endif + if (g_touch->cbs.on_measure_done) { + need_yield |= g_touch->cbs.on_measure_done(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_SCAN_DONE) { +#if CONFIG_IDF_TARGET_ESP32S2 + /* Workaround for the fake scan done interrupt. + (Only happens when both channel 13 and 14 are enabled) + The scan done interrupt will be triggered twice for channel 13 and 14, + but we only hope it be triggered after channel 14 measurement done. */ + bool fake_scan_done = data.chan_id == 13 && (g_touch->chan_mask >> 13 == 0x03); + if (g_touch->cbs.on_scan_done && !fake_scan_done) +#else + if (g_touch->cbs.on_scan_done) +#endif + { + need_yield |= g_touch->cbs.on_scan_done(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_PROX_DONE) { + /* Accumulated proximity sensing data is stored in the benchmark data register. + Read it out to latch the last proximity sensing data. */ + touch_ll_read_chan_data(data.chan_id, TOUCH_LL_READ_BENCHMARK, &data.chan->prox_val[0]); + // TODO: support to judge by software if the proximity channel triggered + if (g_touch->cbs.on_proximity_meas_done) { + need_yield |= g_touch->cbs.on_proximity_meas_done(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_ACTIVE) { + /* When the guard ring activated, disable the scanning of other channels to avoid fake touch */ + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->waterproof_en && data.chan == g_touch->guard_chan) { + touch_ll_enable_scan_mask(~BIT(data.chan->id), false); + } + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->cbs.on_active) { + need_yield |= g_touch->cbs.on_active(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_INACTIVE) { + /* When the guard ring inactivated, enable the scanning of other channels again */ + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->waterproof_en && data.chan == g_touch->guard_chan) { + touch_ll_enable_scan_mask(g_touch->chan_mask & (~BIT(g_touch->shield_chan->id)), true); + } + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->cbs.on_inactive) { + need_yield |= g_touch->cbs.on_inactive(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_TIMEOUT) { + g_touch->is_meas_timeout = true; + touch_ll_force_done_curr_measurement(); + if ((g_touch->cbs.on_timeout)) { + need_yield |= g_touch->cbs.on_timeout(g_touch, &data, g_touch->user_ctx); + } + } + + if (need_yield) { + portYIELD_FROM_ISR(); + } +} + +static esp_err_t s_touch_convert_to_hal_config(touch_sensor_handle_t sens_handle, const touch_sensor_config_t *sens_cfg, touch_hal_config_t *hal_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_cfg); + TOUCH_NULL_POINTER_CHECK(hal_cfg); + + ESP_RETURN_ON_FALSE(sens_cfg->sample_cfg_num && sens_cfg->sample_cfg, ESP_ERR_INVALID_ARG, TAG, + "at least one sample configuration required"); + ESP_RETURN_ON_FALSE(sens_cfg->sample_cfg_num <= TOUCH_SAMPLE_CFG_NUM, ESP_ERR_INVALID_ARG, TAG, + "at most %d sample configurations supported", (int)(TOUCH_SAMPLE_CFG_NUM)); + + /* Get the source clock frequency for the first time */ + if (!sens_handle->src_freq_hz) { + /* Touch sensor actually uses dynamic fast clock LP_DYN_FAST_CLK, but it will only switch to the slow clock during sleep, + * This driver only designed for wakeup case (sleep case should use ULP driver), so we only need to consider RTC_FAST here */ + esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_RTC_FAST, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &sens_handle->src_freq_hz); + ESP_LOGD(TAG, "touch rtc clock source: RTC_FAST, frequency: %"PRIu32" Hz", sens_handle->src_freq_hz); + } + + uint32_t src_freq_mhz = sens_handle->src_freq_hz / 1000000; + hal_cfg->power_on_wait_ticks = (uint32_t)sens_cfg->power_on_wait_us * src_freq_mhz; + hal_cfg->power_on_wait_ticks = hal_cfg->power_on_wait_ticks > TOUCH_LL_PAD_MEASURE_WAIT_MAX ? + TOUCH_LL_PAD_MEASURE_WAIT_MAX : hal_cfg->power_on_wait_ticks; + hal_cfg->meas_interval_ticks = (uint32_t)(sens_cfg->meas_interval_us * src_freq_mhz); + hal_cfg->timeout_ticks = (uint32_t)sens_cfg->max_meas_time_us * src_freq_mhz; + ESP_RETURN_ON_FALSE(hal_cfg->timeout_ticks <= TOUCH_LL_TIMEOUT_MAX, ESP_ERR_INVALID_ARG, TAG, + "max_meas_time_ms should within %"PRIu32, TOUCH_LL_TIMEOUT_MAX / src_freq_mhz); + hal_cfg->sample_cfg_num = sens_cfg->sample_cfg_num; // Only one sample cfg + hal_cfg->sample_cfg = (touch_hal_sample_config_t *)sens_cfg->sample_cfg; + return ESP_OK; +} + +esp_err_t touch_priv_config_controller(touch_sensor_handle_t sens_handle, const touch_sensor_config_t *sens_cfg) +{ +#if CONFIG_TOUCH_ENABLE_DEBUG_LOG + esp_log_level_set(TAG, ESP_LOG_DEBUG); +#endif + /* Check and convert the configuration to hal configurations */ + touch_hal_config_t hal_cfg = {}; + ESP_RETURN_ON_ERROR(s_touch_convert_to_hal_config(sens_handle, sens_cfg, &hal_cfg), + TAG, "parse the configuration failed due to the invalid configuration"); + sens_handle->sample_cfg_num = 1; // Only have one set of sampling configuration + + /* Configure the hardware */ + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_hal_config_controller(&hal_cfg); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + + return ESP_OK; +} + +esp_err_t touch_priv_config_channel(touch_channel_handle_t chan_handle, const touch_channel_config_t *chan_cfg) +{ + // Check the validation of the channel active threshold + ESP_RETURN_ON_FALSE(chan_cfg->active_thresh[0] <= TOUCH_LL_ACTIVE_THRESH_MAX, ESP_ERR_INVALID_ARG, + TAG, "the active threshold out of range 0~%d", TOUCH_LL_ACTIVE_THRESH_MAX); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_set_chan_active_threshold(chan_handle->id, chan_cfg->active_thresh[0]); + touch_ll_set_charge_speed(chan_handle->id, chan_cfg->charge_speed); + touch_ll_set_init_charge_voltage(chan_handle->id, chan_cfg->init_charge_volt); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + return ESP_OK; +} + +esp_err_t touch_priv_deinit_controller(touch_sensor_handle_t sens_handle) +{ + /* Disable the additional functions */ + if (sens_handle->proximity_en) { + touch_sensor_config_proximity_sensing(sens_handle, NULL); + } + if (sens_handle->sleep_en) { + touch_sensor_config_sleep_wakeup(sens_handle, NULL); + } + if (sens_handle->waterproof_en) { + touch_sensor_config_waterproof(sens_handle, NULL); + } + if (sens_handle->denoise_en) { + touch_sensor_config_denoise_channel(sens_handle, NULL); + } + return ESP_OK; +} + +esp_err_t IRAM_ATTR touch_priv_channel_read_data(touch_channel_handle_t chan_handle, touch_chan_data_type_t type, uint32_t *data) +{ + ESP_RETURN_ON_FALSE_ISR(type >= TOUCH_CHAN_DATA_TYPE_RAW && type <= TOUCH_CHAN_DATA_TYPE_PROXIMITY, + ESP_ERR_INVALID_ARG, TAG, "The channel data type is invalid"); + ESP_RETURN_ON_FALSE_ISR(type != TOUCH_CHAN_DATA_TYPE_PROXIMITY || chan_handle->prox_id > 0, ESP_ERR_INVALID_ARG, TAG, "This is not a proximity sensing channel"); + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + switch (type) { + default: // fall through + case TOUCH_CHAN_DATA_TYPE_RAW: + touch_ll_read_chan_data(chan_handle->id, TOUCH_LL_READ_RAW, data); + break; + case TOUCH_CHAN_DATA_TYPE_SMOOTH: + touch_ll_read_chan_data(chan_handle->id, TOUCH_LL_READ_SMOOTH, data); + break; + case TOUCH_CHAN_DATA_TYPE_BENCHMARK: + touch_ll_read_chan_data(chan_handle->id, TOUCH_LL_READ_BENCHMARK, data); + break; + case TOUCH_CHAN_DATA_TYPE_PROXIMITY: + /* Get the proximity value from the stored data. + * The proximity value are updated in the isr when proximity scanning is done */ + *data = chan_handle->prox_val[0]; + break; + } + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + return ESP_OK; +} + +void touch_priv_config_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_config_t *benchmark_cfg) +{ + if (benchmark_cfg->do_reset) { + touch_ll_reset_chan_benchmark(BIT(chan_handle->id)); + } +} + +/****************************************************************************** + * Scope: public APIs * + ******************************************************************************/ + +esp_err_t touch_sensor_config_filter(touch_sensor_handle_t sens_handle, const touch_sensor_filter_config_t *filter_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + if (filter_cfg) { + ESP_RETURN_ON_FALSE(filter_cfg->benchmark.denoise_lvl >= 0 && filter_cfg->benchmark.denoise_lvl <= 4, + ESP_ERR_INVALID_ARG, TAG, "denoise_lvl is out of range"); + } + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + + if (filter_cfg) { + touch_ll_filter_enable(true); + /* Configure the benchmark filter and update strategy */ + touch_ll_filter_set_filter_mode(filter_cfg->benchmark.filter_mode); + if (filter_cfg->benchmark.filter_mode == TOUCH_BM_JITTER_FILTER) { + touch_ll_filter_set_jitter_step(filter_cfg->benchmark.jitter_step); + } + touch_ll_filter_set_denoise_level(filter_cfg->benchmark.denoise_lvl); + /* Configure the touch data filter */ + touch_ll_filter_set_smooth_mode(filter_cfg->data.smooth_filter); + touch_ll_filter_set_active_hysteresis(filter_cfg->data.active_hysteresis); + touch_ll_filter_set_debounce(filter_cfg->data.debounce_cnt); + } else { + touch_ll_filter_enable(false); + } + + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_config_sleep_wakeup(touch_sensor_handle_t sens_handle, const touch_sleep_config_t *sleep_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + int dp_slp_chan_id = -1; + touch_hal_config_t hal_cfg = {}; + touch_hal_config_t *hal_cfg_ptr = NULL; + + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + if (sleep_cfg) { + ESP_GOTO_ON_FALSE(sleep_cfg->slp_wakeup_lvl == TOUCH_LIGHT_SLEEP_WAKEUP || sleep_cfg->slp_wakeup_lvl == TOUCH_DEEP_SLEEP_WAKEUP, + ESP_ERR_INVALID_ARG, err, TAG, "Invalid sleep level"); + /* Enabled touch sensor as wake-up source */ + esp_sleep_enable_touchpad_wakeup(); +#if SOC_PM_SUPPORT_RTC_PERIPH_PD + // Keep ESP_PD_DOMAIN_RTC_PERIPH power domain on during the light/deep sleep, so that to keep the touch sensor working + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); +#endif // SOC_PM_SUPPORT_RC_FAST_PD + + /* If set the deep sleep channel (i.e., enable deep sleep wake-up), + configure the deep sleep related settings. */ + if (sleep_cfg->slp_wakeup_lvl == TOUCH_DEEP_SLEEP_WAKEUP) { + ESP_GOTO_ON_FALSE(sleep_cfg->deep_slp_chan, ESP_ERR_INVALID_ARG, err, TAG, "deep sleep waken channel can't be NULL"); + dp_slp_chan_id = sleep_cfg->deep_slp_chan->id; + + /* Check and convert the configuration to hal configurations */ + if (sleep_cfg->deep_slp_sens_cfg) { + hal_cfg_ptr = &hal_cfg; + ESP_GOTO_ON_ERROR(s_touch_convert_to_hal_config(sens_handle, sleep_cfg->deep_slp_sens_cfg, hal_cfg_ptr), + err, TAG, "parse the configuration failed due to the invalid configuration"); + } + sens_handle->sleep_en = true; + sens_handle->deep_slp_chan = sleep_cfg->deep_slp_chan; + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_sleep_set_threshold(sleep_cfg->deep_slp_thresh[0]); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } + + } else { + /* Disable the touch sensor as wake-up source */ + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TOUCHPAD); +#if SOC_PM_SUPPORT_RTC_PERIPH_PD + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO); +#endif // SOC_PM_SUPPORT_RC_FAST_PD + sens_handle->deep_slp_chan = NULL; + sens_handle->sleep_en = false; + } + + /* Save or update the sleep config */ + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_hal_save_sleep_config(dp_slp_chan_id, hal_cfg_ptr); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +// Water proof can be enabled separately +esp_err_t touch_sensor_config_waterproof(touch_sensor_handle_t sens_handle, const touch_waterproof_config_t *wp_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + if (wp_cfg) { + ESP_GOTO_ON_FALSE(wp_cfg->shield_chan && wp_cfg->shield_chan->id == 14, ESP_ERR_INVALID_ARG, err, TAG, "Shield channel must be channel 14"); + // Check the validation of the waterproof configuration + TOUCH_NULL_POINTER_CHECK(wp_cfg->shield_chan); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->waterproof_en = true; + sens_handle->guard_chan = wp_cfg->guard_chan; + sens_handle->shield_chan = wp_cfg->shield_chan; + touch_ll_waterproof_set_guard_chan(wp_cfg->guard_chan ? wp_cfg->guard_chan->id : TOUCH_LL_NULL_CHANNEL); + // need to disable the scanning of the shield channel + touch_ll_enable_scan_mask(BIT(wp_cfg->shield_chan->id), false); + touch_ll_waterproof_set_shield_driver(wp_cfg->shield_drv); + touch_ll_waterproof_enable(true); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } else { + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_waterproof_enable(false); + touch_ll_waterproof_set_guard_chan(TOUCH_LL_NULL_CHANNEL); + touch_ll_enable_scan_mask(BIT(sens_handle->shield_chan->id), true); + touch_ll_waterproof_set_shield_driver(0); + sens_handle->guard_chan = NULL; + sens_handle->shield_chan = NULL; + sens_handle->waterproof_en = false; + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_config_proximity_sensing(touch_sensor_handle_t sens_handle, const touch_proximity_config_t *prox_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + + /* Reset proximity sensing part of all channels */ + FOR_EACH_TOUCH_CHANNEL(i) { + if (sens_handle->ch[i]) { + sens_handle->ch[i]->prox_id = 0; + sens_handle->ch[i]->prox_cnt = 0; + memset(sens_handle->ch[i]->prox_val, 0, sizeof(sens_handle->ch[i]->prox_val[0]) * TOUCH_SAMPLE_CFG_NUM); + } + } + + if (prox_cfg) { + sens_handle->proximity_en = true; + for (int i = 0; i < TOUCH_PROXIMITY_CHAN_NUM; i++) { + if (prox_cfg->proximity_chan[i]) { + prox_cfg->proximity_chan[i]->prox_id = i + 1; + touch_ll_set_proximity_sensing_channel(i, prox_cfg->proximity_chan[i]->id); + } else { + touch_ll_set_proximity_sensing_channel(i, TOUCH_LL_NULL_CHANNEL); + } + } + touch_ll_proximity_set_total_scan_times(prox_cfg->scan_times); + } else { + for (int i = 0; i < TOUCH_PROXIMITY_CHAN_NUM; i++) { + touch_ll_set_proximity_sensing_channel(i, TOUCH_LL_NULL_CHANNEL); + } + sens_handle->proximity_en = false; + } + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_config_denoise_channel(touch_sensor_handle_t sens_handle, const touch_denoise_chan_config_t *denoise_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + if (denoise_cfg) { + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->denoise_en = true; + sens_handle->chan_mask |= BIT(TOUCH_DENOISE_CHAN_ID); + touch_ll_set_charge_speed(TOUCH_DENOISE_CHAN_ID, denoise_cfg->charge_speed); + touch_ll_set_init_charge_voltage(TOUCH_DENOISE_CHAN_ID, denoise_cfg->init_charge_volt); + touch_ll_denoise_set_reference_cap(denoise_cfg->ref_cap); + touch_ll_denoise_set_resolution(denoise_cfg->resolution); + touch_ll_denoise_enable(true); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } else { + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->denoise_en = false; + sens_handle->chan_mask &= ~BIT(TOUCH_DENOISE_CHAN_ID); + touch_ll_denoise_enable(false); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} diff --git a/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h index cf15c14be8..ddd6813184 100644 --- a/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h +++ b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h @@ -25,6 +25,9 @@ extern "C" { /** * @brief Helper macro to the default configurations of the touch sensor controller * + * @param[in] sample_cfg_number The number of sample configurations, which should be less than or equal to `SOC_TOUCH_SAMPLE_CFG_NUM` + * Given multiple sample configurations to enable the frequency hopping + * @param[in] sample_cfg_array The pointer to the sample configurations array */ #define TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(sample_cfg_number, sample_cfg_array) { \ .power_on_wait_us = 256, \ @@ -39,6 +42,9 @@ extern "C" { * @brief Helper macro to the default sample configurations * @note This default configuration uses `sample frequency = clock frequency / 1` * + * @param[in] _div_num The division of the final data, used to scaling the final data + * @param[in] coarse_freq_tune The coarse frequency tuning value + * @param[in] fine_freq_tune The fine frequency tuning value */ #define TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(_div_num, coarse_freq_tune, fine_freq_tune) { \ .div_num = _div_num, \ @@ -51,6 +57,10 @@ extern "C" { .bypass_shield_output = false, \ } +/** + * @brief Helper macro to the default filter configurations + * + */ #define TOUCH_SENSOR_DEFAULT_FILTER_CONFIG() { \ .benchmark = { \ .filter_mode = TOUCH_BM_IIR_FILTER_4, \ @@ -60,6 +70,7 @@ extern "C" { .data = { \ .smooth_filter = TOUCH_SMOOTH_IIR_FILTER_2, \ .active_hysteresis = 2, \ + .debounce_cnt = 2, \ }, \ } @@ -73,68 +84,6 @@ typedef enum { TOUCH_CHAN_DATA_TYPE_PROXIMITY, /*!< The proximity data of the proximity channel */ } touch_chan_data_type_t; -/** - * @brief The chip sleep level that allows the touch sensor to wake-up - * - */ -typedef enum { - TOUCH_LIGHT_SLEEP_WAKEUP, /*!< Only enable the touch sensor to wake up the chip from light sleep */ - TOUCH_DEEP_SLEEP_WAKEUP, /*!< Enable the touch sensor to wake up the chip from deep sleep or light sleep */ -} touch_sleep_wakeup_level_t; - -/** - * @brief Touch sensor shield channel drive capability level - * - */ -typedef enum { - TOUCH_SHIELD_CAP_40PF, /*!< The max equivalent capacitance in shield channel is 40pf */ - TOUCH_SHIELD_CAP_80PF, /*!< The max equivalent capacitance in shield channel is 80pf */ - TOUCH_SHIELD_CAP_120PF, /*!< The max equivalent capacitance in shield channel is 120pf */ - TOUCH_SHIELD_CAP_160PF, /*!< The max equivalent capacitance in shield channel is 160pf */ - TOUCH_SHIELD_CAP_200PF, /*!< The max equivalent capacitance in shield channel is 200pf */ - TOUCH_SHIELD_CAP_240PF, /*!< The max equivalent capacitance in shield channel is 240pf */ - TOUCH_SHIELD_CAP_280PF, /*!< The max equivalent capacitance in shield channel is 280pf */ - TOUCH_SHIELD_CAP_320PF, /*!< The max equivalent capacitance in shield channel is 320pf */ -} touch_chan_shield_cap_t; - -/** - * @brief Touch channel Infinite Impulse Response (IIR) filter or Jitter filter for benchmark - * @note Recommended filter coefficient selection is `IIR_16`. - */ -typedef enum { - TOUCH_BM_IIR_FILTER_4, /*!< IIR Filter for benchmark, 1/4 raw_value + 3/4 benchmark */ - TOUCH_BM_IIR_FILTER_8, /*!< IIR Filter for benchmark, 1/8 raw_value + 7/8 benchmark */ - TOUCH_BM_IIR_FILTER_16, /*!< IIR Filter for benchmark, 1/16 raw_value + 15/16 benchmark (typical) */ - TOUCH_BM_IIR_FILTER_32, /*!< IIR Filter for benchmark, 1/32 raw_value + 31/32 benchmark */ - TOUCH_BM_IIR_FILTER_64, /*!< IIR Filter for benchmark, 1/64 raw_value + 63/64 benchmark */ - TOUCH_BM_IIR_FILTER_128, /*!< IIR Filter for benchmark, 1/128 raw_value + 127/128 benchmark */ - TOUCH_BM_JITTER_FILTER, /*!< Jitter Filter for benchmark, raw value +/- jitter_step */ -} touch_benchmark_filter_mode_t; - -/** - * @brief Touch channel Infinite Impulse Response (IIR) filter for smooth data - * - */ -typedef enum { - TOUCH_SMOOTH_NO_FILTER, /*!< No filter adopted for smooth data, smooth data equals raw data */ - TOUCH_SMOOTH_IIR_FILTER_2, /*!< IIR filter adopted for smooth data, smooth data equals 1/2 raw data + 1/2 last smooth data (typical) */ - TOUCH_SMOOTH_IIR_FILTER_4, /*!< IIR filter adopted for smooth data, smooth data equals 1/4 raw data + 3/4 last smooth data */ - TOUCH_SMOOTH_IIR_FILTER_8, /*!< IIR filter adopted for smooth data, smooth data equals 1/8 raw data + 7/8 last smooth data */ -} touch_smooth_filter_mode_t; - -/** - * @brief Interrupt events - * - */ -typedef enum { - TOUCH_INTR_EVENT_ACTIVE, /*!< Touch channel active event */ - TOUCH_INTR_EVENT_INACTIVE, /*!< Touch channel inactive event */ - TOUCH_INTR_EVENT_MEASURE_DONE, /*!< Touch channel measure done event */ - TOUCH_INTR_EVENT_SCAN_DONE, /*!< All touch channels scan done event */ - TOUCH_INTR_EVENT_TIMEOUT, /*!< Touch channel measurement timeout event */ - TOUCH_INTR_EVENT_PROXIMITY_DONE, /*!< Proximity channel measurement done event */ -} touch_intr_event_t; - /** * @brief Sample configurations of the touch sensor * @@ -162,7 +111,7 @@ typedef struct { * of this sample configurations below. */ touch_out_mode_t output_mode; /*!< Touch channel counting mode of the binarized touch output */ - uint32_t sample_cfg_num; /*!< The sample configuration number that used for sampling */ + uint32_t sample_cfg_num; /*!< The sample configuration number that used for sampling, CANNOT exceed TOUCH_SAMPLE_CFG_NUM */ touch_sensor_sample_config_t *sample_cfg; /*!< The array of this sample configuration configurations, the length should be specified in `touch_sensor_config_t::sample_cfg_num` */ } touch_sensor_config_t; @@ -224,7 +173,7 @@ typedef struct { typedef touch_sensor_config_t touch_sensor_config_dslp_t; /** - * @brief Configure the touch sensor sleep function + * @brief Configuration of the touch sensor sleep function * */ typedef struct { @@ -248,7 +197,7 @@ typedef struct { } touch_sleep_config_t; /** - * @brief Configure the touch sensor waterproof function + * @brief Configuration of the touch sensor waterproof function * */ typedef struct { @@ -274,7 +223,7 @@ typedef struct { } touch_waterproof_config_t; /** - * @brief Configure the touch sensor proximity function + * @brief Configuration of the touch sensor proximity function * */ typedef struct { @@ -292,13 +241,13 @@ typedef struct { * @brief Base event structure used in touch event queue */ typedef struct { - touch_channel_handle_t chan; /*!< the current triggered touch channel handle */ - int chan_id; /*!< the current triggered touch channel number */ - uint32_t status_mask; /*!< the current channel triggered status. - * For the bits in the status mask, - * if the bit is set, the corresponding channel is active - * if the bit is cleared, the corresponding channel is inactive - */ + touch_channel_handle_t chan; /*!< the current triggered touch channel handle */ + int chan_id; /*!< the current triggered touch channel number */ + uint32_t status_mask; /*!< the current channel triggered status. + * For the bits in the status mask, + * if the bit is set, the corresponding channel is active + * if the bit is cleared, the corresponding channel is inactive + */ } touch_base_event_data_t; /** diff --git a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c index e9335d3965..a98c71d4fa 100644 --- a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c +++ b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c @@ -44,10 +44,6 @@ void touch_priv_enable_module(bool enable) TOUCH_ENTER_CRITICAL(TOUCH_RTC_LOCK); touch_ll_enable_module_clock(enable); touch_ll_enable_out_gate(enable); -#if SOC_TOUCH_SENSOR_VERSION >= 2 - // Reset the benchmark after finished the scanning - touch_ll_reset_chan_benchmark(TOUCH_LL_FULL_CHANNEL_MASK); -#endif TOUCH_EXIT_CRITICAL(TOUCH_RTC_LOCK); } @@ -60,7 +56,7 @@ void IRAM_ATTR touch_priv_default_intr_handler(void *arg) bool need_yield = false; uint32_t status = touch_ll_get_intr_status_mask(); g_touch->is_meas_timeout = false; - touch_ll_intr_clear(status); + touch_ll_interrupt_clear(status); touch_base_event_data_t data; touch_ll_get_active_channel_mask(&data.status_mask); data.chan = g_touch->ch[touch_ll_get_current_meas_channel()]; @@ -253,7 +249,7 @@ esp_err_t touch_priv_channel_read_data(touch_channel_handle_t chan_handle, touch TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); } } else { - if (!chan_handle->is_prox_chan) { + if (!chan_handle->prox_id) { ESP_EARLY_LOGW(TAG, "This is not a proximity sensing channel"); } TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); @@ -436,8 +432,8 @@ esp_err_t touch_sensor_config_proximity_sensing(touch_sensor_handle_t sens_handl /* Reset proximity sensing part of all channels */ FOR_EACH_TOUCH_CHANNEL(i) { - if (sens_handle->ch[i] && sens_handle->ch[i]->is_prox_chan) { - sens_handle->ch[i]->is_prox_chan = false; + if (sens_handle->ch[i] && sens_handle->ch[i]->prox_id > 0) { + sens_handle->ch[i]->prox_id = 0; sens_handle->ch[i]->prox_cnt = 0; for (int i = 0; i < TOUCH_SAMPLE_CFG_NUM; i++) { sens_handle->ch[i]->prox_val[i] = 0; @@ -450,7 +446,7 @@ esp_err_t touch_sensor_config_proximity_sensing(touch_sensor_handle_t sens_handl uint8_t sample_cfg_num = sens_handle->sample_cfg_num; for (int i = 0; i < TOUCH_PROXIMITY_CHAN_NUM; i++) { if (prox_cfg->proximity_chan[i]) { - prox_cfg->proximity_chan[i]->is_prox_chan = true; + prox_cfg->proximity_chan[i]->prox_id = i + 1; touch_ll_set_proximity_sensing_channel(i, prox_cfg->proximity_chan[i]->id); } else { touch_ll_set_proximity_sensing_channel(i, TOUCH_LL_NULL_CHANNEL); diff --git a/components/esp_driver_touch_sens/include/driver/touch_sens.h b/components/esp_driver_touch_sens/include/driver/touch_sens.h index cba510baef..c1e22d5713 100644 --- a/components/esp_driver_touch_sens/include/driver/touch_sens.h +++ b/components/esp_driver_touch_sens/include/driver/touch_sens.h @@ -61,6 +61,8 @@ esp_err_t touch_sensor_new_channel(touch_sensor_handle_t sens_handle, int chan_i /** * @brief Delete the touch channel * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * @note If the channel has been enabled other sub-features like proximity sensing, sleep wakeup, waterproof, denoise. + * The attached sub-features will be disabled while deleting the channel. * * @param[in] chan_handle Touch channel handle * @return @@ -289,6 +291,24 @@ esp_err_t touch_sensor_config_proximity_sensing(touch_sensor_handle_t sens_handl esp_err_t touch_sensor_config_sleep_wakeup(touch_sensor_handle_t sens_handle, const touch_sleep_config_t *sleep_cfg); #endif +#if SOC_TOUCH_SUPPORT_DENOISE_CHAN +/** + * @brief Configure the touch denoise channel + * @note The denoise channel is used to suppress the internal background noise. + * Once the denoise channel enabled, the measured data of the other touch channels + * will minus the data of the denoise channel automatically. + * So the channel data will be attenuated after enabling the denoise channel. + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] denoise_cfg Denoise channel configurations, set NULL to disable the touch channel + * @return + * - ESP_OK: Configure the denoise channel success + * - ESP_ERR_INVALID_ARG: The sensor handle is NULL or invalid denoise configuration + * - ESP_ERR_INVALID_STATE: The touch sensor is enabled + */ +esp_err_t touch_sensor_config_denoise_channel(touch_sensor_handle_t sens_handle, const touch_denoise_chan_config_t *denoise_cfg); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_touch_sens/include/driver/touch_sens_types.h b/components/esp_driver_touch_sens/include/driver/touch_sens_types.h index 3b802cc6cc..d9fa24512c 100644 --- a/components/esp_driver_touch_sens/include/driver/touch_sens_types.h +++ b/components/esp_driver_touch_sens/include/driver/touch_sens_types.h @@ -10,7 +10,7 @@ #include #include #include "soc/soc_caps.h" -#include "hal/touch_sensor_types.h" +#include "hal/touch_sens_types.h" #ifdef __cplusplus extern "C" { @@ -22,6 +22,71 @@ extern "C" { #define TOUCH_PROXIMITY_CHAN_NUM SOC_TOUCH_PROXIMITY_CHANNEL_NUM /*!< The supported proximity channel number in proximity sensing mode */ #endif +/** + * @brief The chip sleep level that allows the touch sensor to wake-up + * + */ +typedef enum { + TOUCH_LIGHT_SLEEP_WAKEUP, /*!< Only enable the touch sensor to wake up the chip from light sleep */ + TOUCH_DEEP_SLEEP_WAKEUP, /*!< Enable the touch sensor to wake up the chip from deep sleep or light sleep */ +} touch_sleep_wakeup_level_t; + +/** + * @brief Touch sensor shield channel drive capability level + * + */ +typedef enum { + TOUCH_SHIELD_CAP_40PF, /*!< The max equivalent capacitance in shield channel is 40pf */ + TOUCH_SHIELD_CAP_80PF, /*!< The max equivalent capacitance in shield channel is 80pf */ + TOUCH_SHIELD_CAP_120PF, /*!< The max equivalent capacitance in shield channel is 120pf */ + TOUCH_SHIELD_CAP_160PF, /*!< The max equivalent capacitance in shield channel is 160pf */ + TOUCH_SHIELD_CAP_200PF, /*!< The max equivalent capacitance in shield channel is 200pf */ + TOUCH_SHIELD_CAP_240PF, /*!< The max equivalent capacitance in shield channel is 240pf */ + TOUCH_SHIELD_CAP_280PF, /*!< The max equivalent capacitance in shield channel is 280pf */ + TOUCH_SHIELD_CAP_320PF, /*!< The max equivalent capacitance in shield channel is 320pf */ +} touch_chan_shield_cap_t; + +/** + * @brief Touch channel Infinite Impulse Response (IIR) filter or Jitter filter for benchmark + * @note Recommended filter coefficient selection is `IIR_16`. + */ +typedef enum { + TOUCH_BM_IIR_FILTER_4, /*!< IIR Filter for benchmark, 1/4 raw_value + 3/4 benchmark */ + TOUCH_BM_IIR_FILTER_8, /*!< IIR Filter for benchmark, 1/8 raw_value + 7/8 benchmark */ + TOUCH_BM_IIR_FILTER_16, /*!< IIR Filter for benchmark, 1/16 raw_value + 15/16 benchmark (typical) */ + TOUCH_BM_IIR_FILTER_32, /*!< IIR Filter for benchmark, 1/32 raw_value + 31/32 benchmark */ + TOUCH_BM_IIR_FILTER_64, /*!< IIR Filter for benchmark, 1/64 raw_value + 63/64 benchmark */ + TOUCH_BM_IIR_FILTER_128, /*!< IIR Filter for benchmark, 1/128 raw_value + 127/128 benchmark */ +#if SOC_TOUCH_SENSOR_VERSION == 2 + TOUCH_BM_IIR_FILTER_256, /*!< IIR Filter for benchmark, 1/256 raw_value + 255/256 benchmark */ +#endif + TOUCH_BM_JITTER_FILTER, /*!< Jitter Filter for benchmark, raw value +/- jitter_step */ +} touch_benchmark_filter_mode_t; + +/** + * @brief Touch channel Infinite Impulse Response (IIR) filter for smooth data + * + */ +typedef enum { + TOUCH_SMOOTH_NO_FILTER, /*!< No filter adopted for smooth data, smooth data equals raw data */ + TOUCH_SMOOTH_IIR_FILTER_2, /*!< IIR filter adopted for smooth data, smooth data equals 1/2 raw data + 1/2 last smooth data (typical) */ + TOUCH_SMOOTH_IIR_FILTER_4, /*!< IIR filter adopted for smooth data, smooth data equals 1/4 raw data + 3/4 last smooth data */ + TOUCH_SMOOTH_IIR_FILTER_8, /*!< IIR filter adopted for smooth data, smooth data equals 1/8 raw data + 7/8 last smooth data */ +} touch_smooth_filter_mode_t; + +/** + * @brief Interrupt events + * + */ +typedef enum { + TOUCH_INTR_EVENT_ACTIVE, /*!< Touch channel active event */ + TOUCH_INTR_EVENT_INACTIVE, /*!< Touch channel inactive event */ + TOUCH_INTR_EVENT_MEASURE_DONE, /*!< Touch channel measure done event */ + TOUCH_INTR_EVENT_SCAN_DONE, /*!< All touch channels scan done event */ + TOUCH_INTR_EVENT_TIMEOUT, /*!< Touch channel measurement timeout event */ + TOUCH_INTR_EVENT_PROXIMITY_DONE, /*!< Proximity channel measurement done event */ +} touch_intr_event_t; + typedef struct touch_sensor_s *touch_sensor_handle_t; /*!< The handle of touch sensor controller */ typedef struct touch_channel_s *touch_channel_handle_t; /*!< The handle of touch channel */ diff --git a/components/esp_driver_touch_sens/include/esp_private/touch_sens_helper.h b/components/esp_driver_touch_sens/include/esp_private/touch_sens_helper.h new file mode 100644 index 0000000000..9760ae187e --- /dev/null +++ b/components/esp_driver_touch_sens/include/esp_private/touch_sens_helper.h @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" +#include "driver/touch_sens_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Touch channel information + * + */ +typedef struct { + int chan_id; /*!< Touch channel number */ + int chan_gpio; /*!< Corresponding GPIO of this channel */ + struct { + uint32_t is_dp_slp: 1; /*!< Whether this channel can wakeup from deep sleep */ + uint32_t is_proxi: 1; /*!< Whether this channel is used for proximity sensing */ + uint32_t is_guard: 1; /*!< Whether this channel is used for waterproof guard channel */ + uint32_t is_shield: 1; /*!< Whether this channel is used for waterproof shield channel */ + } flags; /*!< Channel sub-feature flags */ +} touch_chan_info_t; + +/** + * @brief Get the touch channel information by the channel handle + * + * @param[in] chan_handle Touch channel handle + * @param[out] chan_info Touch channel information + * @return + * - ESP_OK: Success to get the channel information + * - ESP_ERR_INVALID_ARG: NULL pointer + */ +esp_err_t touch_sensor_get_channel_info(touch_channel_handle_t chan_handle, touch_chan_info_t *chan_info); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml b/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml index 16e6ca0369..142c609d4b 100644 --- a/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml +++ b/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml @@ -1,6 +1,8 @@ components/esp_driver_touch_sens/test_apps/touch_sens: disable: - - if: SOC_TOUCH_SENSOR_VERSION != 3 - temporary: currently driver ng only support version 3 + - if: SOC_TOUCH_SENSOR_SUPPORTED != 1 + - if: SOC_TOUCH_SENSOR_VERSION == 1 + temporary: true + reason: currently driver ng does not support version 1 depends_components: - esp_driver_touch_sens diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/README.md b/components/esp_driver_touch_sens/test_apps/touch_sens/README.md index f8ea707124..9b5055b84a 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/README.md +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32-P4 | -| ----------------- | -------- | +| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c index 226b8549fa..9cb166c502 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c @@ -10,29 +10,36 @@ #include "unity.h" #include "driver/touch_sens.h" #include "hal/touch_sensor_ll.h" +#include "esp_private/touch_sens_helper.h" #include "esp_log.h" #include "esp_attr.h" static touch_sensor_sample_config_t s_sample_cfg[TOUCH_SAMPLE_CFG_NUM] = { +#if SOC_TOUCH_SENSOR_VERSION == 2 + TOUCH_SENSOR_V2_DEFAULT_SAMPLE_CONFIG(500, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_2V2), +#elif SOC_TOUCH_SENSOR_VERSION == 3 TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(1, 1, 1), -#if TOUCH_SAMPLE_CFG_NUM > 1 TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(2, 1, 1), -#endif -#if TOUCH_SAMPLE_CFG_NUM > 2 TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(4, 1, 1), +#else +#error "Target not support" #endif }; static touch_channel_config_t s_chan_cfg = { +#if SOC_TOUCH_SENSOR_VERSION == 2 + .active_thresh = { + 2000, + }, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_LOW, +#elif SOC_TOUCH_SENSOR_VERSION == 3 .active_thresh = { 5000, -#if TOUCH_SAMPLE_CFG_NUM > 1 2500, -#endif -#if TOUCH_SAMPLE_CFG_NUM > 2 1000, -#endif }, +#endif }; TEST_CASE("touch_sens_install_uninstall_test", "[touch]") @@ -119,7 +126,13 @@ static bool TEST_TCH_IRAM_ATTR s_test_touch_on_inactive_callback(touch_sensor_ha static void s_test_touch_simulate_touch(touch_sensor_handle_t touch, touch_channel_handle_t touch_chan, bool active) { +#if SOC_TOUCH_SENSOR_VERSION == 2 + touch_chan_info_t chan_info = {}; + touch_sensor_get_channel_info(touch_chan, &chan_info); + touch_ll_set_charge_speed(chan_info.chan_id, active ? TOUCH_CHARGE_SPEED_4 : TOUCH_CHARGE_SPEED_7); +#elif SOC_TOUCH_SENSOR_VERSION == 3 touch_ll_set_internal_capacitor(active ? 0x7f : 0); +#endif } static void s_test_touch_log_data(touch_channel_handle_t touch_chan, uint32_t sample_cfg_num, const char *tag) @@ -146,15 +159,21 @@ TEST_CASE("touch_sens_active_inactive_test", "[touch]") /* Configuring the filter */ touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); TEST_ESP_OK(touch_sensor_config_filter(touch, &filter_cfg)); - TEST_ESP_OK(touch_sensor_new_channel(touch, 0, &s_chan_cfg, &touch_chan)); + TEST_ESP_OK(touch_sensor_new_channel(touch, 1, &s_chan_cfg, &touch_chan)); +#if SOC_TOUCH_SENSOR_VERSION == 3 /* Connect the touch channels to the internal capacitor */ touch_ll_enable_internal_capacitor(true); +#endif // SOC_TOUCH_SENSOR_VERSION == 3 s_test_touch_do_initial_scanning(touch, 3); /* Read benchmark */ uint32_t benchmark[TOUCH_SAMPLE_CFG_NUM] = {0}; TEST_ESP_OK(touch_channel_read_data(touch_chan, TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark)); + /* Test whether success to finish the initial scanning */ + for (int i = 0; i < TOUCH_SAMPLE_CFG_NUM; i++) { + TEST_ASSERT_GREATER_THAN(0, benchmark[i]); + } /* Re-configure the threshold according to the benchmark */ touch_channel_config_t chan_cfg = s_test_get_chan_cfg_by_benchmark(benchmark, TOUCH_SAMPLE_CFG_NUM, TEST_ACTIVE_THRESH_RATIO); TEST_ESP_OK(touch_sensor_reconfig_channel(touch_chan, &chan_cfg)); diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py b/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py index 871cdb6baf..c1205a9117 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py @@ -4,8 +4,9 @@ import pytest from pytest_embedded import Dut +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 @pytest.mark.esp32p4 -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 runners do not support touch pins') @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 5bd82fdd36..108a05c568 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -62,6 +62,7 @@ #include "hal/uart_hal.h" #if SOC_TOUCH_SENSOR_SUPPORTED #include "hal/touch_sensor_hal.h" +#include "hal/touch_sens_hal.h" #endif #if CONFIG_SPIRAM && CONFIG_ESP_LDO_RESERVE_PSRAM @@ -301,7 +302,7 @@ static void ext0_wakeup_prepare(void); static void ext1_wakeup_prepare(void); #endif static esp_err_t timer_wakeup_prepare(int64_t sleep_duration); -#if SOC_TOUCH_SENSOR_SUPPORTED && SOC_TOUCH_SENSOR_VERSION != 1 +#if SOC_TOUCH_SENSOR_VERSION >= 2 static void touch_wakeup_prepare(void); #endif #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP && SOC_DEEP_SLEEP_SUPPORTED @@ -881,11 +882,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m /* In light sleep, the RTC_PERIPH power domain should be in the power-on state (Power on the touch circuit in light sleep), * otherwise the touch sensor FSM will be cleared, causing touch sensor false triggering. */ -#if SOC_TOUCH_SENSOR_VERSION == 3 bool keep_rtc_power_on = touch_ll_is_fsm_repeated_timer_enabled(); -#else - bool keep_rtc_power_on = touch_ll_get_fsm_state(); -#endif if (keep_rtc_power_on) { // Check if the touch sensor is working properly. pd_flags &= ~RTC_SLEEP_PD_RTC_PERIPH; } @@ -1711,26 +1708,7 @@ static esp_err_t timer_wakeup_prepare(int64_t sleep_duration) return ESP_OK; } -#if SOC_TOUCH_SENSOR_VERSION == 2 -/* In deep sleep mode, only the sleep channel is supported, and other touch channels should be turned off. */ -static void touch_wakeup_prepare(void) -{ - uint16_t sleep_cycle = 0; - uint16_t meas_times = 0; - touch_pad_t touch_num = TOUCH_PAD_NUM0; - touch_ll_sleep_get_channel_num(&touch_num); // Check if the sleep pad is enabled. - if ((touch_num > TOUCH_PAD_NUM0) && (touch_num < TOUCH_PAD_MAX) && touch_ll_get_fsm_state()) { - touch_ll_stop_fsm(); - touch_ll_clear_channel_mask(TOUCH_PAD_BIT_MASK_ALL); - touch_ll_intr_clear(TOUCH_PAD_INTR_MASK_ALL); // Clear state from previous wakeup - touch_hal_sleep_channel_get_work_time(&sleep_cycle, &meas_times); - touch_ll_set_meas_times(meas_times); - touch_ll_set_sleep_time(sleep_cycle); - touch_ll_set_channel_mask(BIT(touch_num)); - touch_ll_start_fsm(); - } -} -#elif SOC_TOUCH_SENSOR_VERSION == 3 +#if SOC_TOUCH_SENSOR_VERSION >= 2 static void touch_wakeup_prepare(void) { touch_hal_prepare_deep_sleep();