diff --git a/components/hal/esp32c6/include/hal/rtc_io_ll.h b/components/hal/esp32c6/include/hal/rtc_io_ll.h index 0cd64df36d5..6fcac4cd406 100644 --- a/components/hal/esp32c6/include/hal/rtc_io_ll.h +++ b/components/hal/esp32c6/include/hal/rtc_io_ll.h @@ -309,6 +309,14 @@ static inline void rtcio_ll_wakeup_enable(int rtcio_num, rtcio_ll_wake_type_t ty { LP_IO.pin[rtcio_num].wakeup_enable = 1; LP_IO.pin[rtcio_num].int_type = type; + + /* Work around for HW issue, + need to also enable this clk, otherwise it will + not trigger a wake-up on the ULP. This is not needed + for triggering a wakeup on HP CPU, but always setting this + has no side-effects. + */ + LP_IO.date.clk_en = 1; } /** diff --git a/components/ulp/lp_core/lp_core.c b/components/ulp/lp_core/lp_core.c index cfc8fc81cc0..0efa300ac0f 100644 --- a/components/ulp/lp_core/lp_core.c +++ b/components/ulp/lp_core/lp_core.c @@ -133,7 +133,7 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg) } #endif - if (cfg->wakeup_source & (ULP_LP_CORE_WAKEUP_SOURCE_LP_UART | ULP_LP_CORE_WAKEUP_SOURCE_LP_IO)) { + if (cfg->wakeup_source & (ULP_LP_CORE_WAKEUP_SOURCE_LP_UART)) { ESP_LOGE(TAG, "Wake-up source not yet supported"); return ESP_ERR_INVALID_ARG; } diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index d174a8796b8..c5311cbf9f6 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -293,6 +293,12 @@ examples/system/ulp/lp_core/gpio_intr_pulse_counter: depends_components: - ulp +examples/system/ulp/lp_core/gpio_wakeup: + enable: + - if: (SOC_LP_CORE_SUPPORTED == 1) and (SOC_RTCIO_PIN_COUNT > 0) + depends_components: + - ulp + examples/system/ulp/lp_core/inter_cpu_critical_section/: enable: - if: SOC_LP_CORE_SUPPORTED == 1 diff --git a/examples/system/ulp/lp_core/gpio_wakeup/CMakeLists.txt b/examples/system/ulp/lp_core/gpio_wakeup/CMakeLists.txt new file mode 100644 index 00000000000..8c1a422f3f4 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_wakeup/CMakeLists.txt @@ -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_lp_core_gpio_wakeup_example) diff --git a/examples/system/ulp/lp_core/gpio_wakeup/README.md b/examples/system/ulp/lp_core/gpio_wakeup/README.md new file mode 100644 index 00000000000..66925750726 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_wakeup/README.md @@ -0,0 +1,26 @@ +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | +# ULP-LP-Core simple example with GPIO Interrupt: + +This example demonstrates how to program the LP-Core coprocessor to wake up from a RTC IO interrupt, instead of waking periodically from the ULP timer. + +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 main code running on the ESP (found in lp_core_gpio_wake_up_example_main.c) loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_lp_core_load_binary` function. The main code then configures the ULP GPIO wakeup source and starts the coprocessor by using `ulp_lp_core_run` followed by putting the chip into deep sleep mode. + +When the wakeup source pin is pulled low the LP-Core coprocessor is woken up, sends a wakeup signal to the main CPU and goes back to sleep again. + +In this example the input signal is connected to GPIO2. To change the pin number, check the Chip Pin List document and adjust `WAKEUP_PIN` variable in main.c. + + +## Example output + +``` +Not a LP-Core wakeup, initializing it! +Entering deep sleep + +... + +LP-Core woke up the main CPU! +Entering deep sleep +``` diff --git a/examples/system/ulp/lp_core/gpio_wakeup/main/CMakeLists.txt b/examples/system/ulp/lp_core/gpio_wakeup/main/CMakeLists.txt new file mode 100644 index 00000000000..9970ae3effb --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_wakeup/main/CMakeLists.txt @@ -0,0 +1,27 @@ +# Set usual component variables +set(COMPONENT_SRCS "lp_core_gpio_wake_up_example_main.c") +set(COMPONENT_ADD_INCLUDEDIRS "") +set(COMPONENT_REQUIRES ulp driver) + +register_component() + +# +# 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 "lp_core_gpio_wake_up_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}") diff --git a/examples/system/ulp/lp_core/gpio_wakeup/main/lp_core_gpio_wake_up_example_main.c b/examples/system/ulp/lp_core/gpio_wakeup/main/lp_core_gpio_wake_up_example_main.c new file mode 100644 index 00000000000..7de67d59c36 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_wakeup/main/lp_core_gpio_wake_up_example_main.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* ULP LP-Core GPIO wake-up 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 +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "ulp_lp_core.h" +#include "ulp_main.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#define WAKEUP_PIN 2 + +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"); + +static void init_ulp_program(void); + +static void wakeup_gpio_init(void) +{ + /* Configure the button GPIO as input, enable wakeup */ + rtc_gpio_init(WAKEUP_PIN); + rtc_gpio_set_direction(WAKEUP_PIN, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_dis(WAKEUP_PIN); + rtc_gpio_pullup_en(WAKEUP_PIN); + rtc_gpio_wakeup_enable(WAKEUP_PIN, GPIO_INTR_LOW_LEVEL); +} + +void app_main(void) +{ + /* If user is using USB-serial-jtag then idf monitor needs some time to + * re-connect to the USB port. We wait 1 sec here to allow for it to make the reconnection + * before we print anything. Otherwise the chip will go back to sleep again before the user + * has time to monitor any output. + */ + vTaskDelay(pdMS_TO_TICKS(1000)); + + wakeup_gpio_init(); + + 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 wakeup, initializing it! \n"); + init_ulp_program(); + } + + /* ULP read and detected a change in WAKEUP_PIN, prints */ + if (cause == ESP_SLEEP_WAKEUP_ULP) { + printf("ULP woke up the main CPU! \n"); + } + + /* Go back to sleep, only the ULP will run */ + printf("Entering deep sleep\n\n"); + + /* Small delay to ensure the messages are printed */ + vTaskDelay(100 / portTICK_PERIOD_MS); + + ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup()); + + esp_deep_sleep_start(); +} + +static void init_ulp_program(void) +{ + esp_err_t err = ulp_lp_core_load_binary(ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start)); + ESP_ERROR_CHECK(err); + + /* Start the program */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_IO, + }; + + err = ulp_lp_core_run(&cfg); + ESP_ERROR_CHECK(err); +} diff --git a/examples/system/ulp/lp_core/gpio_wakeup/main/ulp/main.c b/examples/system/ulp/lp_core/gpio_wakeup/main/ulp/main.c new file mode 100644 index 00000000000..0f630ddc0cc --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_wakeup/main/ulp/main.c @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include "ulp_lp_core.h" +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_gpio.h" + + +int main (void) +{ + ulp_lp_core_wakeup_main_processor(); + + /* Wakeup interrupt is a level interrupt, wait 1 sec to + allow user to release button to avoid waking up the ULP multiple times */ + ulp_lp_core_delay_us(1000*1000); + ulp_lp_core_gpio_clear_intr_status(); + + return 0; +} diff --git a/examples/system/ulp/lp_core/gpio_wakeup/sdkconfig.defaults b/examples/system/ulp/lp_core/gpio_wakeup/sdkconfig.defaults new file mode 100644 index 00000000000..456833bc8c3 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_wakeup/sdkconfig.defaults @@ -0,0 +1,9 @@ +# Enable ULP +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_LP_CORE=y +CONFIG_ULP_COPROC_RESERVE_MEM=8128 +# 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