Przeglądaj źródła

Merge branch 'feature/ulp_riscv_adc' into 'master'

ulp-riscv: add support for using ADC as well as an example show-casing it.

Closes IDFGH-7564 and IDF-1714

See merge request espressif/esp-idf!18767
Marius Vikhammer 3 lat temu
rodzic
commit
6cc871d793
33 zmienionych plików z 415 dodań i 29 usunięć
  1. 0 2
      components/bootloader_support/src/bootloader_random_esp32s3.c
  2. 1 1
      components/driver/adc_single.c
  3. 26 0
      components/esp_hw_support/include/esp_private/esp_sleep_internal.h
  4. 2 2
      components/esp_hw_support/sleep_modes.c
  5. 2 2
      components/esp_system/test_apps/rtc_power_modes/README.md
  6. 4 4
      components/esp_system/test_apps/rtc_power_modes/main/test_rtc_power.c
  7. 3 1
      components/hal/platform_port/include/hal/assert.h
  8. 4 2
      components/ulp/CMakeLists.txt
  9. 6 3
      components/ulp/cmake/CMakeLists.txt
  10. 9 0
      components/ulp/ld/esp32s2.periperals.ld
  11. 9 0
      components/ulp/ld/esp32s3.periperals.ld
  12. 1 0
      components/ulp/project_include.cmake
  13. 0 5
      components/ulp/test/CMakeLists.txt
  14. 1 1
      components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv.h
  15. 2 2
      components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_gpio.h
  16. 2 2
      components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_register_ops.h
  17. 2 2
      components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_utils.h
  18. 29 0
      components/ulp/ulp_riscv/include/ulp_riscv_adc.h
  19. 32 0
      components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_adc_ulp_core.h
  20. 0 0
      components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h
  21. 0 0
      components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_register_ops.h
  22. 0 0
      components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_utils.h
  23. 5 0
      components/ulp/ulp_riscv/ulp_core/start.S
  24. 30 0
      components/ulp/ulp_riscv/ulp_core/ulp_riscv_adc.c
  25. 0 0
      components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c
  26. 42 0
      components/ulp/ulp_riscv/ulp_riscv_adc.c
  27. 6 0
      examples/system/ulp_riscv/adc/CMakeLists.txt
  28. 32 0
      examples/system/ulp_riscv/adc/README.md
  29. 25 0
      examples/system/ulp_riscv/adc/main/CMakeLists.txt
  30. 16 0
      examples/system/ulp_riscv/adc/main/ulp/example_config.h
  31. 36 0
      examples/system/ulp_riscv/adc/main/ulp/main.c
  32. 79 0
      examples/system/ulp_riscv/adc/main/ulp_riscv_adc_example_main.c
  33. 9 0
      examples/system/ulp_riscv/adc/sdkconfig.defaults

+ 0 - 2
components/bootloader_support/src/bootloader_random_esp32s3.c

@@ -83,8 +83,6 @@ void bootloader_random_disable(void)
     REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 0);
     REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 0);
 
-    //Stop SAR ADC clock
-    CLEAR_PERI_REG_MASK(SENS_SAR_PERI_CLK_GATE_CONF_REG, SENS_SARADC_CLK_EN);
     //Power off SAR ADC
     REG_SET_FIELD(SENS_SAR_POWER_XPD_SAR_REG, SENS_FORCE_XPD_SAR, 0);
     //return to ADC RTC controller

+ 1 - 1
components/driver/adc_single.c

@@ -225,7 +225,7 @@ esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
 #if SOC_ADC_RTC_CTRL_SUPPORTED
 
 #if SOC_ADC_CALIBRATION_V1_SUPPORTED
-static uint32_t get_calibration_offset(adc_unit_t adc_n, adc_channel_t chan)
+uint32_t get_calibration_offset(adc_unit_t adc_n, adc_channel_t chan)
 {
     adc_atten_t atten = adc_ll_get_atten(adc_n, chan);
     extern uint32_t adc_get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten);

+ 26 - 0
components/esp_hw_support/include/esp_private/esp_sleep_internal.h

