From 06a099b6fb267340122b4e290e3f6ff1c1658c28 Mon Sep 17 00:00:00 2001 From: Hu Rui Date: Tue, 1 Sep 2026 20:08:37 +0800 Subject: [PATCH] test(touch): add touch sensor light sleep wake-up test --- .../test_apps/.build-test-rules.yml | 1 + .../test_apps/touch_sens/main/CMakeLists.txt | 16 +++ .../test_apps/touch_sens/main/test_helper.h | 38 +++++ .../main/test_touch_sens_common.cpp | 136 +++++++++++++++--- .../test_apps/touch_sens/main/ulp_fsm/main.S | 50 +++++++ .../test_apps/touch_sens/main/ulp_lpc/main.c | 23 +++ .../test_apps/touch_sens/main/ulp_rv/main.c | 22 +++ .../test_apps/touch_sens/pytest_touch_sens.py | 2 +- .../touch_sens/sdkconfig.defaults.esp32 | 2 + .../touch_sens/sdkconfig.defaults.esp32p4 | 2 + .../touch_sens/sdkconfig.defaults.esp32s2 | 2 + .../touch_sens/sdkconfig.defaults.esp32s3 | 2 + .../touch_sens/sdkconfig.defaults.esp32s31 | 2 + 13 files changed, 275 insertions(+), 23 deletions(-) create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/main/test_helper.h create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_fsm/main.S create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_lpc/main.c create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_rv/main.c create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32 create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s2 create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s31 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 236708a8274..be9a1c7cfb3 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 @@ -5,4 +5,5 @@ components/esp_driver_touch_sens/test_apps/touch_sens: - esp_driver_touch_sens - esp_hal_touch_sens - esp_hw_support + - ulp - soc diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt b/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt index 4837276cb6d..1c52f6dce95 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt @@ -3,4 +3,20 @@ set(srcs "test_app_main.c" "test_touch_sens_common.cpp") idf_component_register(SRCS ${srcs} INCLUDE_DIRS "." PRIV_REQUIRES unity esp_driver_touch_sens esp_psram + REQUIRES ulp WHOLE_ARCHIVE) + +if(CONFIG_IDF_TARGET_ESP32) + set(ulp_sources "ulp_fsm/main.S") +elseif(CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3) + set(ulp_sources "ulp_rv/main.c") +elseif(CONFIG_IDF_TARGET_ESP32P4 OR CONFIG_IDF_TARGET_ESP32S31) + set(ulp_sources "ulp_lpc/main.c") +endif() + +if(ulp_sources) + set(ulp_app_name ulp_${COMPONENT_NAME}) + set(ulp_exp_dep_srcs "test_touch_sens_common.cpp") + + ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}") +endif() diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_helper.h b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_helper.h new file mode 100644 index 00000000000..3e59735a037 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_helper.h @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#define TEST_TOUCH_WAKEUP_CHANNEL 3 +#define TEST_TOUCH_SIMULATE_HOLD_TIME_US 10000 + +#ifndef __ASSEMBLER__ +#include +#include +#include "soc/soc_caps.h" +#include "hal/touch_sensor_ll.h" + +static inline void test_touch_simulate_touch(int chan_id, bool active) +{ +#if SOC_IS(ESP32S31) + /* ESP32-S31 has no internal capacitor, emulate touch by changing charging cycles. */ + for (int i = 0; i < TOUCH_SAMPLE_CFG_NUM; i++) { + uint16_t ct; + touch_ll_get_charge_times(i, &ct); + /** + * assume original ct = 8q + r, 0 <= r < 8 + * activated ct = 8q + r + q = 9q + r + * deactivated ct = (9q + r) - q = 8q + r = original ct + */ + ct = active ? ct + (ct >> 3) : ct - (ct / 9); + touch_ll_set_charge_times(i, ct); + } +#elif SOC_TOUCH_SENSOR_VERSION <= 2 + touch_ll_set_charge_speed(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 +} +#endif // __ASSEMBLER__ diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.cpp b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.cpp index 5f5753ecffa..6db53fc066e 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.cpp +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.cpp @@ -13,6 +13,17 @@ #include "esp_log.h" #include "esp_attr.h" #include "esp_heap_caps.h" +#include "test_helper.h" +#include "esp_sleep.h" + +#if SOC_LP_CORE_SUPPORTED +#include "ulp_lp_core.h" +#elif SOC_RISCV_COPROC_SUPPORTED +#include "ulp_riscv.h" +#elif SOC_ULP_FSM_SUPPORTED +#include "ulp.h" +#include "ulp_main.h" +#endif /**************************** Configurations ****************************/ @@ -98,26 +109,6 @@ static bool TEST_TCH_IRAM_ATTR s_test_touch_on_inactive_callback(touch_sensor_ha /**************************** Helper Functions ****************************/ -static void s_test_touch_simulate_touch(touch_channel_handle_t touch_chan, bool active) -{ -#if CONFIG_IDF_TARGET_ESP32S31 - /* ESP32-S31 has no internal capacitor, emulate touch by changing charging cycles. */ - for (int i = 0; i < TOUCH_SAMPLE_CFG_NUM; i++) { - uint32_t charge_times = s_sample_cfg[i].charge_times; - if (active) { - charge_times += charge_times >> 1; // 1.5x - } - touch_ll_set_charge_times(i, charge_times); - } -#elif 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_do_initial_scanning(touch_sensor_handle_t touch, int scan_times) { /* Enable the touch sensor to do the initial scanning, so that to initialize the channel data */ @@ -261,13 +252,13 @@ TEST_CASE("touch_sens_active_inactive_test", "[touch]") // Read data before touched s_test_touch_log_data(touch_chan, "Data Before"); // Simulate touch - s_test_touch_simulate_touch(touch_chan, true); + test_touch_simulate_touch(chan_ids[0], true); vTaskDelay(pdMS_TO_TICKS(100)); // Read data after touched s_test_touch_log_data(touch_chan, "Data After "); // Simulate release - s_test_touch_simulate_touch(touch_chan, false); + test_touch_simulate_touch(chan_ids[0], false); vTaskDelay(pdMS_TO_TICKS(100)); } printf("\n"); @@ -322,3 +313,104 @@ TEST_CASE("touch_sens_current_meas_channel_test", "[touch]") TEST_ESP_OK(touch_sensor_del_controller(touch)); } #endif // SOC_TOUCH_SENSOR_VERSION > 1 + +/** + * @note ESP32-P4 + sleep + PSRAM + O0 optimization can cause SPM overflow. + * Therefore, disable the sleep test when iram_safe is enabled. + */ +#if SOC_ULP_SUPPORTED && !(CONFIG_TOUCH_ISR_IRAM_SAFE && SOC_IS(ESP32P4)) +extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); +extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); + +#define TEST_ULP_WAKEUP_PERIOD_US (1 * 1000 * 1000) + +/** + * @note The ULP start APIs (ulp_xxx_run) start a timer to trigger ULP execution periodically, + * but do not guarantee whether the ULP will run once immediately. Therefore, each ULP + * program includes logic to skip the first run, ensuring that the touch event is simulated + * only after entering sleep. + */ +static void s_test_touch_start_ulp(void) +{ +#if SOC_LP_CORE_SUPPORTED + TEST_ESP_OK(ulp_lp_core_load_binary(ulp_main_bin_start, ulp_main_bin_end - ulp_main_bin_start)); + ulp_lp_core_cfg_t cfg = {}; + cfg.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER; + cfg.lp_timer_sleep_duration_us = TEST_ULP_WAKEUP_PERIOD_US; + TEST_ESP_OK(ulp_lp_core_run(&cfg)); +#elif SOC_RISCV_COPROC_SUPPORTED + TEST_ESP_OK(ulp_riscv_load_binary(ulp_main_bin_start, ulp_main_bin_end - ulp_main_bin_start)); + TEST_ESP_OK(ulp_set_wakeup_period(0, TEST_ULP_WAKEUP_PERIOD_US)); + TEST_ESP_OK(ulp_riscv_run()); +#elif SOC_ULP_FSM_SUPPORTED + TEST_ESP_OK(ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t))); + TEST_ESP_OK(ulp_set_wakeup_period(0, TEST_ULP_WAKEUP_PERIOD_US)); + TEST_ESP_OK(ulp_run(&ulp_entry - RTC_SLOW_MEM)); +#else +#error "No supported ULP" +#endif +} + +TEST_CASE("touch_sens_light_sleep_wakeup_test", "[touch]") +{ + test_touch_fixture_t *fixture = (test_touch_fixture_t *)alloca( + sizeof(test_touch_fixture_t) + sizeof(touch_channel_handle_t) * 2); + const uint32_t chan_ids[] = {TEST_TOUCH_WAKEUP_CHANNEL, TEST_TOUCH_WAKEUP_CHANNEL + 1}; + test_touch_cb_data_t cb_data = {}; + s_test_touch_fixture_init(fixture, 2, chan_ids, &cb_data); + touch_sensor_handle_t touch = fixture->sensor; + +#if SOC_TOUCH_SENSOR_VERSION == 3 + /** + * @note For TOUCH_SENSOR_VERSION == 3, since we cannot simulate an isolated trigger on a single channel, + * the thresholds for all other channels are raised to the maximum to prevent them from being triggered. + */ + touch_channel_config_t inactive_cfg; + for (int i = 0; i < TOUCH_SAMPLE_CFG_NUM; i++) { + inactive_cfg.active_thresh[i] = TOUCH_LL_ACTIVE_THRESH_MAX; + } + TEST_ESP_OK(touch_sensor_reconfig_channel(fixture->channels[1], &inactive_cfg)); +#endif + + touch_sleep_config_t sleep_cfg = {}; + sleep_cfg.slp_wakeup_lvl = TOUCH_LIGHT_SLEEP_WAKEUP; + TEST_ESP_OK(touch_sensor_config_sleep_wakeup(touch, &sleep_cfg)); + TEST_ESP_OK(touch_sensor_enable(touch)); + TEST_ESP_OK(touch_sensor_start_continuous_scanning(touch)); + + /* Set up the ULP to simulate touch wake-up */ + s_test_touch_start_ulp(); + + /* Enter light sleep */ + TEST_ESP_OK(esp_light_sleep_start()); + /* Wakeup from sleep */ + uint32_t wakeup_causes = esp_sleep_get_wakeup_causes(); + + if (wakeup_causes & BIT(ESP_SLEEP_WAKEUP_TOUCHPAD)) { + printf("wakeup by touchpad\n"); + } else { + printf("wakeup by other causes: %" PRIu32 "\n", wakeup_causes); + TEST_FAIL(); + } + +#if SOC_TOUCH_SENSOR_VERSION == 1 + printf("hardware active interrupt count: %d\n", cb_data.hw_active_count); + TEST_ASSERT_GREATER_OR_EQUAL(1, cb_data.hw_active_count); +#else + TEST_ASSERT_EQUAL(1, cb_data.active_count); +#endif + for (int cnt = 0; cb_data.inactive_count != cb_data.active_count; cnt++) { + if (cnt > 100) { + TEST_FAIL_MESSAGE("timeout waiting for inactive callback"); + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + TEST_ESP_OK(touch_sensor_stop_continuous_scanning(touch)); + TEST_ESP_OK(touch_sensor_disable(touch)); + TEST_ESP_OK(touch_sensor_config_sleep_wakeup(touch, NULL)); + TEST_ESP_OK(touch_sensor_del_channel(fixture->channels[0])); + TEST_ESP_OK(touch_sensor_del_channel(fixture->channels[1])); + TEST_ESP_OK(touch_sensor_del_controller(touch)); +} +#endif // SOC_ULP_SUPPORTED && !(CONFIG_TOUCH_ISR_IRAM_SAFE && SOC_IS(ESP32P4)) diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_fsm/main.S b/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_fsm/main.S new file mode 100644 index 00000000000..993594f4ca3 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_fsm/main.S @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/rtc_io_reg.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/soc_ulp.h" +#include "test_helper.h" + +#define WRITE_TOUCH_PAD_FIELD_2(chan, value) WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD##chan##_REG, RTC_IO_TOUCH_PAD##chan##_DAC, value) +#define WRITE_TOUCH_PAD_FIELD(chan, value) WRITE_TOUCH_PAD_FIELD_2(chan, value) + +#define ULP_FSM_CLK_CYCLES_PER_US 8 +#define TOUCH_SIMULATE_HOLD_CYCLES (TEST_TOUCH_SIMULATE_HOLD_TIME_US * ULP_FSM_CLK_CYCLES_PER_US) + + .bss +run_count: + .long 0 + + .text + .global entry +entry: + move r1, run_count + ld r0, r1, 0 + add r0, r0, 0 + jump first_run, eq + + /* Simulate touch event */ + WRITE_TOUCH_PAD_FIELD(TEST_TOUCH_WAKEUP_CHANNEL, 4) + + .rept TOUCH_SIMULATE_HOLD_CYCLES / 0xffff + wait 0xffff + .endr + + .if TOUCH_SIMULATE_HOLD_CYCLES % 0xffff + wait TOUCH_SIMULATE_HOLD_CYCLES % 0xffff + .endif + + WRITE_TOUCH_PAD_FIELD(TEST_TOUCH_WAKEUP_CHANNEL, 7) + + /* Disable the ULP timer */ + WRITE_RTC_FIELD(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0) + halt + +first_run: + add r0, r0, 1 + st r0, r1, 0 + halt diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_lpc/main.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_lpc/main.c new file mode 100644 index 00000000000..78e0b98d4b5 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_lpc/main.c @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_lp_timer_shared.h" +#include "test_helper.h" + +int main(void) +{ + static uint8_t run_count = 0; + if (run_count == 0) { + run_count++; + } else { + test_touch_simulate_touch(TEST_TOUCH_WAKEUP_CHANNEL, true); + ulp_lp_core_delay_us(TEST_TOUCH_SIMULATE_HOLD_TIME_US); + test_touch_simulate_touch(TEST_TOUCH_WAKEUP_CHANNEL, false); + ulp_lp_core_lp_timer_disable(); + } + return 0; +} diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_rv/main.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_rv/main.c new file mode 100644 index 00000000000..d38faf4d130 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/ulp_rv/main.c @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ulp_riscv_utils.h" +#include "test_helper.h" + +int main(void) +{ + static uint8_t run_count = 0; + if (run_count == 0) { + run_count++; + } else { + test_touch_simulate_touch(TEST_TOUCH_WAKEUP_CHANNEL, true); + ulp_riscv_delay_us(TEST_TOUCH_SIMULATE_HOLD_TIME_US); + test_touch_simulate_touch(TEST_TOUCH_WAKEUP_CHANNEL, false); + ulp_riscv_timer_stop(); + } + return 0; +} 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 09e9b228f89..0981af9d519 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 @@ -17,4 +17,4 @@ from pytest_embedded_idf.utils import soc_filtered_targets ) @idf_parametrize('target', soc_filtered_targets('SOC_TOUCH_SENSOR_SUPPORTED == 1'), indirect=['target']) def test_touch_sens(dut: Dut) -> None: - dut.run_all_single_board_cases() + dut.run_all_single_board_cases(timeout=20) diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32 b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32 new file mode 100644 index 00000000000..2d1bb700910 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32 @@ -0,0 +1,2 @@ +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_FSM=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32p4 b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32p4 index d2699b2221b..703ba29de76 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32p4 +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32p4 @@ -1,3 +1,5 @@ CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_HEX=y CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0 +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_LP_CORE=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s2 b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s2 new file mode 100644 index 00000000000..a5c1c541702 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s2 @@ -0,0 +1,2 @@ +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_RISCV=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s3 b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s3 index db575808cf9..0911ec0a6b0 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s3 +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s3 @@ -1,2 +1,4 @@ CONFIG_SPIRAM=y CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0 +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_RISCV=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s31 b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..d49ccccc49c --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults.esp32s31 @@ -0,0 +1,2 @@ +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_LP_CORE=y