diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index f4d6b6b869..0590a39954 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -315,6 +315,12 @@ examples/system/ulp/lp_core/interrupt: depends_components: - ulp +examples/system/ulp/lp_core/lp_adc: + disable: + - if: (SOC_LP_ADC_SUPPORTED != 1) + depends_components: + - ulp, esp_adc + examples/system/ulp/lp_core/lp_i2c: enable: - if: SOC_LP_I2C_SUPPORTED == 1 and SOC_DEEP_SLEEP_SUPPORTED == 1 diff --git a/examples/system/ulp/lp_core/lp_adc/CMakeLists.txt b/examples/system/ulp/lp_core/lp_adc/CMakeLists.txt new file mode 100644 index 0000000000..6701b75d56 --- /dev/null +++ b/examples/system/ulp/lp_core/lp_adc/CMakeLists.txt @@ -0,0 +1,8 @@ +# 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) + +list(APPEND SDKCONFIG_DEFAULTS "sdkconfig.defaults") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(lp_core_adc) diff --git a/examples/system/ulp/lp_core/lp_adc/README.md b/examples/system/ulp/lp_core/lp_adc/README.md new file mode 100644 index 0000000000..89b1dd2d29 --- /dev/null +++ b/examples/system/ulp/lp_core/lp_adc/README.md @@ -0,0 +1,63 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | + +# LP ADC Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates how to use the LP ADC peripheral on the LP core. The example sets up the LP ADC from the HP core before putting it to sleep. +It then reads the configured LP ADC channels from the LP core and prints the raw and converted voltage values to the LP UART console. + +## How to use example + +### Hardware Required + +* A development board with ESP SoC such as the ESP32-P4 which supports LP ADC. +* A USB cable for power supply and programming +* A USB to UART converter to monitor the LP core serial console + +In this example, you need to connect a voltage source (e.g. a DC power supply) to the GPIO pins for the input ADC channels. The ADC channels to read can be configured from the menuconfig option for this example. + +**Note:** The following pin assignments are used by default. + +#### LP UART Pin Assignment: + +| | UART Tx Pin | +| ----------------------- | ------------| +| ESP32-P4 | GPIO14 | + +The UART Tx Pin must be connected to the UART Rx pin on the host machine. + +#### LP ADC Pin Assignments: + +| | LP ADC Channel Number | Pin | +| ----------------------- | --------------------------| ------ | +| ESP32-P4 | Channel 4 | GPIO20 | +| ESP32-P4 | Channel 5 | GPIO21 | + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: +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 + +Running this example, you will see the following log output on the LP core serial monitor: + +``` +ESP-ROM-LP:esp32p4-20230811 +Build:Aug 11 2023 +rst:0x14 (SW_RST), wakeup:0x40000 +entry:0x50108180 +lpadc1 chan0 raw value = 0 +lpadc1 chan0 converted value = 0 mV +lpadc1 chan1 raw value = 3894 +lpadc1 chan1 converted value = 4167 mV +``` diff --git a/examples/system/ulp/lp_core/lp_adc/main/CMakeLists.txt b/examples/system/ulp/lp_core/lp_adc/main/CMakeLists.txt new file mode 100644 index 0000000000..92e6a41038 --- /dev/null +++ b/examples/system/ulp/lp_core/lp_adc/main/CMakeLists.txt @@ -0,0 +1,25 @@ +# Register the component +idf_component_register(SRCS "lp_adc_main.c" + INCLUDE_DIRS "." + REQUIRES ulp) + +# +# ULP support additions to component CMakeLists.txt. +# +# 1. The LP Core app name must be unique (if multiple components use LP Core). +set(ulp_app_name lp_core_${COMPONENT_NAME}) +# +# 2. Specify all C files. +# Files should be placed into a separate directory (in this case, lp_core/), +# which should not be added to COMPONENT_SRCS. +set(ulp_lp_core_sources "lp_core/main.c") + +# +# 3. List all the component source files which include automatically +# generated LP Core export file, ${ulp_app_name}.h: +set(ulp_exp_dep_srcs "lp_adc_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_lp_core_sources}" "${ulp_exp_dep_srcs}") diff --git a/examples/system/ulp/lp_core/lp_adc/main/Kconfig.projbuild b/examples/system/ulp/lp_core/lp_adc/main/Kconfig.projbuild new file mode 100644 index 0000000000..f68b55eeea --- /dev/null +++ b/examples/system/ulp/lp_core/lp_adc/main/Kconfig.projbuild @@ -0,0 +1,17 @@ +menu "Example Configuration" + + config EXAMPLE_LP_ADC1_CHANNEL_0_SELECT + int "LP ADC1 Channel 0 Select" + default 4 + range 0 7 + help + Select the channel to be used for LP ADC1 Channel 0 + + config EXAMPLE_LP_ADC1_CHANNEL_1_SELECT + int "LP ADC1 Channel 1 Select" + default 5 + range 0 7 + help + Select the channel to be used for LP ADC1 Channel 1 + +endmenu diff --git a/examples/system/ulp/lp_core/lp_adc/main/lp_adc_main.c b/examples/system/ulp/lp_core/lp_adc/main/lp_adc_main.c new file mode 100644 index 0000000000..e7bd6d6e67 --- /dev/null +++ b/examples/system/ulp/lp_core/lp_adc/main/lp_adc_main.c @@ -0,0 +1,76 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_sleep.h" +#include "lp_core_main.h" +#include "ulp_lp_core.h" +#include "lp_core_uart.h" +#include "ulp_lp_core_lp_adc_shared.h" + +/* LP ADC1 configuration */ +#define EXAMPLE_LP_ADC1_CHAN0 CONFIG_EXAMPLE_LP_ADC1_CHANNEL_0_SELECT +#define EXAMPLE_LP_ADC1_CHAN1 CONFIG_EXAMPLE_LP_ADC1_CHANNEL_1_SELECT +#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_12 + +/* LP core binary */ +extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_main_bin_start"); +extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_main_bin_end"); + +static void lp_uart_init(void) +{ + lp_core_uart_cfg_t cfg = LP_CORE_UART_DEFAULT_CONFIG(); + + ESP_ERROR_CHECK(lp_core_uart_init(&cfg)); + + printf("LP UART initialized successfully\n"); +} + +static void lp_core_init(void) +{ + /* Set LP core wakeup source as the HP CPU */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER, + .lp_timer_sleep_duration_us = 1000000, + }; + + /* Load LP core firmware */ + ESP_ERROR_CHECK(ulp_lp_core_load_binary(lp_core_main_bin_start, (lp_core_main_bin_end - lp_core_main_bin_start))); + + /* Run LP core */ + ESP_ERROR_CHECK(ulp_lp_core_run(&cfg)); + + printf("LP core loaded with firmware and running successfully\n"); +} + +void app_main(void) +{ + /* LP ADC1 Init */ + ESP_ERROR_CHECK(lp_core_lp_adc_init(ADC_UNIT_1)); + + /* LP ADC1 channel config */ + const lp_core_lp_adc_chan_cfg_t config = { + .atten = EXAMPLE_ADC_ATTEN, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ESP_ERROR_CHECK(lp_core_lp_adc_config_channel(ADC_UNIT_1, EXAMPLE_LP_ADC1_CHAN0, &config)); + ESP_ERROR_CHECK(lp_core_lp_adc_config_channel(ADC_UNIT_1, EXAMPLE_LP_ADC1_CHAN1, &config)); + + /* Initialize LP_UART to print the ADC values to the LP core console */ + lp_uart_init(); + + /* Load LP Core binary and start the coprocessor */ + lp_core_init(); + + /* Enable ULP wakeup */ + ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup()); + + /* Enter Deep Sleep */ + printf("Entering deep sleep...\n"); + esp_deep_sleep_start(); +} diff --git a/examples/system/ulp/lp_core/lp_adc/main/lp_core/main.c b/examples/system/ulp/lp_core/lp_adc/main/lp_core/main.c new file mode 100644 index 0000000000..67f85a58c9 --- /dev/null +++ b/examples/system/ulp/lp_core/lp_adc/main/lp_core/main.c @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "sdkconfig.h" +#include "ulp_lp_core_print.h" +#include "ulp_lp_core_lp_adc_shared.h" + +#define EXAMPLE_LP_ADC1_CHAN0 CONFIG_EXAMPLE_LP_ADC1_CHANNEL_0_SELECT +#define EXAMPLE_LP_ADC1_CHAN1 CONFIG_EXAMPLE_LP_ADC1_CHANNEL_1_SELECT +int main (void) +{ + + int adc_raw_value[2]; + int adc_converted_value[2]; + + lp_core_lp_adc_read_channel_raw(ADC_UNIT_1, EXAMPLE_LP_ADC1_CHAN0, &adc_raw_value[0]); + lp_core_printf("lpadc1 chan0 raw value = %d\r\n", adc_raw_value[0]); + lp_core_lp_adc_read_channel_converted(ADC_UNIT_1, EXAMPLE_LP_ADC1_CHAN0, &adc_converted_value[0]); + lp_core_printf("lpadc1 chan0 converted value = %d mV\r\n", adc_converted_value[0]); + + lp_core_lp_adc_read_channel_raw(ADC_UNIT_1, EXAMPLE_LP_ADC1_CHAN1, &adc_raw_value[1]); + lp_core_printf("lpadc1 chan1 raw value = %d\r\n", adc_raw_value[1]); + lp_core_lp_adc_read_channel_converted(ADC_UNIT_1, EXAMPLE_LP_ADC1_CHAN1, &adc_converted_value[1]); + lp_core_printf("lpadc1 chan1 converted value = %d mV\r\n", adc_converted_value[1]); + + lp_core_printf("\n"); + + return 0; +} diff --git a/examples/system/ulp/lp_core/lp_adc/sdkconfig.defaults b/examples/system/ulp/lp_core/lp_adc/sdkconfig.defaults new file mode 100644 index 0000000000..d41662df2a --- /dev/null +++ b/examples/system/ulp/lp_core/lp_adc/sdkconfig.defaults @@ -0,0 +1,10 @@ +# Enable LP Core +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_LP_CORE=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