@@ -0,0 +1,26 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @brief Enables the use of ADC and temperature sensor in monitor (ULP) mode
+ *
+ * @note  This state is kept in RTC memory and will keep its value after a deep sleep wakeup
+ *
+ */
+void esp_sleep_enable_adc_tsens_monitor(bool enable);
+
+
+#ifdef __cplusplus
+}
+#endif

+ 2 - 2
components/esp_hw_support/sleep_modes.c

@@ -182,7 +182,7 @@ static bool s_light_sleep_wakeup = false;
 static portMUX_TYPE spinlock_rtc_deep_sleep = portMUX_INITIALIZER_UNLOCKED;
 
 static const char *TAG = "sleep";
-static bool s_adc_tsen_enabled = false;
+static RTC_FAST_ATTR bool s_adc_tsen_enabled = false;
 //in this mode, 2uA is saved, but RTC memory can't use at high temperature, and RTCIO can't be used as INPUT.
 static bool s_ultra_low_enabled = false;
 
@@ -1386,7 +1386,7 @@ void esp_deep_sleep_disable_rom_logging(void)
     rtc_suppress_rom_log();
 }
 
-void rtc_sleep_enable_adc_tesn_monitor(bool enable)
+void esp_sleep_enable_adc_tsens_monitor(bool enable)
 {
     s_adc_tsen_enabled = enable;
 }

+ 2 - 2
components/esp_system/test_apps/rtc_power_modes/README.md

@@ -8,12 +8,12 @@ This test app is to enter 7 different sub power modes we have, so that the power
 Currently there are 6 sub power modes, 3 for deepsleep and 3 for lightsleep. Show as below (priority from high to low).
 
 ## Deepsleep
-1. Mode for ADC/Temp Sensor in monitor mode (ULP). To enable this mode, call `rtc_sleep_enable_adc_tesn_monitor`.
+1. Mode for ADC/Temp Sensor in monitor mode (ULP). To enable this mode, call `esp_sleep_enable_adc_tsens_monitor`.
 2. Default mode.
 3. Ultra low power mode. To enable this mode, call `rtc_sleep_enable_ultra_low`. Note if mode 1 has higher priority than this.
 
 ## Lightsleep
 1. Mode for using 40 MHz XTAL in lightsleep. To enable this mode, call `esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON)`.
 2. Mode for using 8M clock by digital system (peripherals). To enable this mode, initialize LEDC with 8M clock source.
-3. Mode for ADC/Temp Sensor in monitor mode (ULP). To enable this mdoe, call `rtc_sleep_enable_adc_tesn_monitor`.
+3. Mode for ADC/Temp Sensor in monitor mode (ULP). To enable this mdoe, call `esp_sleep_enable_adc_tsens_monitor`.
 4. Default mode.

+ 4 - 4
components/esp_system/test_apps/rtc_power_modes/main/test_rtc_power.c

@@ -16,6 +16,7 @@
 #include "soc/soc_caps.h"
 #include "driver/ledc.h"
 #include "soc/rtc.h"
+#include "esp_private/esp_sleep_internal.h"
 
 static const char TAG[] = "rtc_power";
 
@@ -30,8 +31,7 @@ TEST_CASE("Power Test: Deepsleep (with ADC/TSEN in monitor)", "[pm]")
 {
     rtc_dig_clk8m_disable();    //This is workaround for bootloader not disable 8M as digital clock source
 
-    extern void rtc_sleep_enable_adc_tesn_monitor(bool);
-    rtc_sleep_enable_adc_tesn_monitor(true);
+    esp_sleep_enable_adc_tsens_monitor(true);
     test_deepsleep();
 }
 
@@ -108,8 +108,8 @@ TEST_CASE("Power Test: Lightsleep (with ADC/TSEN in monitor)", "[pm]")
 {
     rtc_dig_clk8m_disable();    //This is workaround for bootloader not disable 8M as digital clock source
 
-    extern void rtc_sleep_enable_adc_tesn_monitor(bool);
-    rtc_sleep_enable_adc_tesn_monitor(true);
+    extern void esp_sleep_enable_adc_tsens_monitor(bool);
+    esp_sleep_enable_adc_tsens_monitor(true);
     test_lightsleep();
 }
 

+ 3 - 1
components/hal/platform_port/include/hal/assert.h

