Merge branch 'feature/touch_element_sleep' into 'master'

touch_element: add low-power support and example into touch element

Closes IDF-3027 and IDF-4353

See merge request espressif/esp-idf!13001
This commit is contained in:
Kevin (Lao Kaiyao) 2022-08-16 18:57:46 +08:00
commit 38bb2debea
17 changed files with 593 additions and 19 deletions

View File

@ -23,6 +23,7 @@
#include "soc/soc_caps.h"
#include "driver/rtc_io.h"
#include "hal/rtc_io_hal.h"
#include "hal/rtc_cntl_ll.h"
#include "driver/uart.h"

View File

@ -47,6 +47,11 @@ static inline void rtc_cntl_ll_ulp_int_clear(void)
REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_SAR_INT_CLR);
}
static inline void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle)
{
REG_SET_FIELD(RTC_CNTL_TIMER2_REG, RTC_CNTL_ULPCP_TOUCH_START_WAIT, wait_cycle);
}
#ifdef __cplusplus
}
#endif

View File

@ -47,6 +47,11 @@ static inline void rtc_cntl_ll_ulp_int_clear(void)
REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_TRAP_INT_CLR);
}
static inline void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle)
{
REG_SET_FIELD(RTC_CNTL_TIMER2_REG, RTC_CNTL_ULPCP_TOUCH_START_WAIT, wait_cycle);
}
#ifdef __cplusplus
}
#endif

View File

@ -127,6 +127,11 @@ static inline void rtc_cntl_ll_ulp_int_clear(void)
REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_TRAP_INT_CLR);
}
static inline void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle)
{
REG_SET_FIELD(RTC_CNTL_TIMER2_REG, RTC_CNTL_ULPCP_TOUCH_START_WAIT, wait_cycle);
}
#ifdef __cplusplus
}
#endif

View File

@ -292,7 +292,7 @@
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
#define SOC_TOUCH_VERSION_2 (1) /*!<Hardware version of touch sensor */
#define SOC_TOUCH_SENSOR_NUM (15) /*!<15 Touch channels */
#define SOC_TOUCH_PROXIMITY_CHANNEL_NUM (3) /* Sopport touch proximity channel number. */
#define SOC_TOUCH_PROXIMITY_CHANNEL_NUM (3) /*!<Support touch proximity channel number. */
#define SOC_TOUCH_PAD_THRESHOLD_MAX (0x1FFFFF) /*!<If set touch threshold max value, The touch sensor can't be in touched status */
#define SOC_TOUCH_PAD_MEASURE_WAIT_MAX (0xFF) /*!<The timer frequency is 8Mhz, the max value is 0xff */

View File

