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" {
|
||||
#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
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Clears the GPIO wakeup interrupt bit
|
||||
*
|
||||
*/
|
||||
void ulp_riscv_gpio_wakeup_clear(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -20,8 +20,32 @@
|
||||
#include "ulp_common.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
|
||||
/* Reset COCPU when power on. */
|
||||
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. */
|
||||
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE_FORCE);
|
||||
|
||||
/* 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);
|
||||
ret = ulp_riscv_config_wakeup_source(cfg->wakeup_source);
|
||||
|
||||
return ESP_OK;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
/* Reset COCPU when power on. */
|
||||
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_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_CLKGATE_EN);
|
||||
|
||||
/* 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);
|
||||
ret = ulp_riscv_config_wakeup_source(cfg->wakeup_source);
|
||||
|
||||
/* Select RISC-V as the ULP_TIMER trigger target
|
||||
* 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);
|
||||
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
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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