@@ -31,7 +31,9 @@ extern void abort(void);
 #endif
 #endif
 
-#if CONFIG_HAL_DEFAULT_ASSERTION_LEVEL == 1 // silent
+#if IS_ULP_COCPU
+#define HAL_ASSERT(__e) ((void)(__e))
+#elif CONFIG_HAL_DEFAULT_ASSERTION_LEVEL == 1 // silent
 #define HAL_ASSERT(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : abort())
 #elif CONFIG_HAL_DEFAULT_ASSERTION_LEVEL == 2 // full assertion
 #define HAL_ASSERT(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func(__FILE__, __LINE__, __ASSERT_FUNC, #__e))

+ 4 - 2
components/ulp/CMakeLists.txt

@@ -23,7 +23,8 @@ if(CONFIG_SOC_ULP_SUPPORTED OR CONFIG_SOC_RISCV_COPROC_SUPPORTED)
 
     elseif(CONFIG_ULP_COPROC_TYPE_RISCV)
         list(APPEND srcs
-            "ulp_riscv/ulp_riscv.c")
+            "ulp_riscv/ulp_riscv.c"
+            "ulp_riscv/ulp_riscv_adc.c")
 
         list(APPEND includes
             ulp_riscv/include)
@@ -31,4 +32,5 @@ if(CONFIG_SOC_ULP_SUPPORTED OR CONFIG_SOC_RISCV_COPROC_SUPPORTED)
 endif()
 
 idf_component_register(SRCS ${srcs}
-                       INCLUDE_DIRS ${includes})
+                       INCLUDE_DIRS ${includes}
+                       REQUIRES driver)

+ 6 - 3
components/ulp/cmake/CMakeLists.txt

@@ -71,8 +71,9 @@ add_custom_target(${ULP_APP_NAME}_ld_script
 if(ULP_COCPU_IS_RISCV)
     #risc-v ulp uses extra files for building:
     list(APPEND ULP_S_SOURCES
-        "${IDF_PATH}/components/ulp/ulp_riscv/start.S"
-        "${IDF_PATH}/components/ulp/ulp_riscv/ulp_riscv_utils.c")
+        "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/start.S"
+        "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_adc.c"
+        "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c")
 
     #dummy loop to force pre-processed linker file generation:
     foreach(ulp_s_source ${ULP_S_SOURCES})
@@ -95,7 +96,9 @@ if(ULP_COCPU_IS_RISCV)
     list(APPEND EXTRA_LINKER_ARGS "-Wl,--gc-sections")
     list(APPEND EXTRA_LINKER_ARGS "-Wl,-Map=\"${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}.map\"")
     #Makes the csr utillies for riscv visible:
-    target_include_directories(${ULP_APP_NAME} PRIVATE "${IDF_PATH}/components/ulp/ulp_riscv/include")
+    target_include_directories(${ULP_APP_NAME} PRIVATE "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/include")
+    target_link_libraries(${ULP_APP_NAME} "-T \"${IDF_PATH}/components/ulp/ld/${IDF_TARGET}.periperals.ld\"")
+    target_compile_definitions(${ULP_APP_NAME} PRIVATE IS_ULP_COCPU)
 
 else()
 

+ 9 - 0
components/ulp/ld/esp32s2.periperals.ld

@@ -0,0 +1,9 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+PROVIDE ( RTCCNTL = 0x8000 );
+PROVIDE ( RTCIO = 0xA400 );
+PROVIDE ( SENS = 0xC800 );

+ 9 - 0
components/ulp/ld/esp32s3.periperals.ld

@@ -0,0 +1,9 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+PROVIDE ( RTCCNTL = 0x8000 );
+PROVIDE ( RTCIO = 0xA400 );
+PROVIDE ( SENS = 0xC800 );

+ 1 - 0
components/ulp/project_include.cmake

@@ -58,6 +58,7 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs)
                             -DULP_APP_NAME=${app_name}
                             -DCOMPONENT_DIR=${COMPONENT_DIR}
                             -DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>
+                            -DIDF_TARGET=${idf_target}
                             -DIDF_PATH=${idf_path}
                             -DSDKCONFIG_HEADER=${SDKCONFIG_HEADER}
                             -DPYTHON=${python}