@ -94,6 +94,14 @@ typedef struct {
touch_pad_t guard_channel; //!< Waterproof Guard-Sensor channel number (index)
float guard_sensitivity; //!< Waterproof Guard-Sensor sensitivity
} touch_elem_waterproof_config_t;
/**
* @brief Touch element sleep configuration passed to touch_element_enable_light_sleep or touch_element_enable_deep_sleep
*/
typedef struct {
uint16_t sample_count; //!< scan times in every measurement, normally equal to the 'sample_count' field in 'touch_elem_hw_config_t'.
uint16_t sleep_cycle; //!< sleep_cycle decide the interval between two measurements t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency), normally equal to the 'sleep_cycle' field in 'touch_elem_hw_config_t'.
} touch_elem_sleep_config_t;
/* ------------------------------------------------------------------------------------------------------------------ */
typedef void *touch_elem_handle_t; //!< Touch element handle type
typedef uint32_t touch_elem_event_t; //!< Touch element event type
@ -256,6 +264,75 @@ esp_err_t touch_element_waterproof_add(touch_elem_handle_t element_handle);
*/
esp_err_t touch_element_waterproof_remove(touch_elem_handle_t element_handle);
/**
* @brief Touch element light sleep initialization
*
* @note It should be called after touch button element installed.
* Any of installed touch element can wake up from the light sleep
*
* @param[in] sleep_config Sleep configurations, set NULL to use default config
* @return
* - ESP_OK: Successfully initialized touch sleep
* - ESP_ERR_INVALID_STATE: Touch element is not installed or touch sleep has been installed
* - ESP_ERR_INVALID_ARG: inputed argument is NULL
* - ESP_ERR_NO_MEM: no memory for touch sleep struct
* - ESP_ERR_NOT_SUPPORTED: inputed wakeup_elem_handle is not touch_button_handle_t type, currently only touch_button_handle_t supported
*/
esp_err_t touch_element_enable_light_sleep(const touch_elem_sleep_config_t *sleep_config);
/**
* @brief Release the resources that allocated by touch_element_enable_deep_sleep()
*
* This function will also disable the touch sensor to wake up the device
*
* @return
* - ESP_OK: uninstall success
* - ESP_ERR_INVALID_STATE: touch sleep has not been installed
*/
esp_err_t touch_element_disable_light_sleep(void);
/**
* @brief Touch element deep sleep initialization
*
* This function will enable the device wake-up from deep sleep or light sleep by touch sensor
*
* @note It should be called after touch button element installed.
* Only one touch button can be registered as the deep sleep wake-up button
*
* @param[in] wakeup_elem_handle Touch element instance handle for waking up the device, only support button element
* @param[in] sleep_config Sleep configurations, set NULL to use default config
*
* @return
* - ESP_OK: Successfully initialized touch sleep
* - ESP_ERR_INVALID_STATE: Touch element is not installed or touch sleep has been installed
* - ESP_ERR_INVALID_ARG: inputed argument is NULL
* - ESP_ERR_NO_MEM: no memory for touch sleep struct
* - ESP_ERR_NOT_SUPPORTED: inputed wakeup_elem_handle is not touch_button_handle_t type, currently only touch_button_handle_t supported
*/
esp_err_t touch_element_enable_deep_sleep(touch_elem_handle_t wakeup_elem_handle, const touch_elem_sleep_config_t *sleep_config);
/**
* @brief Release the resources that allocated by touch_element_enable_deep_sleep()
*
* This function will also disable the touch sensor to wake up the device
*
* @return
* - ESP_OK: uninstall success
* - ESP_ERR_INVALID_STATE: touch sleep has not been installed
*/
esp_err_t touch_element_disable_deep_sleep(void);
/**
* @brief Touch element wake up calibrations
*
* This function will also disable the touch sensor to wake up the device
*
* @return
* - ESP_OK: uninstall success
* - ESP_ERR_INVALID_STATE: touch sleep has not been installed
*/
esp_err_t touch_element_sleep_enable_wakeup_calibration(touch_elem_handle_t element_handle, bool en);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,6 +10,8 @@
#include "touch_element/touch_button.h"
#include "touch_element/touch_slider.h"
#include "touch_element/touch_matrix.h"
#include "esp_pm.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
@ -54,6 +56,7 @@ typedef struct {
touch_pad_t channel; //!< Touch channel number(index)
te_dev_type_t type; //!< Touch channel type TODO: need to refactor as te_class_type_t
te_dev_state_t state; //!< Touch channel current state
bool is_use_last_threshold;
} te_dev_t;
typedef enum {
@ -79,6 +82,16 @@ struct te_waterproof_s {
bool is_shield_level_set; //Waterproof shield level setting bit
};
typedef struct te_waterproof_s* te_waterproof_handle_t;
/* -------------------------------------------- Sleep basic type --------------------------------------------- */
struct te_sleep_s {
touch_elem_handle_t wakeup_handle;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
uint32_t *non_volatile_threshold;
};
typedef struct te_sleep_s* te_sleep_handle_t;
/* -------------------------------------------- Button basic type --------------------------------------------- */
typedef struct {
touch_elem_dispatch_t dispatch_method; //Button dispatch method
@ -170,6 +183,16 @@ void te_object_method_register(te_object_methods_t *object_methods, te_class_typ
void te_object_method_unregister(te_class_type_t object_type);
bool te_object_check_channel(const touch_pad_t *channel_array, uint8_t channel_sum);
bool waterproof_check_mask_handle(touch_elem_handle_t te_handle);
bool te_is_touch_dsleep_wakeup(void);
touch_pad_t te_get_sleep_channel(void);
bool is_button_object_handle(touch_elem_handle_t element_handle);
bool is_slider_object_handle(touch_elem_handle_t element_handle);
bool is_matrix_object_handle(touch_elem_handle_t element_handle);
void button_enable_wakeup_calibration(te_button_handle_t button_handle, bool en);
void slider_enable_wakeup_calibration(te_slider_handle_t slider_handle, bool en);
void matrix_enable_wakeup_calibration(te_matrix_handle_t matrix_handle, bool en);
/* ------------------------------------------------------------------------------------------------------------------ */
#ifdef __cplusplus

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -296,6 +296,20 @@ static esp_err_t button_object_remove_instance(te_button_handle_t button_handle)
return ret;
}
bool is_button_object_handle(touch_elem_handle_t element_handle)
{
te_button_handle_list_t *item;
xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {
if (element_handle == item->button_handle) {
xSemaphoreGive(s_te_btn_obj->mutex);
return true;
}
}
xSemaphoreGive(s_te_btn_obj->mutex);
return false;
}
static bool button_channel_check(te_button_handle_t button_handle, touch_pad_t channel_num)
{
return (channel_num == button_handle->device->channel);
@ -346,6 +360,11 @@ static inline void button_dispatch(te_button_handle_t button_handle, touch_elem_
}
}
void button_enable_wakeup_calibration(te_button_handle_t button_handle, bool en)
{
button_handle->device->is_use_last_threshold = !en;
}
/**
* @brief Button process
*

View File

@ -9,11 +9,15 @@
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "esp_sleep.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_check.h"
#include "hal/touch_sensor_hal.h" //TODO: remove hal
#include "touch_element/touch_element_private.h"
#include "esp_rom_sys.h"
#define TE_CLASS_ITEM(cls, cls_type, cls_item) ((&((cls)[cls_type]))->cls_item)
#define TE_CLASS_FOREACH(cls_var, cls_start, cls_end) \
@ -87,6 +91,7 @@ typedef struct {
te_object_methods_t object_methods[TE_CLS_TYPE_MAX]; //Class(object) methods
touch_elem_global_config_t *global_config; //Global initialization
te_waterproof_handle_t waterproof_handle; //Waterproof configuration
te_sleep_handle_t sleep_handle;
esp_timer_handle_t proc_timer; //Processing timer handle
QueueHandle_t event_msg_queue; //Application event message queue (for user)
QueueHandle_t intr_msg_queue; //Interrupt message (for internal)
@ -96,6 +101,7 @@ typedef struct {
} te_obj_t;
static te_obj_t *s_te_obj = NULL;
RTC_FAST_ATTR uint32_t threshold_shadow[TOUCH_PAD_MAX - 1] = {0};
/**
* Internal de-noise channel(Touch channel 0) equivalent capacitance table, depends on hardware design
@ -313,6 +319,36 @@ esp_err_t te_event_give(touch_elem_message_t te_message)
return ESP_OK;
}
uint32_t te_get_threshold(touch_pad_t channel_num)
{
uint32_t threshold = 0;
touch_pad_sleep_channel_t sleep_channel_info;
touch_pad_sleep_channel_get_info(&sleep_channel_info);
if (channel_num != sleep_channel_info.touch_num) {
touch_pad_get_thresh(channel_num, &threshold);
} else {
touch_pad_sleep_get_threshold(channel_num, &threshold);
}
return threshold;
}
bool te_is_touch_dsleep_wakeup(void)
{
soc_reset_reason_t reset_reason = esp_rom_get_reset_reason(0);
if (reset_reason != RESET_REASON_CORE_DEEP_SLEEP) {
return false;
}
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
return wakeup_reason == ESP_SLEEP_WAKEUP_TOUCHPAD;
}
touch_pad_t te_get_sleep_channel(void)
{
touch_pad_sleep_channel_t sleep_channel_info;
touch_pad_sleep_channel_get_info(&sleep_channel_info);
return sleep_channel_info.touch_num;
}
/**
* @brief Touch sensor interrupt service routine
*
@ -323,22 +359,41 @@ static void te_intr_cb(void *arg)
{
TE_UNUSED(arg);
static int scan_done_cnt = 0;
static uint32_t touch_pre_trig_status = 0;
int task_awoken = pdFALSE;
te_intr_msg_t te_intr_msg;
/*< Figure out which touch sensor channel is triggered and the trigger type */
uint32_t intr_mask = touch_pad_read_intr_status_mask();
te_intr_msg.channel_num = touch_pad_get_current_meas_channel();
if (intr_mask == 0x0) { //For dummy interrupt
return;
}
bool need_send_queue = true;
if (intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) {
te_intr_msg.channel_state = TE_STATE_PRESS;
te_intr_msg.intr_type = TE_INTR_PRESS;
} else if (intr_mask & TOUCH_PAD_INTR_MASK_INACTIVE) {
te_intr_msg.channel_state = TE_STATE_RELEASE;
te_intr_msg.intr_type = TE_INTR_RELEASE;
} else if (intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) {
uint8_t pad_num = 0;
uint32_t touch_trig_status = touch_pad_get_status();
uint32_t touch_trig_diff = touch_trig_status ^ touch_pre_trig_status;
while (touch_trig_diff) {
if (touch_trig_diff & 0x1) {
if (touch_trig_status & BIT(pad_num)) {
if (s_te_obj->sleep_handle != NULL) {
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock);
#endif
}
te_intr_msg.channel_state = TE_STATE_PRESS;
te_intr_msg.intr_type = TE_INTR_PRESS;
} else {
te_intr_msg.channel_state = TE_STATE_RELEASE;
te_intr_msg.intr_type = TE_INTR_RELEASE;
}
touch_pre_trig_status = touch_trig_status;
te_intr_msg.channel_num = pad_num;
}
pad_num++;
touch_trig_diff >>= 1;
}
if (intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) {
te_intr_msg.channel_state = TE_STATE_IDLE;
te_intr_msg.intr_type = TE_INTR_TIMEOUT;
} else if (intr_mask & TOUCH_PAD_INTR_MASK_SCAN_DONE) {
@ -354,8 +409,6 @@ static void te_intr_cb(void *arg)
}
/*< De-noise channel signal must be read at the time between SCAN_DONE and next measurement beginning(sleep)!!! */
touch_pad_denoise_read_data(&s_te_obj->denoise_channel_raw); //Update de-noise signal
} else {
te_intr_msg.intr_type = TE_INTR_MAX; // Unknown Exception
}
if (need_send_queue) {
xQueueSendFromISR(s_te_obj->intr_msg_queue, &te_intr_msg, &task_awoken);
@ -385,11 +438,21 @@ static void te_proc_timer_cb(void *arg)
if (ret == pdPASS) {
if (te_intr_msg.intr_type == TE_INTR_PRESS || te_intr_msg.intr_type == TE_INTR_RELEASE) {
te_object_update_state(te_intr_msg);
if ((s_te_obj->sleep_handle != NULL) && (te_intr_msg.intr_type == TE_INTR_RELEASE)) {
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock);
#endif
}
} else if (te_intr_msg.intr_type == TE_INTR_SCAN_DONE) {
if (s_te_obj->is_set_threshold != true) {
s_te_obj->is_set_threshold = true;
te_object_set_threshold(); //TODO: add set threshold error processing
ESP_LOGD(TE_DEBUG_TAG, "Set threshold");
if (s_te_obj->sleep_handle != NULL) {
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock);
#endif
}
}
if (waterproof_check_state()) {
te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;
@ -500,6 +563,7 @@ esp_err_t te_dev_init(te_dev_t **device, uint8_t device_num, te_dev_type_t type,
device[idx]->sens = sens[idx] * divider;
device[idx]->type = type;
device[idx]->state = TE_STATE_IDLE;
device[idx]->is_use_last_threshold = false;
esp_err_t ret = touch_pad_config(device[idx]->channel);
TE_CHECK(ret == ESP_OK, ret);
}
@ -513,10 +577,37 @@ void te_dev_deinit(te_dev_t **device, uint8_t device_num)
}
}
static esp_err_t te_config_thresh(touch_pad_t channel_num, uint32_t threshold)
{
esp_err_t ret;
touch_pad_sleep_channel_t sleep_channel_info;
touch_pad_sleep_channel_get_info(&sleep_channel_info);
if (channel_num != sleep_channel_info.touch_num) {
ret = touch_pad_set_thresh(channel_num, threshold);
} else {
ret = touch_pad_sleep_set_threshold(channel_num, threshold);
}
return ret;
}
esp_err_t te_dev_set_threshold(te_dev_t *device)
{
uint32_t smo_val = te_read_smooth_signal(device->channel);
esp_err_t ret = touch_pad_set_thresh(device->channel, device->sens * smo_val);
esp_err_t ret = ESP_OK;
uint32_t smo_val = 0;
if (s_te_obj->sleep_handle && device->is_use_last_threshold) {
if (te_is_touch_dsleep_wakeup()) { //Deep sleep wakeup reset
ret = te_config_thresh(device->channel, s_te_obj->sleep_handle->non_volatile_threshold[device->channel - 1]);
} else { //Other reset
smo_val = te_read_smooth_signal(device->channel);
ret = te_config_thresh(device->channel, device->sens * smo_val);
uint32_t threshold = te_get_threshold(device->channel);
s_te_obj->sleep_handle->non_volatile_threshold[device->channel - 1] = threshold; //Write threshold into RTC Fast Memory
}
} else {
smo_val = te_read_smooth_signal(device->channel);
ret = te_config_thresh(device->channel, device->sens * smo_val);
}
ESP_LOGD(TE_DEBUG_TAG, "channel: %"PRIu8", smo_val: %"PRIu32, device->channel, smo_val);
return ret;
}
@ -648,7 +739,8 @@ static esp_err_t te_sw_init(const touch_elem_sw_config_t *software_init)
const esp_timer_create_args_t te_proc_timer_args = {
.name = "te_proc_timer_cb",
.arg = NULL,
.callback = &te_proc_timer_cb
.callback = &te_proc_timer_cb,
.skip_unhandled_events = true,
};
ret = esp_timer_create(&te_proc_timer_args, &s_te_obj->proc_timer);
TE_CHECK_GOTO(ret == ESP_OK, cleanup);
@ -879,3 +971,147 @@ static void waterproof_guard_update_state(touch_pad_t current_channel, te_state_
}
ESP_LOGD(TE_DEBUG_TAG, "waterproof guard state update %d", guard_device->state);
}
esp_err_t touch_element_enable_light_sleep(const touch_elem_sleep_config_t *sleep_config)
{
TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);
TE_CHECK(s_te_obj->sleep_handle == NULL, ESP_ERR_INVALID_STATE);
uint16_t sample_count = 500;
uint16_t sleep_cycle = 0x0f;
if (sleep_config) {
sample_count = sleep_config->sample_count;
sleep_cycle = sleep_config->sleep_cycle;
}
s_te_obj->sleep_handle = calloc(1, sizeof(struct te_sleep_s));
TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_NO_MEM);
esp_err_t ret = ESP_OK;
touch_pad_sleep_channel_set_work_time(sleep_cycle, sample_count);
TE_CHECK_GOTO(esp_sleep_enable_touchpad_wakeup() == ESP_OK, cleanup);
TE_CHECK_GOTO(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON) == ESP_OK, cleanup);
s_te_obj->sleep_handle->non_volatile_threshold = threshold_shadow;
#ifdef CONFIG_PM_ENABLE
TE_CHECK_GOTO(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "touch_element", &s_te_obj->sleep_handle->pm_lock) == ESP_OK, cleanup);
TE_CHECK_GOTO(esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock) == ESP_OK, cleanup);
#endif
return ESP_OK;
cleanup:
#ifdef CONFIG_PM_ENABLE
if (s_te_obj->sleep_handle->pm_lock != NULL) {
if (esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock) != ESP_OK) {
abort();
}
}
#endif
TE_FREE_AND_NULL(s_te_obj->sleep_handle);
return ret;
}
esp_err_t touch_element_disable_light_sleep(void)
{
TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_INVALID_STATE);
#ifdef CONFIG_PM_ENABLE
if (s_te_obj->sleep_handle->pm_lock != NULL) {
/* Sleep channel is going to uninstall, pm lock is not needed anymore,
but we need to make sure that pm lock has been released before delete it. */
while(esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock) == ESP_OK);
esp_err_t ret = esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock);
TE_CHECK(ret == ESP_OK, ret);
s_te_obj->sleep_handle->pm_lock = NULL;
}
#endif
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TOUCHPAD);
TE_FREE_AND_NULL(s_te_obj->sleep_handle);
return ESP_OK;
}
esp_err_t touch_element_enable_deep_sleep(touch_elem_handle_t wakeup_elem_handle, const touch_elem_sleep_config_t *sleep_config)
{
TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);
TE_CHECK(s_te_obj->sleep_handle == NULL, ESP_ERR_INVALID_STATE);
TE_CHECK(wakeup_elem_handle != NULL, ESP_ERR_INVALID_ARG);
TE_CHECK(sleep_config != NULL, ESP_ERR_INVALID_ARG);
uint16_t sample_count = 500;
uint16_t sleep_cycle = 0x0f;
if (sleep_config) {
sample_count = sleep_config->sample_count;
sleep_cycle = sleep_config->sleep_cycle;
}
s_te_obj->sleep_handle = calloc(1, sizeof(struct te_sleep_s));
TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_NO_MEM);
esp_err_t ret = ESP_OK;
touch_pad_sleep_channel_set_work_time(sleep_cycle, sample_count);
TE_CHECK_GOTO(esp_sleep_enable_touchpad_wakeup() == ESP_OK, cleanup);
TE_CHECK_GOTO(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON) == ESP_OK, cleanup);
s_te_obj->sleep_handle->non_volatile_threshold = threshold_shadow;
#ifdef CONFIG_PM_ENABLE
TE_CHECK_GOTO(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "touch_element", &s_te_obj->sleep_handle->pm_lock) == ESP_OK, cleanup);
TE_CHECK_GOTO(esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock) == ESP_OK, cleanup);
#endif
//Only support one channel/element as the deep sleep wakeup channel/element
TE_CHECK(is_button_object_handle(wakeup_elem_handle), ESP_ERR_NOT_SUPPORTED);
s_te_obj->sleep_handle->wakeup_handle = wakeup_elem_handle;
te_button_handle_t button_handle = wakeup_elem_handle;
ret = touch_pad_sleep_channel_enable(button_handle->device->channel, true);
TE_CHECK(ret == ESP_OK, ret);
return ESP_OK;
cleanup:
#ifdef CONFIG_PM_ENABLE
if (s_te_obj->sleep_handle->pm_lock != NULL) {
if (esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock) != ESP_OK) {
abort();
}
}
#endif
TE_FREE_AND_NULL(s_te_obj->sleep_handle);
return ret;
}
esp_err_t touch_element_disable_deep_sleep(void)
{
TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_INVALID_STATE);
esp_err_t ret;
#ifdef CONFIG_PM_ENABLE
if (s_te_obj->sleep_handle->pm_lock != NULL) {
/* Sleep channel is going to uninstall, pm lock is not needed anymore,
but we need to make sure that pm lock has been released before delete it. */
while(esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock) == ESP_OK);
ret = esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock);
TE_CHECK(ret == ESP_OK, ret);
s_te_obj->sleep_handle->pm_lock = NULL;
}
#endif
te_button_handle_t button_handle = s_te_obj->sleep_handle->wakeup_handle;
ret = touch_pad_sleep_channel_enable(button_handle->device->channel, false);
TE_CHECK(ret == ESP_OK, ret);
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TOUCHPAD);
s_te_obj->sleep_handle->wakeup_handle = NULL;
TE_FREE_AND_NULL(s_te_obj->sleep_handle);
return ESP_OK;
}
esp_err_t touch_element_sleep_enable_wakeup_calibration(touch_elem_handle_t element_handle, bool en)
{
TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG);
if (is_button_object_handle(element_handle)) {
button_enable_wakeup_calibration(element_handle, en);
} else if (is_slider_object_handle(element_handle)) {
slider_enable_wakeup_calibration(element_handle, en);
} else if (is_matrix_object_handle(element_handle)) {
matrix_enable_wakeup_calibration(element_handle, en);
} else {
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -335,6 +335,20 @@ static esp_err_t matrix_object_remove_instance(te_matrix_handle_t matrix_handle)
return ret;
}
bool is_matrix_object_handle(touch_elem_handle_t element_handle)
{
te_matrix_handle_list_t *item;
xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {
if (element_handle == item->matrix_handle) {
xSemaphoreGive(s_te_mat_obj->mutex);
return true;
}
}
xSemaphoreGive(s_te_mat_obj->mutex);
return false;
}
static bool matrix_channel_check(te_matrix_handle_t matrix_handle, touch_pad_t channel_num)
{
te_dev_t *device;
@ -403,6 +417,13 @@ static inline void matrix_dispatch(te_matrix_handle_t matrix_handle, touch_elem_
}
}
void matrix_enable_wakeup_calibration(te_matrix_handle_t matrix_handle, bool en)
{
for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; ++idx) {
matrix_handle->device[idx]->is_use_last_threshold = !en;
}
}
/**
* @brief Scan the matrix channel
*

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -328,6 +328,20 @@ static esp_err_t slider_object_remove_instance(te_slider_handle_t slider_handle)
return ret;
}
bool is_slider_object_handle(touch_elem_handle_t element_handle)
{
te_slider_handle_list_t *item;
xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {
if (element_handle == item->slider_handle) {
xSemaphoreGive(s_te_sld_obj->mutex);
return true;
}
}
xSemaphoreGive(s_te_sld_obj->mutex);
return false;
}
static bool slider_channel_check(te_slider_handle_t slider_handle, touch_pad_t channel_num)
{
te_dev_t *device;
@ -406,6 +420,13 @@ static inline void slider_dispatch(te_slider_handle_t slider_handle, touch_elem_
}
}
void slider_enable_wakeup_calibration(te_slider_handle_t slider_handle, bool en)
{
for (int idx = 0; idx < slider_handle->channel_sum; ++idx) {
slider_handle->device[idx]->is_use_last_threshold = !en;
}
}
/**
* @brief Slider process
*

View File

@ -355,6 +355,34 @@ In code, the waterproof configuration may look like as follows:
...
}
Wakeup from Light/Deep Sleep
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Only Touch Button can be configured as wake up source.
Light or deep sleep are both supported to be waken up by touch sensor. For the light sleep, any installed touch button can wake it up. But only the sleep button can wake up from deep sleep, and the touch sensor will do a calibration immediately, the reference value will be calibrated to a wrong value if our finger doesn't remove timely. Though the wrong reference value will recover after the finger remove away and have no affect to the driver logic, if you don't want to see a wrong reference value while waking up from deep sleep, you can call :cpp:func:`touch_element_sleep_enable_wakeup_calibration` to disable the wakeup calibration.
The Touch Element Wakeup example is available in `example/system/light_sleep` directory.
.. code-block:: c
void app_main()
{
...
touch_element_install();
touch_button_install(); //Initialize the touch button
touch_button_create(&element_handle); //Create a new Touch element
...
// ESP_ERROR_CHECK(touch_element_enable_light_sleep(&sleep_config));
ESP_ERROR_CHECK(touch_element_enable_deep_sleep(button_handle[0], &sleep_config));
// ESP_ERROR_CHECK(touch_element_sleep_enable_wakeup_calibration(button_handle[0], false)); // (optional) Disable wakeup calibration to prevent updating the base line to a wrong value
touch_element_start();
...
}
Application Example
-------------------

View File

@ -61,6 +61,14 @@ Note #2: only UART0 and UART1 (if has) are supported to be configured as wake up
Note #3: due to limitation of the HW, the bytes that received during light sleep is only used for waking up, and it will not be received by UART peripheral or passed to the driver.
### Wake-up by Touch Pad
For this example, pressing any registered touch buttons can wake up the chip.
Note #1: For light sleep, all registered touch buttons can wake up the chip. But only the channel which is configured as wake up channel can wake up the chip from deep sleep.
Note #2: Waking-up by touch pad relies on 'touch_element' driver, which can only support ESP32-S2 and ESP32-S3 currently.
```
Entering light sleep
Returned from light sleep, reason: timer, t=2713 ms, slept for 1999 ms
@ -83,6 +91,11 @@ Entering light sleep
Returned from light sleep, reason: pin, t=12564 ms, slept for 1 ms
Waiting for GPIO9 to go high...
Entering light sleep
...
I (361) touch_wakeup: Button[1] Press
Returned from light sleep, reason: touch, t=14471 ms, slept for 467 ms
Entering light sleep
...
```

View File

@ -3,5 +3,11 @@ set(srcs "light_sleep_example_main.c"
"timer_wakeup.c"
"uart_wakeup.c")
set(TOUCH_ELEMENT_COMPATIBLE_TARGETS "esp32s2" "esp32s3")
if(IDF_TARGET IN_LIST TOUCH_ELEMENT_COMPATIBLE_TARGETS)
list(APPEND srcs "touch_wakeup.c")
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ".")

View File

@ -18,6 +18,10 @@ esp_err_t example_register_timer_wakeup(void);
esp_err_t example_register_uart_wakeup(void);
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
void example_register_touch_wakeup(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -50,6 +50,11 @@ static void light_sleep_task(void *args)
* Otherwise the chip may fall sleep again before running uart task */
vTaskDelay(1);
break;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
case ESP_SLEEP_WAKEUP_TOUCHPAD:
wakeup_reason = "touch";
break;
#endif
default:
wakeup_reason = "other";
break;
@ -72,6 +77,10 @@ void app_main(void)
example_register_timer_wakeup();
/* Enable wakeup from light sleep by uart */
example_register_uart_wakeup();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
/* Enable wakeup from light sleep by touch element */
example_register_touch_wakeup();
#endif
xTaskCreate(light_sleep_task, "light_sleep_task", 4096, NULL, 6, NULL);
}

