diff --git a/components/touch_element/Kconfig b/components/touch_element/Kconfig new file mode 100644 index 0000000000..3aafd12e64 --- /dev/null +++ b/components/touch_element/Kconfig @@ -0,0 +1,10 @@ +menu "Touch Element" + + config TE_SKIP_DSLEEP_WAKEUP_CALIBRATION + bool "Enable skip deep sleep wakeup calibration" + default n + help + This option allows to store all Touch Sensor channels' threshold into RTC Fast Memory. So that Touch Sensor + threshold will only be configured once after Power-on Reset. + +endmenu \ No newline at end of file diff --git a/components/touch_element/include/touch_element/touch_element.h b/components/touch_element/include/touch_element/touch_element.h index 429fc2503f..c172d853b7 100644 --- a/components/touch_element/include/touch_element/touch_element.h +++ b/components/touch_element/include/touch_element/touch_element.h @@ -256,6 +256,21 @@ 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); +typedef struct { + uint16_t scan_time; + uint16_t sleep_time; +} touch_elem_sleep_config_t; + +esp_err_t touch_element_sleep_install(touch_elem_sleep_config_t *sleep_config); +void touch_element_sleep_uninstall(void); +esp_err_t touch_element_sleep_add_wakeup(touch_elem_handle_t element_handle); +esp_err_t touch_element_sleep_remove_wakeup(touch_elem_handle_t element_handle); +esp_err_t touch_element_sleep_add_wakeup_channel(touch_pad_t wakeup_channel); +esp_err_t touch_element_sleep_remove_wakeup_channel(touch_pad_t wakeup_channel); +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION +esp_err_t touch_element_sleep_config_wakeup_calibration(touch_elem_handle_t element_handle, bool en); +#endif + #ifdef __cplusplus } #endif diff --git a/components/touch_element/include/touch_element/touch_element_private.h b/components/touch_element/include/touch_element/touch_element_private.h index 49971ae2d4..fb287d33a1 100644 --- a/components/touch_element/include/touch_element/touch_element_private.h +++ b/components/touch_element/include/touch_element/touch_element_private.h @@ -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,9 @@ 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 +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION + bool is_use_last_threshold; +#endif } te_dev_t; typedef enum { @@ -69,6 +74,7 @@ typedef struct { esp_err_t (*set_threshold) (void); void (*process_state) (void); void (*update_state) (touch_pad_t, te_state_t); + touch_elem_handle_t (*search_channel_handle) (touch_pad_t); } te_object_methods_t; /* -------------------------------------------- Waterproof basic type --------------------------------------------- */ @@ -79,6 +85,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; + esp_pm_lock_handle_t pm_lock; +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION + uint32_t *non_volatile_threshold; +#endif +}; + +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 +186,18 @@ 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); +inline touch_pad_t te_get_sleep_channel(void); + +bool button_object_handle_check(touch_elem_handle_t element_handle); +bool slider_object_handle_check(touch_elem_handle_t element_handle); +bool matrix_object_handle_check(touch_elem_handle_t element_handle); + +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION +void button_config_wakeup_calibration(te_button_handle_t button_handle, bool en); +void slider_config_wakeup_calibration(te_slider_handle_t slider_handle, bool en); +void matrix_config_wakeup_calibration(te_matrix_handle_t matrix_handle, bool en); +#endif /* ------------------------------------------------------------------------------------------------------------------ */ #ifdef __cplusplus diff --git a/components/touch_element/touch_button.c b/components/touch_element/touch_button.c index 7a93d03f93..cf775435bd 100644 --- a/components/touch_element/touch_button.c +++ b/components/touch_element/touch_button.c @@ -40,6 +40,7 @@ static bool button_object_check_channel(touch_pad_t channel_num); static esp_err_t button_object_set_threshold(void); static void button_object_process_state(void); static void button_object_update_state(touch_pad_t channel_num, te_state_t channel_state); +static te_button_handle_t button_object_search_channel_handle(touch_pad_t channel_num); /* ------------------------------------------------------------------------------------------------------------------ */ esp_err_t touch_button_install(const touch_button_global_config_t *global_config) @@ -268,6 +269,21 @@ static void button_object_update_state(touch_pad_t channel_num, te_state_t chann } } +static te_button_handle_t button_object_search_channel_handle(touch_pad_t channel_num) +{ + te_button_handle_list_t *item; + te_button_handle_t button_handle = NULL; + SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) { + touch_pad_t button_channel = item->button_handle->device->channel; + if (channel_num == button_channel) { + button_handle = item->button_handle; + break; + } + } + + return button_handle; +} + static esp_err_t button_object_add_instance(te_button_handle_t button_handle) { te_button_handle_list_t *item = (te_button_handle_list_t *)calloc(1, sizeof(te_button_handle_list_t)); @@ -296,6 +312,20 @@ static esp_err_t button_object_remove_instance(te_button_handle_t button_handle) return ret; } +bool button_object_handle_check(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 +376,13 @@ static inline void button_dispatch(te_button_handle_t button_handle, touch_elem_ } } +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION +void button_config_wakeup_calibration(te_button_handle_t button_handle, bool en) +{ + button_handle->device->is_use_last_threshold = en; +} +#endif + /** * @brief Button process * diff --git a/components/touch_element/touch_element.c b/components/touch_element/touch_element.c index ec465c95b3..90c888ba1a 100644 --- a/components/touch_element/touch_element.c +++ b/components/touch_element/touch_element.c @@ -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 "hal/touch_sensor_hal.h" //TODO: remove hal #include "touch_element/touch_element_private.h" +#include "esp32s2/rom/rtc.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,15 +91,21 @@ 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) SemaphoreHandle_t mutex; //Global resource mutex bool is_set_threshold; //Threshold configuration state bit uint32_t denoise_channel_raw; //De-noise channel(TO) raw signal +// touch_elem_sleep_config_t *sleep_config; +// esp_pm_lock_handle_t pm_lock_handle; } te_obj_t; static te_obj_t *s_te_obj = NULL; +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION +RTC_FAST_ATTR uint32_t threshold_shadow[TOUCH_PAD_MAX - 1] = {0}; +#endif /** * Internal de-noise channel(Touch channel 0) equivalent capacitance table, depends on hardware design @@ -313,6 +323,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) +{ + RESET_REASON rtc_reset_reason = rtc_get_reset_reason(0); + if (rtc_reset_reason != DEEPSLEEP_RESET) { + return false; + } + esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); + return wakeup_reason == ESP_SLEEP_WAKEUP_TOUCHPAD; +} + +inline 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 +363,39 @@ 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) { + esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock); + } + 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) { @@ -355,7 +412,7 @@ 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 +// 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 +442,19 @@ 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 (te_intr_msg.intr_type == TE_INTR_RELEASE) { + if (s_te_obj->sleep_handle != NULL) { + esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock); + } + } } 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) { + esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock); + } } if (waterproof_check_state()) { te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle; @@ -500,6 +565,9 @@ 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; +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION + device[idx]->is_use_last_threshold = false; +#endif esp_err_t ret = touch_pad_config(device[idx]->channel); TE_CHECK(ret == ESP_OK, ret); } @@ -513,10 +581,48 @@ void te_dev_deinit(te_dev_t **device, uint8_t device_num) } } +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; +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION + if (s_te_obj->sleep_handle == NULL) { + ESP_LOGE(TE_TAG, "Touch Element sleep is not installed"); + return ESP_ERR_INVALID_STATE; + } + if (device->is_use_last_threshold) { + if (te_is_touch_dsleep_wakeup()) { //Deep sleep wakeup reset + touch_pad_t sleep_channel = te_get_sleep_channel(); + ets_printf("----config rtc %ld %ld\n", s_te_obj->sleep_handle->non_volatile_threshold[device->channel - 1], sleep_channel); + 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); + } + +#else + smo_val = te_read_smooth_signal(device->channel); + ret = te_config_thresh(device->channel, device->sens * smo_val); +#endif ESP_LOGD(TE_DEBUG_TAG, "channel: %"PRIu8", smo_val: %"PRIu32, device->channel, smo_val); return ret; } @@ -648,7 +754,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 +986,145 @@ 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_sleep_install(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(sleep_config != NULL, ESP_ERR_INVALID_ARG); + + s_te_obj->sleep_handle = calloc(1, sizeof(struct te_sleep_s)); + if (s_te_obj->sleep_handle == NULL) { + return ESP_ERR_NO_MEM; + } + + esp_err_t ret; + touch_pad_sleep_channel_set_work_time(sleep_config->sleep_time, sleep_config->scan_time); + ret = esp_sleep_enable_touchpad_wakeup(); + TE_CHECK_GOTO(ret == ESP_OK, cleanup); + +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION + ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON); + TE_CHECK_GOTO(ret == ESP_OK, cleanup); + s_te_obj->sleep_handle->non_volatile_threshold = threshold_shadow; +#endif + + ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "touch_element", &s_te_obj->sleep_handle->pm_lock); + TE_CHECK_GOTO(ret == ESP_OK, cleanup); + ret = esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock); + TE_CHECK_GOTO(ret == ESP_OK, cleanup); + return ESP_OK; + +cleanup: + if (s_te_obj->sleep_handle->pm_lock != NULL) { + esp_err_t del_ret = esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock); + if (del_ret != ESP_OK) { + abort(); + } + } + TE_FREE_AND_NULL(s_te_obj->sleep_handle); + return ret; +} + +void touch_element_sleep_uninstall(void) +{ + esp_err_t ret; + if (s_te_obj->sleep_handle->pm_lock != NULL) { + ret = esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock); + if (ret != ESP_OK) { + abort(); + } + } + if (s_te_obj->sleep_handle->wakeup_handle != NULL) { + te_button_handle_t button_handle = s_te_obj->sleep_handle->wakeup_handle; + ret = touch_pad_sleep_channel_enable(button_handle->device->channel, false); + if (ret != ESP_OK) { + abort(); + } + } + s_te_obj->sleep_handle->pm_lock = NULL; + s_te_obj->sleep_handle->wakeup_handle = NULL; + TE_FREE_AND_NULL(s_te_obj->sleep_handle); +} + +esp_err_t touch_element_sleep_add_wakeup(touch_elem_handle_t element_handle) +{ + TE_CHECK(s_te_obj->sleep_handle != NULL, ESP_ERR_INVALID_STATE); + TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG); + if (s_te_obj->sleep_handle->wakeup_handle != NULL) { + ESP_LOGE(TE_TAG, "sleep not null"); + return ESP_ERR_NOT_SUPPORTED; //Only support one channel/element as the deep sleep wakeup channel/element + } + if (!button_object_handle_check(element_handle)) { + ESP_LOGE(TE_TAG, "not button handle"); + return ESP_ERR_NOT_SUPPORTED; //Only support button element as the deep sleep wakeup channel + } + s_te_obj->sleep_handle->wakeup_handle = element_handle; + te_button_handle_t button_handle = element_handle; + esp_err_t ret = touch_pad_sleep_channel_enable(button_handle->device->channel, true); + if (ret != ESP_OK) { + return ret; + } + return ESP_OK; +} + +esp_err_t touch_element_sleep_remove_wakeup(touch_elem_handle_t element_handle) +{ + TE_CHECK(s_te_obj->sleep_handle != NULL, ESP_ERR_INVALID_STATE); + TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG); + TE_CHECK(s_te_obj->sleep_handle->wakeup_handle != NULL && + s_te_obj->sleep_handle->wakeup_handle == element_handle, + ESP_ERR_NOT_FOUND); + s_te_obj->sleep_handle->wakeup_handle = NULL; + + te_button_handle_t button_handle = element_handle; //Now we are sure it's absolutely a button element + esp_err_t ret = touch_pad_sleep_channel_enable(button_handle->device->channel, false); + if (ret != ESP_OK) { + return ret; + } + return ESP_OK; +} + +esp_err_t touch_element_sleep_add_wakeup_channel(touch_pad_t wakeup_channel) +{ + TE_CHECK(s_te_obj->sleep_handle != NULL, ESP_ERR_INVALID_STATE); + TE_CHECK(wakeup_channel > TOUCH_PAD_NUM0 && wakeup_channel < TOUCH_PAD_MAX, ESP_ERR_INVALID_ARG); + touch_pad_sleep_channel_t sleep_channel_info; + touch_pad_sleep_channel_get_info(&sleep_channel_info); + if (sleep_channel_info.touch_num == wakeup_channel) { + return ESP_ERR_INVALID_ARG; + } + esp_err_t ret = touch_pad_sleep_channel_enable(wakeup_channel, true); + if (ret != ESP_OK) { + return ret; + } + return ESP_OK; +} + +esp_err_t touch_element_sleep_remove_wakeup_channel(touch_pad_t wakeup_channel) +{ + TE_CHECK(s_te_obj->sleep_handle != NULL, ESP_ERR_INVALID_STATE); + TE_CHECK(wakeup_channel > TOUCH_PAD_NUM0 && wakeup_channel < TOUCH_PAD_MAX, ESP_ERR_INVALID_ARG); + esp_err_t ret = touch_pad_sleep_channel_enable(wakeup_channel, false); + if (ret != ESP_OK) { + return ret; + } + return ESP_OK; +} + +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION +esp_err_t touch_element_sleep_config_wakeup_calibration(touch_elem_handle_t element_handle, bool en) +{ + TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG); + if (button_object_handle_check(element_handle)) { + button_config_wakeup_calibration(element_handle, en); + } else if (slider_object_handle_check(element_handle)) { + slider_config_wakeup_calibration(element_handle, en); + } else if (matrix_object_handle_check(element_handle)) { + matrix_config_wakeup_calibration(element_handle, en); + } else { + return ESP_ERR_NOT_FOUND; + } + return ESP_OK; +} +#endif \ No newline at end of file diff --git a/components/touch_element/touch_matrix.c b/components/touch_element/touch_matrix.c index 8b61b07baf..2cbdb7b41c 100644 --- a/components/touch_element/touch_matrix.c +++ b/components/touch_element/touch_matrix.c @@ -43,6 +43,7 @@ static bool matrix_object_check_channel(touch_pad_t channel_num); static esp_err_t matrix_object_set_threshold(void); static void matrix_object_process_state(void); static void matrix_object_update_state(touch_pad_t channel_num, te_state_t channel_state); +static te_matrix_handle_t matrix_object_search_channel_handle(touch_pad_t channel_num); /* ------------------------------------------------------------------------------------------------------------------ */ esp_err_t touch_matrix_install(const touch_matrix_global_config_t *global_config) @@ -307,6 +308,24 @@ static void matrix_object_update_state(touch_pad_t channel_num, te_state_t chann } } +static te_matrix_handle_t matrix_object_search_channel_handle(touch_pad_t channel_num) +{ + te_matrix_handle_list_t *item; + te_matrix_handle_t matrix_handle = NULL; + SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) { + for (int idx = 0; idx < item->matrix_handle->x_channel_num + item->matrix_handle->y_channel_num; idx++) { + touch_pad_t matrix_channel = item->matrix_handle->device[idx]->channel; + if (channel_num == matrix_channel) { + matrix_handle = item->matrix_handle; + goto found; + } + } + } + +found: + return matrix_handle; +} + static esp_err_t matrix_object_add_instance(te_matrix_handle_t matrix_handle) { te_matrix_handle_list_t *item = (te_matrix_handle_list_t *)calloc(1, sizeof(te_matrix_handle_list_t)); @@ -335,6 +354,20 @@ static esp_err_t matrix_object_remove_instance(te_matrix_handle_t matrix_handle) return ret; } +bool matrix_object_handle_check(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 +436,15 @@ static inline void matrix_dispatch(te_matrix_handle_t matrix_handle, touch_elem_ } } +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION +void matrix_config_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; + } +} +#endif + /** * @brief Scan the matrix channel * diff --git a/components/touch_element/touch_slider.c b/components/touch_element/touch_slider.c index 15acaa8802..f5a35c5dc2 100644 --- a/components/touch_element/touch_slider.c +++ b/components/touch_element/touch_slider.c @@ -49,6 +49,7 @@ static bool slider_object_check_channel(touch_pad_t channel_num); static esp_err_t slider_object_set_threshold(void); static void slider_object_process_state(void); static void slider_object_update_state(touch_pad_t channel_num, te_state_t channel_state); +static te_slider_handle_t slider_object_search_channel_handle(touch_pad_t channel_num); /* ------------------------------------------------------------------------------------------------------------------ */ esp_err_t touch_slider_install(const touch_slider_global_config_t *global_config) @@ -300,6 +301,24 @@ static void slider_object_update_state(touch_pad_t channel_num, te_state_t chann } } +static te_slider_handle_t slider_object_search_channel_handle(touch_pad_t channel_num) +{ + te_slider_handle_list_t *item; + te_slider_handle_t slider_handle = NULL; + SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) { + for (int idx = 0; idx < item->slider_handle->channel_sum; idx++) { + touch_pad_t slider_channel = item->slider_handle->device[idx]->channel; + if (channel_num == slider_channel) { + slider_handle = item->slider_handle; + goto found; + } + } + } + +found: + return slider_handle; +} + static esp_err_t slider_object_add_instance(te_slider_handle_t slider_handle) { te_slider_handle_list_t *item = (te_slider_handle_list_t *)calloc(1, sizeof(te_slider_handle_list_t)); @@ -328,6 +347,20 @@ static esp_err_t slider_object_remove_instance(te_slider_handle_t slider_handle) return ret; } +bool slider_object_handle_check(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 +439,15 @@ static inline void slider_dispatch(te_slider_handle_t slider_handle, touch_elem_ } } +#ifdef CONFIG_TE_SKIP_DSLEEP_WAKEUP_CALIBRATION +void slider_config_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; + } +} +#endif + /** * @brief Slider process * diff --git a/examples/peripherals/touch_element/touch_element_sleep/CMakeLists.txt b/examples/peripherals/touch_element/touch_element_sleep/CMakeLists.txt new file mode 100644 index 0000000000..1b4cd9e672 --- /dev/null +++ b/examples/peripherals/touch_element/touch_element_sleep/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(touch_element_sleep) diff --git a/examples/peripherals/touch_element/touch_element_sleep/main/CMakeLists.txt b/examples/peripherals/touch_element/touch_element_sleep/main/CMakeLists.txt new file mode 100644 index 0000000000..5ad924d077 --- /dev/null +++ b/examples/peripherals/touch_element/touch_element_sleep/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "touch_element_sleep.c" + INCLUDE_DIRS ".") diff --git a/examples/peripherals/touch_element/touch_element_sleep/main/Kconfig.projbuild b/examples/peripherals/touch_element/touch_element_sleep/main/Kconfig.projbuild new file mode 100644 index 0000000000..2518e7429a --- /dev/null +++ b/examples/peripherals/touch_element/touch_element_sleep/main/Kconfig.projbuild @@ -0,0 +1,15 @@ +menu "Example Configuration" + + choice TOUCH_SENSOR_EXAMPLE_TYPE + bool "Select touch element dispatch method" + default TOUCH_ELEM_EVENT + help + Select touch element dispatch method (event task or callback) for this example. + + config TOUCH_ELEM_EVENT + bool "Dispatch by event task" + config TOUCH_ELEM_CALLBACK + bool "Dispatch by callback" + endchoice + +endmenu diff --git a/examples/peripherals/touch_element/touch_element_sleep/main/touch_element_sleep.c b/examples/peripherals/touch_element/touch_element_sleep/main/touch_element_sleep.c new file mode 100644 index 0000000000..d0777077b5 --- /dev/null +++ b/examples/peripherals/touch_element/touch_element_sleep/main/touch_element_sleep.c @@ -0,0 +1,143 @@ +/* Touch Sensor - Example + + For other examples please check: + https://github.com/espressif/esp-idf/tree/master/examples + + See README.md file to get detailed usage of this example. + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "touch_element/touch_button.h" +#include "esp_log.h" +#include "esp_sleep.h" +#include "soc/soc.h" +#include "soc/rtc_cntl_reg.h" +#include "esp_pm.h" + +static const char *TAG = "Touch Button Example"; +#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, +}; + +#ifdef CONFIG_TOUCH_ELEM_EVENT +/* 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[%d] Press", (uint32_t)element_message.arg); + } else if (button_message->event == TOUCH_BUTTON_EVT_ON_RELEASE) { + ESP_LOGI(TAG, "Button[%d] Release", (uint32_t)element_message.arg); + } else if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) { + ESP_LOGI(TAG, "Button[%d] LongPress", (uint32_t)element_message.arg); + } + } +} +#elif CONFIG_TOUCH_ELEM_CALLBACK +/* Button callback routine */ +static void button_handler(touch_button_handle_t out_handle, touch_button_message_t *out_message, void *arg) +{ + (void) out_handle; //Unused + if (out_message->event == TOUCH_BUTTON_EVT_ON_PRESS) { + ESP_LOGI(TAG, "Button[%d] Press", (uint32_t)arg); + if (out_handle == button_handle[0]) { +// esp_deep_sleep_start(); + } else if (out_handle == button_handle[1]) { + esp_deep_sleep_start(); + } + } else if (out_message->event == TOUCH_BUTTON_EVT_ON_RELEASE) { + ESP_LOGI(TAG, "Button[%d] Release", (uint32_t)arg); + } else if (out_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) { + ESP_LOGI(TAG, "Button[%d] LongPress", (uint32_t)arg); + } +} +#endif + +void app_main(void) +{ +// esp_pm_config_esp32s2_t pm_config = { +// .max_freq_mhz = 160, +// .min_freq_mhz = 160, +// .light_sleep_enable = true +// }; +// ESP_ERROR_CHECK( esp_pm_configure(&pm_config) ); + /* 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])); + /* 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])); +#ifdef CONFIG_TOUCH_ELEM_EVENT + /* Set EVENT as the dispatch method */ + ESP_ERROR_CHECK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT)); +#elif CONFIG_TOUCH_ELEM_CALLBACK + /* Set EVENT as the dispatch method */ + ESP_ERROR_CHECK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK)); + /* Register a handler function to handle event messages */ + ESP_ERROR_CHECK(touch_button_set_callback(button_handle[i], button_handler)); +#endif + /* Set LongPress event trigger threshold time */ + ESP_ERROR_CHECK(touch_button_set_longpress(button_handle[i], 1000)); + } + ESP_LOGI(TAG, "Touch buttons created"); + touch_elem_sleep_config_t sleep_config = { + .scan_time = global_config.hardware.sample_count, + .sleep_time = global_config.hardware.sleep_cycle, + }; + ESP_ERROR_CHECK(touch_element_sleep_install(&sleep_config)); + ESP_ERROR_CHECK(touch_element_sleep_add_wakeup(button_handle[0])); + ESP_ERROR_CHECK(touch_element_sleep_config_wakeup_calibration(button_handle[0], true)); + touch_pad_sleep_channel_t sleep_channel_info; + touch_pad_sleep_channel_get_info(&sleep_channel_info); + printf("----------%d\n", sleep_channel_info.touch_num); + touch_element_start(); + ESP_LOGI(TAG, "Touch element library start"); + vTaskDelay(pdMS_TO_TICKS(1000)); +} diff --git a/examples/peripherals/touch_sensor/touch_sensor_v2/touch_pad_interrupt/main/tp_interrupt_main.c b/examples/peripherals/touch_sensor/touch_sensor_v2/touch_pad_interrupt/main/tp_interrupt_main.c index 1285558143..20271deafe 100644 --- a/examples/peripherals/touch_sensor/touch_sensor_v2/touch_pad_interrupt/main/tp_interrupt_main.c +++ b/examples/peripherals/touch_sensor/touch_sensor_v2/touch_pad_interrupt/main/tp_interrupt_main.c @@ -144,6 +144,8 @@ static void tp_example_read_task(void *pvParameter) } } +#include "esp_sleep.h" +#include "hal/touch_sensor_ll.h" void app_main(void) { if (que_touch == NULL) { @@ -209,4 +211,11 @@ void app_main(void) // Start a task to show what pads have been touched xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 4096, NULL, 5, NULL); + + touch_ll_sleep_low_power(true); + while (1) { + esp_sleep_enable_timer_wakeup(100 * 1000); + esp_light_sleep_start(); + vTaskDelay(pdMS_TO_TICKS(100)); + } }