-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/lp_core_pcnt' into 'master'
feat(ulp): add pulse counter example for lp core Closes IDF-9137 See merge request espressif/esp-idf!31163
- Loading branch information
Showing
14 changed files
with
331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
examples/system/ulp/lp_core/gpio_intr_pulse_counter/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# For more information about build system see | ||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html | ||
# The following five 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(lp_core_pulse_counter) |
66 changes: 66 additions & 0 deletions
66
examples/system/ulp/lp_core/gpio_intr_pulse_counter/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
| Supported Targets | ESP32-C6 | ESP32-P4 | | ||
| ----------------- | -------- | -------- | | ||
|
||
# LP Core Pulse Counting Example | ||
|
||
This example demonstrates how to program the ULP Core coprocessor to count pulses on an IO while the main CPUs are either running some other code or are in deep sleep. See the README.md file in the upper level 'examples' directory for more information about examples. | ||
|
||
At runtime, the main code running on the ESP (found in lp_core_pulse_counter_example_main.c) loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_lp_core_load_binary` function. Main code configures the ULP program by setting up values of some variables and then starts it using `ulp_lp_core_run`. Once the ULP program is started, it monitors the IO pin for pulses. | ||
|
||
When the ULP program finds an edge in the input signal, it performs debouncing and increments the variable maintaining the total edge count. Once the edge count reaches certain value, ULP triggers wake up from deep sleep. Note that the ULP program keeps running and monitoring the input signal even when the SoC is woken up. | ||
|
||
## How to use example | ||
|
||
### Hardware Required | ||
|
||
To run this example, you should have a development board based on any of the chips listed in the supported targets table at the top and a host machine with a serial input connection. | ||
|
||
#### Pin Assignment: | ||
|
||
**Note:** The following pin assignments are used by default. | ||
|
||
|
||
| | Uart Tx | Pulse Count Input | | ||
| ----------------------- | ------- | ----------------- | | ||
| ESP32-C6 | GPIO5 | GPIO6 | | ||
| ESP32-P4 | GPIO14 | GPIO6 | | ||
| Host machine | Rx | N/A | | ||
|
||
### Build and Flash | ||
|
||
Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project. | ||
|
||
(To exit the serial monitor, type ``Ctrl-]``.) | ||
|
||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. | ||
|
||
Use another serial monitor program/instance such as idf.py monitor, minicom or miniterm to send and receive data from the LP core. | ||
The default baudrate used for the example is 115200. Care must be taken that the configuration matches on both the device and the serial terminal. | ||
|
||
## Example Output | ||
|
||
The log output from the serial monitor connected to the main core should indicate that the LP core and the LP UART peripheral have been successfully initialized. The main CPU would then enter deep sleep mode. | ||
|
||
```bash | ||
Using pin 6 as pulse counter input | ||
ULP will wake up processor after every 10 pulses | ||
Not a ULP wakeup, initializing it! | ||
Entering in deep sleep | ||
... | ||
rst:0x5 (SLEEP_WAKEUP),boot:0xc (SPI_FAST_FLASH_BOOT) | ||
... | ||
ULP woke up the main CPU! | ||
Pulse count: 11 | ||
Entering in deep sleep | ||
``` | ||
|
||
The log output from the serial monitor connected to the LP core should display output as below - | ||
|
||
```bash | ||
LP Core pulse counter started | ||
Pulse count: 10, wake-up main CPU | ||
``` | ||
|
||
## Troubleshooting | ||
|
||
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) |
22 changes: 22 additions & 0 deletions
22
examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
idf_component_register(SRCS "lp_core_pulse_counter_example_main.c" | ||
INCLUDE_DIRS ".") | ||
# | ||
# 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_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 ${app_sources}) | ||
|
||
# | ||
# 4. Call function to build ULP binary and embed in project using the argument | ||
# values above. | ||
ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}") |
20 changes: 20 additions & 0 deletions
20
examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/Kconfig.projbuild
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
menu "Example Configuration" | ||
config EXAMPLE_PULSE_COUNT_PIN | ||
int "Input pin for the pulse counter" | ||
default 6 | ||
help | ||
GPIO pin used as the input for the pulse counter | ||
|
||
config EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT | ||
int "Wake-up pulse count limit" | ||
default 10 | ||
help | ||
Number of pulses counted after which the ULP will wake up the main CPU | ||
|
||
config EXAMPLE_PULSE_COUNT_SIMULATE | ||
bool "Simulate pulses on input pin" | ||
default n | ||
help | ||
The ULP will periodically toggle the input pin to simulate pulses | ||
|
||
endmenu |
85 changes: 85 additions & 0 deletions
85
...ples/system/ulp/lp_core/gpio_intr_pulse_counter/main/lp_core_pulse_counter_example_main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Unlicense OR CC0-1.0 | ||
*/ | ||
/* LP core gpio 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 <inttypes.h> | ||
#include "esp_sleep.h" | ||
#include "driver/gpio.h" | ||
#include "driver/rtc_io.h" | ||
#include "freertos/FreeRTOS.h" | ||
#include "freertos/task.h" | ||
#include "ulp_lp_core.h" | ||
#include "ulp_main.h" | ||
#include "lp_core_uart.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) | ||
{ | ||
/* 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)); | ||
|
||
/* Initialize selected GPIO as RTC IO, enable input/output, disable pullup and pulldown */ | ||
printf("Using pin %d as pulse counter input\n", CONFIG_EXAMPLE_PULSE_COUNT_PIN); | ||
rtc_gpio_init(CONFIG_EXAMPLE_PULSE_COUNT_PIN); | ||
rtc_gpio_set_direction(CONFIG_EXAMPLE_PULSE_COUNT_PIN, RTC_GPIO_MODE_INPUT_OUTPUT); | ||
rtc_gpio_pulldown_dis(CONFIG_EXAMPLE_PULSE_COUNT_PIN); | ||
rtc_gpio_pullup_dis(CONFIG_EXAMPLE_PULSE_COUNT_PIN); | ||
|
||
printf("ULP will wake up processor after every %d pulses\n", CONFIG_EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT); | ||
|
||
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(); | ||
} else { | ||
printf("ULP woke up the main CPU!\n"); | ||
printf("Pulse count: %"PRIu32"\n", ulp_pulse_count); | ||
} | ||
|
||
/* Go back to sleep, only the ULP will run */ | ||
printf("Entering in deep sleep\n\n"); | ||
|
||
/* Small delay to ensure the messages are printed */ | ||
ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup()); | ||
|
||
esp_deep_sleep_start(); | ||
} | ||
|
||
static void init_ulp_program(void) | ||
{ | ||
lp_core_uart_cfg_t uart_cfg = LP_CORE_UART_DEFAULT_CONFIG(); | ||
|
||
ESP_ERROR_CHECK(lp_core_uart_init(&uart_cfg)); | ||
|
||
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_HP_CPU, | ||
}; | ||
|
||
err = ulp_lp_core_run(&cfg); | ||
ESP_ERROR_CHECK(err); | ||
} |
64 changes: 64 additions & 0 deletions
64
examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/ulp/main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Unlicense OR CC0-1.0 | ||
*/ | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include "sdkconfig.h" | ||
#include "ulp_lp_core.h" | ||
#include "ulp_lp_core_utils.h" | ||
#include "ulp_lp_core_gpio.h" | ||
#include "ulp_lp_core_interrupts.h" | ||
#include "ulp_lp_core_print.h" | ||
#include "riscv/csr.h" | ||
|
||
#define DEBOUNCE_INTERVAL_CYCLES 10 // 10 cycles is about 0.625 us at 16 MHz | ||
|
||
#define SIMULATED_PULSE_FREQUENCY_HZ 2 | ||
#define SIMULATED_PULSE_DELAY_US (1000000 / SIMULATED_PULSE_FREQUENCY_HZ) / 2 | ||
|
||
uint32_t pulse_count; | ||
static uint32_t last_trigger_time_cycles; | ||
|
||
void LP_CORE_ISR_ATTR ulp_lp_core_lp_io_intr_handler(void) | ||
{ | ||
ulp_lp_core_gpio_clear_intr_status(); | ||
uint32_t trigger_time_cycles = RV_READ_CSR(mcycle); | ||
/* Do some simple debouncing, do not count spurious pulses */ | ||
if (trigger_time_cycles - last_trigger_time_cycles > DEBOUNCE_INTERVAL_CYCLES) { | ||
pulse_count++; | ||
last_trigger_time_cycles = trigger_time_cycles; | ||
} | ||
|
||
if (pulse_count % CONFIG_EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT == 0) { | ||
lp_core_printf("Pulse count: %d, wake-up main CPU\n", pulse_count); | ||
ulp_lp_core_wakeup_main_processor(); | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
int main (void) | ||
{ | ||
lp_core_printf("LP Core pulse counter started\n"); | ||
ulp_lp_core_intr_enable(); | ||
ulp_lp_core_gpio_intr_enable(CONFIG_EXAMPLE_PULSE_COUNT_PIN, LP_IO_INTR_POSEDGE); | ||
|
||
while(1) { | ||
|
||
#if CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE | ||
/* No external device connected to generate pulses, we simulate them ourselves instead */ | ||
ulp_lp_core_delay_us(SIMULATED_PULSE_DELAY_US); | ||
ulp_lp_core_gpio_set_level(CONFIG_EXAMPLE_PULSE_COUNT_PIN, 1); | ||
ulp_lp_core_delay_us(SIMULATED_PULSE_DELAY_US); | ||
ulp_lp_core_gpio_set_level(CONFIG_EXAMPLE_PULSE_COUNT_PIN, 0); | ||
#else | ||
/* Put CPU into a wait state to reduce power consumption while waiting for pulses */ | ||
ulp_lp_core_wait_for_intr(); | ||
#endif //CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE | ||
} | ||
|
||
return 0; | ||
} |
30 changes: 30 additions & 0 deletions
30
examples/system/ulp/lp_core/gpio_intr_pulse_counter/pytest_lp_core_pcnt.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD | ||
# SPDX-License-Identifier: CC0-1.0 | ||
import logging | ||
|
||
import pytest | ||
from pytest_embedded import Dut | ||
|
||
|
||
@pytest.mark.esp32c6 | ||
@pytest.mark.esp32p4 | ||
@pytest.mark.generic | ||
def test_lp_core_pcnt(dut: Dut) -> None: | ||
|
||
res = dut.expect(r'ULP will wake up processor after every (\d+) pulses') | ||
wakeup_limit = res.group(1).decode('utf-8') | ||
assert (int(wakeup_limit) > 0) | ||
logging.info(f'Wake-up limit: {wakeup_limit} pulses') | ||
|
||
dut.expect_exact('Not a ULP wakeup, initializing it!') | ||
dut.expect_exact('Entering in deep sleep') | ||
|
||
dut.expect_exact('ULP woke up the main CPU!') | ||
|
||
res = dut.expect(r'Pulse count: (\d+)') | ||
pulse_count = res.group(1).decode('utf-8') | ||
logging.info(f'Pulse count: {pulse_count}') | ||
|
||
# Check that pulse count is correct, we could have gotten pulses between triggering | ||
# the wakeup signal and printing the count, but it should at be equal to or greater | ||
assert (int(pulse_count) >= int(wakeup_limit)) |
1 change: 1 addition & 0 deletions
1
examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.ci
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE=y |
9 changes: 9 additions & 0 deletions
9
examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.defaults
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |