mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(ulp-riscv): Added new example to demonstrate ULP RISC-V interrupts
This commit adds a new example which demonstrates how the ULP RISC-V co-processor handles interrupts.
This commit is contained in:
parent
94e2516f6c
commit
4230acb971
@ -360,6 +360,12 @@ examples/system/ulp/ulp_riscv/i2c:
|
||||
depends_components:
|
||||
- ulp
|
||||
|
||||
examples/system/ulp/ulp_riscv/interrupts:
|
||||
enable:
|
||||
- if: SOC_RISCV_COPROC_SUPPORTED == 1
|
||||
depends_components:
|
||||
- ulp
|
||||
|
||||
examples/system/ulp/ulp_riscv/touch:
|
||||
enable:
|
||||
- if: SOC_RISCV_COPROC_SUPPORTED == 1
|
||||
|
6
examples/system/ulp/ulp_riscv/interrupts/CMakeLists.txt
Normal file
6
examples/system/ulp/ulp_riscv/interrupts/CMakeLists.txt
Normal 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_interrupts)
|
71
examples/system/ulp/ulp_riscv/interrupts/README.md
Normal file
71
examples/system/ulp/ulp_riscv/interrupts/README.md
Normal file
@ -0,0 +1,71 @@
|
||||
| Supported Targets | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
||||
# ULP-RISC-V Interrupt Handling:
|
||||
|
||||
This example demonstrates how the ULP-RISC-V coprocessor can register and handle interrupts. Currently this example supports handling of -
|
||||
- Software triggered interrupts
|
||||
- RTC IO triggered interrupts
|
||||
|
||||
The example keeps a count of the software interrupts triggered on the ULP RISC-V core and wakes up the main processor from deep sleep after a certain threshold.
|
||||
Additionaly, it wakes up the main processor from deep sleep when a button is pressed and the GPIO interrupt is triggered.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
The example can be run on any ESP32-S2 or ESP32-S3 based development board connected to a computer with a single USB cable for flashing and monitoring. The external interface should have 3.3V outputs. You may use e.g. 3.3V compatible USB-to-Serial dongle.
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
By default, this example uses GPIO#0 which is connected to the "Boot" button on esp32-s2/s3 development boards. To trigger the GPIO interrupt on the ULP RISC-V core, press the Boot button.
|
||||
|
||||
## Example Output
|
||||
|
||||
Output from main CPU:
|
||||
|
||||
```
|
||||
Not a ULP RISC-V wakeup, initializing it!
|
||||
Entering in deep sleep
|
||||
|
||||
ESP-ROM:esp32s3-20210327
|
||||
Build:Mar 27 2021
|
||||
rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT)
|
||||
pro cpu reset by JTAG
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:1
|
||||
load:0x3fce3810,len:0x12b4
|
||||
load:0x403c9700,len:0x4
|
||||
load:0x403c9704,len:0xaf4
|
||||
load:0x403cc700,len:0x2bcc
|
||||
entry 0x403c9898
|
||||
W (91) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
|
||||
ULP RISC-V woke up the main CPU!
|
||||
ULP RISC-V SW Interrupt triggered 5 times.
|
||||
Entering in deep sleep
|
||||
|
||||
ESP-ROM:esp32s3-20210327
|
||||
Build:Mar 27 2021
|
||||
rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT)
|
||||
pro cpu reset by JTAG
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:1
|
||||
load:0x3fce3810,len:0x12b4
|
||||
load:0x403c9700,len:0x4
|
||||
load:0x403c9704,len:0xaf4
|
||||
load:0x403cc700,len:0x2bcc
|
||||
entry 0x403c9898
|
||||
W (91) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
|
||||
ULP RISC-V woke up the main CPU!
|
||||
ULP RISC-V GPIO Interrupt triggered.
|
||||
Entering in deep sleep
|
||||
|
||||
```
|
27
examples/system/ulp/ulp_riscv/interrupts/main/CMakeLists.txt
Normal file
27
examples/system/ulp/ulp_riscv/interrupts/main/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
# Set usual component variables
|
||||
set(COMPONENT_SRCS "ulp_riscv_example_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
set(COMPONENT_REQUIRES ulp)
|
||||
|
||||
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 "ulp_riscv_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}")
|
@ -0,0 +1,10 @@
|
||||
menu "ULP RISC-V Interrupt Example Configuration"
|
||||
|
||||
config EXAMPLE_GPIO_INT
|
||||
int "GPIO interrupt pin"
|
||||
range 0 21
|
||||
default 0
|
||||
help
|
||||
GPIO number to trigger an interrupt on the ULP RISC-V core.
|
||||
|
||||
endmenu
|
63
examples/system/ulp/ulp_riscv/interrupts/main/ulp/main.c
Normal file
63
examples/system/ulp/ulp_riscv/interrupts/main/ulp/main.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* ULP RISC-V interrupts 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.
|
||||
|
||||
This code runs on ULP RISC-V coprocessor
|
||||
*/
|
||||
|
||||
#include "ulp_riscv_utils.h"
|
||||
#include "ulp_riscv_gpio.h"
|
||||
|
||||
#define WAKE_PIN CONFIG_EXAMPLE_GPIO_INT
|
||||
|
||||
int sw_int_cnt = 0;
|
||||
int wake_by_sw = 0;
|
||||
int wake_by_gpio = 0;
|
||||
|
||||
/* SW Interrupt Handler */
|
||||
void sw_int_handler(void *arg)
|
||||
{
|
||||
sw_int_cnt++;
|
||||
}
|
||||
|
||||
/* GPIO Interrupt Handler */
|
||||
void gpio_int_handler(void *arg)
|
||||
{
|
||||
wake_by_gpio = 1;
|
||||
ulp_riscv_wakeup_main_processor();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
/* Register SW interrupt handler */
|
||||
ulp_riscv_enable_sw_intr(sw_int_handler, NULL);
|
||||
|
||||
/* Configure GPIO in input mode for interrupt */
|
||||
ulp_riscv_gpio_init(WAKE_PIN);
|
||||
ulp_riscv_gpio_input_enable(WAKE_PIN);
|
||||
|
||||
/* Register GPIO interrupt handler */
|
||||
ulp_riscv_gpio_isr_register(WAKE_PIN, ULP_RISCV_GPIO_INTR_POSEDGE, gpio_int_handler, NULL);
|
||||
|
||||
while (1) {
|
||||
/* Trigger SW interrupt */
|
||||
ulp_riscv_trigger_sw_intr();
|
||||
|
||||
if ((sw_int_cnt % 5 == 0) && !wake_by_gpio) {
|
||||
wake_by_sw = 1;
|
||||
ulp_riscv_wakeup_main_processor();
|
||||
}
|
||||
|
||||
ulp_riscv_delay_cycles(1000 * ULP_RISCV_CYCLES_PER_MS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* ULP RISC-V interrupts 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 <stdio.h>
|
||||
#include "esp_sleep.h"
|
||||
#include "ulp_riscv.h"
|
||||
#include "ulp_main.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
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);
|
||||
|
||||
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 it! \n");
|
||||
init_ulp_program();
|
||||
}
|
||||
|
||||
/* ULP RISC-V handled an interrupt on GPIO#0 */
|
||||
if (cause == ESP_SLEEP_WAKEUP_ULP) {
|
||||
printf("ULP RISC-V woke up the main CPU! \n");
|
||||
if (ulp_wake_by_sw) {
|
||||
printf("ULP RISC-V SW Interrupt triggered %lu times.\r\n", ulp_sw_int_cnt);
|
||||
ulp_wake_by_sw = 0;
|
||||
} else if (ulp_wake_by_gpio) {
|
||||
printf("ULP RISC-V GPIO Interrupt triggered.\r\n");
|
||||
ulp_wake_by_gpio = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Go back 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);
|
||||
|
||||
ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup());
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
static void init_ulp_program(void)
|
||||
{
|
||||
esp_err_t err = ulp_riscv_load_binary(ulp_main_bin_start, (ulp_main_bin_end - 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 program */
|
||||
err = ulp_riscv_run();
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.generic
|
||||
def test_ulp_riscv_interrupts(dut: Dut) -> None:
|
||||
|
||||
dut.expect_exact('Not a ULP RISC-V wakeup, initializing it!')
|
||||
dut.expect_exact('Entering in deep sleep')
|
||||
|
||||
# Give the chip time to enter deepsleep and trigger a software interrupt
|
||||
time.sleep(5)
|
||||
|
||||
# Verify if SW interrupt got triggered
|
||||
dut.expect_exact('ULP RISC-V SW Interrupt triggered 5 times.')
|
||||
|
||||
# Set GPIO#0 using DTR
|
||||
dut.serial.proc.setDTR(True)
|
||||
time.sleep(1)
|
||||
dut.serial.proc.setDTR(False)
|
||||
|
||||
# Verify if GPIO interrupt got triggered
|
||||
dut.expect_exact('ULP RISC-V GPIO Interrupt triggered.', timeout=5)
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user