+ 0 - 5
components/ulp/test/CMakeLists.txt

@@ -1,8 +1,3 @@
-if(IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET STREQUAL "esp32s3")
-    #Disabled for now due to RTC bug IDF-4801
-    return()
-endif()
-
 if(NOT CONFIG_ULP_COPROC_TYPE_FSM AND NOT CONFIG_ULP_COPROC_TYPE_RISCV)
     # Nothing to test if no co-processor enabled
     return()

+ 1 - 1
components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv.h

@@ -6,4 +6,4 @@
 #pragma once
 
 #warning Contents of ulp_riscv/ulp_riscv.h have been deprecated. Please include the header which contains the actual definitions you are trying to use, e.g. "ulp_riscv_register_ops.h".
-#include "../ulp_riscv_register_ops.h"
+#include "../../ulp_core/include/ulp_riscv_register_ops.h"

+ 2 - 2
components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_gpio.h

@@ -6,5 +6,5 @@
 
 #pragma once
 
-#warning "ulp_riscv_gpio.h has been moved one level up. Please include the file without the ulp_riscv prefix."
-#include "../ulp_riscv_gpio.h"
+#warning "ulp_riscv_gpio.h has been moved. Please include the file without the ulp_riscv prefix."
+#include "../../ulp_core/include/ulp_riscv_gpio.h"

+ 2 - 2
components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_register_ops.h

@@ -5,5 +5,5 @@
  */
 #pragma once
 
-#warning ulp_riscv_register_ops.h has been moved one level up. Please include the file without the ulp_riscv prefix.
-#include "../ulp_riscv_register_ops.h"
+#warning ulp_riscv_register_ops.h has been moved. Please include the file without the ulp_riscv prefix.
+#include "../../ulp_core/include/ulp_riscv_register_ops.h"

+ 2 - 2
components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_utils.h

@@ -5,5 +5,5 @@
  */
 #pragma once
 
-#warning ulp_riscv_utils.h has been moved one level up. Please include the file without the ulp_riscv prefix.
-#include "../ulp_riscv_utils.h"
+#warning ulp_riscv_utils.h has been moved. Please include the file without the ulp_riscv prefix.
+#include "../../ulp_core/include/ulp_riscv_utils.h"

+ 29 - 0
components/ulp/ulp_riscv/include/ulp_riscv_adc.h

@@ -0,0 +1,29 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include "hal/adc_types.h"
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    adc_unit_t adc_n;       // ADC Unit
+    adc_channel_t channel;  // ADC channel
+    adc_atten_t atten;      // ADC channel attenuation
+    adc_bits_width_t width; // ADC bit width, only used for ADC unit 1
+} ulp_riscv_adc_cfg_t;      // ULP Riscv ADC configuration parameters
+
+/**
+ * @brief Initialize and calibrate the ADC for use by ULP RISCV
+ *
+ * @param cfg           Configuration parameters
+ * @return esp_err_t    ESP_OK for successful.
+ */
+esp_err_t ulp_riscv_adc_init(const ulp_riscv_adc_cfg_t *cfg);

+ 32 - 0
components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_adc_ulp_core.h

@@ -0,0 +1,32 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include "hal/adc_ll.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Start an ADC conversion and get the converted value.
+ *
+ * @note Will block until the conversion is completed
+ *
+ * @note ADC should be initilized for ULP by main CPU by calling ulp_riscv_adc_init()
+ *       before calling this.
+ *
+ * @param      adc_n   ADC unit.
+ * @param      channel ADC channel number.
+ *
+ * @return             Converted value, -1 if conversion failed
+ */
+int32_t ulp_riscv_adc_read_channel(adc_unit_t adc_n, int channel);
+
+#ifdef __cplusplus
+}
+#endif

+ 0 - 0
components/ulp/ulp_riscv/include/ulp_riscv_gpio.h → components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h


+ 0 - 0
components/ulp/ulp_riscv/include/ulp_riscv_register_ops.h → components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_register_ops.h


+ 0 - 0
components/ulp/ulp_riscv/include/ulp_riscv_utils.h → components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_utils.h


+ 5 - 0
components/ulp/ulp_riscv/start.S → components/ulp/ulp_riscv/ulp_core/start.S

@@ -1,3 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 	.section .text.vectors
 	.global irq_vector
 	.global reset_vector

+ 30 - 0
components/ulp/ulp_riscv/ulp_core/ulp_riscv_adc.c

@@ -0,0 +1,30 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "ulp_riscv_adc.h"
+#include "hal/adc_ll.h"
+
+int32_t ulp_riscv_adc_read_channel(adc_unit_t adc_n, int channel)
+{
+    uint32_t event = (adc_n == ADC_UNIT_1) ? ADC_LL_EVENT_ADC1_ONESHOT_DONE : ADC_LL_EVENT_ADC2_ONESHOT_DONE;
+    adc_oneshot_ll_clear_event(event);
+    adc_oneshot_ll_disable_all_unit();
+    adc_oneshot_ll_enable(adc_n);
+    adc_oneshot_ll_set_channel(adc_n, channel);
+
+    adc_oneshot_ll_start(adc_n);
+    while (adc_oneshot_ll_get_event(event) != true) {
+        ;
+    }
+    int32_t out_raw = adc_oneshot_ll_get_raw_result(adc_n);
+    if (adc_oneshot_ll_raw_check_valid(adc_n, out_raw) == false) {
+        return -1;
+    }
+
+    //HW workaround: when enabling periph clock, this should be false
+    adc_oneshot_ll_disable_all_unit();
+
+    return out_raw;
+}

+ 0 - 0
components/ulp/ulp_riscv/ulp_riscv_utils.c → components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c


+ 42 - 0
components/ulp/ulp_riscv/ulp_riscv_adc.c

@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "ulp_riscv_adc.h"
+#include "esp_err.h"
+#include "esp_check.h"
+#include "esp_log.h"
+#include "driver/adc.h"
+#include "hal/adc_hal_common.h"
+#include "esp_private/esp_sleep_internal.h"
+
+
+/* Will be refactored when ADC NG is merged, TODO IDF-5513 */
+extern esp_err_t adc1_rtc_mode_acquire(void);
+extern uint32_t get_calibration_offset(adc_unit_t adc_n, adc_channel_t chan);
+
+static const char *TAG = "ulp_riscv_adc";
+
+esp_err_t ulp_riscv_adc_init(const ulp_riscv_adc_cfg_t *cfg)
+{
+    esp_err_t ret = ESP_OK;
+
+    ESP_GOTO_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, err, TAG, "cfg == NULL");
+    ESP_GOTO_ON_FALSE(cfg->adc_n == ADC_UNIT_1, ESP_ERR_INVALID_ARG, err, TAG, "Only ADC_UNIT_1 is supported for now");
+
+    adc1_config_channel_atten(cfg->channel, cfg->atten);
+    adc1_config_width(cfg->width);
+
+    //Calibrate the ADC
+    uint32_t cal_val = get_calibration_offset(cfg->adc_n, cfg->channel);
+    adc_hal_set_calibration_param(cfg->adc_n, cal_val);
+
+    adc1_rtc_mode_acquire();
+
+    esp_sleep_enable_adc_tsens_monitor(true);
+
+err:
+    return ret;
+}

+ 6 - 0
examples/system/ulp_riscv/adc/CMakeLists.txt

@@ -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-adc-example)

+ 32 - 0
examples/system/ulp_riscv/adc/README.md

@@ -0,0 +1,32 @@
+| Supported Targets | ESP32-S3 |
+| ----------------- | -------- |
+
+# ULP-RISC-V ADC Example
+
+This example demonstrates how to use the ULP-RISC-V coprocessor to poll the ADC in deep sleep.
+
+The ULP program periodically measures the input voltage on EXAMPLE_ADC_CHANNEL (by default ADC1 channel 0, GPIO1 on both ESP32-S2 and ESP32-S3). The voltage is compared to an upper threshold. If the voltage is higher than the threshold, the ULP wakes up the system.
+
+By default, the threshold is set to 1.75V, approximately.
+
+In this example, you need to connect a voltage source (e.g. a DC power supply) to the GPIO pin corresponding to the ADC channel specified in `ulp/example_config.h` (see the macros defined on the top of the header file). Feel free to modify the channel setting.
+
+### Hardware Required
+
+* A development board with a SOC which has a RISC-V ULP coprocessor (e.g., ESP32-S2 Saola)
+* A USB cable for power supply and programming
+
+## Example output
+
+Below is the output from this example.
+
+```
+Not a ULP-RISC-V wakeup (cause = 0), initializing it!
+Entering in deep sleep
+
+ULP-RISC-V woke up the main CPU
+Threshold: high = 2000
+Value = 4095 was above threshold
+Entering in deep sleep
+```
+

