mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/riscv_ulp_gpio_intr' into 'master'
ULP: Add example of using GPIO to wakeup the ULP-RISCV processor Closes IDFGH-6589 See merge request espressif/esp-idf!17288
This commit is contained in:
commit
706a14884f
@ -15,8 +15,32 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ULP_RISCV_WAKEUP_SOURCE_TIMER,
|
||||||
|
ULP_RISCV_WAKEUP_SOURCE_GPIO,
|
||||||
|
} ulp_riscv_wakeup_source_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ulp_riscv_wakeup_source_t wakeup_source;
|
||||||
|
} ulp_riscv_cfg_t;
|
||||||
|
|
||||||
|
#define ULP_RISCV_DEFAULT_CONFIG() \
|
||||||
|
{ \
|
||||||
|
.wakeup_source = ULP_RISCV_WAKEUP_SOURCE_TIMER, \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run the program loaded into RTC memory
|
* @brief Configure the ULP and run the program loaded into RTC memory
|
||||||
|
*
|
||||||
|
* @param cfg pointer to the config struct
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t ulp_riscv_config_and_run(ulp_riscv_cfg_t* cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure the ULP with default settings
|
||||||
|
* and run the program loaded into RTC memory
|
||||||
|
*
|
||||||
* @return ESP_OK on success
|
* @return ESP_OK on success
|
||||||
*/
|
*/
|
||||||
esp_err_t ulp_riscv_run(void);
|
esp_err_t ulp_riscv_run(void);
|
||||||
|
@ -96,6 +96,12 @@ void ulp_riscv_timer_resume(void);
|
|||||||
*/
|
*/
|
||||||
void ulp_riscv_delay_cycles(uint32_t cycles);
|
void ulp_riscv_delay_cycles(uint32_t cycles);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the GPIO wakeup interrupt bit
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ulp_riscv_gpio_wakeup_clear(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,8 +20,32 @@
|
|||||||
#include "ulp_common.h"
|
#include "ulp_common.h"
|
||||||
#include "esp_rom_sys.h"
|
#include "esp_rom_sys.h"
|
||||||
|
|
||||||
esp_err_t ulp_riscv_run(void)
|
static esp_err_t ulp_riscv_config_wakeup_source(ulp_riscv_wakeup_source_t wakeup_source)
|
||||||
{
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
|
switch (wakeup_source) {
|
||||||
|
case ULP_RISCV_WAKEUP_SOURCE_TIMER:
|
||||||
|
/* start ULP_TIMER */
|
||||||
|
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_CTRL_REG, RTC_CNTL_ULP_CP_FORCE_START_TOP);
|
||||||
|
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ULP_RISCV_WAKEUP_SOURCE_GPIO:
|
||||||
|
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_GPIO_WAKEUP_ENA);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t ulp_riscv_config_and_run(ulp_riscv_cfg_t* cfg)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S2
|
||||||
/* Reset COCPU when power on. */
|
/* Reset COCPU when power on. */
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN);
|
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN);
|
||||||
@ -42,11 +66,8 @@ esp_err_t ulp_riscv_run(void)
|
|||||||
/* Select ULP-RISC-V to send the DONE signal. */
|
/* Select ULP-RISC-V to send the DONE signal. */
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE_FORCE);
|
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE_FORCE);
|
||||||
|
|
||||||
/* start ULP_TIMER */
|
ret = ulp_riscv_config_wakeup_source(cfg->wakeup_source);
|
||||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_CTRL_REG, RTC_CNTL_ULP_CP_FORCE_START_TOP);
|
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
/* Reset COCPU when power on. */
|
/* Reset COCPU when power on. */
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLK_FO);
|
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLK_FO);
|
||||||
@ -73,9 +94,7 @@ esp_err_t ulp_riscv_run(void)
|
|||||||
/* Set the CLKGATE_EN signal */
|
/* Set the CLKGATE_EN signal */
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLKGATE_EN);
|
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLKGATE_EN);
|
||||||
|
|
||||||
/* start ULP_TIMER */
|
ret = ulp_riscv_config_wakeup_source(cfg->wakeup_source);
|
||||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_CTRL_REG, RTC_CNTL_ULP_CP_FORCE_START_TOP);
|
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
|
||||||
|
|
||||||
/* Select RISC-V as the ULP_TIMER trigger target
|
/* Select RISC-V as the ULP_TIMER trigger target
|
||||||
* Selecting the RISC-V as the Coprocessor at the end is a workaround
|
* Selecting the RISC-V as the Coprocessor at the end is a workaround
|
||||||
@ -87,8 +106,16 @@ esp_err_t ulp_riscv_run(void)
|
|||||||
esp_rom_delay_us(20);
|
esp_rom_delay_us(20);
|
||||||
REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_INT_CLR | RTC_CNTL_COCPU_TRAP_INT_CLR | RTC_CNTL_ULP_CP_INT_CLR);
|
REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_INT_CLR | RTC_CNTL_COCPU_TRAP_INT_CLR | RTC_CNTL_ULP_CP_INT_CLR);
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t ulp_riscv_run(void)
|
||||||
|
{
|
||||||
|
ulp_riscv_cfg_t cfg = ULP_RISCV_DEFAULT_CONFIG();
|
||||||
|
return ulp_riscv_config_and_run(&cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ulp_riscv_timer_stop(void)
|
void ulp_riscv_timer_stop(void)
|
||||||
|
@ -53,3 +53,8 @@ void ulp_riscv_timer_resume(void)
|
|||||||
{
|
{
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ulp_riscv_gpio_wakeup_clear(void)
|
||||||
|
{
|
||||||
|
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_GPIO_WAKEUP_CLR);
|
||||||
|
}
|
||||||
|
12
examples/system/ulp_riscv/gpio_interrupt/CMakeLists.txt
Normal file
12
examples/system/ulp_riscv/gpio_interrupt/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# 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.5)
|
||||||
|
|
||||||
|
if(NOT IDF_TARGET STREQUAL "esp32s2")
|
||||||
|
#IDF-4514
|
||||||
|
message(FATAL_ERROR "DO NOT BUILD THIS APP FOR ANY TARGET OTHER THAN ESP32-S2 OTHERWISE YOU MAY BRICK YOUR DEVICE")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(ulp_riscv_example)
|
27
examples/system/ulp_riscv/gpio_interrupt/README.md
Normal file
27
examples/system/ulp_riscv/gpio_interrupt/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
| Supported Targets | ESP32-S2 |
|
||||||
|
| ----------------- | -------- |
|
||||||
|
|
||||||
|
# ULP-RISC-V simple example with GPIO Interrupt:
|
||||||
|
|
||||||
|
This example demonstrates how to program the ULP-RISC-V 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 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 GPIO wakeup source and starts the coprocessor by using `ulp_riscv_config_and_run` followed by putting the chip into deep sleep mode.
|
||||||
|
|
||||||
|
When the wakeup source pin is pulled low the ULP-RISC-V 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 GPIO0. Note that this pin was chosen because most development boards have a button connected to it, so the pulses to be counted can be generated by pressing the button. For real world applications this is not a good choice of a pin, because GPIO0 also acts as a bootstrapping pin. To change the pin number, check the Chip Pin List document and adjust `WAKEUP_PIN` variable in main.c.
|
||||||
|
|
||||||
|
|
||||||
|
## Example output
|
||||||
|
|
||||||
|
```
|
||||||
|
Not a ULP-RISC-V wakeup, initializing it!
|
||||||
|
Entering in deep sleep
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
ULP-RISC-V woke up the main CPU!
|
||||||
|
Entering in deep sleep
|
||||||
|
```
|
27
examples/system/ulp_riscv/gpio_interrupt/main/CMakeLists.txt
Normal file
27
examples/system/ulp_riscv/gpio_interrupt/main/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Set usual component variables
|
||||||
|
set(COMPONENT_SRCS "ulp_riscv_gpio_intr_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_gpio_intr_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}")
|
31
examples/system/ulp_riscv/gpio_interrupt/main/ulp/main.c
Normal file
31
examples/system/ulp_riscv/gpio_interrupt/main/ulp/main.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
*/
|
||||||
|
/* ULP-RISC-V 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.h"
|
||||||
|
#include "ulp_riscv_utils.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
ulp_riscv_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_riscv_delay_cycles(1000*1000 * ULP_RISCV_CYCLES_PER_US);
|
||||||
|
ulp_riscv_gpio_wakeup_clear();
|
||||||
|
|
||||||
|
/* ulp_riscv_halt() is called automatically when main exits */
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
*/
|
||||||
|
/* ULP riscv DS18B20 1wire temperature sensor 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 "soc/sens_reg.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "ulp_riscv.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
#define WAKEUP_PIN 0
|
||||||
|
|
||||||
|
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 */
|
||||||
|
gpio_config_t config = {
|
||||||
|
.pin_bit_mask = BIT64(WAKEUP_PIN),
|
||||||
|
.mode = GPIO_MODE_INPUT
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(gpio_config(&config));
|
||||||
|
|
||||||
|
gpio_wakeup_enable(WAKEUP_PIN, GPIO_INTR_LOW_LEVEL);
|
||||||
|
gpio_hold_en(WAKEUP_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
wakeup_gpio_init();
|
||||||
|
init_ulp_program();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cause == ESP_SLEEP_WAKEUP_ULP) {
|
||||||
|
printf("ULP-RISC-V woke up the main CPU! \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* RTC peripheral power domain needs to be kept on to detect
|
||||||
|
the GPIO state change */
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Start the program */
|
||||||
|
ulp_riscv_cfg_t cfg = {
|
||||||
|
.wakeup_source = ULP_RISCV_WAKEUP_SOURCE_GPIO,
|
||||||
|
};
|
||||||
|
|
||||||
|
err = ulp_riscv_config_and_run(&cfg);
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
}
|
@ -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