View File

@ -0,0 +1,101 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "touch_element/touch_button.h"
static const char *TAG = "touch_wakeup";
#define TOUCH_BUTTON_NUM 5
/* Touch buttons handle */
static touch_button_handle_t button_handle[TOUCH_BUTTON_NUM];
/* Touch buttons channel array */
static const touch_pad_t channel_array[TOUCH_BUTTON_NUM] = {
TOUCH_PAD_NUM1,
TOUCH_PAD_NUM2,
TOUCH_PAD_NUM3,
TOUCH_PAD_NUM4,
TOUCH_PAD_NUM5,
};
/* Touch buttons channel sensitivity array */
static const float channel_sens_array[TOUCH_BUTTON_NUM] = {
0.03F,
0.03F,
0.03F,
0.03F,
0.03F,
};
/* Button event handler task */
static void button_handler_task(void *arg)
{
(void) arg; //Unused
touch_elem_message_t element_message;
while (1) {
/* Waiting for touch element messages */
touch_element_message_receive(&element_message, portMAX_DELAY);
if (element_message.element_type != TOUCH_ELEM_TYPE_BUTTON) {
continue;
}
/* Decode message */
const touch_button_message_t *button_message = touch_button_get_message(&element_message);
if (button_message->event == TOUCH_BUTTON_EVT_ON_PRESS) {
ESP_LOGI(TAG, "Button[%"PRIu32"] Press", (uint32_t)element_message.arg);
} else if (button_message->event == TOUCH_BUTTON_EVT_ON_RELEASE) {
ESP_LOGI(TAG, "Button[%"PRIu32"] Release", (uint32_t)element_message.arg);
} else if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {
ESP_LOGI(TAG, "Button[%"PRIu32"] LongPress", (uint32_t)element_message.arg);
}
}
vTaskDelete(NULL);
}
esp_err_t example_register_touch_wakeup(void)
{
/* Initialize Touch Element library */
touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
ESP_ERROR_CHECK(touch_element_install(&global_config));
ESP_LOGI(TAG, "Touch element library installed");
touch_button_global_config_t button_global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
ESP_ERROR_CHECK(touch_button_install(&button_global_config));
ESP_LOGI(TAG, "Touch button installed");
for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
touch_button_config_t button_config = {
.channel_num = channel_array[i],
.channel_sens = channel_sens_array[i]
};
/* Create Touch buttons */
ESP_ERROR_CHECK(touch_button_create(&button_config, &button_handle[i]));
/* Set EVENT as the dispatch method */
ESP_ERROR_CHECK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
/* Subscribe touch button events (On Press, On Release, On LongPress) */
ESP_ERROR_CHECK(touch_button_subscribe_event(button_handle[i],
TOUCH_ELEM_EVENT_ON_PRESS |
TOUCH_ELEM_EVENT_ON_RELEASE |
TOUCH_ELEM_EVENT_ON_LONGPRESS,
(void *)channel_array[i]));
}
ESP_LOGI(TAG, "Touch buttons created");
touch_elem_sleep_config_t sleep_config = {
.sample_count = global_config.hardware.sample_count,
.sleep_cycle = global_config.hardware.sleep_cycle,
};
/* Enable one of registered touch button as light/deep sleep wake-up source */
ESP_ERROR_CHECK(touch_element_enable_light_sleep(&sleep_config));
touch_element_start();
xTaskCreate(&button_handler_task, "button_handler_task", 4 * 1024, NULL, 6, NULL);
ESP_LOGI(TAG, "touch wakeup source is ready");
return ESP_OK;
}