+ 25 - 0
examples/system/ulp_riscv/adc/main/CMakeLists.txt

@@ -0,0 +1,25 @@
+idf_component_register(SRCS "ulp_riscv_adc_example_main.c"
+                    INCLUDE_DIRS ""
+                    REQUIRES soc ulp esp_adc_cal)
+
+
+#
+# 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_adc_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}")

+ 16 - 0
examples/system/ulp_riscv/adc/main/ulp/example_config.h

@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+#pragma once
+
+#include "hal/adc_types.h"
+
+#define EXAMPLE_ADC_CHANNEL     ADC_CHANNEL_0
+#define EXAMPLE_ADC_UNIT        ADC_UNIT_1
+#define EXAMPLE_ADC_ATTEN       ADC_ATTEN_DB_11
+#define EXAMPLE_ADC_WIDTH       ADC_WIDTH_BIT_12
+
+/* Set high threshold, approx. 1.75V*/
+#define EXAMPLE_ADC_TRESHOLD    2000

+ 36 - 0
examples/system/ulp_riscv/adc/main/ulp/main.c

@@ -0,0 +1,36 @@
+/*
+ * 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 <stdint.h>
+#include "ulp_riscv_utils.h"
+#include "ulp_riscv_adc_ulp_core.h"
+
+#include "example_config.h"
+
+uint32_t adc_threshold = EXAMPLE_ADC_TRESHOLD;
+int32_t wakeup_result;
+
+int main (void)
+{
+    int32_t last_result = ulp_riscv_adc_read_channel(EXAMPLE_ADC_UNIT, EXAMPLE_ADC_CHANNEL);
+
+    if (last_result > adc_threshold) {
+        wakeup_result = last_result;
+        ulp_riscv_wakeup_main_processor();
+    }
+
+    return 0;
+}

+ 79 - 0
examples/system/ulp_riscv/adc/main/ulp_riscv_adc_example_main.c

@@ -0,0 +1,79 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+/* ULP riscv 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_riscv_adc.h"
+#include "ulp_main.h"
+#include "ulp/example_config.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) && (cause != ESP_SLEEP_WAKEUP_TIMER)) {
+        printf("Not a ULP-RISC-V wakeup (cause = %d), initializing it! \n", cause);
+        init_ulp_program();
+    }
+
+    /* ULP Risc-V read and detected a temperature above the limit */
+    if (cause == ESP_SLEEP_WAKEUP_ULP) {
+        printf("ULP-RISC-V woke up the main CPU\n");
+        printf("Threshold: high = %d\n", ulp_adc_threshold);
+        printf("Value = %d was above threshold\n", ulp_wakeup_result);
+    }
+
+    /* Go back to sleep, only the ULP Risc-V will run */
+    printf("Entering in deep sleep\n\n");
+
+    /* RTC peripheral power domain needs to be kept on to keep SAR ADC related configs during sleep */
+    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)
+{
+    ulp_riscv_adc_cfg_t cfg = {
+        .adc_n   = EXAMPLE_ADC_UNIT,
+        .channel = EXAMPLE_ADC_CHANNEL,
+        .width   = EXAMPLE_ADC_WIDTH,
+        .atten   = EXAMPLE_ADC_ATTEN,
+    };
+
+    ESP_ERROR_CHECK(ulp_riscv_adc_init(&cfg));
+
+    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);
+}

+ 9 - 0
examples/system/ulp_riscv/adc/sdkconfig.defaults

@@ -0,0 +1,9 @@
+# Enable ULP
+CONFIG_ULP_COPROC_ENABLED=y
+CONFIG_ULP_COPROC_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