diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c index bca7ba4ab6..3bde311c53 100644 --- a/components/esp_adc/adc_oneshot.c +++ b/components/esp_adc/adc_oneshot.c @@ -100,16 +100,24 @@ esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, a unit->unit_id = init_config->unit_id; unit->ulp_mode = init_config->ulp_mode; - adc_oneshot_clk_src_t clk_src = ADC_DIGI_CLK_SRC_DEFAULT; - if (init_config->clk_src) { - clk_src = init_config->clk_src; + adc_oneshot_clk_src_t clk_src; +#if SOC_LP_ADC_SUPPORTED + if (init_config->ulp_mode != ADC_ULP_MODE_DISABLE) { + clk_src = LP_ADC_CLK_SRC_LP_DYN_FAST; + } else +#endif /* CONFIG_SOC_LP_ADC_SUPPORTED */ + { + clk_src = ADC_DIGI_CLK_SRC_DEFAULT; + if (init_config->clk_src) { + clk_src = init_config->clk_src; + } } uint32_t clk_src_freq_hz = 0; ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz), err, TAG, "clock source not supported"); adc_oneshot_hal_cfg_t config = { .unit = init_config->unit_id, - .work_mode = (init_config->ulp_mode == ADC_ULP_MODE_FSM) ? ADC_HAL_ULP_FSM_MODE : ADC_HAL_SINGLE_READ_MODE, + .work_mode = (init_config->ulp_mode != ADC_ULP_MODE_DISABLE) ? ADC_HAL_LP_MODE : ADC_HAL_SINGLE_READ_MODE, .clk_src = clk_src, .clk_src_freq_hz = clk_src_freq_hz, }; diff --git a/components/hal/adc_hal_common.c b/components/hal/adc_hal_common.c index 4ea7ff9536..e1d8a652f2 100644 --- a/components/hal/adc_hal_common.c +++ b/components/hal/adc_hal_common.c @@ -18,8 +18,8 @@ static adc_ll_controller_t get_controller(adc_unit_t unit, adc_hal_work_mode_t w { if (unit == ADC_UNIT_1) { switch (work_mode) { -#if SOC_ULP_HAS_ADC - case ADC_HAL_ULP_FSM_MODE: +#if SOC_ULP_HAS_ADC || SOC_LP_CORE_SUPPORT_LP_ADC + case ADC_HAL_LP_MODE: return ADC_LL_CTRL_ULP; #endif case ADC_HAL_SINGLE_READ_MODE: @@ -35,8 +35,8 @@ static adc_ll_controller_t get_controller(adc_unit_t unit, adc_hal_work_mode_t w } } else { switch (work_mode) { -#if SOC_ULP_HAS_ADC - case ADC_HAL_ULP_FSM_MODE: +#if SOC_ULP_HAS_ADC || SOC_LP_CORE_SUPPORT_LP_ADC + case ADC_HAL_LP_MODE: return ADC_LL_CTRL_ULP; #endif #if !SOC_ADC_ARBITER_SUPPORTED //No ADC2 arbiter on ESP32 diff --git a/components/hal/adc_oneshot_hal.c b/components/hal/adc_oneshot_hal.c index c74079d464..00e9be9de3 100644 --- a/components/hal/adc_oneshot_hal.c +++ b/components/hal/adc_oneshot_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -62,8 +62,16 @@ void adc_oneshot_hal_setup(adc_oneshot_hal_ctx_t *hal, adc_channel_t chan) adc_ll_digi_clk_sel(hal->clk_src); adc_ll_digi_controller_clk_div(ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT); adc_ll_digi_set_clk_div(ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT); +#else +#if SOC_LP_ADC_SUPPORTED + if (hal->work_mode == ADC_HAL_LP_MODE) { + adc_ll_set_sar_clk_div(unit, LP_ADC_LL_SAR_CLK_DIV_DEFAULT(unit)); + } else { + adc_ll_set_sar_clk_div(unit, ADC_LL_SAR_CLK_DIV_DEFAULT(unit)); + } #else adc_ll_set_sar_clk_div(unit, ADC_LL_SAR_CLK_DIV_DEFAULT(unit)); +#endif //SOC_LP_ADC_SUPPORTED if (unit == ADC_UNIT_2) { adc_ll_pwdet_set_cct(ADC_LL_PWDET_CCT_DEFAULT); } diff --git a/components/hal/esp32p4/include/hal/adc_ll.h b/components/hal/esp32p4/include/hal/adc_ll.h index 881cfd0c63..17745bb07a 100644 --- a/components/hal/esp32p4/include/hal/adc_ll.h +++ b/components/hal/esp32p4/include/hal/adc_ll.h @@ -39,6 +39,7 @@ extern "C" { ---------------------------------------------------------------*/ #define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (0) #define ADC_LL_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (1) +#define LP_ADC_LL_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (2) #define ADC_LL_DELAY_CYCLE_AFTER_DONE_SIGNAL (0) /*--------------------------------------------------------------- @@ -616,8 +617,8 @@ static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t c break; case ADC_LL_CTRL_ULP: LP_ADC.meas1_mux.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control. - LP_ADC.meas1_ctrl2.meas1_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. - LP_ADC.meas1_ctrl2.sar1_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + LP_ADC.meas1_ctrl2.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas1_ctrl2.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; break; case ADC_LL_CTRL_DIG: LP_ADC.meas1_mux.sar1_dig_force = 1; // 1: Select digital control; 0: Select RTC control. @@ -636,8 +637,8 @@ static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t c break; case ADC_LL_CTRL_ULP: LP_ADC.meas2_mux.sar2_rtc_force = 0; // 1: Select digital control; 0: Select RTC control. - LP_ADC.meas2_ctrl2.meas2_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. - LP_ADC.meas2_ctrl2.sar2_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + LP_ADC.meas2_ctrl2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas2_ctrl2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; break; case ADC_LL_CTRL_DIG: LP_ADC.meas2_mux.sar2_rtc_force = 0; // 1: Select digital control; 0: Select RTC control. diff --git a/components/hal/include/hal/adc_hal_common.h b/components/hal/include/hal/adc_hal_common.h index 11503873e9..7c563a3c1e 100644 --- a/components/hal/include/hal/adc_hal_common.h +++ b/components/hal/include/hal/adc_hal_common.h @@ -26,7 +26,7 @@ typedef enum adc_hal_work_mode_t { ADC_HAL_SINGLE_READ_MODE, ADC_HAL_CONTINUOUS_READ_MODE, ADC_HAL_PWDET_MODE, - ADC_HAL_ULP_FSM_MODE, + ADC_HAL_LP_MODE, } adc_hal_work_mode_t; /** @@ -61,7 +61,7 @@ void adc_hal_arbiter_config(adc_arbiter_t *config); /** * @brief Initialize default parameter for the calibration block. * - * @param adc_n ADC index numer + * @param adc_n ADC index number */ void adc_hal_calibration_init(adc_unit_t adc_n); diff --git a/components/hal/include/hal/adc_types.h b/components/hal/include/hal/adc_types.h index 34445ee3d5..8660047579 100644 --- a/components/hal/include/hal/adc_types.h +++ b/components/hal/include/hal/adc_types.h @@ -64,6 +64,9 @@ typedef enum { ADC_ULP_MODE_DISABLE = 0, ///< ADC ULP mode is disabled ADC_ULP_MODE_FSM = 1, ///< ADC is controlled by ULP FSM ADC_ULP_MODE_RISCV = 2, ///< ADC is controlled by ULP RISCV +#if SOC_LP_ADC_SUPPORTED + ADC_ULP_MODE_LP_CORE = 3, ///< ADC is controlled by LP Core +#endif // SOC_LP_ADC_SUPPORTED } adc_ulp_mode_t; /** diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index f1ac7a0dd8..628bbd742b 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -259,6 +259,10 @@ config SOC_LP_SPI_SUPPORTED bool default y +config SOC_LP_ADC_SUPPORTED + bool + default y + config SOC_SPIRAM_SUPPORTED bool default y @@ -1926,3 +1930,7 @@ config SOC_LCDCAM_CAM_DATA_WIDTH_MAX config SOC_LP_CORE_SUPPORT_ETM bool default y + +config SOC_LP_CORE_SUPPORT_LP_ADC + bool + default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 307392faab..8e140f0571 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -635,6 +635,20 @@ typedef enum { ADC_RTC_CLK_SRC_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the default clock choice */ } soc_periph_adc_rtc_clk_src_t; +///////////////////////////////////////////////LP_ADC/////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of LP_ADC + */ +#define SOC_LP_ADC_CLKS {SOC_MOD_CLK_LP_DYN_FAST} + +/** + * @brief LP ADC controller clock source + */ +typedef enum { + LP_ADC_CLK_SRC_LP_DYN_FAST = SOC_MOD_CLK_LP_DYN_FAST, /*!< Select LP_DYN_FAST as the source clock */ +} soc_periph_lp_adc_clk_src_t; + //////////////////////////////////////////////////MWDT///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index a1ccd05234..4653f982da 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -82,9 +82,9 @@ #define SOC_LP_I2C_SUPPORTED 1 #define SOC_LP_I2S_SUPPORTED 1 #define SOC_LP_SPI_SUPPORTED 1 +#define SOC_LP_ADC_SUPPORTED 1 #define SOC_SPIRAM_SUPPORTED 1 #define SOC_PSRAM_DMA_CAPABLE 1 -// #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534 #define SOC_SDMMC_HOST_SUPPORTED 1 #define SOC_CLK_TREE_SUPPORTED 1 #define SOC_ASSIST_DEBUG_SUPPORTED 1 @@ -738,3 +738,4 @@ /*------------------------------------- ULP CAPS -------------------------------------*/ #define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */ +#define SOC_LP_CORE_SUPPORT_LP_ADC (1) /*!< LP ADC can be accessed from the LP-Core */ diff --git a/components/ulp/CMakeLists.txt b/components/ulp/CMakeLists.txt index 24ea46461d..96b38e2025 100644 --- a/components/ulp/CMakeLists.txt +++ b/components/ulp/CMakeLists.txt @@ -73,6 +73,10 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE) if(CONFIG_SOC_LP_CORE_SUPPORT_ETM) list(APPEND srcs "lp_core/lp_core_etm.c") endif() + + if(CONFIG_SOC_LP_ADC_SUPPORTED) + list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_adc_shared.c") + endif() endif() idf_component_register(SRCS ${srcs} diff --git a/components/ulp/cmake/IDFULPProject.cmake b/components/ulp/cmake/IDFULPProject.cmake index f76bb89b7e..6febf12601 100644 --- a/components/ulp/cmake/IDFULPProject.cmake +++ b/components/ulp/cmake/IDFULPProject.cmake @@ -124,7 +124,8 @@ function(ulp_apply_default_sources ulp_app_name) "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_interrupt.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c" - "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_ubsan.c") + "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_ubsan.c" + "${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c") set(target_folder ${IDF_TARGET}) diff --git a/components/ulp/lp_core/shared/include/ulp_lp_core_lp_adc_shared.h b/components/ulp/lp_core/shared/include/ulp_lp_core_lp_adc_shared.h new file mode 100644 index 0000000000..310caa0b1a --- /dev/null +++ b/components/ulp/lp_core/shared/include/ulp_lp_core_lp_adc_shared.h @@ -0,0 +1,113 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" +#include "hal/adc_types.h" +#include "esp_adc/adc_oneshot.h" + +/** + * @brief LP ADC channel configurations + */ +typedef adc_oneshot_chan_cfg_t lp_core_lp_adc_chan_cfg_t; + +/** + * @brief Initialize the LP ADC + * + * @note We only support LP ADC1 and not LP ADC2 due to a HW issue. + * + * @param unit_id LP ADC unit to initialize + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG if the unit_id is invalid + * ESP_ERR_NOT_SUPPORTED if the API is not supported on the LP Core + * ESP_FAIL if the ADC unit failed to initialize + */ +esp_err_t lp_core_lp_adc_init(adc_unit_t unit_id); + +/** + * @brief Deinitialize the LP ADC + * + * @param unit_id LP ADC unit to deinitialize + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG if the unit_id is invalid + * ESP_ERR_NOT_SUPPORTED if the API is not supported on the LP Core + * ESP_FAIL if the ADC unit failed to deinitialize + */ +esp_err_t lp_core_lp_adc_deinit(adc_unit_t unit_id); + +/** + * @brief Configure an LP ADC channel + * + * @param unit_id ADC unit to configure the channel for + * @param channel ADC channel to configure + * @param chan_config Configuration for the channel + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG if the unit_id is invalid + * ESP_ERR_NOT_SUPPORTED if the API is not supported on the LP Core + * ESP_FAIL if the channel configuration fails + */ +esp_err_t lp_core_lp_adc_config_channel(adc_unit_t unit_id, adc_channel_t channel, const lp_core_lp_adc_chan_cfg_t *chan_config); + +/** + * @brief Read the raw ADC value from a channel + * + * @note The raw value is the 12-bit value read from the ADC. + * The value is between 0 and 4095. To convert this value + * to a voltage, use the formula: + * voltage = (raw_value * (1.1v / 4095)) * attenuation + * + * Alternatively, use lp_core_lp_adc_read_channel_converted() + * to get the converted value. + * + * @param[in] unit_id ADC unit to configure the channel for + * @param[in] channel ADC channel to configure + * @param[in] adc_raw Pointer to store the raw 12-bit ADC value + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG if the unit_id is invalid + * ESP_FAIL if the read fails + */ +esp_err_t lp_core_lp_adc_read_channel_raw(adc_unit_t unit_id, adc_channel_t channel, int *adc_raw); + +/** + * @brief Read the converted ADC value in millivolts from a channel + * + * @note The API converts the measured voltage based on the + * internal reference voltage of 1.1v and the the attenuation + * factors. It uses the formula: + * voltage = (raw_value * (1.1v / 4095)) * attenuation + * + * To avoid complex floating-point operations at runtime, + * the API converts the raw data to millivolts. Also, the + * conversion approximates the calculation when scaling + * the voltage by using pre-computed attenuation factors. + * + * @note The conversion approximates the measured voltage based on the + * internal reference voltage of 1.1v and the approximations of + * the attenuation factors. + * + * @param[in] unit_id ADC unit to configure the channel for + * @param[in] channel ADC channel to configure + * @param[out] voltage_mv Pointer to store the converted ADC value in millivolts + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG if the unit_id is invalid or voltage_mv is NULL + * ESP_FAIL if the read fails + */ +esp_err_t lp_core_lp_adc_read_channel_converted(adc_unit_t unit_id, adc_channel_t channel, int *voltage_mv); + +#ifdef __cplusplus +} +#endif diff --git a/components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c b/components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c new file mode 100644 index 0000000000..63bc549019 --- /dev/null +++ b/components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c @@ -0,0 +1,157 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" +#if SOC_LP_ADC_SUPPORTED + +#include "ulp_lp_core_lp_adc_shared.h" +#include "hal/adc_types.h" +#include "hal/adc_ll.h" + +#define VREF (1100) /* Internal Reference voltage in millivolts (1.1V) */ +#define INV_ATTEN_0DB (1000) /* Inverse of 10^0 * 1000 */ +#define INV_ATTEN_2_5DB (1335) /* Inverse of 10^(-2.5/20) * 1000 */ +#define INV_ATTEN_6DB (1996) /* Inverse of 10^(-6/20) * 1000 */ +#define INV_ATTEN_12DB (3984) /* Inverse of 10^(-12/20) * 1000 */ + +adc_oneshot_unit_handle_t s_adc1_handle; + +esp_err_t lp_core_lp_adc_init(adc_unit_t unit_id) +{ + if (unit_id != ADC_UNIT_1) { + // TODO: LP ADC2 does not work during sleep (DIG-396) + // For now, we do not allow LP ADC2 usage. + return ESP_ERR_INVALID_ARG; + } + +#if IS_ULP_COCPU + // Not supported + return ESP_ERR_NOT_SUPPORTED; +#else + /* LP ADC is being initialized from the HP core. + * Hence, we use the standard ADC driver APIs here. + */ + + /* Initialize ADC */ + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = unit_id, + .ulp_mode = ADC_ULP_MODE_LP_CORE, // LP Core will use the ADC + }; + + return (adc_oneshot_new_unit(&init_config, &s_adc1_handle)); +#endif /* IS_ULP_COCPU */ +} + +esp_err_t lp_core_lp_adc_deinit(adc_unit_t unit_id) +{ + if (unit_id != ADC_UNIT_1) { + return ESP_ERR_INVALID_ARG; + } + +#if IS_ULP_COCPU + // Not supported + return ESP_ERR_NOT_SUPPORTED; +#else + return (adc_oneshot_del_unit(s_adc1_handle)); +#endif /* IS_ULP_COCPU */ +} + +esp_err_t lp_core_lp_adc_config_channel(adc_unit_t unit_id, adc_channel_t channel, const lp_core_lp_adc_chan_cfg_t *chan_config) +{ + if (unit_id != ADC_UNIT_1) { + // TODO: LP ADC2 does not work during sleep (DIG-396) + // For now, we do not allow LP ADC2 usage. + return ESP_ERR_INVALID_ARG; + } +#if IS_ULP_COCPU + // Not supported + return ESP_ERR_NOT_SUPPORTED; +#else + adc_oneshot_chan_cfg_t config = { + .atten = chan_config->atten, + .bitwidth = chan_config->bitwidth, + }; + + return (adc_oneshot_config_channel(s_adc1_handle, channel, &config)); +#endif /* IS_ULP_COCPU */ +} + +esp_err_t lp_core_lp_adc_read_channel_raw(adc_unit_t unit_id, adc_channel_t channel, int *adc_raw) +{ + if (unit_id != ADC_UNIT_1 || adc_raw == NULL) { + return ESP_ERR_INVALID_ARG; + } + +#if IS_ULP_COCPU + uint32_t event = ADC_LL_EVENT_ADC1_ONESHOT_DONE; + + adc_oneshot_ll_clear_event(event); + adc_oneshot_ll_disable_all_unit(); + adc_oneshot_ll_enable(unit_id); + adc_oneshot_ll_set_channel(unit_id, channel); + + adc_oneshot_ll_start(unit_id); + while (!adc_oneshot_ll_get_event(event)) { + ; + } + *adc_raw = adc_oneshot_ll_get_raw_result(unit_id); + + adc_oneshot_ll_disable_all_unit(); +#else + return (adc_oneshot_read(s_adc1_handle, channel, adc_raw)); +#endif /* IS_ULP_COCPU */ + + return ESP_OK; +} + +esp_err_t lp_core_lp_adc_read_channel_converted(adc_unit_t unit_id, adc_channel_t channel, int *voltage_mv) +{ + esp_err_t ret = ESP_OK; + + if (unit_id != ADC_UNIT_1 || voltage_mv == NULL) { + return ESP_ERR_INVALID_ARG; + } + + /* Read the raw ADC value */ + int adc_raw; + ret = lp_core_lp_adc_read_channel_raw(unit_id, channel, &adc_raw); + if (ret != ESP_OK) { + return ret; + } + + /* On the esp32p4, the ADC raw value can be 12-bit wide. The internal Vref is 1.1V. + * The formula to convert the raw value to voltage is: + * voltage = (((raw_value / (2^12 - 1)) * 1.1V) * attenuation) + * + * To avoid many floating point calculations, we precompute the attenuation factors + * and perform the conversion in millivolts instead of volts. + */ + + int measured_voltage = adc_raw * VREF; // millivolts + measured_voltage /= 4095; + + adc_atten_t atten = adc_ll_get_atten(unit_id, channel); + switch (atten) { + case ADC_ATTEN_DB_0: + *voltage_mv = (measured_voltage * INV_ATTEN_0DB) / 1000; + break; + case ADC_ATTEN_DB_2_5: + *voltage_mv = (measured_voltage * INV_ATTEN_2_5DB) / 1000; + break; + case ADC_ATTEN_DB_6: + *voltage_mv = (measured_voltage * INV_ATTEN_6DB) / 1000; + break; + case ADC_ATTEN_DB_12: + *voltage_mv = (measured_voltage * INV_ATTEN_12DB) / 1000; + break; + default: + ret = ESP_ERR_INVALID_STATE; + } + + return ret; +} + +#endif /* CONFIG_SOC_LP_ADC_SUPPORTED */ diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt index 86b34fdf66..63d8f905d7 100644 --- a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt @@ -16,6 +16,10 @@ if(CONFIG_SOC_LP_CORE_SUPPORT_ETM AND CONFIG_SOC_ETM_SUPPORTED) list(APPEND app_sources "test_lp_core_etm.c") endif() +if(CONFIG_SOC_LP_ADC_SUPPORTED) + list(APPEND app_sources "test_lp_core_adc.c") +endif() + set(lp_core_sources "lp_core/test_main.c") set(lp_core_sources_counter "lp_core/test_main_counter.c") @@ -38,6 +42,10 @@ if(CONFIG_SOC_LP_SPI_SUPPORTED) set(lp_core_sources_spi_slave "lp_core/test_main_spi_slave.c") endif() +if(CONFIG_SOC_LP_ADC_SUPPORTED) + set(lp_core_sources_adc "lp_core/test_main_adc.c") +endif() + idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "lp_core" REQUIRES ulp unity esp_timer test_utils @@ -67,3 +75,7 @@ if(CONFIG_SOC_LP_SPI_SUPPORTED) ulp_embed_binary(lp_core_test_app_spi_master "${lp_core_sources_spi_master}" "${lp_core_exp_dep_srcs}") ulp_embed_binary(lp_core_test_app_spi_slave "${lp_core_sources_spi_slave}" "${lp_core_exp_dep_srcs}") endif() + +if(CONFIG_SOC_LP_ADC_SUPPORTED) + ulp_embed_binary(lp_core_test_app_adc "${lp_core_sources_adc}" "${lp_core_exp_dep_srcs}") +endif() diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_adc.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_adc.c new file mode 100644 index 0000000000..4bc1b60220 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_adc.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "ulp_lp_core_lp_adc_shared.h" + +volatile int adc_raw[8]; + +int main(void) +{ + while (1) { + for (int i = 0; i < 8; i++) { + lp_core_lp_adc_read_channel_raw(ADC_UNIT_1, i, (int *)&adc_raw[i]); + } + } + + return 0; +} diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_adc.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_adc.c new file mode 100644 index 0000000000..537d93b44b --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_adc.c @@ -0,0 +1,243 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "hal/adc_types.h" +#include "lp_core_test_app_adc.h" +#include "ulp_lp_core.h" +#include "ulp_lp_core_lp_adc_shared.h" +#include "soc/adc_periph.h" +#include "driver/gpio.h" +#include "driver/temperature_sensor.h" + +#include "unity.h" + +extern const uint8_t lp_core_main_adc_bin_start[] asm("_binary_lp_core_test_app_adc_bin_start"); +extern const uint8_t lp_core_main_adc_bin_end[] asm("_binary_lp_core_test_app_adc_bin_end"); + +#if CONFIG_IDF_TARGET_ESP32P4 +// Threshold values picked up empirically after manual testing +#define ADC_TEST_LOW_VAL 1500 +#define ADC_TEST_HIGH_VAL 2000 +#else +#error "ADC threshold values not defined" +#endif + +#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel]) + +static void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level) +{ + TEST_ASSERT(channel < SOC_ADC_CHANNEL_NUM(unit) && "invalid channel"); + +#if !ADC_LL_RTC_GPIO_SUPPORTED + uint32_t io_num = ADC_GET_IO_NUM(unit, channel); + TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY : GPIO_PULLDOWN_ONLY))); +#else + gpio_num_t io_num = ADC_GET_IO_NUM(unit, channel); + if (level) { + TEST_ESP_OK(rtc_gpio_pullup_en(io_num)); + TEST_ESP_OK(rtc_gpio_pulldown_dis(io_num)); + } else { + TEST_ESP_OK(rtc_gpio_pullup_dis(io_num)); + TEST_ESP_OK(rtc_gpio_pulldown_en(io_num)); + } +#endif +} + +static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) +{ + TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, + (firmware_end - firmware_start)) == ESP_OK); + + TEST_ASSERT(ulp_lp_core_run(cfg) == ESP_OK); + +} + +void test_lp_adc(adc_unit_t unit_id) +{ + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + load_and_start_lp_core_firmware(&cfg, lp_core_main_adc_bin_start, lp_core_main_adc_bin_end); + + /* LP ADC Init */ + ESP_ERROR_CHECK(lp_core_lp_adc_init(unit_id)); + + /* LP ADC channel config */ + const lp_core_lp_adc_chan_cfg_t config = { + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + + /* Configure all ADC channels. + * LP ADC1: Channels 0 - 7 + * LP ADC2: Channels 0 - 5 + */ + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_0, &config) == ESP_OK); + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_1, &config) == ESP_OK); + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_2, &config) == ESP_OK); + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_3, &config) == ESP_OK); + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_4, &config) == ESP_OK); + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_5, &config) == ESP_OK); + if (unit_id == ADC_UNIT_1) { + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_6, &config) == ESP_OK); + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_7, &config) == ESP_OK); + } + + /* Set all the ADC channel IOs to low */ + test_adc_set_io_level(unit_id, ADC_CHANNEL_0, 0); + test_adc_set_io_level(unit_id, ADC_CHANNEL_1, 0); + test_adc_set_io_level(unit_id, ADC_CHANNEL_2, 0); + test_adc_set_io_level(unit_id, ADC_CHANNEL_3, 0); + test_adc_set_io_level(unit_id, ADC_CHANNEL_4, 0); + test_adc_set_io_level(unit_id, ADC_CHANNEL_5, 0); + test_adc_set_io_level(unit_id, ADC_CHANNEL_6, 0); + test_adc_set_io_level(unit_id, ADC_CHANNEL_7, 0); + + vTaskDelay(10); + + int *adc_raw = (int *)&ulp_adc_raw; + + /* Verify that the LP ADC values reflect a low-state of the input pins */ + for (int i = 0; i < SOC_ADC_CHANNEL_NUM(unit_id); i++) { + printf("LP ADC low[%d] = %d\n", i, adc_raw[i]); + TEST_ASSERT_LESS_THAN_INT(ADC_TEST_LOW_VAL, adc_raw[i]); + } + + /* Set all the ADC channel IOs to high */ + test_adc_set_io_level(unit_id, ADC_CHANNEL_0, 1); + test_adc_set_io_level(unit_id, ADC_CHANNEL_1, 1); + test_adc_set_io_level(unit_id, ADC_CHANNEL_2, 1); + test_adc_set_io_level(unit_id, ADC_CHANNEL_3, 1); + test_adc_set_io_level(unit_id, ADC_CHANNEL_4, 1); + test_adc_set_io_level(unit_id, ADC_CHANNEL_5, 1); + test_adc_set_io_level(unit_id, ADC_CHANNEL_6, 1); + test_adc_set_io_level(unit_id, ADC_CHANNEL_7, 1); + + vTaskDelay(10); + + /* Verify that the LP ADC values reflect a high-state of the input pins */ + for (int i = 0; i < SOC_ADC_CHANNEL_NUM(unit_id); i++) { + printf("LP ADC high[%d] = %d\n", i, adc_raw[i]); + TEST_ASSERT_GREATER_THAN_INT(ADC_TEST_HIGH_VAL, adc_raw[i]); + } + + /* Deinit LP ADC */ + ESP_ERROR_CHECK(lp_core_lp_adc_deinit(unit_id)); +} + +TEST_CASE("LP ADC 1 raw read test", "[lp_core]") +{ + test_lp_adc(ADC_UNIT_1); +} + +// Enable when DIG-396 is fixed +// TEST_CASE("LP ADC 2 raw read test", "[lp_core]") +// { +// test_lp_adc(ADC_UNIT_2); +// } + +static void test_lp_adc_stress(adc_unit_t unit_id) +{ + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + load_and_start_lp_core_firmware(&cfg, lp_core_main_adc_bin_start, lp_core_main_adc_bin_end); + + for (int i = 0; i < 100; i++) { + /* LP ADC Init */ + ESP_ERROR_CHECK(lp_core_lp_adc_init(unit_id)); + + /* LP ADC channel config */ + const lp_core_lp_adc_chan_cfg_t config = { + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + + TEST_ASSERT(lp_core_lp_adc_config_channel(unit_id, ADC_CHANNEL_0, &config) == ESP_OK); + + /* Set LP ADC channel IO and read raw value */ + test_adc_set_io_level(unit_id, ADC_CHANNEL_0, 1); + vTaskDelay(10); + int *adc_raw = (int *)&ulp_adc_raw; + TEST_ASSERT_NOT_EQUAL(0, adc_raw[0]); + + /* De-init LP ADC */ + ESP_ERROR_CHECK(lp_core_lp_adc_deinit(unit_id)); + } +} + +TEST_CASE("LP ADC 1 raw read stress test", "[lp_core]") +{ + test_lp_adc_stress(ADC_UNIT_1); +} + +// Enable when DIG-396 is fixed +// TEST_CASE("LP ADC 2 raw read stress test", "[lp_core]") +// { +// test_lp_adc_stress(ADC_UNIT_2); +// } + +TEST_CASE("Test temperature sensor does not affect LP ADC", "[lp_core]") +{ + printf("Install temperature sensor, expected temp ranger range: 10~50 ℃\n"); + temperature_sensor_handle_t temp_sensor = NULL; + temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80); + TEST_ESP_OK(temperature_sensor_install(&temp_sensor_config, &temp_sensor)); + int cnt = 2; + float tsens_value; + while (cnt--) { + temperature_sensor_enable(temp_sensor); + TEST_ESP_OK(temperature_sensor_get_celsius(temp_sensor, &tsens_value)); + printf("Temperature value %.02f ℃\n", tsens_value); + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ESP_OK(temperature_sensor_disable(temp_sensor)); + } + + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + load_and_start_lp_core_firmware(&cfg, lp_core_main_adc_bin_start, lp_core_main_adc_bin_end); + + /* LP ADC Init */ + ESP_ERROR_CHECK(lp_core_lp_adc_init(ADC_UNIT_1)); + + /* LP ADC channel config */ + const lp_core_lp_adc_chan_cfg_t config = { + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + + /* Configure ADC channel 0 */ + TEST_ASSERT(lp_core_lp_adc_config_channel(ADC_UNIT_1, ADC_CHANNEL_0, &config) == ESP_OK); + + int *adc_raw = (int *)&ulp_adc_raw; + cnt = 2; + while (cnt--) { + printf("LP ADC%d Channel[%d] Raw Data: %d\n", ADC_UNIT_1 + 1, 0, adc_raw[0]); + vTaskDelay(pdMS_TO_TICKS(100)); + } + + TEST_ESP_OK(lp_core_lp_adc_deinit(ADC_UNIT_1)); + + cnt = 2; + while (cnt--) { + temperature_sensor_enable(temp_sensor); + TEST_ESP_OK(temperature_sensor_get_celsius(temp_sensor, &tsens_value)); + printf("Temperature value %.02f ℃\n", tsens_value); + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ESP_OK(temperature_sensor_disable(temp_sensor)); + } + + TEST_ESP_OK(temperature_sensor_uninstall(temp_sensor)); +} diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index 6e4cdcc0af..c36d0e2539 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -311,6 +311,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