Merge branch 'feature/ulp_riscv_touch' into 'master'

ulp-riscv: Added touch sensor support to ULP RISC-V

Closes IDFGH-9077

See merge request espressif/esp-idf!23859
This commit is contained in:
Sudeep Mohanty 2023-06-09 16:49:08 +08:00
commit 4b35e00d45
10 changed files with 504 additions and 1 deletions

View File

@ -63,7 +63,8 @@ if(ULP_COCPU_IS_RISCV)
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_uart.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_print.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_i2c.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c")
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_touch.c")
target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles")
target_link_options(${ULP_APP_NAME} PRIVATE -Wl,--gc-sections)

View File

@ -0,0 +1,96 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "hal/touch_sensor_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Read raw data of touch sensor on the ULP RISC-V core
* @note Refer `touch_pad_read_raw_data()` for more details
*
* @param touch_num Touch pad index
* @param raw_data Pointer to accept touch sensor value
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_read_raw_data(touch_pad_t touch_num, uint32_t *raw_data);
/**
* @brief Read benchmark of touch sensor on the ULP RISC-V core
* @note Refer `touch_pad_read_benchmark()` for more details
*
* @param touch_num Touch pad index
* @param benchmark Pointer to accept touch sensor benchmark value
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_read_benchmark(touch_pad_t touch_num, uint32_t *benchmark);
/**
* @brief Read the filtered (smoothened) touch sensor data on the ULP RISC-V core
* @note Refer `touch_pad_filter_read_smooth()` for more details
*
* @param touch_num Touch pad index
* @param smooth_data Pointer to accept smoothened touch sensor value
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_filter_read_smooth(touch_pad_t touch_num, uint32_t *smooth_data);
/**
* @brief Force reset benchmark to raw data of touch sensor.
* @note Refer `touch_pad_reset_benchmark()` for more details
*
* @param touch_num Touch pad index (TOUCH_PAD_MAX resets basaline of all channels)
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_reset_benchmark(touch_pad_t touch_num);
/**
* @brief Read raw data of touch sensor sleep channel on the ULP RISC-V core
* @note Refer `touch_pad_sleep_channel_read_data()` for more details
*
* @param touch_num Touch pad index (Only one touch sensor channel is supported in deep sleep)
* @param raw_data Pointer to accept touch sensor value
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_data(touch_pad_t touch_num, uint32_t *raw_data);
/**
* @brief Read benchmark of touch sensor sleep channel on the ULP RISC-V core
* @note Refer `touch_pad_sleep_channel_read_benchmark()` for more details
*
* @param touch_num Touch pad index (Only one touch sensor channel is supported in deep sleep)
* @param benchmark Pointer to accept touch sensor benchmark value
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_benchmark(touch_pad_t touch_num, uint32_t *benchmark);
/**
* @brief Read the filtered (smoothened) touch sensor sleep channel data on the ULP RISC-V core
* @note Refer `touch_pad_sleep_channel_read_smooth()` for more details
*
* @param touch_num Touch pad index (Only one touch sensor channel is supported in deep sleep)
* @param smooth_data Pointer to accept smoothened touch sensor value
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_smooth(touch_pad_t touch_num, uint32_t *smooth_data);
/**
* @brief Reset benchmark of touch sensor sleep channel.
* @note Refer `touch_pad_sleep_channel_reset_benchmark()` for more details
*
* @return esp_err_t ESP_OK when successful
*/
esp_err_t ulp_riscv_touch_pad_sleep_channel_reset_benchmark(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ulp_riscv_touch_ulp_core.h"
#include "soc/soc_caps.h"
#include "soc/touch_sensor_pins.h"
#include "hal/touch_sensor_hal.h"
/* Check Touch Channel correctness */
#define ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(channel) \
{ \
if (channel >= SOC_TOUCH_SENSOR_NUM || \
channel < 0 || \
channel == SOC_TOUCH_DENOISE_CHANNEL) { \
return ESP_ERR_INVALID_ARG; \
} \
} \
esp_err_t ulp_riscv_touch_pad_read_raw_data(touch_pad_t touch_num, uint32_t *raw_data)
{
/* Check Arguments */
if (!raw_data) {
return ESP_ERR_INVALID_ARG;
}
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
/* Read raw touch data */
*raw_data = touch_hal_read_raw_data(touch_num);
return ESP_OK;
}
esp_err_t ulp_riscv_touch_pad_read_benchmark(touch_pad_t touch_num, uint32_t *benchmark)
{
/* Check Arguments */
if (!benchmark) {
return ESP_ERR_INVALID_ARG;
}
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
/* Read benchmark data */
touch_hal_read_benchmark(touch_num, benchmark);
return ESP_OK;
}
esp_err_t ulp_riscv_touch_pad_filter_read_smooth(touch_pad_t touch_num, uint32_t *smooth_data)
{
/* Check Arguments */
if (!smooth_data) {
return ESP_ERR_INVALID_ARG;
}
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
/* Read smoothened touch sensor data */
touch_hal_filter_read_smooth(touch_num, smooth_data);
return ESP_OK;
}
esp_err_t ulp_riscv_touch_pad_reset_benchmark(touch_pad_t touch_num)
{
/* Check Arguments */
if (touch_num > TOUCH_PAD_MAX || touch_num < 0) {
return ESP_ERR_INVALID_ARG;
}
/* Reset benchmark */
touch_hal_reset_benchmark(touch_num);
return ESP_OK;
}
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_data(touch_pad_t touch_num, uint32_t *raw_data)
{
/* Check Arguments */
if (!raw_data) {
return ESP_ERR_INVALID_ARG;
}
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
/* Read raw touch data */
touch_hal_sleep_read_data(raw_data);
return ESP_OK;
}
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_benchmark(touch_pad_t touch_num, uint32_t *benchmark)
{
/* Check Arguments */
if (!benchmark) {
return ESP_ERR_INVALID_ARG;
}
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
/* Read benchmark data */
touch_hal_sleep_read_benchmark(benchmark);
return ESP_OK;
}
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_smooth(touch_pad_t touch_num, uint32_t *smooth_data)
{
/* Check Arguments */
if (!smooth_data) {
return ESP_ERR_INVALID_ARG;
}
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
/* Read smoothened touch sensor data */
touch_hal_sleep_read_smooth(smooth_data);
return ESP_OK;
}
esp_err_t ulp_riscv_touch_pad_sleep_channel_reset_benchmark(void)
{
/* Reset benchmark */
touch_hal_sleep_reset_benchmark();
return ESP_OK;
}

View File

@ -217,6 +217,10 @@ examples/system/ulp/ulp_riscv/i2c:
enable:
- if: SOC_RISCV_COPROC_SUPPORTED == 1
examples/system/ulp/ulp_riscv/touch:
enable:
- if: SOC_RISCV_COPROC_SUPPORTED == 1
examples/system/ulp/ulp_riscv/uart_print:
enable:
- if: SOC_RISCV_COPROC_SUPPORTED == 1

View File

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

View File

@ -0,0 +1,48 @@
| Supported Targets | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- |
# ULP-RISC-V Touch Sensor example:
This example demonstrates how to program the ULP RISC-V coprocessor to read touch pad sensors.
ULP program written in C can be found across `ulp/main.c`. The build system compiles and links this program, converts it into binary format, and embeds it into the .rodata section of the ESP-IDF application.
At runtime, the application running inside the main CPU loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_riscv_load_binary` function. The main code then configures the ULP wakeup period and starts the coprocessor by using `ulp_riscv_run`. Once the ULP program is started, it runs periodically, with the period set by the main program. The main program enables ULP wakeup source and puts the chip into deep sleep mode.
The ULP Program scans all touch pad sensors periodically. When the ULP program finds a touch pad is active (touched), it captures the touch pad number in a variable and wakes up the main CPU. The main CPU reports which touch pad sensor was touched.
## How to use the example
### Hardware Required
* A development board with ESP32-S2 or ESP32-S3
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
```
Not a ULP wakeup, initializing it!
Entering in deep sleep
...
ULP-RISC-V woke up the main CPU!
T3 touched
T4 touched
Entering in deep sleep
```

View File

@ -0,0 +1,25 @@
# Register the component
idf_component_register(SRCS "ulp_riscv_touch_example_main.c"
INCLUDE_DIRS ""
REQUIRES ulp)
#
# ULP support additions to component CMakeLists.txt.
#
# 1. The ULP app name must be unique (if multiple components use ULP).
set(ulp_app_name ulp_${COMPONENT_NAME})
#
# 2. Specify all C and Assembly source files.
# Files should be placed into a separate directory (in this case, ulp/),
# which should not be added to COMPONENT_SRCS.
set(ulp_riscv_sources "ulp/main.c")
#
# 3. List all the component source files which include automatically
# generated ULP export file, ${ulp_app_name}.h:
set(ulp_exp_dep_srcs "ulp_riscv_touch_example_main.c")
#
# 4. Call function to build ULP binary and embed in project using the argument
# values above.
ulp_embed_binary(${ulp_app_name} "${ulp_riscv_sources}" "${ulp_exp_dep_srcs}")

View File

@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/*
* ULP-RISC-V touch sensor example
* This code runs on ULP-RISC-V coprocessor
*/
#include <stdint.h>
#include "ulp_riscv.h"
#include "ulp_riscv_utils.h"
#include "ulp_riscv_touch_ulp_core.h"
/* This variable will be exported as a public symbol, visible from main CPU: */
uint32_t touch_data = 0;
/* Touch pad threshold */
#define TOUCH_PAD_THRESHOLD 1000U
#define TOUCH_BUTTON_NUM 14U
static const touch_pad_t button[TOUCH_BUTTON_NUM] = {
TOUCH_PAD_NUM1,
TOUCH_PAD_NUM2,
TOUCH_PAD_NUM3,
TOUCH_PAD_NUM4,
TOUCH_PAD_NUM5,
TOUCH_PAD_NUM6,
TOUCH_PAD_NUM7,
TOUCH_PAD_NUM8,
TOUCH_PAD_NUM9,
TOUCH_PAD_NUM10,
TOUCH_PAD_NUM11,
TOUCH_PAD_NUM12,
TOUCH_PAD_NUM13,
TOUCH_PAD_NUM14
};
int main (void)
{
esp_err_t err = ESP_OK;
uint32_t benchmark = 0;
uint32_t smooth = 0;
uint32_t touch_value = 0;
for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
/* Read the benchmark and the filtered (smooth) touch data */
err = ulp_riscv_touch_pad_read_benchmark(button[i], &benchmark);
err = ulp_riscv_touch_pad_filter_read_smooth(button[i], &smooth);
if (err != ESP_OK) {
/* Skip channel this time */
continue;
}
/* The difference between the benchmark and the smooth touch data
* is used to determine an active touch pad.
* Check if the touch value breaches the wakeup threshold.
*/
if (smooth > benchmark) {
if ((smooth - benchmark) > TOUCH_PAD_THRESHOLD) {
touch_value |= (1 << button[i]);
}
}
}
if (touch_value) {
touch_data = touch_value;
ulp_riscv_wakeup_main_processor();
touch_value = 0;
}
/* ulp_riscv_halt() is called automatically when main exits */
return 0;
}

View File

@ -0,0 +1,113 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* ULP RISC-V touch sensor example */
#include <stdio.h>
#include "esp_sleep.h"
#include "ulp_riscv.h"
#include "ulp_main.h"
#include "driver/touch_pad.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
extern const uint8_t _binary_ulp_main_bin_start[];
extern const uint8_t _binary_ulp_main_bin_end[];
#define TOUCH_BUTTON_NUM 14U
static const touch_pad_t button[TOUCH_BUTTON_NUM] = {
TOUCH_PAD_NUM1,
TOUCH_PAD_NUM2,
TOUCH_PAD_NUM3,
TOUCH_PAD_NUM4,
TOUCH_PAD_NUM5,
TOUCH_PAD_NUM6,
TOUCH_PAD_NUM7,
TOUCH_PAD_NUM8,
TOUCH_PAD_NUM9,
TOUCH_PAD_NUM10,
TOUCH_PAD_NUM11,
TOUCH_PAD_NUM12,
TOUCH_PAD_NUM13,
TOUCH_PAD_NUM14
};
static void init_touch_pad(void)
{
/* Initialize touch pad peripheral. */
touch_pad_init();
for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
touch_pad_config(button[i]);
}
/* Denoise setting at TouchSensor 0. */
touch_pad_denoise_t denoise = {
/* The bits to be cancelled are determined according to the noise level. */
.grade = TOUCH_PAD_DENOISE_BIT4,
.cap_level = TOUCH_PAD_DENOISE_CAP_L4,
};
touch_pad_denoise_set_config(&denoise);
touch_pad_denoise_enable();
/* Enable touch sensor clock. Work mode is "timer trigger". */
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
touch_pad_fsm_start();
}
static void init_ulp_program(void)
{
esp_err_t err = ulp_riscv_load_binary(_binary_ulp_main_bin_start, (_binary_ulp_main_bin_end - _binary_ulp_main_bin_start));
ESP_ERROR_CHECK(err);
/* The first argument is the period index, which is not used by the ULP-RISC-V timer
* The second argument is the period in microseconds, which gives a wakeup time period of: 20ms
*/
ulp_set_wakeup_period(0, 20000);
/* Start the ULP program */
err = ulp_riscv_run();
ESP_ERROR_CHECK(err);
}
void app_main(void)
{
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
/* not a wakeup from ULP, load the firmware */
if (cause != ESP_SLEEP_WAKEUP_ULP) {
printf("Not a ULP-RISC-V wakeup, initializing ...\n");
/* Initialize Touch peripheral */
init_touch_pad();
/* Initialize ULP core */
init_ulp_program();
}
/* ULP RISC-V detected a touch input */
if (cause == ESP_SLEEP_WAKEUP_ULP) {
printf("ULP-RISC-V woke up the main CPU! \n");
uint32_t touch_data = ulp_touch_data;
for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
if ((touch_data >> button[i]) & 0x1) {
printf("T%d touched\n", button[i]);
}
}
printf("\n");
}
/* Go to sleep, only the ULP RISC-V will run */
printf("Entering in deep sleep\n\n");
/* Small delay to ensure the messages are printed */
vTaskDelay(100);
/* Keep RTC_PERIPH powered on to keep all touch pad channels active */
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());
esp_deep_sleep_start();
}

View File

@ -0,0 +1,9 @@
# Enable ULP
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_RISCV=y
CONFIG_ULP_COPROC_RESERVE_MEM=4096
# Set log level to Warning to produce clean output
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2
CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_DEFAULT_LEVEL=2