mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feat/lp_core_lp_adc_support' into 'master'
feat(lp_adc): Addded support for LP ADC for the LP core on esp32p4 Closes IDF-6875 and IDF-10205 See merge request espressif/esp-idf!33117
This commit is contained in:
commit
1b6a829e81
@ -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->unit_id = init_config->unit_id;
|
||||||
unit->ulp_mode = init_config->ulp_mode;
|
unit->ulp_mode = init_config->ulp_mode;
|
||||||
|
|
||||||
adc_oneshot_clk_src_t clk_src = ADC_DIGI_CLK_SRC_DEFAULT;
|
adc_oneshot_clk_src_t clk_src;
|
||||||
if (init_config->clk_src) {
|
#if SOC_LP_ADC_SUPPORTED
|
||||||
clk_src = init_config->clk_src;
|
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;
|
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");
|
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 = {
|
adc_oneshot_hal_cfg_t config = {
|
||||||
.unit = init_config->unit_id,
|
.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 = clk_src,
|
||||||
.clk_src_freq_hz = clk_src_freq_hz,
|
.clk_src_freq_hz = clk_src_freq_hz,
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
if (unit == ADC_UNIT_1) {
|
||||||
switch (work_mode) {
|
switch (work_mode) {
|
||||||
#if SOC_ULP_HAS_ADC
|
#if SOC_ULP_HAS_ADC || SOC_LP_CORE_SUPPORT_LP_ADC
|
||||||
case ADC_HAL_ULP_FSM_MODE:
|
case ADC_HAL_LP_MODE:
|
||||||
return ADC_LL_CTRL_ULP;
|
return ADC_LL_CTRL_ULP;
|
||||||
#endif
|
#endif
|
||||||
case ADC_HAL_SINGLE_READ_MODE:
|
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 {
|
} else {
|
||||||
switch (work_mode) {
|
switch (work_mode) {
|
||||||
#if SOC_ULP_HAS_ADC
|
#if SOC_ULP_HAS_ADC || SOC_LP_CORE_SUPPORT_LP_ADC
|
||||||
case ADC_HAL_ULP_FSM_MODE:
|
case ADC_HAL_LP_MODE:
|
||||||
return ADC_LL_CTRL_ULP;
|
return ADC_LL_CTRL_ULP;
|
||||||
#endif
|
#endif
|
||||||
#if !SOC_ADC_ARBITER_SUPPORTED //No ADC2 arbiter on ESP32
|
#if !SOC_ADC_ARBITER_SUPPORTED //No ADC2 arbiter on ESP32
|
||||||
|
@ -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
|
* 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_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_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);
|
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
|
#else
|
||||||
adc_ll_set_sar_clk_div(unit, ADC_LL_SAR_CLK_DIV_DEFAULT(unit));
|
adc_ll_set_sar_clk_div(unit, ADC_LL_SAR_CLK_DIV_DEFAULT(unit));
|
||||||
|
#endif //SOC_LP_ADC_SUPPORTED
|
||||||
if (unit == ADC_UNIT_2) {
|
if (unit == ADC_UNIT_2) {
|
||||||
adc_ll_pwdet_set_cct(ADC_LL_PWDET_CCT_DEFAULT);
|
adc_ll_pwdet_set_cct(ADC_LL_PWDET_CCT_DEFAULT);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ extern "C" {
|
|||||||
---------------------------------------------------------------*/
|
---------------------------------------------------------------*/
|
||||||
#define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (0)
|
#define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (0)
|
||||||
#define ADC_LL_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (1)
|
#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)
|
#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;
|
break;
|
||||||
case ADC_LL_CTRL_ULP:
|
case ADC_LL_CTRL_ULP:
|
||||||
LP_ADC.meas1_mux.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
|
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.meas1_start_force = 1; // 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.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||||
break;
|
break;
|
||||||
case ADC_LL_CTRL_DIG:
|
case ADC_LL_CTRL_DIG:
|
||||||
LP_ADC.meas1_mux.sar1_dig_force = 1; // 1: Select digital control; 0: Select RTC control.
|
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;
|
break;
|
||||||
case ADC_LL_CTRL_ULP:
|
case ADC_LL_CTRL_ULP:
|
||||||
LP_ADC.meas2_mux.sar2_rtc_force = 0; // 1: Select digital control; 0: Select RTC control.
|
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.meas2_start_force = 1; // 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.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||||
break;
|
break;
|
||||||
case ADC_LL_CTRL_DIG:
|
case ADC_LL_CTRL_DIG:
|
||||||
LP_ADC.meas2_mux.sar2_rtc_force = 0; // 1: Select digital control; 0: Select RTC control.
|
LP_ADC.meas2_mux.sar2_rtc_force = 0; // 1: Select digital control; 0: Select RTC control.
|
||||||
|
@ -26,7 +26,7 @@ typedef enum adc_hal_work_mode_t {
|
|||||||
ADC_HAL_SINGLE_READ_MODE,
|
ADC_HAL_SINGLE_READ_MODE,
|
||||||
ADC_HAL_CONTINUOUS_READ_MODE,
|
ADC_HAL_CONTINUOUS_READ_MODE,
|
||||||
ADC_HAL_PWDET_MODE,
|
ADC_HAL_PWDET_MODE,
|
||||||
ADC_HAL_ULP_FSM_MODE,
|
ADC_HAL_LP_MODE,
|
||||||
} adc_hal_work_mode_t;
|
} 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.
|
* @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);
|
void adc_hal_calibration_init(adc_unit_t adc_n);
|
||||||
|
|
||||||
|
@ -64,6 +64,9 @@ typedef enum {
|
|||||||
ADC_ULP_MODE_DISABLE = 0, ///< ADC ULP mode is disabled
|
ADC_ULP_MODE_DISABLE = 0, ///< ADC ULP mode is disabled
|
||||||
ADC_ULP_MODE_FSM = 1, ///< ADC is controlled by ULP FSM
|
ADC_ULP_MODE_FSM = 1, ///< ADC is controlled by ULP FSM
|
||||||
ADC_ULP_MODE_RISCV = 2, ///< ADC is controlled by ULP RISCV
|
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;
|
} adc_ulp_mode_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -259,6 +259,10 @@ config SOC_LP_SPI_SUPPORTED
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_LP_ADC_SUPPORTED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_SPIRAM_SUPPORTED
|
config SOC_SPIRAM_SUPPORTED
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
@ -1926,3 +1930,7 @@ config SOC_LCDCAM_CAM_DATA_WIDTH_MAX
|
|||||||
config SOC_LP_CORE_SUPPORT_ETM
|
config SOC_LP_CORE_SUPPORT_ETM
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_LP_CORE_SUPPORT_LP_ADC
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
@ -635,6 +635,20 @@ typedef enum {
|
|||||||
ADC_RTC_CLK_SRC_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the default clock choice */
|
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;
|
} 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/////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////MWDT/////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,9 +82,9 @@
|
|||||||
#define SOC_LP_I2C_SUPPORTED 1
|
#define SOC_LP_I2C_SUPPORTED 1
|
||||||
#define SOC_LP_I2S_SUPPORTED 1
|
#define SOC_LP_I2S_SUPPORTED 1
|
||||||
#define SOC_LP_SPI_SUPPORTED 1
|
#define SOC_LP_SPI_SUPPORTED 1
|
||||||
|
#define SOC_LP_ADC_SUPPORTED 1
|
||||||
#define SOC_SPIRAM_SUPPORTED 1
|
#define SOC_SPIRAM_SUPPORTED 1
|
||||||
#define SOC_PSRAM_DMA_CAPABLE 1
|
#define SOC_PSRAM_DMA_CAPABLE 1
|
||||||
// #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534
|
|
||||||
#define SOC_SDMMC_HOST_SUPPORTED 1
|
#define SOC_SDMMC_HOST_SUPPORTED 1
|
||||||
#define SOC_CLK_TREE_SUPPORTED 1
|
#define SOC_CLK_TREE_SUPPORTED 1
|
||||||
#define SOC_ASSIST_DEBUG_SUPPORTED 1
|
#define SOC_ASSIST_DEBUG_SUPPORTED 1
|
||||||
@ -738,3 +738,4 @@
|
|||||||
|
|
||||||
/*------------------------------------- ULP CAPS -------------------------------------*/
|
/*------------------------------------- ULP CAPS -------------------------------------*/
|
||||||
#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */
|
#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 */
|
||||||
|
@ -73,6 +73,10 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
|
|||||||
if(CONFIG_SOC_LP_CORE_SUPPORT_ETM)
|
if(CONFIG_SOC_LP_CORE_SUPPORT_ETM)
|
||||||
list(APPEND srcs "lp_core/lp_core_etm.c")
|
list(APPEND srcs "lp_core/lp_core_etm.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_SOC_LP_ADC_SUPPORTED)
|
||||||
|
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_adc_shared.c")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
|
@ -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_interrupt.c"
|
||||||
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.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_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})
|
set(target_folder ${IDF_TARGET})
|
||||||
|
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
157
components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c
Normal file
157
components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c
Normal file
@ -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 */
|
@ -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")
|
list(APPEND app_sources "test_lp_core_etm.c")
|
||||||
endif()
|
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 "lp_core/test_main.c")
|
||||||
set(lp_core_sources_counter "lp_core/test_main_counter.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")
|
set(lp_core_sources_spi_slave "lp_core/test_main_spi_slave.c")
|
||||||
endif()
|
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}
|
idf_component_register(SRCS ${app_sources}
|
||||||
INCLUDE_DIRS "lp_core"
|
INCLUDE_DIRS "lp_core"
|
||||||
REQUIRES ulp unity esp_timer test_utils
|
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_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}")
|
ulp_embed_binary(lp_core_test_app_spi_slave "${lp_core_sources_spi_slave}" "${lp_core_exp_dep_srcs}")
|
||||||
endif()
|
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()
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#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;
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
@ -311,6 +311,12 @@ examples/system/ulp/lp_core/interrupt:
|
|||||||
depends_components:
|
depends_components:
|
||||||
- ulp
|
- 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:
|
examples/system/ulp/lp_core/lp_i2c:
|
||||||
enable:
|
enable:
|
||||||
- if: SOC_LP_I2C_SUPPORTED == 1 and SOC_DEEP_SLEEP_SUPPORTED == 1
|
- if: SOC_LP_I2C_SUPPORTED == 1 and SOC_DEEP_SLEEP_SUPPORTED == 1
|
||||||
|
8
examples/system/ulp/lp_core/lp_adc/CMakeLists.txt
Normal file
8
examples/system/ulp/lp_core/lp_adc/CMakeLists.txt
Normal file
@ -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)
|
63
examples/system/ulp/lp_core/lp_adc/README.md
Normal file
63
examples/system/ulp/lp_core/lp_adc/README.md
Normal file
@ -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
|
||||||
|
```
|
25
examples/system/ulp/lp_core/lp_adc/main/CMakeLists.txt
Normal file
25
examples/system/ulp/lp_core/lp_adc/main/CMakeLists.txt
Normal file
@ -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}")
|
17
examples/system/ulp/lp_core/lp_adc/main/Kconfig.projbuild
Normal file
17
examples/system/ulp/lp_core/lp_adc/main/Kconfig.projbuild
Normal file
@ -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
|
76
examples/system/ulp/lp_core/lp_adc/main/lp_adc_main.c
Normal file
76
examples/system/ulp/lp_core/lp_adc/main/lp_adc_main.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#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();
|
||||||
|
}
|
33
examples/system/ulp/lp_core/lp_adc/main/lp_core/main.c
Normal file
33
examples/system/ulp/lp_core/lp_adc/main/lp_core/main.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#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;
|
||||||
|
}
|
10
examples/system/ulp/lp_core/lp_adc/sdkconfig.defaults
Normal file
10
examples/system/ulp/lp_core/lp_adc/sdkconfig.defaults
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user