mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/adc_driver_ng' into 'master'
ADC Driver NG Closes IDF-4560, IDF-3908, IDF-4225, IDF-2482, IDF-4111, IDF-3610, IDF-4058, IDF-3801, IDF-3636, IDF-2537, IDF-4310, IDF-5150, IDF-5151, and IDF-4979 See merge request espressif/esp-idf!17960
This commit is contained in:
commit
9f6f61345b
@ -77,7 +77,7 @@
|
||||
/components/cxx/ @esp-idf-codeowners/system
|
||||
/components/driver/ @esp-idf-codeowners/peripherals
|
||||
/components/efuse/ @esp-idf-codeowners/system
|
||||
/components/esp_adc_cal/ @esp-idf-codeowners/peripherals
|
||||
/components/esp_adc/ @esp-idf-codeowners/peripherals
|
||||
/components/esp_common/ @esp-idf-codeowners/system
|
||||
/components/esp_eth/ @esp-idf-codeowners/network
|
||||
/components/esp_event/ @esp-idf-codeowners/system
|
||||
|
@ -24,9 +24,11 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target}/include")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_ADC_SUPPORTED)
|
||||
list(APPEND srcs
|
||||
"adc_single.c"
|
||||
"adc.c")
|
||||
list(APPEND srcs "deprecated/adc_legacy.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_ADC_DMA_SUPPORTED)
|
||||
list(APPEND srcs "deprecated/adc_dma_legacy.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_MCPWM_SUPPORTED)
|
||||
@ -87,8 +89,7 @@ if(${target} STREQUAL "esp32")
|
||||
"sdio_slave.c"
|
||||
"touch_sensor_common.c"
|
||||
"esp32/touch_sensor.c"
|
||||
"esp32/adc.c"
|
||||
"adc_deprecated.c"
|
||||
"deprecated/adc_i2s_deprecated.c"
|
||||
"esp32/dac.c")
|
||||
endif()
|
||||
|
||||
@ -96,9 +97,6 @@ if(${target} STREQUAL "esp32s2")
|
||||
list(APPEND srcs "dac_common.c"
|
||||
"touch_sensor_common.c"
|
||||
"esp32s2/touch_sensor.c"
|
||||
"esp32s2/adc.c"
|
||||
"adc_deprecated.c"
|
||||
"esp32s2/adc2_init_cal.c"
|
||||
"esp32s2/dac.c")
|
||||
endif()
|
||||
|
||||
@ -107,19 +105,18 @@ if(${target} STREQUAL "esp32s3")
|
||||
"esp32s3/touch_sensor.c")
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "esp32c3")
|
||||
list(APPEND srcs "esp32c3/adc2_init_cal.c")
|
||||
endif()
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
# Bootloader shall NOT depend on the drivers
|
||||
idf_component_register()
|
||||
else()
|
||||
# (REQUIRES cannot hide soc headers, since many arguments in the driver headers are chip-dependent)
|
||||
# (Legacy drivers requires `esp_adc`, due to ADC HW resource mutex logics are there.
|
||||
# Can be removed together with legacy drivers)
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ${includes}
|
||||
PRIV_INCLUDE_DIRS "include/driver"
|
||||
PRIV_REQUIRES efuse esp_timer
|
||||
PRIV_REQUIRES efuse esp_timer esp_adc
|
||||
REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support
|
||||
LDFRAGMENTS linker.lf)
|
||||
endif()
|
||||
|
@ -1,16 +1,9 @@
|
||||
menu "Driver Configurations"
|
||||
|
||||
menu "ADC Configuration"
|
||||
|
||||
config ADC_FORCE_XPD_FSM
|
||||
bool "Use the FSM to control ADC power"
|
||||
default n
|
||||
help
|
||||
ADC power can be controlled by the FSM instead of software. This allows the ADC to
|
||||
be shut off when it is not working leading to lower power consumption. However
|
||||
using the FSM control ADC power will increase the noise of ADC.
|
||||
menu "Legacy ADC Configuration"
|
||||
|
||||
config ADC_DISABLE_DAC
|
||||
depends on SOC_DAC_SUPPORTED
|
||||
bool "Disable DAC when ADC2 is used on GPIO 25 and 26"
|
||||
default y
|
||||
help
|
||||
@ -19,6 +12,54 @@ menu "Driver Configurations"
|
||||
|
||||
For testing, disable this option so that we can measure the output of DAC by internal ADC.
|
||||
|
||||
config ADC_SUPPRESS_DEPRECATE_WARN
|
||||
bool "Suppress legacy driver deprecated warning"
|
||||
default n
|
||||
help
|
||||
Wether to suppress the deprecation warnings when using legacy adc driver (driver/adc.h).
|
||||
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
|
||||
you can enable this option.
|
||||
|
||||
menu "Legacy ADC Calibration Configuration"
|
||||
|
||||
config ADC_CAL_EFUSE_TP_ENABLE
|
||||
depends on IDF_TARGET_ESP32
|
||||
bool "Use Two Point Values"
|
||||
default "y"
|
||||
help
|
||||
Some ESP32s have Two Point calibration values burned into eFuse BLOCK3.
|
||||
This option will allow the ADC calibration component to characterize the
|
||||
ADC-Voltage curve using Two Point values if they are available.
|
||||
|
||||
config ADC_CAL_EFUSE_VREF_ENABLE
|
||||
depends on IDF_TARGET_ESP32
|
||||
bool "Use eFuse Vref"
|
||||
default "y"
|
||||
help
|
||||
Some ESP32s have Vref burned into eFuse BLOCK0. This option will allow
|
||||
the ADC calibration component to characterize the ADC-Voltage curve using
|
||||
eFuse Vref if it is available.
|
||||
|
||||
config ADC_CAL_LUT_ENABLE
|
||||
depends on IDF_TARGET_ESP32
|
||||
bool "Use Lookup Tables"
|
||||
default "y"
|
||||
help
|
||||
This option will allow the ADC calibration component to use Lookup Tables
|
||||
to correct for non-linear behavior in 11db attenuation. Other attenuations
|
||||
do not exhibit non-linear behavior hence will not be affected by this option.
|
||||
|
||||
config ADC_CALI_SUPPRESS_DEPRECATE_WARN
|
||||
bool "Suppress legacy driver deprecated warning"
|
||||
default n
|
||||
help
|
||||
Wether to suppress the deprecation warnings when using legacy adc calibration
|
||||
driver (esp_adc_cal.h).
|
||||
If you want to continue using the legacy driver, and don't want to see related
|
||||
deprecation warnings, you can enable this option.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu # ADC Configuration
|
||||
|
||||
menu "SPI Configuration"
|
||||
|
@ -1,640 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------------
|
||||
This file contains ESP32 and ESP32S2 Depricated ADC APIs and functions
|
||||
-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal_conf.h"
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
#include "esp_pm.h"
|
||||
#endif
|
||||
#include "adc.h"
|
||||
#include "esp_private/adc_cali.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#include "deprecated/driver/adc_types_deprecated.h"
|
||||
|
||||
static const char *ADC_TAG = "ADC";
|
||||
|
||||
#define ADC_CHECK_RET(fun_ret) ({ \
|
||||
if (fun_ret != ESP_OK) { \
|
||||
ESP_LOGE(ADC_TAG,"%s:%d\n",__FUNCTION__,__LINE__); \
|
||||
return ESP_FAIL; \
|
||||
} \
|
||||
})
|
||||
|
||||
#define ADC_CHECK(a, str, ret_val) ({ \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(ADC_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
||||
return (ret_val); \
|
||||
} \
|
||||
})
|
||||
|
||||
#define ADC_CHANNEL_CHECK(periph, channel) ADC_CHECK(channel < SOC_ADC_CHANNEL_NUM(periph), "ADC"#periph" channel error", ESP_ERR_INVALID_ARG)
|
||||
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
|
||||
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_handle_t adc_digi_arbiter_lock = NULL;
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/*---------------------------------------------------------------
|
||||
ESP32 Depricated ADC APIs and functions
|
||||
---------------------------------------------------------------*/
|
||||
#define ADC_MEAS_NUM_LIM_DEFAULT (1)
|
||||
#define ADC_MAX_MEAS_NUM_DEFAULT (255)
|
||||
#define DIG_ADC_OUTPUT_FORMAT_DEFUALT (ADC_DIGI_FORMAT_12BIT)
|
||||
#define DIG_ADC_ATTEN_DEFUALT (ADC_ATTEN_DB_11)
|
||||
#define DIG_ADC_BIT_WIDTH_DEFUALT (ADC_WIDTH_BIT_12)
|
||||
|
||||
esp_err_t adc_digi_init(void)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT,
|
||||
ADC_HAL_FSM_STANDBY_WAIT_DEFAULT);
|
||||
adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT);
|
||||
adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT);
|
||||
adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1));
|
||||
adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2));
|
||||
adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_deinit(void)
|
||||
{
|
||||
adc_power_release();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_deinit(NULL);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set adc output 16-bit-data format from digital controller.
|
||||
*
|
||||
* @param data_sel 1: [15] unit, [14:11] channel, [10:0] data, 11-bit-width at most. Only work under `ADC_LL_DIGI_CONV_BOTH_UNIT` or `ADC_LL_DIGI_CONV_ALTER_UNIT` mode.
|
||||
* 0: [15:12] channel, [11:0] data, 12-bit-width at most. Only work under `ADC_LL_DIGI_CONV_ONLY_ADC1` or `ADC_LL_DIGI_CONV_ONLY_ADC2` mode
|
||||
* @note see `adc_ll_digi_pattern_table_t` for more detail of data bit width
|
||||
*/
|
||||
static inline void adc_ll_digi_set_output_format(bool data_sel)
|
||||
{
|
||||
SYSCON.saradc_ctrl.data_sar_sel = data_sel;
|
||||
}
|
||||
|
||||
static inline void adc_ll_digi_prepare_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern)
|
||||
{
|
||||
uint32_t tab;
|
||||
uint8_t index = pattern_index / 4;
|
||||
uint8_t offset = (pattern_index % 4) * 8;
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
tab = SYSCON.saradc_sar1_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
SYSCON.saradc_sar1_patt_tab[index] = tab; // Write back
|
||||
} else { // adc_n == ADC_UNIT_2
|
||||
tab = SYSCON.saradc_sar2_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
SYSCON.saradc_sar2_patt_tab[index] = tab; // Write back
|
||||
}
|
||||
}
|
||||
|
||||
void adc_digi_controller_reg_set(const adc_digi_config_t *cfg)
|
||||
{
|
||||
/* On ESP32, only support ADC1 */
|
||||
switch (cfg->conv_mode) {
|
||||
case ADC_CONV_SINGLE_UNIT_1:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1);
|
||||
break;
|
||||
case ADC_CONV_SINGLE_UNIT_2:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC2);
|
||||
break;
|
||||
case ADC_CONV_BOTH_UNIT:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT);
|
||||
break;
|
||||
case ADC_CONV_ALTER_UNIT:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ALTER_UNIT);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) {
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
|
||||
if (cfg->adc1_pattern_len) {
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_1);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, cfg->adc1_pattern_len);
|
||||
for (uint32_t i = 0; i < cfg->adc1_pattern_len; i++) {
|
||||
adc_ll_digi_prepare_pattern_table(ADC_UNIT_1, i, cfg->adc1_pattern[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) {
|
||||
adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_DIG);
|
||||
if (cfg->adc2_pattern_len) {
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_2);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, cfg->adc2_pattern_len);
|
||||
for (uint32_t i = 0; i < cfg->adc2_pattern_len; i++) {
|
||||
adc_ll_digi_prepare_pattern_table(ADC_UNIT_2, i, cfg->adc2_pattern[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
adc_ll_digi_set_output_format(cfg->format);
|
||||
if (cfg->conv_limit_en) {
|
||||
adc_ll_digi_set_convert_limit_num(cfg->conv_limit_num);
|
||||
adc_ll_digi_convert_limit_enable();
|
||||
} else {
|
||||
adc_ll_digi_convert_limit_disable();
|
||||
}
|
||||
adc_ll_digi_set_data_source(ADC_I2S_DATA_SRC_ADC);
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
{
|
||||
adc_power_acquire();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_digi_controller_reg_set(config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src)
|
||||
{
|
||||
ADC_CHECK(src < ADC_I2S_DATA_SRC_MAX, "ADC i2s data source error", ESP_ERR_INVALID_ARG);
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_set_data_source(src);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
extern esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
|
||||
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
ADC_CHECK((SOC_ADC_SUPPORT_DMA_MODE(ADC_UNIT_1)), "ADC1 not support DMA for now.", ESP_ERR_INVALID_ARG);
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_1, channel);
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
//ADC2 does not support DMA mode
|
||||
ADC_CHECK((SOC_ADC_SUPPORT_DMA_MODE(ADC_UNIT_2)), "ADC2 not support DMA for now.", ESP_ERR_INVALID_ARG);
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_2, channel);
|
||||
}
|
||||
|
||||
adc_digi_pattern_table_t adc1_pattern[1];
|
||||
adc_digi_pattern_table_t adc2_pattern[1];
|
||||
adc_digi_config_t dig_cfg = {
|
||||
.conv_limit_en = ADC_MEAS_NUM_LIM_DEFAULT,
|
||||
.conv_limit_num = ADC_MAX_MEAS_NUM_DEFAULT,
|
||||
.format = DIG_ADC_OUTPUT_FORMAT_DEFUALT,
|
||||
.conv_mode = ADC_CONV_SINGLE_UNIT_1,
|
||||
};
|
||||
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
adc1_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT;
|
||||
adc1_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT;
|
||||
adc1_pattern[0].channel = channel;
|
||||
dig_cfg.adc1_pattern_len = 1;
|
||||
dig_cfg.adc1_pattern = adc1_pattern;
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
adc2_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT;
|
||||
adc2_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT;
|
||||
adc2_pattern[0].channel = channel;
|
||||
dig_cfg.adc2_pattern_len = 1;
|
||||
dig_cfg.adc2_pattern = adc2_pattern;
|
||||
}
|
||||
adc_common_gpio_init(adc_unit, channel);
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT,
|
||||
ADC_HAL_FSM_STANDBY_WAIT_DEFAULT);
|
||||
adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT);
|
||||
adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT);
|
||||
adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1));
|
||||
adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2));
|
||||
adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT);
|
||||
adc_digi_controller_reg_set(&dig_cfg);
|
||||
ADC_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
/*---------------------------------------------------------------
|
||||
ESP32S2 Depricated ADC functions and APIs
|
||||
---------------------------------------------------------------*/
|
||||
esp_err_t adc_arbiter_config(adc_unit_t adc_unit, adc_arbiter_t *config)
|
||||
{
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_arbiter_config(config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param intr Interrupt bitmask.
|
||||
*/
|
||||
static inline void adc_ll_digi_intr_enable(adc_unit_t adc_n, adc_digi_intr_t intr)
|
||||
{
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
if (intr & ADC_DIGI_INTR_MASK_MONITOR) {
|
||||
APB_SARADC.int_ena.adc1_thres = 1;
|
||||
}
|
||||
if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) {
|
||||
APB_SARADC.int_ena.adc1_done = 1;
|
||||
}
|
||||
} else { // adc_n == ADC_UNIT_2
|
||||
if (intr & ADC_DIGI_INTR_MASK_MONITOR) {
|
||||
APB_SARADC.int_ena.adc2_thres = 1;
|
||||
}
|
||||
if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) {
|
||||
APB_SARADC.int_ena.adc2_done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_intr_enable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
adc_ll_digi_intr_enable(ADC_UNIT_1, intr_mask);
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
adc_ll_digi_intr_enable(ADC_UNIT_2, intr_mask);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param intr Interrupt bitmask.
|
||||
*/
|
||||
static inline void adc_ll_digi_intr_disable(adc_unit_t adc_n, adc_digi_intr_t intr)
|
||||
{
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
if (intr & ADC_DIGI_INTR_MASK_MONITOR) {
|
||||
APB_SARADC.int_ena.adc1_thres = 0;
|
||||
}
|
||||
if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) {
|
||||
APB_SARADC.int_ena.adc1_done = 0;
|
||||
}
|
||||
} else { // adc_n == ADC_UNIT_2
|
||||
if (intr & ADC_DIGI_INTR_MASK_MONITOR) {
|
||||
APB_SARADC.int_ena.adc2_thres = 0;
|
||||
}
|
||||
if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) {
|
||||
APB_SARADC.int_ena.adc2_done = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_intr_disable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
adc_ll_digi_intr_disable(ADC_UNIT_1, intr_mask);
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
adc_ll_digi_intr_disable(ADC_UNIT_2, intr_mask);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param intr Interrupt bitmask.
|
||||
*/
|
||||
static inline void adc_ll_digi_intr_clear(adc_unit_t adc_n, adc_digi_intr_t intr)
|
||||
{
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
if (intr & ADC_DIGI_INTR_MASK_MONITOR) {
|
||||
APB_SARADC.int_clr.adc1_thres = 1;
|
||||
}
|
||||
if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) {
|
||||
APB_SARADC.int_clr.adc1_done = 1;
|
||||
}
|
||||
} else { // adc_n == ADC_UNIT_2
|
||||
if (intr & ADC_DIGI_INTR_MASK_MONITOR) {
|
||||
APB_SARADC.int_clr.adc2_thres = 1;
|
||||
}
|
||||
if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) {
|
||||
APB_SARADC.int_clr.adc2_done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_intr_clear(adc_unit_t adc_unit, adc_digi_intr_t intr_mask)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
adc_ll_digi_intr_clear(ADC_UNIT_1, intr_mask);
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
adc_ll_digi_intr_clear(ADC_UNIT_2, intr_mask);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interrupt status mask of adc digital controller.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @return
|
||||
* - intr Interrupt bitmask.
|
||||
*/
|
||||
static inline uint32_t adc_ll_digi_get_intr_status(adc_unit_t adc_n)
|
||||
{
|
||||
uint32_t int_st = APB_SARADC.int_st.val;
|
||||
uint32_t ret_msk = 0;
|
||||
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
if (int_st & APB_SARADC_ADC1_DONE_INT_ST_M) {
|
||||
ret_msk |= ADC_DIGI_INTR_MASK_MEAS_DONE;
|
||||
}
|
||||
if (int_st & APB_SARADC_ADC1_THRES_INT_ST) {
|
||||
ret_msk |= ADC_DIGI_INTR_MASK_MONITOR;
|
||||
}
|
||||
} else { // adc_n == ADC_UNIT_2
|
||||
if (int_st & APB_SARADC_ADC2_DONE_INT_ST_M) {
|
||||
ret_msk |= ADC_DIGI_INTR_MASK_MEAS_DONE;
|
||||
}
|
||||
if (int_st & APB_SARADC_ADC2_THRES_INT_ST_M) {
|
||||
ret_msk |= ADC_DIGI_INTR_MASK_MONITOR;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_msk;
|
||||
}
|
||||
|
||||
uint32_t adc_digi_intr_get_status(adc_unit_t adc_unit)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
ret = adc_ll_digi_get_intr_status(ADC_UNIT_1);
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
ret = adc_ll_digi_get_intr_status(ADC_UNIT_2);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint8_t s_isr_registered = 0;
|
||||
static intr_handle_t s_adc_isr_handle = NULL;
|
||||
|
||||
esp_err_t adc_digi_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags)
|
||||
{
|
||||
ADC_CHECK((fn != NULL), "Parameter error", ESP_ERR_INVALID_ARG);
|
||||
ADC_CHECK(s_isr_registered == 0, "ADC ISR have installed, can not install again", ESP_FAIL);
|
||||
|
||||
esp_err_t ret = esp_intr_alloc(ETS_APB_ADC_INTR_SOURCE, intr_alloc_flags, fn, arg, &s_adc_isr_handle);
|
||||
if (ret == ESP_OK) {
|
||||
s_isr_registered = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_isr_deregister(void)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
if (s_isr_registered) {
|
||||
ret = esp_intr_free(s_adc_isr_handle);
|
||||
if (ret == ESP_OK) {
|
||||
s_isr_registered = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_init(void)
|
||||
{
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT,
|
||||
ADC_HAL_FSM_STANDBY_WAIT_DEFAULT);
|
||||
adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT);
|
||||
adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT);
|
||||
adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1));
|
||||
adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2));
|
||||
adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT);
|
||||
adc_hal_arbiter_config(&config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
|
||||
adc_hal_calibration_init(ADC_UNIT_1);
|
||||
adc_hal_calibration_init(ADC_UNIT_2);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_deinit(void)
|
||||
{
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (adc_digi_arbiter_lock) {
|
||||
esp_pm_lock_delete(adc_digi_arbiter_lock);
|
||||
adc_digi_arbiter_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
adc_power_release();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_deinit(NULL);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset FSM of adc digital controller.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_reset(void)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_reset();
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_1);
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_2);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set adc output data format for digital controller.
|
||||
*
|
||||
* @param format Output data format.
|
||||
*/
|
||||
static inline void adc_ll_digi_set_output_format(adc_digi_output_format_t format)
|
||||
{
|
||||
APB_SARADC.ctrl.data_sar_sel = format;
|
||||
}
|
||||
|
||||
static inline void adc_ll_digi_prepare_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern)
|
||||
{
|
||||
uint32_t tab;
|
||||
uint8_t index = pattern_index / 4;
|
||||
uint8_t offset = (pattern_index % 4) * 8;
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
tab = APB_SARADC.sar1_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
APB_SARADC.sar1_patt_tab[index] = tab; // Write back
|
||||
} else { // adc_n == ADC_UNIT_2
|
||||
tab = APB_SARADC.sar2_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
APB_SARADC.sar2_patt_tab[index] = tab; // Write back
|
||||
}
|
||||
}
|
||||
|
||||
static void adc_digi_controller_reg_set(const adc_digi_config_t *cfg)
|
||||
{
|
||||
/* Single channel mode or multi channel mode. */
|
||||
switch (cfg->conv_mode) {
|
||||
case ADC_CONV_SINGLE_UNIT_1:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1);
|
||||
break;
|
||||
case ADC_CONV_SINGLE_UNIT_2:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC2);
|
||||
break;
|
||||
case ADC_CONV_BOTH_UNIT:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT);
|
||||
break;
|
||||
case ADC_CONV_ALTER_UNIT:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ALTER_UNIT);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) {
|
||||
if (cfg->adc1_pattern_len) {
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_1);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, cfg->adc1_pattern_len);
|
||||
for (uint32_t i = 0; i < cfg->adc1_pattern_len; i++) {
|
||||
adc_ll_digi_prepare_pattern_table(ADC_UNIT_1, i, cfg->adc1_pattern[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) {
|
||||
if (cfg->adc2_pattern_len) {
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_2);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, cfg->adc2_pattern_len);
|
||||
for (uint32_t i = 0; i < cfg->adc2_pattern_len; i++) {
|
||||
adc_ll_digi_prepare_pattern_table(ADC_UNIT_2, i, cfg->adc2_pattern[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) {
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
|
||||
}
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) {
|
||||
adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_ARB);
|
||||
}
|
||||
adc_ll_digi_set_output_format(cfg->format);
|
||||
if (cfg->conv_limit_en) {
|
||||
adc_ll_digi_set_convert_limit_num(cfg->conv_limit_num);
|
||||
adc_ll_digi_convert_limit_enable();
|
||||
} else {
|
||||
adc_ll_digi_convert_limit_disable();
|
||||
}
|
||||
|
||||
adc_ll_digi_set_trigger_interval(cfg->interval);
|
||||
adc_ll_digi_controller_clk_div(cfg->dig_clk.div_num, cfg->dig_clk.div_b, cfg->dig_clk.div_a);
|
||||
adc_ll_digi_clk_sel(cfg->dig_clk.use_apll);
|
||||
adc_ll_digi_dma_set_eof_num(cfg->dma_eof_num);
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
{
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_err_t err;
|
||||
if (adc_digi_arbiter_lock == NULL) {
|
||||
if (config->dig_clk.use_apll) {
|
||||
err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "adc_dma", &adc_digi_arbiter_lock);
|
||||
} else {
|
||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &adc_digi_arbiter_lock);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
adc_digi_arbiter_lock = NULL;
|
||||
ESP_LOGE(ADC_TAG, "ADC-DMA pm lock error");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
if (config->conv_mode & ADC_CONV_SINGLE_UNIT_1) {
|
||||
for (int i = 0; i < config->adc1_pattern_len; i++) {
|
||||
adc_cal_offset(ADC_UNIT_1, config->adc1_pattern[i].atten);
|
||||
}
|
||||
}
|
||||
if (config->conv_mode & ADC_CONV_SINGLE_UNIT_2) {
|
||||
for (int i = 0; i < config->adc2_pattern_len; i++) {
|
||||
adc_cal_offset(ADC_UNIT_2, config->adc2_pattern[i].atten);
|
||||
}
|
||||
}
|
||||
|
||||
/* If enable digtal controller, adc xpd should always on. */
|
||||
adc_power_acquire();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_digi_controller_reg_set(config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // #if CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
/*---------------------------------------------------------------
|
||||
ESP32S2 Depricated ADC functions and APIs
|
||||
---------------------------------------------------------------*/
|
||||
esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
gpio_num_t gpio_num = 0;
|
||||
//If called with `ADC_UNIT_BOTH (ADC_UNIT_1 | ADC_UNIT_2)`, both if blocks will be run
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_1, channel);
|
||||
gpio_num = ADC_GET_IO_NUM(ADC_UNIT_1, channel);
|
||||
ADC_CHECK_RET(rtc_gpio_init(gpio_num));
|
||||
ADC_CHECK_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED));
|
||||
ADC_CHECK_RET(rtc_gpio_pulldown_dis(gpio_num));
|
||||
ADC_CHECK_RET(rtc_gpio_pullup_dis(gpio_num));
|
||||
}
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_2, channel);
|
||||
gpio_num = ADC_GET_IO_NUM(ADC_UNIT_2, channel);
|
||||
ADC_CHECK_RET(rtc_gpio_init(gpio_num));
|
||||
ADC_CHECK_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED));
|
||||
ADC_CHECK_RET(rtc_gpio_pulldown_dis(gpio_num));
|
||||
ADC_CHECK_RET(rtc_gpio_pullup_dis(gpio_num));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
@ -19,11 +19,15 @@
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/adc.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "esp_private/adc_lock.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/dma_types.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
|
||||
//For calibration
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp_efuse_rtc_table.h"
|
||||
@ -37,7 +41,6 @@
|
||||
#include "hal/spi_types.h"
|
||||
#include "esp_private/spi_common_internal.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
#include "hal/i2s_types.h"
|
||||
#include "driver/i2s_types.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "esp_private/i2s_platform.h"
|
||||
@ -51,21 +54,6 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi
|
||||
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
/**
|
||||
* 1. sar_adc1_lock: this mutex lock is to protect the SARADC1 module.
|
||||
* 2. sar_adc2_lock: this mutex lock is to protect the SARADC2 module.
|
||||
* 3. adc_reg_lock: this spin lock is to protect the shared registers used by ADC1 / ADC2 single read mode.
|
||||
*/
|
||||
static _lock_t sar_adc1_lock;
|
||||
#define SAR_ADC1_LOCK_ACQUIRE() _lock_acquire(&sar_adc1_lock)
|
||||
#define SAR_ADC1_LOCK_RELEASE() _lock_release(&sar_adc1_lock)
|
||||
static _lock_t sar_adc2_lock;
|
||||
#define SAR_ADC2_LOCK_ACQUIRE() _lock_acquire(&sar_adc2_lock)
|
||||
#define SAR_ADC2_LOCK_RELEASE() _lock_release(&sar_adc2_lock)
|
||||
portMUX_TYPE adc_reg_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define ADC_REG_LOCK_ENTER() portENTER_CRITICAL(&adc_reg_lock)
|
||||
#define ADC_REG_LOCK_EXIT() portEXIT_CRITICAL(&adc_reg_lock)
|
||||
|
||||
#define INTERNAL_BUF_NUM 5
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
@ -101,10 +89,6 @@ static adc_digi_context_t *s_adc_digi_ctx = NULL;
|
||||
extern esp_pm_lock_handle_t adc_digi_arbiter_lock;
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
uint32_t adc_get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten);
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Continuous Read Mode (via DMA)
|
||||
---------------------------------------------------------------*/
|
||||
@ -152,9 +136,54 @@ static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask)
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_deinitialize(void)
|
||||
{
|
||||
if (!s_adc_digi_ctx) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (s_adc_digi_ctx->driver_start_flag != 0) {
|
||||
ESP_LOGE(ADC_TAG, "The driver is not stopped");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (s_adc_digi_ctx->ringbuf_hdl) {
|
||||
vRingbufferDelete(s_adc_digi_ctx->ringbuf_hdl);
|
||||
s_adc_digi_ctx->ringbuf_hdl = NULL;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (s_adc_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_delete(s_adc_digi_ctx->pm_lock);
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
free(s_adc_digi_ctx->rx_dma_buf);
|
||||
free(s_adc_digi_ctx->hal.rx_desc);
|
||||
free(s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern);
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
gdma_disconnect(s_adc_digi_ctx->rx_dma_channel);
|
||||
gdma_del_channel(s_adc_digi_ctx->rx_dma_channel);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
esp_intr_free(s_adc_digi_ctx->intr_hdl);
|
||||
spicommon_dma_chan_free(s_adc_digi_ctx->spi_host);
|
||||
spicommon_periph_free(s_adc_digi_ctx->spi_host);
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
esp_intr_free(s_adc_digi_ctx->intr_hdl);
|
||||
i2s_platform_release_occupation(s_adc_digi_ctx->i2s_host);
|
||||
#endif
|
||||
free(s_adc_digi_ctx);
|
||||
s_adc_digi_ctx = NULL;
|
||||
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE((init_config->conv_num_each_intr % SOC_ADC_DIGI_DATA_BYTES_PER_CONV == 0), ESP_ERR_INVALID_ARG, ADC_TAG, "conv_frame_size should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`");
|
||||
|
||||
s_adc_digi_ctx = calloc(1, sizeof(adc_digi_context_t));
|
||||
if (s_adc_digi_ctx == NULL) {
|
||||
@ -282,7 +311,7 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
|
||||
#endif
|
||||
.desc_max_num = INTERNAL_BUF_NUM,
|
||||
.dma_chan = dma_chan,
|
||||
.eof_num = init_config->conv_num_each_intr / ADC_HAL_DATA_LEN_PER_CONV
|
||||
.eof_num = init_config->conv_num_each_intr / SOC_ADC_DIGI_DATA_BYTES_PER_CONV
|
||||
};
|
||||
adc_hal_dma_ctx_config(&s_adc_digi_ctx->hal, &config);
|
||||
|
||||
@ -362,116 +391,83 @@ static IRAM_ATTR bool s_adc_dma_intr(adc_digi_context_t *adc_digi_ctx)
|
||||
|
||||
esp_err_t adc_digi_start(void)
|
||||
{
|
||||
if (s_adc_digi_ctx) {
|
||||
if (s_adc_digi_ctx->driver_start_flag != 0) {
|
||||
ESP_LOGE(ADC_TAG, "The driver is already started");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
adc_power_acquire();
|
||||
//reset flags
|
||||
s_adc_digi_ctx->ringbuf_overflow_flag = 0;
|
||||
s_adc_digi_ctx->driver_start_flag = 1;
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
SAR_ADC1_LOCK_ACQUIRE();
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
SAR_ADC2_LOCK_ACQUIRE();
|
||||
}
|
||||
|
||||
if (s_adc_digi_ctx->driver_start_flag != 0) {
|
||||
ESP_LOGE(ADC_TAG, "The driver is already started");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
adc_power_acquire();
|
||||
//reset flags
|
||||
s_adc_digi_ctx->ringbuf_overflow_flag = 0;
|
||||
s_adc_digi_ctx->driver_start_flag = 1;
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
adc_lock_acquire(ADC_UNIT_1);
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
adc_lock_acquire(ADC_UNIT_2);
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
// Lock APB frequency while ADC driver is in use
|
||||
esp_pm_lock_acquire(s_adc_digi_ctx->pm_lock);
|
||||
// Lock APB frequency while ADC driver is in use
|
||||
esp_pm_lock_acquire(s_adc_digi_ctx->pm_lock);
|
||||
#endif
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_1, s_adc_digi_ctx->adc1_atten);
|
||||
adc_hal_set_calibration_param(ADC_UNIT_1, cal_val);
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_2, s_adc_digi_ctx->adc2_atten);
|
||||
adc_hal_set_calibration_param(ADC_UNIT_2, cal_val);
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
adc_set_hw_calibration_code(ADC_UNIT_1, s_adc_digi_ctx->adc1_atten);
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
adc_set_hw_calibration_code(ADC_UNIT_2, s_adc_digi_ctx->adc2_atten);
|
||||
}
|
||||
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
#if SOC_ADC_ARBITER_SUPPORTED
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_arbiter_config(&config);
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_arbiter_config(&config);
|
||||
#endif //#if SOC_ADC_ARBITER_SUPPORTED
|
||||
|
||||
adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE);
|
||||
adc_hal_set_controller(ADC_UNIT_2, ADC_HAL_CONTINUOUS_READ_MODE);
|
||||
adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE);
|
||||
adc_hal_set_controller(ADC_UNIT_2, ADC_HAL_CONTINUOUS_READ_MODE);
|
||||
|
||||
adc_hal_digi_init(&s_adc_digi_ctx->hal);
|
||||
adc_hal_digi_controller_config(&s_adc_digi_ctx->hal, &s_adc_digi_ctx->hal_digi_ctrlr_cfg);
|
||||
adc_hal_digi_init(&s_adc_digi_ctx->hal);
|
||||
adc_hal_digi_controller_config(&s_adc_digi_ctx->hal, &s_adc_digi_ctx->hal_digi_ctrlr_cfg);
|
||||
|
||||
//start conversion
|
||||
adc_hal_digi_start(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf);
|
||||
//start conversion
|
||||
adc_hal_digi_start(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf);
|
||||
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
//For being compatible with the deprecated behaviour
|
||||
else {
|
||||
ESP_LOGE(ADC_TAG, "API used without driver initialization before. The following behaviour is deprecated!!");
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
ESP_RETURN_ON_FALSE((adc_digi_arbiter_lock), ESP_FAIL, ADC_TAG, "Should start after call `adc_digi_controller_config`");
|
||||
esp_pm_lock_acquire(adc_digi_arbiter_lock);
|
||||
#endif
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_dma_enable();
|
||||
adc_ll_digi_trigger_enable();
|
||||
ADC_EXIT_CRITICAL();
|
||||
}
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32S2
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_stop(void)
|
||||
{
|
||||
if (s_adc_digi_ctx) {
|
||||
if (s_adc_digi_ctx->driver_start_flag != 1) {
|
||||
ESP_LOGE(ADC_TAG, "The driver is already stopped");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
s_adc_digi_ctx->driver_start_flag = 0;
|
||||
if (s_adc_digi_ctx->driver_start_flag != 1) {
|
||||
ESP_LOGE(ADC_TAG, "The driver is already stopped");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
s_adc_digi_ctx->driver_start_flag = 0;
|
||||
|
||||
//disable the in suc eof intrrupt
|
||||
adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
//clear the in suc eof interrupt
|
||||
adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
//stop ADC
|
||||
adc_hal_digi_stop(&s_adc_digi_ctx->hal);
|
||||
//disable the in suc eof intrrupt
|
||||
adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
//clear the in suc eof interrupt
|
||||
adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
//stop ADC
|
||||
adc_hal_digi_stop(&s_adc_digi_ctx->hal);
|
||||
|
||||
adc_hal_digi_deinit(&s_adc_digi_ctx->hal);
|
||||
adc_hal_digi_deinit(&s_adc_digi_ctx->hal);
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (s_adc_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_release(s_adc_digi_ctx->pm_lock);
|
||||
}
|
||||
if (s_adc_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_release(s_adc_digi_ctx->pm_lock);
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
SAR_ADC1_LOCK_RELEASE();
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
SAR_ADC2_LOCK_RELEASE();
|
||||
}
|
||||
adc_power_release();
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
adc_lock_release(ADC_UNIT_2);
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
else {
|
||||
//For being compatible with the deprecated behaviour
|
||||
ESP_LOGE(ADC_TAG, "API used without driver initialization before. The following behaviour is deprecated!!");
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (adc_digi_arbiter_lock) {
|
||||
esp_pm_lock_release(adc_digi_arbiter_lock);
|
||||
}
|
||||
#endif
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_trigger_disable();
|
||||
adc_ll_digi_dma_disable();
|
||||
ADC_EXIT_CRITICAL();
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
adc_lock_release(ADC_UNIT_1);
|
||||
}
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32S2
|
||||
adc_power_release();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -507,50 +503,6 @@ esp_err_t adc_digi_read_bytes(uint8_t *buf, uint32_t length_max, uint32_t *out_l
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_deinitialize(void)
|
||||
{
|
||||
if (!s_adc_digi_ctx) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (s_adc_digi_ctx->driver_start_flag != 0) {
|
||||
ESP_LOGE(ADC_TAG, "The driver is not stopped");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (s_adc_digi_ctx->ringbuf_hdl) {
|
||||
vRingbufferDelete(s_adc_digi_ctx->ringbuf_hdl);
|
||||
s_adc_digi_ctx->ringbuf_hdl = NULL;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (s_adc_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_delete(s_adc_digi_ctx->pm_lock);
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
free(s_adc_digi_ctx->rx_dma_buf);
|
||||
free(s_adc_digi_ctx->hal.rx_desc);
|
||||
free(s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern);
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
gdma_disconnect(s_adc_digi_ctx->rx_dma_channel);
|
||||
gdma_del_channel(s_adc_digi_ctx->rx_dma_channel);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
esp_intr_free(s_adc_digi_ctx->intr_hdl);
|
||||
spicommon_dma_chan_free(s_adc_digi_ctx->spi_host);
|
||||
spicommon_periph_free(s_adc_digi_ctx->spi_host);
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
esp_intr_free(s_adc_digi_ctx->intr_hdl);
|
||||
i2s_platform_release_occupation(s_adc_digi_ctx->i2s_host);
|
||||
#endif
|
||||
free(s_adc_digi_ctx);
|
||||
s_adc_digi_ctx = NULL;
|
||||
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
---------------------------------------------------------------*/
|
||||
@ -573,9 +525,6 @@ esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config)
|
||||
}
|
||||
#endif
|
||||
ESP_RETURN_ON_FALSE(config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC sampling frequency out of range");
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
ESP_RETURN_ON_FALSE(config->conv_limit_en == 1, ESP_ERR_INVALID_ARG, ADC_TAG, "`conv_limit_en` should be set to 1");
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1");
|
||||
@ -589,8 +538,6 @@ esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config)
|
||||
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2");
|
||||
#endif
|
||||
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_en = config->conv_limit_en;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_num = config->conv_limit_num;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern_len = config->pattern_num;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.sample_freq_hz = config->sample_freq_hz;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_mode = config->conv_mode;
|
||||
@ -626,319 +573,18 @@ esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
/*---------------------------------------------------------------
|
||||
ADC Single Read Mode
|
||||
---------------------------------------------------------------*/
|
||||
static adc_atten_t s_atten1_single[ADC1_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC1, used by single read API
|
||||
static adc_atten_t s_atten2_single[ADC2_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC2, used by single read API
|
||||
|
||||
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
|
||||
/**
|
||||
* @brief This function will be called during start up, to check that adc_continuous driver is not running along with the legacy adc_continuous driver
|
||||
*/
|
||||
__attribute__((constructor))
|
||||
static void check_adc_continuous_driver_conflict(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint32_t channel = ADC2_CHANNEL_MAX;
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
for (int i = 0; i < ADC2_CHANNEL_MAX; i++) {
|
||||
if (gpio == ADC_GET_IO_NUM(ADC_UNIT_2, i)) {
|
||||
channel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (channel == ADC2_CHANNEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
// This function was declared as weak here. adc_continuous driver has one implementation.
|
||||
// So if adc_continuous driver is not linked in, then `adc_continuous_new_handle` should be NULL at runtime.
|
||||
extern __attribute__((weak)) esp_err_t adc_continuous_new_handle(const void *init_config, void **ret_handle);
|
||||
if ((void *)adc_continuous_new_handle != NULL) {
|
||||
ESP_EARLY_LOGE(ADC_TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver");
|
||||
abort();
|
||||
}
|
||||
|
||||
adc_power_acquire();
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_vref_output(ADC_UNIT_1, channel, true);
|
||||
ADC_EXIT_CRITICAL();
|
||||
} else { //ADC_UNIT_2
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_vref_output(ADC_UNIT_2, channel, true);
|
||||
ADC_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel));
|
||||
|
||||
return ret;
|
||||
ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_continuous.h`");
|
||||
}
|
||||
|
||||
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
|
||||
{
|
||||
//On ESP32C3, the data width is always 12-bits.
|
||||
if (width_bit != ADC_WIDTH_BIT_12) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC1 channel error");
|
||||
ESP_RETURN_ON_FALSE((atten < SOC_ADC_ATTEN_NUM), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC Atten Err");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
s_atten1_single[channel] = atten;
|
||||
ret = adc_digi_gpio_init(ADC_UNIT_1, BIT(channel));
|
||||
|
||||
adc_hal_calibration_init(ADC_UNIT_1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int adc1_get_raw(adc1_channel_t channel)
|
||||
{
|
||||
int raw_out = 0;
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
adc_power_acquire();
|
||||
|
||||
SAR_ADC1_LOCK_ACQUIRE();
|
||||
|
||||
adc_atten_t atten = s_atten1_single[channel];
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_1, atten);
|
||||
adc_hal_set_calibration_param(ADC_UNIT_1, cal_val);
|
||||
|
||||
ADC_REG_LOCK_ENTER();
|
||||
adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten);
|
||||
adc_hal_convert(ADC_UNIT_1, channel, &raw_out);
|
||||
ADC_REG_LOCK_EXIT();
|
||||
|
||||
SAR_ADC1_LOCK_RELEASE();
|
||||
|
||||
adc_power_release();
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
return raw_out;
|
||||
}
|
||||
|
||||
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_2), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 channel error");
|
||||
ESP_RETURN_ON_FALSE((atten <= ADC_ATTEN_11db), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 Atten Err");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
s_atten2_single[channel] = atten;
|
||||
ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel));
|
||||
|
||||
adc_hal_calibration_init(ADC_UNIT_2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out)
|
||||
{
|
||||
//On ESP32C3, the data width is always 12-bits.
|
||||
if (width_bit != ADC_WIDTH_BIT_12) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
adc_power_acquire();
|
||||
|
||||
SAR_ADC2_LOCK_ACQUIRE();
|
||||
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_arbiter_config(&config);
|
||||
|
||||
adc_atten_t atten = s_atten2_single[channel];
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_2, atten);
|
||||
adc_hal_set_calibration_param(ADC_UNIT_2, cal_val);
|
||||
|
||||
ADC_REG_LOCK_ENTER();
|
||||
adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten);
|
||||
ret = adc_hal_convert(ADC_UNIT_2, channel, raw_out);
|
||||
ADC_REG_LOCK_EXIT();
|
||||
|
||||
SAR_ADC2_LOCK_RELEASE();
|
||||
|
||||
adc_power_release();
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* Digital controller filter setting */
|
||||
/*************************************/
|
||||
|
||||
esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_filter_reset(idx);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_filter_set_factor(idx, config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_filter_get_factor(idx, config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_filter_enable(idx, enable);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
/* Digital controller monitor setting */
|
||||
/**************************************/
|
||||
|
||||
esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_monitor_config(idx, config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable)
|
||||
{
|
||||
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_monitor_enable(idx, enable);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
Hardware Calibration Setting
|
||||
---------------------------------------------------------------*/
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#define esp_efuse_rtc_calib_get_ver() esp_efuse_rtc_table_read_calib_version()
|
||||
|
||||
static inline uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten)
|
||||
{
|
||||
int tag = esp_efuse_rtc_table_get_tag(version, adc_unit + 1, atten, RTCCALIB_V2_PARAM_VINIT);
|
||||
return esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint16_t s_adc_cali_param[SOC_ADC_PERIPH_NUM][SOC_ADC_ATTEN_NUM] = {};
|
||||
|
||||
//NOTE: according to calibration version, different types of lock may be taken during the process:
|
||||
// 1. Semaphore when reading efuse
|
||||
// 2. Lock (Spinlock, or Mutex) if we actually do ADC calibration in the future
|
||||
//This function shoudn't be called inside critical section or ISR
|
||||
uint32_t adc_get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten)
|
||||
{
|
||||
if (s_adc_cali_param[adc_n][atten]) {
|
||||
ESP_LOGV(ADC_TAG, "Use calibrated val ADC%d atten=%d: %04X", adc_n, atten, s_adc_cali_param[adc_n][atten]);
|
||||
return (uint32_t)s_adc_cali_param[adc_n][atten];
|
||||
}
|
||||
|
||||
// check if we can fetch the values from eFuse.
|
||||
int version = esp_efuse_rtc_calib_get_ver();
|
||||
|
||||
uint32_t init_code = 0;
|
||||
|
||||
if (version == ESP_EFUSE_ADC_CALIB_VER) {
|
||||
init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten);
|
||||
|
||||
} else {
|
||||
ESP_LOGD(ADC_TAG, "Calibration eFuse is not configured, use self-calibration for ICode");
|
||||
adc_power_acquire();
|
||||
ADC_ENTER_CRITICAL();
|
||||
const bool internal_gnd = true;
|
||||
init_code = adc_hal_self_calibration(adc_n, atten, internal_gnd);
|
||||
ADC_EXIT_CRITICAL();
|
||||
adc_power_release();
|
||||
}
|
||||
|
||||
s_adc_cali_param[adc_n][atten] = init_code;
|
||||
ESP_LOGV(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code);
|
||||
|
||||
return init_code;
|
||||
}
|
||||
|
||||
// Internal function to calibrate PWDET for WiFi
|
||||
esp_err_t adc_cal_offset(adc_unit_t adc_n, adc_atten_t atten)
|
||||
{
|
||||
adc_hal_calibration_init(adc_n);
|
||||
uint32_t cal_val = adc_get_calibration_offset(adc_n, atten);
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_set_calibration_param(adc_n, cal_val);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Deprecated API
|
||||
---------------------------------------------------------------*/
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#include "deprecated/driver/adc_deprecated.h"
|
||||
#include "deprecated/driver/adc_types_deprecated.h"
|
||||
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
{
|
||||
if (!s_adc_digi_ctx) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_RETURN_ON_FALSE((config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW), ESP_ERR_INVALID_ARG, ADC_TAG, "DC sampling frequency out of range");
|
||||
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_en = config->conv_limit_en;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_num = config->conv_limit_num;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern_len = config->adc_pattern_len;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.sample_freq_hz = config->sample_freq_hz;
|
||||
|
||||
for (int i = 0; i < config->adc_pattern_len; i++) {
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i].atten = config->adc_pattern[i].atten;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i].channel = config->adc_pattern[i].channel;
|
||||
s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i].unit = config->adc_pattern[i].unit;
|
||||
}
|
||||
|
||||
|
||||
const int atten_uninitialized = 999;
|
||||
s_adc_digi_ctx->adc1_atten = atten_uninitialized;
|
||||
s_adc_digi_ctx->adc2_atten = atten_uninitialized;
|
||||
s_adc_digi_ctx->use_adc1 = 0;
|
||||
s_adc_digi_ctx->use_adc2 = 0;
|
||||
for (int i = 0; i < config->adc_pattern_len; i++) {
|
||||
const adc_digi_pattern_config_t *pat = &s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i];
|
||||
if (pat->unit == ADC_UNIT_1) {
|
||||
s_adc_digi_ctx->use_adc1 = 1;
|
||||
|
||||
if (s_adc_digi_ctx->adc1_atten == atten_uninitialized) {
|
||||
s_adc_digi_ctx->adc1_atten = pat->atten;
|
||||
} else if (s_adc_digi_ctx->adc1_atten != pat->atten) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
} else if (pat->unit == ADC_UNIT_2) {
|
||||
//See whether ADC2 will be used or not. If yes, the ``sar_adc2_mutex`` should be acquired in the continuous read driver
|
||||
s_adc_digi_ctx->use_adc2 = 1;
|
||||
|
||||
if (s_adc_digi_ctx->adc2_atten == atten_uninitialized) {
|
||||
s_adc_digi_ctx->adc2_atten = pat->atten;
|
||||
} else if (s_adc_digi_ctx->adc2_atten != pat->atten) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32C3
|
252
components/driver/deprecated/adc_i2s_deprecated.c
Normal file
252
components/driver/deprecated/adc_i2s_deprecated.c
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------------
|
||||
This file contains ESP32 and ESP32S2 Depricated ADC APIs and functions
|
||||
-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal_conf.h"
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
#include "esp_pm.h"
|
||||
#endif
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#include "driver/adc_i2s_legacy.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
|
||||
static __attribute__((unused)) const char *ADC_TAG = "ADC";
|
||||
|
||||
#define ADC_CHECK_RET(fun_ret) ({ \
|
||||
if (fun_ret != ESP_OK) { \
|
||||
ESP_LOGE(ADC_TAG,"%s:%d\n",__FUNCTION__,__LINE__); \
|
||||
return ESP_FAIL; \
|
||||
} \
|
||||
})
|
||||
|
||||
#define ADC_CHECK(a, str, ret_val) ({ \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(ADC_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
||||
return (ret_val); \
|
||||
} \
|
||||
})
|
||||
|
||||
#define ADC_CHANNEL_CHECK(periph, channel) ADC_CHECK(channel < SOC_ADC_CHANNEL_NUM(periph), "ADC"#periph" channel error", ESP_ERR_INVALID_ARG)
|
||||
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
|
||||
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_handle_t adc_digi_arbiter_lock = NULL;
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/*---------------------------------------------------------------
|
||||
ESP32 Depricated ADC APIs and functions
|
||||
---------------------------------------------------------------*/
|
||||
#define DIG_ADC_OUTPUT_FORMAT_DEFUALT (ADC_DIGI_FORMAT_12BIT)
|
||||
#define DIG_ADC_ATTEN_DEFUALT (ADC_ATTEN_DB_11)
|
||||
#define DIG_ADC_BIT_WIDTH_DEFUALT (3) //3 for ADC_WIDTH_BIT_12
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller (DMA mode) conversion rules setting.
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
|
||||
0: measurement range 0 - 800mV,
|
||||
1: measurement range 0 - 1100mV,
|
||||
2: measurement range 0 - 1350mV,
|
||||
3: measurement range 0 - 2600mV. */
|
||||
uint8_t bit_width: 2; /*!< ADC resolution.
|
||||
- 0: 9 bit;
|
||||
- 1: 10 bit;
|
||||
- 2: 11 bit;
|
||||
- 3: 12 bit. */
|
||||
int8_t channel: 4; /*!< ADC channel index. */
|
||||
};
|
||||
uint8_t val; /*!<Raw data value */
|
||||
};
|
||||
} adc_digi_pattern_table_t;
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller (DMA mode) output data format option.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_DIGI_FORMAT_12BIT, /*!<ADC to DMA data format, [15:12]-channel, [11: 0]-12 bits ADC data (`adc_digi_output_data_t`). Note: For single convert mode. */
|
||||
ADC_DIGI_FORMAT_11BIT, /*!<ADC to DMA data format, [15]-adc unit, [14:11]-channel, [10: 0]-11 bits ADC data (`adc_digi_output_data_t`). Note: For multi or alter convert mode. */
|
||||
ADC_DIGI_FORMAT_MAX,
|
||||
} adc_digi_format_t;
|
||||
|
||||
/**
|
||||
* Explanation of the relationship between `conv_limit_num`, `dma_eof_num` and the number of DMA outputs:
|
||||
*
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | conv_mode | single | both | alter |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | trigger meas times | 1 | 1 | 1 |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | conv_limit_num | +1 | +1 | +1 |
|
||||
* | dma_eof_num | +1 | +2 | +1 |
|
||||
* | dma output (byte) | +2 | +4 | +2 |
|
||||
* +---------------------+--------+--------+--------+
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t adc1_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 16 (0: Don't change the pattern table setting).
|
||||
The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
|
||||
resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
|
||||
pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
|
||||
uint32_t adc2_pattern_len; /*!<Refer to ``adc1_pattern_len`` */
|
||||
adc_digi_pattern_table_t *adc1_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc1_pattern_len`. */
|
||||
adc_digi_pattern_table_t *adc2_pattern; /*!<Refer to `adc1_pattern` */
|
||||
adc_digi_convert_mode_t conv_mode; /*!<ADC conversion mode for digital controller. See ``adc_digi_convert_mode_t``. */
|
||||
adc_digi_format_t format; /*!<ADC output data format for digital controller. See ``adc_digi_format_t``. */
|
||||
} adc_digi_config_t;
|
||||
|
||||
/**
|
||||
* Set adc output 16-bit-data format from digital controller.
|
||||
*
|
||||
* @param data_sel 1: [15] unit, [14:11] channel, [10:0] data, 11-bit-width at most. Only work under `ADC_LL_DIGI_CONV_BOTH_UNIT` or `ADC_LL_DIGI_CONV_ALTER_UNIT` mode.
|
||||
* 0: [15:12] channel, [11:0] data, 12-bit-width at most. Only work under `ADC_LL_DIGI_CONV_ONLY_ADC1` or `ADC_LL_DIGI_CONV_ONLY_ADC2` mode
|
||||
* @note see `adc_ll_digi_pattern_table_t` for more detail of data bit width
|
||||
*/
|
||||
static inline void adc_ll_digi_set_output_format(bool data_sel)
|
||||
{
|
||||
SYSCON.saradc_ctrl.data_sar_sel = data_sel;
|
||||
}
|
||||
|
||||
static inline void adc_ll_digi_prepare_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern)
|
||||
{
|
||||
uint32_t tab;
|
||||
uint8_t index = pattern_index / 4;
|
||||
uint8_t offset = (pattern_index % 4) * 8;
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
tab = SYSCON.saradc_sar1_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
SYSCON.saradc_sar1_patt_tab[index] = tab; // Write back
|
||||
} else { // adc_n == ADC_UNIT_2
|
||||
tab = SYSCON.saradc_sar2_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
SYSCON.saradc_sar2_patt_tab[index] = tab; // Write back
|
||||
}
|
||||
}
|
||||
|
||||
static void adc_digi_controller_reg_set(const adc_digi_config_t *cfg)
|
||||
{
|
||||
/* On ESP32, only support ADC1 */
|
||||
switch (cfg->conv_mode) {
|
||||
case ADC_CONV_SINGLE_UNIT_1:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1);
|
||||
break;
|
||||
case ADC_CONV_SINGLE_UNIT_2:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC2);
|
||||
break;
|
||||
case ADC_CONV_BOTH_UNIT:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT);
|
||||
break;
|
||||
case ADC_CONV_ALTER_UNIT:
|
||||
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ALTER_UNIT);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) {
|
||||
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
|
||||
if (cfg->adc1_pattern_len) {
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_1);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, cfg->adc1_pattern_len);
|
||||
for (uint32_t i = 0; i < cfg->adc1_pattern_len; i++) {
|
||||
adc_ll_digi_prepare_pattern_table(ADC_UNIT_1, i, cfg->adc1_pattern[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) {
|
||||
adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_DIG);
|
||||
if (cfg->adc2_pattern_len) {
|
||||
adc_ll_digi_clear_pattern_table(ADC_UNIT_2);
|
||||
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, cfg->adc2_pattern_len);
|
||||
for (uint32_t i = 0; i < cfg->adc2_pattern_len; i++) {
|
||||
adc_ll_digi_prepare_pattern_table(ADC_UNIT_2, i, cfg->adc2_pattern[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
adc_ll_digi_set_output_format(cfg->format);
|
||||
adc_ll_digi_convert_limit_enable(ADC_LL_DEFAULT_CONV_LIMIT_EN);
|
||||
adc_ll_digi_set_convert_limit_num(ADC_LL_DEFAULT_CONV_LIMIT_NUM);
|
||||
adc_ll_digi_set_data_source(ADC_I2S_DATA_SRC_ADC);
|
||||
}
|
||||
|
||||
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src)
|
||||
{
|
||||
ADC_CHECK((src == ADC_I2S_DATA_SRC_IO_SIG || src == ADC_I2S_DATA_SRC_ADC), "ADC i2s data source error", ESP_ERR_INVALID_ARG);
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_set_data_source(src);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
extern esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
|
||||
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_1, channel);
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
//ADC2 does not support DMA mode
|
||||
ADC_CHECK(false, "ADC2 not support DMA for now.", ESP_ERR_INVALID_ARG);
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_2, channel);
|
||||
}
|
||||
|
||||
adc_digi_pattern_table_t adc1_pattern[1];
|
||||
adc_digi_pattern_table_t adc2_pattern[1];
|
||||
adc_digi_config_t dig_cfg = {
|
||||
.format = DIG_ADC_OUTPUT_FORMAT_DEFUALT,
|
||||
.conv_mode = ADC_CONV_SINGLE_UNIT_1,
|
||||
};
|
||||
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
adc1_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT;
|
||||
adc1_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT;
|
||||
adc1_pattern[0].channel = channel;
|
||||
dig_cfg.adc1_pattern_len = 1;
|
||||
dig_cfg.adc1_pattern = adc1_pattern;
|
||||
} else if (adc_unit == ADC_UNIT_2) {
|
||||
adc2_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT;
|
||||
adc2_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT;
|
||||
adc2_pattern[0].channel = channel;
|
||||
dig_cfg.adc2_pattern_len = 1;
|
||||
dig_cfg.adc2_pattern = adc2_pattern;
|
||||
}
|
||||
adc_common_gpio_init(adc_unit, channel);
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT,
|
||||
ADC_HAL_FSM_STANDBY_WAIT_DEFAULT);
|
||||
adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT);
|
||||
adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT);
|
||||
adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1));
|
||||
adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2));
|
||||
adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT);
|
||||
adc_digi_controller_reg_set(&dig_cfg);
|
||||
ADC_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32
|
@ -8,6 +8,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
@ -17,11 +18,14 @@
|
||||
#include "driver/rtc_io.h"
|
||||
#include "sys/lock.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/adc.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "adc1_private.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/adc_hal_conf.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/adc_lock.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
|
||||
#if SOC_DAC_SUPPORTED
|
||||
#include "driver/dac.h"
|
||||
@ -79,7 +83,6 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi
|
||||
#define FSM_ENTER() RTC_ENTER_CRITICAL()
|
||||
#define FSM_EXIT() RTC_EXIT_CRITICAL()
|
||||
|
||||
//TODO: IDF-3610
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
//prevent ADC1 being used by I2S dma and other tasks at the same time.
|
||||
static _lock_t adc1_dma_lock;
|
||||
@ -102,97 +105,20 @@ In ADC2, there're two locks used for different cases:
|
||||
Since conversions are short (about 31us), app returns the lock very soon,
|
||||
we use a spinlock to stand there waiting to do conversions one by one.
|
||||
|
||||
adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock.
|
||||
adc2_spinlock should be acquired first, then call `adc_lock_release(ADC_UNIT_2)` or rtc_spinlock.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
//prevent ADC2 being used by wifi and other tasks at the same time.
|
||||
static _lock_t adc2_wifi_lock;
|
||||
/** For ESP32S2 the ADC2 The right to use ADC2 is controlled by the arbiter, and there is no need to set a lock. */
|
||||
#define SARADC2_ACQUIRE() _lock_acquire( &adc2_wifi_lock )
|
||||
#define SARADC2_RELEASE() _lock_release( &adc2_wifi_lock )
|
||||
#define SARADC2_TRY_ACQUIRE() _lock_try_acquire( &adc2_wifi_lock )
|
||||
#define SARADC2_LOCK_CHECK() ((uint32_t *)adc2_wifi_lock != NULL)
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#define SARADC2_ACQUIRE()
|
||||
#define SARADC2_RELEASE()
|
||||
#define SARADC2_TRY_ACQUIRE() (0) //WIFI controller and rtc controller have independent parameter configuration.
|
||||
#define SARADC2_LOCK_CHECK() (true)
|
||||
|
||||
#endif // CONFIG_IDF_TARGET_*
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
static esp_pm_lock_handle_t s_adc2_arbiter_lock;
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
static esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw);
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Common
|
||||
---------------------------------------------------------------*/
|
||||
// ADC Power
|
||||
|
||||
// This gets incremented when adc_power_acquire() is called, and decremented when
|
||||
// adc_power_release() is called. ADC is powered down when the value reaches zero.
|
||||
// Should be modified within critical section (ADC_ENTER/EXIT_CRITICAL).
|
||||
static int s_adc_power_on_cnt;
|
||||
|
||||
static void adc_power_on_internal(void)
|
||||
{
|
||||
/* Set the power always on to increase precision. */
|
||||
adc_hal_set_power_manage(ADC_POWER_SW_ON);
|
||||
}
|
||||
|
||||
void adc_power_acquire(void)
|
||||
{
|
||||
ADC_POWER_ENTER();
|
||||
s_adc_power_on_cnt++;
|
||||
if (s_adc_power_on_cnt == 1) {
|
||||
adc_power_on_internal();
|
||||
}
|
||||
ADC_POWER_EXIT();
|
||||
}
|
||||
|
||||
void adc_power_on(void)
|
||||
{
|
||||
ADC_POWER_ENTER();
|
||||
adc_power_on_internal();
|
||||
ADC_POWER_EXIT();
|
||||
}
|
||||
|
||||
static void adc_power_off_internal(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
adc_hal_set_power_manage(ADC_POWER_SW_OFF);
|
||||
#else
|
||||
adc_hal_set_power_manage(ADC_POWER_BY_FSM);
|
||||
#endif
|
||||
}
|
||||
|
||||
void adc_power_release(void)
|
||||
{
|
||||
ADC_POWER_ENTER();
|
||||
s_adc_power_on_cnt--;
|
||||
/* Sanity check */
|
||||
if (s_adc_power_on_cnt < 0) {
|
||||
ADC_POWER_EXIT();
|
||||
ESP_LOGE(ADC_TAG, "%s called, but s_adc_power_on_cnt == 0", __func__);
|
||||
abort();
|
||||
} else if (s_adc_power_on_cnt == 0) {
|
||||
adc_power_off_internal();
|
||||
}
|
||||
ADC_POWER_EXIT();
|
||||
}
|
||||
|
||||
void adc_power_off(void)
|
||||
{
|
||||
ADC_POWER_ENTER();
|
||||
adc_power_off_internal();
|
||||
ADC_POWER_EXIT();
|
||||
}
|
||||
|
||||
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_1, channel);
|
||||
@ -207,6 +133,7 @@ esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_2, channel);
|
||||
@ -220,20 +147,10 @@ esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------RTC Single Read----------------------------------------------//
|
||||
#if SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
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);
|
||||
|
||||
return adc_get_calibration_offset(adc_n, atten);
|
||||
}
|
||||
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
esp_err_t adc_set_clk_div(uint8_t clk_div)
|
||||
{
|
||||
DIGI_CONTROLLER_ENTER();
|
||||
@ -264,11 +181,6 @@ static void adc_rtc_chan_init(adc_unit_t adc_unit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is NOT an API.
|
||||
* Now some to-be-deprecated APIs are using this function, so don't make it static for now.
|
||||
* Will make this static on v5.0
|
||||
*/
|
||||
esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
gpio_num_t gpio_num = 0;
|
||||
@ -314,21 +226,25 @@ esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit)
|
||||
ADC_CHECK(width_bit < ADC_WIDTH_MAX, "unsupported bit width", ESP_ERR_INVALID_ARG);
|
||||
adc_bitwidth_t bitwidth = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
switch(width_bit) {
|
||||
case ADC_WIDTH_BIT_9:
|
||||
bitwidth = ADC_BITWIDTH_9;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_10:
|
||||
bitwidth = ADC_BITWIDTH_10;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_11:
|
||||
bitwidth = ADC_BITWIDTH_11;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_12:
|
||||
bitwidth = ADC_BITWIDTH_12;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) {
|
||||
bitwidth = SOC_ADC_RTC_MAX_BITWIDTH;
|
||||
} else {
|
||||
switch(width_bit) {
|
||||
case ADC_WIDTH_BIT_9:
|
||||
bitwidth = ADC_BITWIDTH_9;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_10:
|
||||
bitwidth = ADC_BITWIDTH_10;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_11:
|
||||
bitwidth = ADC_BITWIDTH_11;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_12:
|
||||
bitwidth = ADC_BITWIDTH_12;
|
||||
break;
|
||||
default:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
bitwidth = ADC_BITWIDTH_13;
|
||||
@ -392,21 +308,25 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit)
|
||||
ADC_CHECK(width_bit < ADC_WIDTH_MAX, "unsupported bit width", ESP_ERR_INVALID_ARG);
|
||||
adc_bitwidth_t bitwidth = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
switch(width_bit) {
|
||||
case ADC_WIDTH_BIT_9:
|
||||
bitwidth = ADC_BITWIDTH_9;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_10:
|
||||
bitwidth = ADC_BITWIDTH_10;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_11:
|
||||
bitwidth = ADC_BITWIDTH_11;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_12:
|
||||
bitwidth = ADC_BITWIDTH_12;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) {
|
||||
bitwidth = SOC_ADC_RTC_MAX_BITWIDTH;
|
||||
} else {
|
||||
switch(width_bit) {
|
||||
case ADC_WIDTH_BIT_9:
|
||||
bitwidth = ADC_BITWIDTH_9;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_10:
|
||||
bitwidth = ADC_BITWIDTH_10;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_11:
|
||||
bitwidth = ADC_BITWIDTH_11;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_12:
|
||||
bitwidth = ADC_BITWIDTH_12;
|
||||
break;
|
||||
default:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
bitwidth = ADC_BITWIDTH_13;
|
||||
@ -470,9 +390,8 @@ int adc1_get_raw(adc1_channel_t channel)
|
||||
adc1_rtc_mode_acquire();
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
// Get calibration value before going into critical section
|
||||
uint32_t cal_val = get_calibration_offset(ADC_UNIT_1, channel);
|
||||
adc_hal_set_calibration_param(ADC_UNIT_1, cal_val);
|
||||
adc_atten_t atten = adc_ll_get_atten(ADC_UNIT_1, channel);
|
||||
adc_set_hw_calibration_code(ADC_UNIT_1, atten);
|
||||
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
SARADC1_ENTER();
|
||||
@ -515,27 +434,10 @@ void adc1_ulp_enable(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
/*---------------------------------------------------------------
|
||||
ADC2
|
||||
---------------------------------------------------------------*/
|
||||
/** For ESP32S2 the ADC2 The right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/
|
||||
esp_err_t adc2_wifi_acquire(void)
|
||||
{
|
||||
/* Wi-Fi module will use adc2. Use locks to avoid conflicts. */
|
||||
SARADC2_ACQUIRE();
|
||||
ESP_LOGD( ADC_TAG, "Wi-Fi takes adc2 lock." );
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc2_wifi_release(void)
|
||||
{
|
||||
ADC_CHECK(SARADC2_LOCK_CHECK(), "wifi release called before acquire", ESP_ERR_INVALID_STATE );
|
||||
SARADC2_RELEASE();
|
||||
ESP_LOGD( ADC_TAG, "Wi-Fi returns adc2 lock." );
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_UNIT_2, channel);
|
||||
@ -543,10 +445,13 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
|
||||
|
||||
adc_common_gpio_init(ADC_UNIT_2, channel);
|
||||
|
||||
if ( SARADC2_TRY_ACQUIRE() == -1 ) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/** For ESP32S2 and S3, the right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/
|
||||
if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) {
|
||||
//try the lock, return if failed (wifi using).
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
//avoid collision with other tasks
|
||||
SARADC2_ENTER();
|
||||
@ -554,7 +459,9 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
|
||||
adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten);
|
||||
SARADC2_EXIT();
|
||||
|
||||
SARADC2_RELEASE();
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
adc_lock_release(ADC_UNIT_2);
|
||||
#endif
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_hal_calibration_init(ADC_UNIT_2);
|
||||
@ -610,21 +517,25 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
ADC_CHECK(channel < ADC2_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG);
|
||||
ADC_CHECK(width_bit < ADC_WIDTH_MAX, "unsupported bit width", ESP_ERR_INVALID_ARG);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
switch(width_bit) {
|
||||
case ADC_WIDTH_BIT_9:
|
||||
bitwidth = ADC_BITWIDTH_9;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_10:
|
||||
bitwidth = ADC_BITWIDTH_10;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_11:
|
||||
bitwidth = ADC_BITWIDTH_11;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_12:
|
||||
bitwidth = ADC_BITWIDTH_12;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) {
|
||||
bitwidth = SOC_ADC_RTC_MAX_BITWIDTH;
|
||||
} else {
|
||||
switch(width_bit) {
|
||||
case ADC_WIDTH_BIT_9:
|
||||
bitwidth = ADC_BITWIDTH_9;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_10:
|
||||
bitwidth = ADC_BITWIDTH_10;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_11:
|
||||
bitwidth = ADC_BITWIDTH_11;
|
||||
break;
|
||||
case ADC_WIDTH_BIT_12:
|
||||
bitwidth = ADC_BITWIDTH_12;
|
||||
break;
|
||||
default:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
bitwidth = ADC_BITWIDTH_13;
|
||||
@ -633,15 +544,17 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
#endif
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
// Get calibration value before going into critical section
|
||||
uint32_t cal_val = get_calibration_offset(ADC_UNIT_2, channel);
|
||||
adc_hal_set_calibration_param(ADC_UNIT_2, cal_val);
|
||||
adc_atten_t atten = adc_ll_get_atten(ADC_UNIT_2, channel);
|
||||
adc_set_hw_calibration_code(ADC_UNIT_2, atten);
|
||||
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
if ( SARADC2_TRY_ACQUIRE() == -1 ) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/** For ESP32S2 and S3, the right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/
|
||||
if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) {
|
||||
//try the lock, return if failed (wifi using).
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
#endif
|
||||
adc_power_acquire(); //in critical section with whole rtc module
|
||||
|
||||
//avoid collision with other tasks
|
||||
@ -689,17 +602,14 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
SARADC2_EXIT();
|
||||
|
||||
adc_power_release();
|
||||
SARADC2_RELEASE();
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
adc_lock_release(ADC_UNIT_2);
|
||||
#endif
|
||||
|
||||
*raw_out = adc_value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
|
||||
{
|
||||
return adc_vref_to_gpio(ADC_UNIT_2, gpio);
|
||||
}
|
||||
|
||||
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
@ -736,3 +646,278 @@ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
|
||||
}
|
||||
|
||||
#endif //SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
|
||||
|
||||
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
Legacy ADC Single Read Mode
|
||||
when RTC controller isn't supported
|
||||
---------------------------------------------------------------*/
|
||||
#include "esp_check.h"
|
||||
|
||||
portMUX_TYPE adc_reg_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define ADC_REG_LOCK_ENTER() portENTER_CRITICAL(&adc_reg_lock)
|
||||
#define ADC_REG_LOCK_EXIT() portEXIT_CRITICAL(&adc_reg_lock)
|
||||
|
||||
static adc_atten_t s_atten1_single[ADC1_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC1, used by single read API
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
static adc_atten_t s_atten2_single[ADC2_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC2, used by single read API
|
||||
#endif
|
||||
|
||||
|
||||
static int8_t adc_digi_get_io_num(adc_unit_t adc_unit, uint8_t adc_channel)
|
||||
{
|
||||
assert(adc_unit <= SOC_ADC_PERIPH_NUM);
|
||||
uint8_t adc_n = (adc_unit == ADC_UNIT_1) ? 0 : 1;
|
||||
return adc_channel_io_map[adc_n][adc_channel];
|
||||
}
|
||||
|
||||
static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint64_t gpio_mask = 0;
|
||||
uint32_t n = 0;
|
||||
int8_t io = 0;
|
||||
|
||||
while (channel_mask) {
|
||||
if (channel_mask & 0x1) {
|
||||
io = adc_digi_get_io_num(adc_unit, n);
|
||||
if (io < 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gpio_mask |= BIT64(io);
|
||||
}
|
||||
channel_mask = channel_mask >> 1;
|
||||
n++;
|
||||
}
|
||||
|
||||
gpio_config_t cfg = {
|
||||
.pin_bit_mask = gpio_mask,
|
||||
.mode = GPIO_MODE_DISABLE,
|
||||
};
|
||||
ret = gpio_config(&cfg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint32_t channel = ADC2_CHANNEL_MAX;
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
for (int i = 0; i < ADC2_CHANNEL_MAX; i++) {
|
||||
if (gpio == ADC_GET_IO_NUM(ADC_UNIT_2, i)) {
|
||||
channel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (channel == ADC2_CHANNEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
adc_power_acquire();
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
RTC_ENTER_CRITICAL();
|
||||
adc_hal_vref_output(ADC_UNIT_1, channel, true);
|
||||
RTC_EXIT_CRITICAL();
|
||||
} else { //ADC_UNIT_2
|
||||
RTC_ENTER_CRITICAL();
|
||||
adc_hal_vref_output(ADC_UNIT_2, channel, true);
|
||||
RTC_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
|
||||
{
|
||||
//On ESP32C3, the data width is always 12-bits.
|
||||
if (width_bit != ADC_WIDTH_BIT_12) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC1 channel error");
|
||||
ESP_RETURN_ON_FALSE((atten < SOC_ADC_ATTEN_NUM), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC Atten Err");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
s_atten1_single[channel] = atten;
|
||||
ret = adc_digi_gpio_init(ADC_UNIT_1, BIT(channel));
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_hal_calibration_init(ADC_UNIT_1);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int adc1_get_raw(adc1_channel_t channel)
|
||||
{
|
||||
int raw_out = 0;
|
||||
|
||||
if (adc_lock_try_acquire(ADC_UNIT_1) != ESP_OK) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
adc_power_acquire();
|
||||
adc_ll_digi_clk_sel(0);
|
||||
|
||||
adc_atten_t atten = s_atten1_single[channel];
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_set_hw_calibration_code(ADC_UNIT_1, atten);
|
||||
#endif
|
||||
|
||||
ADC_REG_LOCK_ENTER();
|
||||
adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten);
|
||||
adc_hal_convert(ADC_UNIT_1, channel, &raw_out);
|
||||
ADC_REG_LOCK_EXIT();
|
||||
|
||||
adc_power_release();
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
adc_lock_release(ADC_UNIT_1);
|
||||
|
||||
return raw_out;
|
||||
}
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_2), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 channel error");
|
||||
ESP_RETURN_ON_FALSE((atten <= ADC_ATTEN_DB_11), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 Atten Err");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
s_atten2_single[channel] = atten;
|
||||
ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel));
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_hal_calibration_init(ADC_UNIT_2);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out)
|
||||
{
|
||||
//On ESP32C3, the data width is always 12-bits.
|
||||
if (width_bit != ADC_WIDTH_BIT_12) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
adc_power_acquire();
|
||||
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_arbiter_config(&config);
|
||||
|
||||
adc_atten_t atten = s_atten2_single[channel];
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_set_hw_calibration_code(ADC_UNIT_2, atten);
|
||||
#endif
|
||||
|
||||
ADC_REG_LOCK_ENTER();
|
||||
adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten);
|
||||
ret = adc_hal_convert(ADC_UNIT_2, channel, raw_out);
|
||||
ADC_REG_LOCK_EXIT();
|
||||
|
||||
adc_power_release();
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
adc_lock_release(ADC_UNIT_2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
|
||||
|
||||
static void adc_hal_onetime_start(adc_unit_t adc_n)
|
||||
{
|
||||
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
(void)adc_n;
|
||||
/**
|
||||
* There is a hardware limitation. If the APB clock frequency is high, the step of this reg signal: ``onetime_start`` may not be captured by the
|
||||
* ADC digital controller (when its clock frequency is too slow). A rough estimate for this step should be at least 3 ADC digital controller
|
||||
* clock cycle.
|
||||
*
|
||||
* This limitation will be removed in hardware future versions.
|
||||
*
|
||||
*/
|
||||
uint32_t digi_clk = APB_CLK_FREQ / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1);
|
||||
//Convert frequency to time (us). Since decimals are removed by this division operation. Add 1 here in case of the fact that delay is not enough.
|
||||
uint32_t delay = (1000 * 1000) / digi_clk + 1;
|
||||
//3 ADC digital controller clock cycle
|
||||
delay = delay * 3;
|
||||
//This coefficient (8) is got from test. When digi_clk is not smaller than ``APB_CLK_FREQ/8``, no delay is needed.
|
||||
if (digi_clk >= APB_CLK_FREQ/8) {
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
adc_oneshot_ll_start(false);
|
||||
esp_rom_delay_us(delay);
|
||||
adc_oneshot_ll_start(true);
|
||||
|
||||
//No need to delay here. Becuase if the start signal is not seen, there won't be a done intr.
|
||||
#else
|
||||
adc_oneshot_ll_start(adc_n);
|
||||
#endif
|
||||
}
|
||||
|
||||
static esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw)
|
||||
{
|
||||
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_hal_onetime_start(adc_n);
|
||||
|
||||
while (adc_oneshot_ll_get_event(event) != true) {
|
||||
;
|
||||
}
|
||||
|
||||
*out_raw = adc_oneshot_ll_get_raw_result(adc_n);
|
||||
if (adc_oneshot_ll_raw_check_valid(adc_n, *out_raw) == false) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
//HW workaround: when enabling periph clock, this should be false
|
||||
adc_oneshot_ll_disable_all_unit();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
//wrapper should be removed after I2S deprecation
|
||||
/**
|
||||
* @brief This function will be called during start up, to check that adc_oneshot driver is not running along with the legacy adc oneshot driver
|
||||
*/
|
||||
__attribute__((constructor))
|
||||
static void check_adc_oneshot_driver_conflict(void)
|
||||
{
|
||||
// This function was declared as weak here. adc_oneshot driver has one implementation.
|
||||
// So if adc_oneshot driver is not linked in, then `adc_oneshot_new_unit` should be NULL at runtime.
|
||||
extern __attribute__((weak)) esp_err_t adc_oneshot_new_unit(const void *init_config, void **ret_unit);
|
||||
if ((void *)adc_oneshot_new_unit != NULL) {
|
||||
ESP_EARLY_LOGE(ADC_TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver");
|
||||
abort();
|
||||
}
|
||||
ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_oneshot.h`");
|
||||
}
|
||||
#endif
|
@ -1,152 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
/*----------------------------------------------------------------------------------
|
||||
This file contains Deprecated ADC APIs
|
||||
-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#pragma once
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#if !CONFIG_ADC_SUPPRESS_DEPRECATE_WARN
|
||||
#warning "legacy adc driver is deprecated, please migrate to use esp_adc/adc_oneshot.h and esp_adc/adc_continuous.h for oneshot mode and continuous mode drivers respectively"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
|
||||
typedef enum {
|
||||
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 */
|
||||
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 */
|
||||
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO38 */
|
||||
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO39 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO32 */
|
||||
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO33 */
|
||||
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO34 */
|
||||
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO35 */
|
||||
ADC1_CHANNEL_MAX,
|
||||
} adc1_channel_t;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // TODO ESP32-S3 channels are wrong IDF-1776
|
||||
/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
|
||||
typedef enum {
|
||||
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO1 */
|
||||
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO2 */
|
||||
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO3 */
|
||||
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO4 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO5 */
|
||||
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO6 */
|
||||
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO7 */
|
||||
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO8 */
|
||||
ADC1_CHANNEL_8, /*!< ADC1 channel 8 is GPIO9 */
|
||||
ADC1_CHANNEL_9, /*!< ADC1 channel 9 is GPIO10 */
|
||||
ADC1_CHANNEL_MAX,
|
||||
} adc1_channel_t;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2
|
||||
/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
|
||||
typedef enum {
|
||||
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO0 */
|
||||
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO1 */
|
||||
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO2 */
|
||||
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO3 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO4 */
|
||||
ADC1_CHANNEL_MAX,
|
||||
} adc1_channel_t;
|
||||
#endif // CONFIG_IDF_TARGET_*
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // TODO ESP32-S3 channels are wrong IDF-1776
|
||||
/**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
|
||||
typedef enum {
|
||||
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 (ESP32), GPIO11 (ESP32-S2) */
|
||||
ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 (ESP32), GPIO12 (ESP32-S2) */
|
||||
ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 (ESP32), GPIO13 (ESP32-S2) */
|
||||
ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 (ESP32), GPIO14 (ESP32-S2) */
|
||||
ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 (ESP32), GPIO15 (ESP32-S2) */
|
||||
ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 (ESP32), GPIO16 (ESP32-S2) */
|
||||
ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 (ESP32), GPIO17 (ESP32-S2) */
|
||||
ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 (ESP32), GPIO18 (ESP32-S2) */
|
||||
ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 (ESP32), GPIO19 (ESP32-S2) */
|
||||
ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */
|
||||
ADC2_CHANNEL_MAX,
|
||||
} adc2_channel_t;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2
|
||||
/**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
|
||||
typedef enum {
|
||||
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO5 */
|
||||
ADC2_CHANNEL_MAX,
|
||||
} adc2_channel_t;
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief ADC rtc controller attenuation option.
|
||||
*
|
||||
* @note This definitions are only for being back-compatible
|
||||
*/
|
||||
#define ADC_ATTEN_0db ADC_ATTEN_DB_0
|
||||
#define ADC_ATTEN_2_5db ADC_ATTEN_DB_2_5
|
||||
#define ADC_ATTEN_6db ADC_ATTEN_DB_6
|
||||
#define ADC_ATTEN_11db ADC_ATTEN_DB_11
|
||||
|
||||
/**
|
||||
* The default (max) bit width of the ADC of current version. You can also get the maximum bitwidth
|
||||
* by `SOC_ADC_RTC_MAX_BITWIDTH` defined in soc_caps.h.
|
||||
*/
|
||||
#define ADC_WIDTH_BIT_DEFAULT (ADC_WIDTH_MAX-1)
|
||||
|
||||
//this definitions are only for being back-compatible
|
||||
#define ADC_WIDTH_9Bit ADC_WIDTH_BIT_9
|
||||
#define ADC_WIDTH_10Bit ADC_WIDTH_BIT_10
|
||||
#define ADC_WIDTH_11Bit ADC_WIDTH_BIT_11
|
||||
#define ADC_WIDTH_12Bit ADC_WIDTH_BIT_12
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller encode option.
|
||||
*
|
||||
* @deprecated The ESP32-S2 doesn't use I2S DMA. Call ``adc_digi_output_format_t`` instead.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_ENCODE_12BIT, /*!< ADC to DMA data format, , [15:12]-channel [11:0]-12 bits ADC data */
|
||||
ADC_ENCODE_11BIT, /*!< ADC to DMA data format, [15]-unit, [14:11]-channel [10:0]-11 bits ADC data */
|
||||
ADC_ENCODE_MAX,
|
||||
} adc_i2s_encode_t;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Common setting
|
||||
Deprecated API
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Enable ADC power
|
||||
* @deprecated Use adc_power_acquire and adc_power_release instead.
|
||||
*/
|
||||
void adc_power_on(void) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Power off SAR ADC
|
||||
* @deprecated Use adc_power_acquire and adc_power_release instead.
|
||||
* This function will force power down for ADC.
|
||||
* This function is deprecated because forcing power ADC power off may
|
||||
* disrupt operation of other components which may be using the ADC.
|
||||
*/
|
||||
void adc_power_off(void) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Increment the usage counter for ADC module.
|
||||
* ADC will stay powered on while the counter is greater than 0.
|
||||
* Call adc_power_release when done using the ADC.
|
||||
*/
|
||||
void adc_power_acquire(void);
|
||||
|
||||
/**
|
||||
* @brief Decrement the usage counter for ADC module.
|
||||
* ADC will stay powered on while the counter is greater than 0.
|
||||
* Call this function when done using the ADC.
|
||||
*/
|
||||
void adc_power_release(void);
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Single Read Setting
|
||||
---------------------------------------------------------------*/
|
||||
@ -288,6 +167,7 @@ esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit);
|
||||
void adc1_ulp_enable(void);
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
/**
|
||||
* @brief Get the GPIO number of a specific ADC2 channel.
|
||||
*
|
||||
@ -396,59 +276,13 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
* - ESP_ERR_INVALID_ARG: Unsupported GPIO
|
||||
*/
|
||||
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio);
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
|
||||
/**
|
||||
* @brief Output ADC2 reference voltage to ``adc2_channe_t``'s IO.
|
||||
*
|
||||
* This function routes the internal reference voltage of ADCn to one of
|
||||
* ADC2's channels. This reference voltage can then be manually measured
|
||||
* for calibration purposes.
|
||||
*
|
||||
* @deprecated Use ``adc_vref_to_gpio`` instead.
|
||||
*
|
||||
* @param[in] gpio GPIO number (ADC2's channels are supported)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: v_ref successfully routed to selected GPIO
|
||||
* - ESP_ERR_INVALID_ARG: Unsupported GPIO
|
||||
*/
|
||||
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) __attribute__((deprecated));
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
DMA setting
|
||||
ADC DMA Read Setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Digital ADC DMA read max timeout value, it may make the ``adc_digi_read_bytes`` block forever if the OS supports
|
||||
*/
|
||||
#define ADC_MAX_DELAY UINT32_MAX
|
||||
|
||||
/**
|
||||
* @brief ADC DMA driver configuration
|
||||
*/
|
||||
typedef struct adc_digi_init_config_s {
|
||||
uint32_t max_store_buf_size; ///< Max length of the converted data that driver can store before they are processed.
|
||||
uint32_t conv_num_each_intr; ///< Bytes of data that can be converted in 1 interrupt.
|
||||
uint32_t adc1_chan_mask; ///< Channel list of ADC1 to be initialized.
|
||||
uint32_t adc2_chan_mask; ///< Channel list of ADC2 to be initialized.
|
||||
} adc_digi_init_config_t;
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller settings
|
||||
*/
|
||||
typedef struct {
|
||||
bool conv_limit_en; ///< To limit ADC conversion times. Conversion stops after finishing `conv_limit_num` times conversion
|
||||
uint32_t conv_limit_num; ///< Set the upper limit of the number of ADC conversion triggers. Range: 1 ~ 255.
|
||||
uint32_t pattern_num; ///< Number of ADC channels that will be used
|
||||
adc_digi_pattern_config_t *adc_pattern; ///< List of configs for each ADC channel that will be used
|
||||
uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Range: 611Hz ~ 83333Hz
|
||||
Fs = Fd / interval / 2
|
||||
Fs: sampling frequency;
|
||||
Fd: digital controller frequency, no larger than 5M for better performance
|
||||
interval: interval between 2 measurement trigger signal, the smallest interval should not be smaller than the ADC measurement period, the largest interval should not be larger than 4095 */
|
||||
adc_digi_convert_mode_t conv_mode; ///< ADC DMA conversion mode, see `adc_digi_convert_mode_t`.
|
||||
adc_digi_output_format_t format; ///< ADC DMA conversion output format, see `adc_digi_output_format_t`.
|
||||
} adc_digi_configuration_t;
|
||||
|
||||
#if SOC_ADC_DMA_SUPPORTED
|
||||
/**
|
||||
* @brief Initialize the Digital ADC.
|
||||
*
|
||||
@ -515,130 +349,6 @@ esp_err_t adc_digi_deinitialize(void);
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config);
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
//TODO IDF-3610
|
||||
/**
|
||||
* @brief Reset adc digital controller filter.
|
||||
*
|
||||
* @param idx Filter index.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Set adc digital controller filter configuration.
|
||||
*
|
||||
* @note For ESP32S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time.
|
||||
*
|
||||
* @param idx Filter index.
|
||||
* @param config See ``adc_digi_filter_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config);
|
||||
|
||||
/**
|
||||
* @brief Get adc digital controller filter configuration.
|
||||
*
|
||||
* @note For ESP32S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time.
|
||||
*
|
||||
* @param idx Filter index.
|
||||
* @param config See ``adc_digi_filter_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable adc digital controller filter.
|
||||
* Filtering the ADC data to obtain smooth data at higher sampling rates.
|
||||
*
|
||||
* @note For ESP32S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time.
|
||||
*
|
||||
* @param idx Filter index.
|
||||
* @param enable Enable/Disable filter.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable);
|
||||
|
||||
/**
|
||||
* @brief Config monitor of adc digital controller.
|
||||
*
|
||||
* @note For ESP32S2, The monitor will monitor all the enabled channel data of the each ADC unit at the same time.
|
||||
*
|
||||
* @param idx Monitor index.
|
||||
* @param config See ``adc_digi_monitor_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable monitor of adc digital controller.
|
||||
*
|
||||
* @note For ESP32S2, The monitor will monitor all the enabled channel data of the each ADC unit at the same time.
|
||||
*
|
||||
* @param idx Monitor index.
|
||||
* @param enable True or false enable monitor.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable);
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//TODO IDF-3610
|
||||
/**
|
||||
* @brief Read Hall Sensor
|
||||
*
|
||||
* @note When the power switch of SARADC1, SARADC2, HALL sensor and AMP sensor is turned on,
|
||||
* the input of GPIO36 and GPIO39 will be pulled down for about 80ns.
|
||||
* When enabling power for any of these peripherals, ignore input from GPIO36 and GPIO39.
|
||||
* Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue.
|
||||
*
|
||||
* @note The Hall Sensor uses channels 0 and 3 of ADC1. Do not configure
|
||||
* these channels for use as ADC channels.
|
||||
*
|
||||
* @note The ADC1 module must be enabled by calling
|
||||
* adc1_config_width() before calling hall_sensor_read(). ADC1
|
||||
* should be configured for 12 bit readings, as the hall sensor
|
||||
* readings are low values and do not cover the full range of the
|
||||
* ADC.
|
||||
*
|
||||
* @return The hall sensor reading.
|
||||
*/
|
||||
int hall_sensor_read(void);
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
To Be Deprecated TODO: IDF-3610
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Set I2S data source
|
||||
* @param src I2S DMA data source, I2S DMA can get data from digital signals or from ADC.
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
*/
|
||||
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src);
|
||||
|
||||
/**
|
||||
* @brief Initialize I2S ADC mode
|
||||
* @param adc_unit ADC unit index
|
||||
* @param channel ADC channel index
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------------
|
||||
This file contains Deprecated ADC APIs
|
||||
-----------------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_err.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "driver/adc_types_deprecated.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
/*---------------------------------------------------------------
|
||||
ESP32S2 Deprecated ADC APIs
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Config ADC module arbiter.
|
||||
* The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority,
|
||||
* the low priority controller will read the invalid ADC2 data, and the validity of the data can be judged by the flag bit in the data.
|
||||
*
|
||||
* @note Only ADC2 support arbiter.
|
||||
* @note Default priority: Wi-Fi > RTC > Digital;
|
||||
* @note In normal use, there is no need to call this interface to config arbiter.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param config Refer to `adc_arbiter_t`.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_NOT_SUPPORTED ADC unit not support arbiter.
|
||||
*/
|
||||
esp_err_t adc_arbiter_config(adc_unit_t adc_unit, adc_arbiter_t *config) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Enable interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_intr_enable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Disable interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_intr_disable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Clear interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_intr_clear(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Get interrupt status mask of adc digital controller.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @return
|
||||
* - intr Interrupt bitmask, See ``adc_digi_intr_t``.
|
||||
*/
|
||||
uint32_t adc_digi_intr_get_status(adc_unit_t adc_unit) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Register ADC interrupt handler, the handler is an ISR.
|
||||
* The handler will be attached to the same CPU core that this function is running on.
|
||||
*
|
||||
* @param fn Interrupt handler function.
|
||||
* @param arg Parameter for handler function
|
||||
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
|
||||
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
|
||||
* - ESP_ERR_INVALID_ARG Function pointer error.
|
||||
*/
|
||||
esp_err_t adc_digi_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Deregister ADC interrupt handler, the handler is an ISR.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG hander error.
|
||||
* - ESP_FAIL ISR not be registered.
|
||||
*/
|
||||
esp_err_t adc_digi_isr_deregister(void) __attribute__((deprecated));
|
||||
#endif // #if CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
/*---------------------------------------------------------------
|
||||
ESP32, ESP32S2 Deprecated ADC APIs
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief ADC digital controller initialization.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_init(void) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller deinitialization.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_deinit(void) __attribute__((deprecated));
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
/*---------------------------------------------------------------
|
||||
ESP32, ESP32S2, ESP32C3 Deprecated ADC APIs
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Setting the digital controller.
|
||||
*
|
||||
* @param config Pointer to digital controller paramter. Refer to ``adc_digi_config_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Initialize ADC pad
|
||||
* @param adc_unit ADC unit index
|
||||
* @param channel ADC channel index
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) __attribute__((deprecated));;
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
51
components/driver/deprecated/driver/adc_i2s_legacy.h
Normal file
51
components/driver/deprecated/driver/adc_i2s_legacy.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
/**
|
||||
* @brief ESP32 ADC DMA source selection.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_I2S_DATA_SRC_IO_SIG = 0, /*!< I2S data from GPIO matrix signal */
|
||||
ADC_I2S_DATA_SRC_ADC = 1, /*!< I2S data from ADC */
|
||||
} adc_i2s_source_t;
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/*---------------------------------------------------------------
|
||||
ESP32 Deprecated API
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Set I2S data source
|
||||
* @param src I2S DMA data source, I2S DMA can get data from digital signals or from ADC.
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
*/
|
||||
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src);
|
||||
|
||||
/**
|
||||
* @brief Initialize I2S ADC mode
|
||||
* @param adc_unit ADC unit index
|
||||
* @param channel ADC channel index
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,203 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_err.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/*---------------------------------------------------------------
|
||||
ESP32 Deprecated Types
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief ADC digital controller (DMA mode) conversion rules setting.
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
|
||||
0: measurement range 0 - 800mV,
|
||||
1: measurement range 0 - 1100mV,
|
||||
2: measurement range 0 - 1350mV,
|
||||
3: measurement range 0 - 2600mV. */
|
||||
uint8_t bit_width: 2; /*!< ADC resolution.
|
||||
- 0: 9 bit;
|
||||
- 1: 10 bit;
|
||||
- 2: 11 bit;
|
||||
- 3: 12 bit. */
|
||||
int8_t channel: 4; /*!< ADC channel index. */
|
||||
};
|
||||
uint8_t val; /*!<Raw data value */
|
||||
};
|
||||
} adc_digi_pattern_table_t __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* Explanation of the relationship between `conv_limit_num`, `dma_eof_num` and the number of DMA outputs:
|
||||
*
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | conv_mode | single | both | alter |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | trigger meas times | 1 | 1 | 1 |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | conv_limit_num | +1 | +1 | +1 |
|
||||
* | dma_eof_num | +1 | +2 | +1 |
|
||||
* | dma output (byte) | +2 | +4 | +2 |
|
||||
* +---------------------+--------+--------+--------+
|
||||
*/
|
||||
typedef struct {
|
||||
bool conv_limit_en; /*!<Enable the function of limiting ADC conversion times.
|
||||
If the number of ADC conversion trigger count is equal to the `limit_num`, the conversion is stopped. */
|
||||
uint32_t conv_limit_num; /*!<Set the upper limit of the number of ADC conversion triggers. Range: 1 ~ 255. */
|
||||
uint32_t adc1_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 16 (0: Don't change the pattern table setting).
|
||||
The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
|
||||
resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
|
||||
pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
|
||||
uint32_t adc2_pattern_len; /*!<Refer to ``adc1_pattern_len`` */
|
||||
adc_digi_pattern_table_t *adc1_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc1_pattern_len`. */
|
||||
adc_digi_pattern_table_t *adc2_pattern; /*!<Refer to `adc1_pattern` */
|
||||
adc_digi_convert_mode_t conv_mode; /*!<ADC conversion mode for digital controller. See ``adc_digi_convert_mode_t``. */
|
||||
adc_digi_output_format_t format; /*!<ADC output data format for digital controller. See ``adc_digi_output_format_t``. */
|
||||
} adc_digi_config_t __attribute__((deprecated));
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
/*---------------------------------------------------------------
|
||||
ESP32S2 Deprecated Types
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief ADC digital controller (DMA mode) conversion rules setting.
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
|
||||
0: measurement range 0 - 800mV,
|
||||
1: measurement range 0 - 1100mV,
|
||||
2: measurement range 0 - 1350mV,
|
||||
3: measurement range 0 - 2600mV. */
|
||||
uint8_t reserved: 2; /*!< reserved0 */
|
||||
uint8_t channel: 4; /*!< ADC channel index. */
|
||||
};
|
||||
uint8_t val; /*!<Raw data value */
|
||||
};
|
||||
} adc_digi_pattern_table_t __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller (DMA mode) configuration parameters.
|
||||
*
|
||||
* Example setting: When using ADC1 channel0 to measure voltage, the sampling rate is required to be 1 kHz:
|
||||
*
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | sample rate | 1 kHz | 1 kHz | 1 kHz |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | conv_mode | single | both | alter |
|
||||
* | adc1_pattern_len | 1 | 1 | 1 |
|
||||
* | dig_clk.use_apll | 0 | 0 | 0 |
|
||||
* | dig_clk.div_num | 99 | 99 | 99 |
|
||||
* | dig_clk.div_b | 0 | 0 | 0 |
|
||||
* | dig_clk.div_a | 0 | 0 | 0 |
|
||||
* | interval | 400 | 400 | 200 |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | `trigger_meas_freq` | 1 kHz | 1 kHz | 2 kHz |
|
||||
* +---------------------+--------+--------+--------+
|
||||
*
|
||||
* Explanation of the relationship between `conv_limit_num`, `dma_eof_num` and the number of DMA outputs:
|
||||
*
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | conv_mode | single | both | alter |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | trigger meas times | 1 | 1 | 1 |
|
||||
* +---------------------+--------+--------+--------+
|
||||
* | conv_limit_num | +1 | +1 | +1 |
|
||||
* | dma_eof_num | +1 | +2 | +1 |
|
||||
* | dma output (byte) | +2 | +4 | +2 |
|
||||
* +---------------------+--------+--------+--------+
|
||||
*/
|
||||
typedef struct {
|
||||
bool conv_limit_en; /*!<Enable the function of limiting ADC conversion times.
|
||||
If the number of ADC conversion trigger count is equal to the `limit_num`, the conversion is stopped. */
|
||||
uint32_t conv_limit_num; /*!<Set the upper limit of the number of ADC conversion triggers. Range: 1 ~ 255. */
|
||||
uint32_t adc1_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 16 (0: Don't change the pattern table setting).
|
||||
The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
|
||||
resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
|
||||
pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
|
||||
uint32_t adc2_pattern_len; /*!<Refer to ``adc1_pattern_len`` */
|
||||
adc_digi_pattern_table_t *adc1_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc1_pattern_len`. */
|
||||
adc_digi_pattern_table_t *adc2_pattern; /*!<Refer to `adc1_pattern` */
|
||||
adc_digi_convert_mode_t conv_mode; /*!<ADC conversion mode for digital controller. See ``adc_digi_convert_mode_t``. */
|
||||
adc_digi_output_format_t format; /*!<ADC output data format for digital controller. See ``adc_digi_output_format_t``. */
|
||||
uint32_t interval; /*!<The number of interval clock cycles for the digital controller to trigger the measurement.
|
||||
The unit is the divided clock. Range: 40 ~ 4095.
|
||||
Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. Refer to ``adc_digi_clk_t``.
|
||||
Note: The sampling rate of each channel is also related to the conversion mode (See ``adc_digi_convert_mode_t``) and pattern table settings. */
|
||||
adc_digi_clk_t dig_clk; /*!<ADC digital controller clock divider settings. Refer to ``adc_digi_clk_t``.
|
||||
Note: The clocks of the DAC digital controller use the ADC digital controller clock divider. */
|
||||
uint32_t dma_eof_num; /*!<DMA eof num of adc digital controller.
|
||||
If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated in DMA.
|
||||
Note: The converted data in the DMA in link buffer will be multiple of two bytes. */
|
||||
} adc_digi_config_t __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller (DMA mode) interrupt type options.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_DIGI_INTR_MASK_MONITOR = 0x1,
|
||||
ADC_DIGI_INTR_MASK_MEAS_DONE = 0x2,
|
||||
ADC_DIGI_INTR_MASK_ALL = 0x3,
|
||||
} adc_digi_intr_t __attribute__((deprecated));
|
||||
FLAG_ATTR(adc_digi_intr_t)
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
/*---------------------------------------------------------------
|
||||
ESP32C3 Deprecated Types
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief ADC digital controller (DMA mode) conversion rules setting.
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
|
||||
0: measurement range 0 - 800mV,
|
||||
1: measurement range 0 - 1100mV,
|
||||
2: measurement range 0 - 1350mV,
|
||||
3: measurement range 0 - 2600mV. */
|
||||
uint8_t channel: 3; /*!< ADC channel index. */
|
||||
uint8_t unit: 1; /*!< ADC unit index. */
|
||||
uint8_t reserved: 2; /*!< reserved0 */
|
||||
};
|
||||
uint8_t val; /*!<Raw data value */
|
||||
};
|
||||
} adc_digi_pattern_table_t __attribute__((deprecated));
|
||||
|
||||
typedef struct {
|
||||
bool conv_limit_en; /*!<Enable the function of limiting ADC conversion times.
|
||||
If the number of ADC conversion trigger count is equal to the `limit_num`, the conversion is stopped. */
|
||||
uint32_t conv_limit_num; /*!<Set the upper limit of the number of ADC conversion triggers. Range: 1 ~ 255. */
|
||||
uint32_t adc_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 7 (0: Don't change the pattern table setting).
|
||||
The pattern table that defines the conversion rules for each SAR ADC. Each table has 7 items, in which channel selection,
|
||||
resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
|
||||
pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
|
||||
adc_digi_pattern_table_t *adc_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc_pattern_len`. */
|
||||
uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Range: 611Hz ~ 83333Hz
|
||||
Fs = Fd / interval / 2
|
||||
Fs: sampling frequency;
|
||||
Fd: digital controller frequency, no larger than 5M for better performance
|
||||
interval: interval between 2 measurement trigger signal, the smallest interval should not be smaller than the ADC measurement period, the largest interval should not be larger than 4095 */
|
||||
} adc_digi_config_t __attribute__((deprecated));
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
128
components/driver/deprecated/driver/adc_types_legacy.h
Normal file
128
components/driver/deprecated/driver/adc_types_legacy.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC resolution setting option.
|
||||
* @note Only used in single read mode
|
||||
*/
|
||||
typedef enum {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
ADC_WIDTH_BIT_9 = 9, /*!< ADC capture width is 9Bit. */
|
||||
ADC_WIDTH_BIT_10 = 10, /*!< ADC capture width is 10Bit. */
|
||||
ADC_WIDTH_BIT_11 = 11, /*!< ADC capture width is 11Bit. */
|
||||
ADC_WIDTH_BIT_12 = 12, /*!< ADC capture width is 12Bit. */
|
||||
#elif SOC_ADC_RTC_MAX_BITWIDTH == 12
|
||||
ADC_WIDTH_BIT_12 = 12, /*!< ADC capture width is 12Bit. */
|
||||
#elif SOC_ADC_RTC_MAX_BITWIDTH == 13
|
||||
ADC_WIDTH_BIT_13 = 13, /*!< ADC capture width is 13Bit. */
|
||||
#endif
|
||||
ADC_WIDTH_MAX,
|
||||
} adc_bits_width_t;
|
||||
|
||||
/**
|
||||
* The default (max) bit width of the ADC of current version. You can also get the maximum bitwidth
|
||||
* by `SOC_ADC_RTC_MAX_BITWIDTH` defined in soc_caps.h.
|
||||
*/
|
||||
#define ADC_WIDTH_BIT_DEFAULT (ADC_WIDTH_MAX-1)
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
typedef enum {
|
||||
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 */
|
||||
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 */
|
||||
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO38 */
|
||||
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO39 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO32 */
|
||||
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO33 */
|
||||
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO34 */
|
||||
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO35 */
|
||||
ADC1_CHANNEL_MAX,
|
||||
} adc1_channel_t;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
typedef enum {
|
||||
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO1 */
|
||||
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO2 */
|
||||
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO3 */
|
||||
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO4 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO5 */
|
||||
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO6 */
|
||||
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO7 */
|
||||
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO8 */
|
||||
ADC1_CHANNEL_8, /*!< ADC1 channel 8 is GPIO9 */
|
||||
ADC1_CHANNEL_9, /*!< ADC1 channel 9 is GPIO10 */
|
||||
ADC1_CHANNEL_MAX,
|
||||
} adc1_channel_t;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H2
|
||||
typedef enum {
|
||||
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO0 */
|
||||
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO1 */
|
||||
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO2 */
|
||||
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO3 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO4 */
|
||||
ADC1_CHANNEL_MAX,
|
||||
} adc1_channel_t;
|
||||
#endif // CONFIG_IDF_TARGET_*
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
typedef enum {
|
||||
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 (ESP32), GPIO11 (ESP32-S2) */
|
||||
ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 (ESP32), GPIO12 (ESP32-S2) */
|
||||
ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 (ESP32), GPIO13 (ESP32-S2) */
|
||||
ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 (ESP32), GPIO14 (ESP32-S2) */
|
||||
ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 (ESP32), GPIO15 (ESP32-S2) */
|
||||
ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 (ESP32), GPIO16 (ESP32-S2) */
|
||||
ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 (ESP32), GPIO17 (ESP32-S2) */
|
||||
ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 (ESP32), GPIO18 (ESP32-S2) */
|
||||
ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 (ESP32), GPIO19 (ESP32-S2) */
|
||||
ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */
|
||||
ADC2_CHANNEL_MAX,
|
||||
} adc2_channel_t;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H2
|
||||
typedef enum {
|
||||
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO5 */
|
||||
ADC2_CHANNEL_MAX,
|
||||
} adc2_channel_t;
|
||||
#endif
|
||||
|
||||
#if SOC_ADC_DMA_SUPPORTED
|
||||
/**
|
||||
* @brief Digital ADC DMA read max timeout value, it may make the ``adc_digi_read_bytes`` block forever if the OS supports
|
||||
*/
|
||||
#define ADC_MAX_DELAY UINT32_MAX
|
||||
|
||||
/**
|
||||
* @brief ADC DMA driver configuration
|
||||
*/
|
||||
typedef struct adc_digi_init_config_s {
|
||||
uint32_t max_store_buf_size; ///< Max length of the converted data that driver can store before they are processed.
|
||||
uint32_t conv_num_each_intr; ///< Bytes of data that can be converted in 1 interrupt. This should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`.
|
||||
uint32_t adc1_chan_mask; ///< Channel list of ADC1 to be initialized.
|
||||
uint32_t adc2_chan_mask; ///< Channel list of ADC2 to be initialized.
|
||||
} adc_digi_init_config_t;
|
||||
|
||||
/**
|
||||
* @brief ADC digital controller settings
|
||||
*/
|
||||
typedef struct {
|
||||
bool conv_limit_en; ///< Suggest leaving it empty, this parameter has been deprecated
|
||||
uint32_t conv_limit_num; ///< suggest leaving it empty, this parameter has been deprecated
|
||||
uint32_t pattern_num; ///< Number of ADC channels that will be used
|
||||
adc_digi_pattern_config_t *adc_pattern; ///< List of configs for each ADC channel that will be used
|
||||
uint32_t sample_freq_hz; /*!< Please refer to `soc/soc_caps.h` to know the ADC sampling frequency range*/
|
||||
adc_digi_convert_mode_t conv_mode; ///< ADC DMA conversion mode, see `adc_digi_convert_mode_t`.
|
||||
adc_digi_output_format_t format; ///< ADC DMA conversion output format, see `adc_digi_output_format_t`.
|
||||
} adc_digi_configuration_t;
|
||||
#endif // #if SOC_ADC_DMA_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -27,8 +27,10 @@
|
||||
#include "hal/i2s_hal.h"
|
||||
#if SOC_I2S_SUPPORTS_DAC
|
||||
#include "driver/dac.h"
|
||||
#include "driver/adc.h"
|
||||
#include "../adc1_private.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "adc1_private.h"
|
||||
#include "driver/adc_i2s_legacy.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
#endif // SOC_I2S_SUPPORTS_ADC
|
||||
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "sys/lock.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp_private/rtc_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/adc.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Enable built-in checks in queue.h in debug builds
|
||||
#define INVARIANTS
|
||||
#endif
|
||||
#include "sys/queue.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal.h"
|
||||
|
||||
|
||||
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
|
||||
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
|
||||
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
HALL SENSOR
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
static int hall_sensor_get_value(void) //hall sensor without LNA
|
||||
{
|
||||
int hall_value;
|
||||
|
||||
adc_power_acquire();
|
||||
|
||||
ADC_ENTER_CRITICAL();
|
||||
/* disable other peripherals. */
|
||||
adc_ll_amp_disable();
|
||||
adc_ll_hall_enable();
|
||||
// set controller
|
||||
adc_ll_set_controller( ADC_UNIT_1, ADC_LL_CTRL_RTC );
|
||||
hall_value = adc_hal_hall_convert();
|
||||
adc_ll_hall_disable();
|
||||
ADC_EXIT_CRITICAL();
|
||||
|
||||
adc_power_release();
|
||||
return hall_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* To Be Deprecated
|
||||
*/
|
||||
extern esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
|
||||
int hall_sensor_read(void)
|
||||
{
|
||||
adc_common_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_0);
|
||||
adc_common_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_3);
|
||||
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0);
|
||||
adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_0);
|
||||
return hall_sensor_get_value();
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "sys/lock.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_ll.h"
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
|
||||
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
/**
|
||||
* Config monitor of adc digital controller.
|
||||
*
|
||||
* @note The monitor will monitor all the enabled channel data of the each ADC unit at the same time.
|
||||
* @param adc_n ADC unit.
|
||||
* @param config Refer to ``adc_digi_monitor_t``.
|
||||
*/
|
||||
static void adc_digi_monitor_config(adc_unit_t adc_n, adc_digi_monitor_t *config)
|
||||
{
|
||||
adc_ll_digi_monitor_set_mode(adc_n, config->mode);
|
||||
adc_ll_digi_monitor_set_thres(adc_n, config->threshold);
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* Digital controller filter setting */
|
||||
/*************************************/
|
||||
|
||||
esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (idx == ADC_DIGI_FILTER_IDX0) {
|
||||
adc_ll_digi_filter_reset(ADC_UNIT_1);
|
||||
} else if (idx == ADC_DIGI_FILTER_IDX1) {
|
||||
adc_ll_digi_filter_reset(ADC_UNIT_2);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (idx == ADC_DIGI_FILTER_IDX0) {
|
||||
adc_ll_digi_filter_set_factor(ADC_UNIT_1, config->mode);
|
||||
} else if (idx == ADC_DIGI_FILTER_IDX1) {
|
||||
adc_ll_digi_filter_set_factor(ADC_UNIT_2, config->mode);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (idx == ADC_DIGI_FILTER_IDX0) {
|
||||
config->adc_unit = ADC_UNIT_1;
|
||||
config->channel = SOC_ADC_CHANNEL_NUM(0);
|
||||
adc_ll_digi_filter_get_factor(ADC_UNIT_1, &config->mode);
|
||||
} else if (idx == ADC_DIGI_FILTER_IDX1) {
|
||||
config->adc_unit = ADC_UNIT_2;
|
||||
config->channel = SOC_ADC_CHANNEL_NUM(1);
|
||||
adc_ll_digi_filter_get_factor(ADC_UNIT_2, &config->mode);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (idx == ADC_DIGI_FILTER_IDX0) {
|
||||
adc_ll_digi_filter_enable(ADC_UNIT_1, enable);
|
||||
} else if (idx == ADC_DIGI_FILTER_IDX1) {
|
||||
adc_ll_digi_filter_enable(ADC_UNIT_2, enable);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the filtered data of adc digital controller filter. For debug.
|
||||
* The data after each measurement and filtering is updated to the DMA by the digital controller. But it can also be obtained manually through this API.
|
||||
*
|
||||
* @note For ESP32S2, The filter will filter all the enabled channel data of the each ADC unit at the same time.
|
||||
* @param idx Filter index.
|
||||
* @return Filtered data. if <0, the read data invalid.
|
||||
*/
|
||||
int adc_digi_filter_read_data(adc_digi_filter_idx_t idx)
|
||||
{
|
||||
if (idx == ADC_DIGI_FILTER_IDX0) {
|
||||
return adc_ll_digi_filter_read_data(ADC_UNIT_1);
|
||||
} else if (idx == ADC_DIGI_FILTER_IDX1) {
|
||||
return adc_ll_digi_filter_read_data(ADC_UNIT_2);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
/* Digital controller monitor setting */
|
||||
/**************************************/
|
||||
|
||||
esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (idx == ADC_DIGI_MONITOR_IDX0) {
|
||||
adc_digi_monitor_config(ADC_UNIT_1, config);
|
||||
} else if (idx == ADC_DIGI_MONITOR_IDX1) {
|
||||
adc_digi_monitor_config(ADC_UNIT_2, config);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (idx == ADC_DIGI_MONITOR_IDX0) {
|
||||
adc_ll_digi_monitor_enable(ADC_UNIT_1, enable);
|
||||
} else if (idx == ADC_DIGI_MONITOR_IDX1) {
|
||||
adc_ll_digi_monitor_enable(ADC_UNIT_2, enable);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
#include "hal/adc_ll.h"
|
||||
#include "driver/adc_i2s_legacy.h"
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
#include "clk_ctrl_os.h"
|
||||
|
@ -1,11 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file is only a wrapper for `driver/adc.h` for back-compatability.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// Internal header for calibration, don't use in app
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "hal/adc_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
/**
|
||||
* @brief Calibrate the offset of ADC. (Based on the pre-stored efuse or actual calibration)
|
||||
*
|
||||
* @param adc_n ADC unit to calibrate
|
||||
* @param atten Attenuation to use
|
||||
* @return Always ESP_OK
|
||||
*/
|
||||
extern esp_err_t adc_cal_offset(adc_unit_t adc_n, adc_atten_t atten);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
idf_component_register(SRC_DIRS . param_test touch_sensor_test adc_dma_test dac_dma_test
|
||||
idf_component_register(SRC_DIRS . param_test touch_sensor_test dac_dma_test
|
||||
PRIV_INCLUDE_DIRS include param_test/include touch_sensor_test/include
|
||||
PRIV_REQUIRES cmock test_utils driver nvs_flash esp_serial_slave_link
|
||||
esp_adc_cal esp_timer)
|
||||
esp_timer esp_adc)
|
||||
|
@ -1,654 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
Tests for the adc device driver on ESP32-S2 only
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2) //TODO: IDF-3160
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/adc.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "unity.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "soc/adc_periph.h"
|
||||
#include "test/test_common_adc.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "driver/dac.h"
|
||||
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "test/test_adc_dac_dma.h"
|
||||
|
||||
#include "driver/adc_deprecated.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "esp_pm.h"
|
||||
|
||||
static const char *TAG = "test_adc";
|
||||
|
||||
#define PLATFORM_SELECT (1) //0: pxp; 1: chip
|
||||
#if (PLATFORM_SELECT == 0) //PXP platform
|
||||
#include "soc/syscon_reg.h"
|
||||
#define SET_BREAK_POINT(flag) REG_WRITE(SYSCON_DATE_REG, flag)
|
||||
//PXP clk is slower.
|
||||
#define SYS_DELAY_TIME_MOM (1/40)
|
||||
#define RTC_SLOW_CLK_FLAG 1 // Slow clock is 32KHz.
|
||||
static void test_pxp_deinit_io(void)
|
||||
{
|
||||
for (int i = 0; i < 22; i++) {
|
||||
rtc_gpio_init(i);
|
||||
}
|
||||
}
|
||||
#else
|
||||
//PXP clk is slower.
|
||||
#define SET_BREAK_POINT(flag)
|
||||
#define SYS_DELAY_TIME_MOM (1)
|
||||
#define RTC_SLOW_CLK_FLAG 0 // Slow clock is 32KHz.
|
||||
#endif
|
||||
|
||||
#define ADC_REG_BASE_TEST() ({ \
|
||||
TEST_ASSERT_EQUAL_UINT32(REG_GET_FIELD(APB_SARADC_APB_CTRL_DATE_REG, APB_SARADC_APB_CTRL_DATE), APB_SARADC.apb_ctrl_date); \
|
||||
TEST_ASSERT_EQUAL_UINT32(REG_GET_FIELD(SENS_SARDATE_REG, SENS_SAR_DATE), SENS.sardate.sar_date); \
|
||||
TEST_ASSERT_EQUAL_UINT32(REG_GET_FIELD(RTC_IO_DATE_REG, RTC_IO_IO_DATE), RTCIO.date.date); \
|
||||
})
|
||||
/** Sample rate = APB_CLK(80 MHz) / (CLK_DIV + 1) / TRIGGER_INTERVAL / 2. */
|
||||
#define TEST_ADC_TRIGGER_INTERVAL_DEFAULT (40)
|
||||
#define TEST_ADC_DIGI_CLK_DIV_DEFAULT (9)
|
||||
static uint8_t adc_test_num = 9;
|
||||
static adc_channel_t adc_list[SOC_ADC_PATT_LEN_MAX] = {
|
||||
ADC_CHANNEL_0,
|
||||
ADC_CHANNEL_1,
|
||||
ADC_CHANNEL_2,
|
||||
ADC_CHANNEL_3,
|
||||
ADC_CHANNEL_4,
|
||||
ADC_CHANNEL_5,
|
||||
ADC_CHANNEL_6,
|
||||
// ADC_CHANNEL_7, // Workaround: IO18 is pullup outside in ESP32S2-Saola Runner.
|
||||
ADC_CHANNEL_8,
|
||||
ADC_CHANNEL_9,
|
||||
};
|
||||
/* For ESP32S2, it should use same atten, or, it will have error. */
|
||||
#define TEST_ADC_ATTEN_DEFAULT (ADC_ATTEN_11db)
|
||||
|
||||
|
||||
/* Work mode.
|
||||
* single: eof_num;
|
||||
* double: SAR_EOF_NUMBER/2;
|
||||
* alter: eof_num;
|
||||
* */
|
||||
#define SAR_SIMPLE_NUM 512 // Set sample number of enabled unit.
|
||||
/* Use two DMA linker to save ADC data. ADC sample 1 times -> 2 byte data -> 2 DMA link buf. */
|
||||
#define SAR_DMA_DATA_SIZE(unit, sample_num) (SAR_EOF_NUMBER(unit, sample_num))
|
||||
#define SAR_EOF_NUMBER(unit, sample_num) ((sample_num) * (unit))
|
||||
#define SAR_MEAS_LIMIT_NUM(unit, sample_num) (SAR_SIMPLE_NUM)
|
||||
#define SAR_SIMPLE_TIMEOUT_MS 1000
|
||||
|
||||
typedef struct dma_msg {
|
||||
uint32_t int_msk;
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
} adc_dma_event_t;
|
||||
|
||||
static uint8_t link_buf[2][SAR_DMA_DATA_SIZE(2, SAR_SIMPLE_NUM)] = {0};
|
||||
static lldesc_t dma1 = {0};
|
||||
static lldesc_t dma2 = {0};
|
||||
static QueueHandle_t que_adc = NULL;
|
||||
static adc_dma_event_t adc_evt;
|
||||
|
||||
/**
|
||||
* @brief Reset FSM of adc digital controller.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
static esp_err_t adc_digi_reset(void)
|
||||
{
|
||||
adc_ll_digi_reset();
|
||||
adc_ll_digi_clear_pattern_table(ADC_NUM_1);
|
||||
adc_ll_digi_clear_pattern_table(ADC_NUM_2);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/** ADC-DMA ISR handler. */
|
||||
static IRAM_ATTR void adc_dma_isr(void *arg)
|
||||
{
|
||||
uint32_t int_st = REG_READ(SPI_DMA_INT_ST_REG(3));
|
||||
int task_awoken = pdFALSE;
|
||||
REG_WRITE(SPI_DMA_INT_CLR_REG(3), int_st);
|
||||
if (int_st & SPI_IN_SUC_EOF_INT_ST_M) {
|
||||
adc_evt.int_msk = int_st;
|
||||
xQueueSendFromISR(que_adc, &adc_evt, &task_awoken);
|
||||
}
|
||||
if (int_st & SPI_IN_DONE_INT_ST) {
|
||||
adc_evt.int_msk = int_st;
|
||||
xQueueSendFromISR(que_adc, &adc_evt, &task_awoken);
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "int msk%x\n", int_st);
|
||||
if (task_awoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DMA liner initialization and start.
|
||||
* @param is_loop
|
||||
* - true: The two dma linked lists are connected end to end, with no end mark (eof).
|
||||
* - false: The two dma linked lists are connected end to end, with end mark (eof).
|
||||
*/
|
||||
static uint32_t adc_dma_linker_init(adc_unit_t adc, bool is_loop)
|
||||
{
|
||||
dma1 = (lldesc_t) {
|
||||
.size = SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM),
|
||||
.owner = 1,
|
||||
.buf = &link_buf[0][0],
|
||||
.qe.stqe_next = &dma2,
|
||||
};
|
||||
dma2 = (lldesc_t) {
|
||||
.size = SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM),
|
||||
.owner = 1,
|
||||
.buf = &link_buf[1][0],
|
||||
};
|
||||
if (is_loop) {
|
||||
dma2.qe.stqe_next = &dma1;
|
||||
} else {
|
||||
dma2.qe.stqe_next = NULL;
|
||||
}
|
||||
return (uint32_t)&dma1;
|
||||
}
|
||||
|
||||
#define DEBUG_CHECK_ENABLE 1
|
||||
#define DEBUG_PRINT_ENABLE 1
|
||||
#define DEBUG_CHECK_ERROR 10
|
||||
|
||||
/**
|
||||
* Check the ADC-DMA data in linker buffer by input level.
|
||||
* ideal_level
|
||||
* - -1: Don't check data.
|
||||
* - 0: ADC channel voltage is 0v.
|
||||
* - 1: ADC channel voltage is 3.3v.
|
||||
* - 2: ADC channel voltage is 1.4v.
|
||||
*/
|
||||
static esp_err_t adc_dma_data_check(adc_unit_t adc, int ideal_level)
|
||||
{
|
||||
int unit_old = 1;
|
||||
int ch_cnt = 0;
|
||||
for (int cnt = 0; cnt < 2; cnt++) {
|
||||
esp_rom_printf("\n[%s] link_buf[%d]: \n", __func__, cnt % 2);
|
||||
for (int i = 0; i < SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM); i += 2) {
|
||||
uint8_t h = link_buf[cnt % 2][i + 1], l = link_buf[cnt % 2][i];
|
||||
uint16_t temp = (h << 8 | l);
|
||||
adc_digi_output_data_t *data = (adc_digi_output_data_t *)&temp;
|
||||
|
||||
if (adc > ADC_UNIT_2) { //ADC_ENCODE_11BIT
|
||||
#if DEBUG_PRINT_ENABLE
|
||||
if (i % 16 == 0) {
|
||||
esp_rom_printf("\n");
|
||||
}
|
||||
esp_rom_printf("[%d_%d_%04x] ", data->type2.unit, data->type2.channel, data->type2.data);
|
||||
#endif
|
||||
#if DEBUG_CHECK_ENABLE
|
||||
if (ideal_level >= 0) {
|
||||
TEST_ASSERT_NOT_EQUAL(unit_old, data->type2.unit);
|
||||
unit_old = data->type2.unit;
|
||||
if (data->type2.channel > ADC_CHANNEL_MAX) {
|
||||
printf("Data invalid [%d]\n", data->type2.channel);
|
||||
continue;
|
||||
}
|
||||
int cur_ch = ((ch_cnt++ / 2) % adc_test_num);
|
||||
TEST_ASSERT_EQUAL( data->type2.channel, adc_list[cur_ch] );
|
||||
}
|
||||
if (ideal_level == 1) { // high level 3.3v
|
||||
TEST_ASSERT_EQUAL( 0x7FF, data->type2.data );
|
||||
} else if (ideal_level == 0) { // low level 0v
|
||||
TEST_ASSERT_LESS_THAN( 10, data->type2.data );
|
||||
} else if (ideal_level == 2) { // middle level 1.4v
|
||||
TEST_ASSERT_INT_WITHIN( 128, 1100, data->type2.data );
|
||||
} else if (ideal_level == 3) { // normal level
|
||||
} else { // no check
|
||||
}
|
||||
#endif
|
||||
} else { //ADC_ENCODE_12BIT
|
||||
#if DEBUG_PRINT_ENABLE
|
||||
if (i % 16 == 0) {
|
||||
esp_rom_printf("\n");
|
||||
}
|
||||
esp_rom_printf("[%d_%04x] ", data->type1.channel, data->type1.data);
|
||||
#endif
|
||||
#if DEBUG_CHECK_ENABLE
|
||||
if (ideal_level >= 0) {
|
||||
int cur_ch = ((ch_cnt++) % adc_test_num);
|
||||
TEST_ASSERT_EQUAL( adc_list[cur_ch], data->type1.channel );
|
||||
}
|
||||
if (ideal_level == 1) { // high level 3.3v
|
||||
TEST_ASSERT_EQUAL( 0XFFF, data->type1.data );
|
||||
} else if (ideal_level == 0) { // low level 0v
|
||||
TEST_ASSERT_LESS_THAN( 10, data->type1.data );
|
||||
} else if (ideal_level == 2) { // middle level 1.4v
|
||||
TEST_ASSERT_INT_WITHIN( 256, 2200, data->type1.data );
|
||||
} else if (ideal_level == 3) { // normal level
|
||||
} else { // no check
|
||||
}
|
||||
#endif
|
||||
}
|
||||
link_buf[cnt % 2][i] = 0;
|
||||
link_buf[cnt % 2][i + 1] = 0;
|
||||
}
|
||||
esp_rom_printf("\n");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc, void *dma_addr, uint32_t int_mask)
|
||||
{
|
||||
adc_dma_event_t evt;
|
||||
|
||||
ESP_LOGI(TAG, "adc IO normal, test ...");
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc_io_normal(adc, adc_list[i]);
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_start() );
|
||||
while (1) {
|
||||
TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE );
|
||||
if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_stop() );
|
||||
adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
|
||||
adc_digi_reset();
|
||||
TEST_ESP_OK( adc_dma_data_check(adc, -1) ); // Don't check data.
|
||||
|
||||
ESP_LOGI(TAG, "adc IO fake tie high, test ...");
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc_fake_tie_high(adc, adc_list[i]);
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_start() );
|
||||
while (1) {
|
||||
TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE );
|
||||
if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_stop() );
|
||||
adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
|
||||
adc_digi_reset();
|
||||
TEST_ESP_OK( adc_dma_data_check(adc, 1) );
|
||||
|
||||
ESP_LOGI(TAG, "adc IO fake tie low, test ...");
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc_fake_tie_low(adc, adc_list[i]);
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_start() );
|
||||
while (1) {
|
||||
TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE );
|
||||
if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_stop() );
|
||||
adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
|
||||
adc_digi_reset();
|
||||
TEST_ESP_OK( adc_dma_data_check(adc, 0) );
|
||||
|
||||
ESP_LOGI(TAG, "adc IO fake tie middle, test ...");
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc_fake_tie_middle(adc, adc_list[i]);
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_start() );
|
||||
while (1) {
|
||||
TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE );
|
||||
if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_stop() );
|
||||
adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
|
||||
adc_digi_reset();
|
||||
TEST_ESP_OK( adc_dma_data_check(adc, 2) );
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#include "soc/apb_saradc_struct.h"
|
||||
/**
|
||||
* Test the partten table setting. It's easy wrong.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param in_partten_len The length of partten be set.
|
||||
* @param in_last_ch The channel number of the last message.
|
||||
*/
|
||||
static esp_err_t adc_check_patt_table(adc_unit_t adc, uint32_t in_partten_len, adc_channel_t in_last_ch)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint8_t index = (in_partten_len - 1) / 4;
|
||||
uint8_t offset = 24 - ((in_partten_len - 1) % 4) * 8;
|
||||
uint32_t temp = 0, len;
|
||||
|
||||
if (adc & ADC_UNIT_1) {
|
||||
len = APB_SARADC.ctrl.sar1_patt_len + 1;
|
||||
temp = APB_SARADC.sar1_patt_tab[index];
|
||||
printf("patt1 len %d\n", len);
|
||||
printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[0]);
|
||||
printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[1]);
|
||||
printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[2]);
|
||||
printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[3]);
|
||||
if (in_partten_len == len) {
|
||||
if (in_last_ch == (((temp >> (offset + 4))) & 0xf)) {
|
||||
ret = ESP_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (adc & ADC_UNIT_2) {
|
||||
len = APB_SARADC.ctrl.sar2_patt_len + 1;
|
||||
temp = APB_SARADC.sar2_patt_tab[index];
|
||||
printf("patt2 len %d\n", len);
|
||||
printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[0]);
|
||||
printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[1]);
|
||||
printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[2]);
|
||||
printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[3]);
|
||||
if (in_partten_len == len) {
|
||||
if (in_last_ch == (((temp >> (offset + 4))) & 0xf)) {
|
||||
ret = ESP_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Testcase: Check the base function of ADC-DMA. Include:
|
||||
* - Various conversion modes.
|
||||
* - Whether the channel and data are lost.
|
||||
* - Whether the data is the same as the channel voltage.
|
||||
*/
|
||||
int test_adc_dig_dma_single_unit(adc_unit_t adc)
|
||||
{
|
||||
ESP_LOGI(TAG, " >> %s << ", __func__);
|
||||
ESP_LOGI(TAG, " >> adc unit: %x << ", adc);
|
||||
|
||||
TEST_ESP_OK( adc_digi_init() );
|
||||
/* arbiter config */
|
||||
adc_arbiter_t arb_cfg = {
|
||||
.mode = ADC_ARB_MODE_FIX,
|
||||
.dig_pri = 0,
|
||||
.pwdet_pri = 2,
|
||||
.rtc_pri = 1,
|
||||
};
|
||||
TEST_ESP_OK( adc_arbiter_config(ADC_UNIT_2, &arb_cfg) ); // If you want use force
|
||||
|
||||
adc_digi_config_t config = {
|
||||
.conv_limit_en = false,
|
||||
.conv_limit_num = 0,
|
||||
.interval = TEST_ADC_TRIGGER_INTERVAL_DEFAULT,
|
||||
.dig_clk.use_apll = 0, // APB clk
|
||||
.dig_clk.div_num = TEST_ADC_DIGI_CLK_DIV_DEFAULT,
|
||||
.dig_clk.div_b = 0,
|
||||
.dig_clk.div_a = 0,
|
||||
.dma_eof_num = SAR_EOF_NUMBER((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM),
|
||||
};
|
||||
/* Config pattern table */
|
||||
adc_digi_pattern_table_t adc1_patt[SOC_ADC_PATT_LEN_MAX] = {0};
|
||||
adc_digi_pattern_table_t adc2_patt[SOC_ADC_PATT_LEN_MAX] = {0};
|
||||
if (adc & ADC_UNIT_1) {
|
||||
config.adc1_pattern_len = adc_test_num;
|
||||
config.adc1_pattern = adc1_patt;
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc1_patt[i].atten = TEST_ADC_ATTEN_DEFAULT;
|
||||
adc1_patt[i].channel = adc_list[i];
|
||||
adc_gpio_init(ADC_UNIT_1, adc_list[i]);
|
||||
}
|
||||
}
|
||||
if (adc & ADC_UNIT_2) {
|
||||
config.adc2_pattern_len = adc_test_num;
|
||||
config.adc2_pattern = adc2_patt;
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc2_patt[i].atten = TEST_ADC_ATTEN_DEFAULT;
|
||||
adc2_patt[i].channel = adc_list[i];
|
||||
adc_gpio_init(ADC_UNIT_2, adc_list[i]);
|
||||
}
|
||||
}
|
||||
if (adc == ADC_UNIT_1) {
|
||||
config.conv_mode = ADC_CONV_SINGLE_UNIT_1;
|
||||
config.format = ADC_DIGI_FORMAT_12BIT;
|
||||
} else if (adc == ADC_UNIT_2) {
|
||||
config.conv_mode = ADC_CONV_SINGLE_UNIT_2;
|
||||
config.format = ADC_DIGI_FORMAT_12BIT;
|
||||
} else if (adc == ADC_UNIT_BOTH) {
|
||||
config.conv_mode = ADC_CONV_BOTH_UNIT;
|
||||
config.format = ADC_DIGI_FORMAT_11BIT;
|
||||
} else if (adc == ADC_UNIT_ALTER) {
|
||||
config.conv_mode = ADC_CONV_ALTER_UNIT;
|
||||
config.format = ADC_DIGI_FORMAT_11BIT;
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_controller_config(&config) );
|
||||
|
||||
/* ADC-DMA linker init */
|
||||
if (que_adc == NULL) {
|
||||
que_adc = xQueueCreate(5, sizeof(adc_dma_event_t));
|
||||
} else {
|
||||
xQueueReset(que_adc);
|
||||
}
|
||||
uint32_t int_mask = SPI_IN_SUC_EOF_INT_ENA;
|
||||
uint32_t dma_addr = adc_dma_linker_init(adc, false);
|
||||
adc_dac_dma_isr_register(adc_dma_isr, NULL, int_mask);
|
||||
adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
|
||||
|
||||
TEST_ESP_OK( adc_check_patt_table(adc, adc_test_num, adc_list[adc_test_num - 1]) );
|
||||
adc_dma_data_multi_st_check(adc, (void *)dma_addr, int_mask);
|
||||
|
||||
adc_dac_dma_linker_deinit();
|
||||
adc_dac_dma_isr_deregister(adc_dma_isr, NULL);
|
||||
TEST_ESP_OK( adc_digi_deinit() );
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_CASE("ADC DMA single read", "[ADC]")
|
||||
{
|
||||
test_adc_dig_dma_single_unit(ADC_UNIT_BOTH);
|
||||
|
||||
test_adc_dig_dma_single_unit(ADC_UNIT_ALTER);
|
||||
|
||||
test_adc_dig_dma_single_unit(ADC_UNIT_1);
|
||||
|
||||
test_adc_dig_dma_single_unit(ADC_UNIT_2);
|
||||
}
|
||||
|
||||
#include "touch_scope.h"
|
||||
/**
|
||||
* 0: ADC1 channels raw data debug.
|
||||
* 1: ADC2 channels raw data debug.
|
||||
* 2: ADC1 one channel raw data debug.
|
||||
*/
|
||||
#define SCOPE_DEBUG_TYPE 0
|
||||
#define SCOPE_DEBUG_CHANNEL_MAX (10)
|
||||
#define SCOPE_DEBUG_ENABLE (0)
|
||||
#define SCOPE_UART_BUADRATE (256000)
|
||||
#define SCOPE_DEBUG_FREQ_MS (50)
|
||||
#define SCOPE_OUTPUT_UART (0)
|
||||
static float scope_temp[SCOPE_DEBUG_CHANNEL_MAX] = {0}; // max scope channel is 10.
|
||||
|
||||
int test_adc_dig_scope_debug_unit(adc_unit_t adc)
|
||||
{
|
||||
ESP_LOGI(TAG, " >> %s << ", __func__);
|
||||
ESP_LOGI(TAG, " >> adc unit: %x << ", adc);
|
||||
|
||||
TEST_ESP_OK( adc_digi_init() );
|
||||
if (adc & ADC_UNIT_2) {
|
||||
/* arbiter config */
|
||||
adc_arbiter_t arb_cfg = {
|
||||
.mode = ADC_ARB_MODE_FIX,
|
||||
.dig_pri = 0,
|
||||
.pwdet_pri = 2,
|
||||
.rtc_pri = 1,
|
||||
};
|
||||
TEST_ESP_OK( adc_arbiter_config(ADC_UNIT_2, &arb_cfg) ); // If you want use force
|
||||
}
|
||||
adc_digi_config_t config = {
|
||||
.conv_limit_en = false,
|
||||
.conv_limit_num = 0,
|
||||
.interval = TEST_ADC_TRIGGER_INTERVAL_DEFAULT,
|
||||
.dig_clk.use_apll = 0, // APB clk
|
||||
.dig_clk.div_num = TEST_ADC_DIGI_CLK_DIV_DEFAULT,
|
||||
.dig_clk.div_a = 0,
|
||||
.dig_clk.div_b = 0,
|
||||
.dma_eof_num = SAR_EOF_NUMBER((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM),
|
||||
};
|
||||
/* Config pattern table */
|
||||
adc_digi_pattern_table_t adc1_patt[SOC_ADC_PATT_LEN_MAX] = {0};
|
||||
adc_digi_pattern_table_t adc2_patt[SOC_ADC_PATT_LEN_MAX] = {0};
|
||||
if (adc & ADC_UNIT_1) {
|
||||
config.adc1_pattern_len = adc_test_num;
|
||||
config.adc1_pattern = adc1_patt;
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc1_patt[i].atten = TEST_ADC_ATTEN_DEFAULT;
|
||||
adc1_patt[i].channel = adc_list[i];
|
||||
adc_gpio_init(ADC_UNIT_1, adc_list[i]);
|
||||
}
|
||||
}
|
||||
if (adc & ADC_UNIT_2) {
|
||||
config.adc2_pattern_len = adc_test_num;
|
||||
config.adc2_pattern = adc2_patt;
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc2_patt[i].atten = TEST_ADC_ATTEN_DEFAULT;
|
||||
adc2_patt[i].channel = adc_list[i];
|
||||
adc_gpio_init(ADC_UNIT_2, adc_list[i]);
|
||||
}
|
||||
}
|
||||
if (adc == ADC_UNIT_1) {
|
||||
config.conv_mode = ADC_CONV_SINGLE_UNIT_1;
|
||||
config.format = ADC_DIGI_FORMAT_12BIT;
|
||||
} else if (adc == ADC_UNIT_2) {
|
||||
config.conv_mode = ADC_CONV_SINGLE_UNIT_2;
|
||||
config.format = ADC_DIGI_FORMAT_12BIT;
|
||||
} else if (adc == ADC_UNIT_BOTH) {
|
||||
config.conv_mode = ADC_CONV_BOTH_UNIT;
|
||||
config.format = ADC_DIGI_FORMAT_11BIT;
|
||||
} else if (adc == ADC_UNIT_ALTER) {
|
||||
config.conv_mode = ADC_CONV_ALTER_UNIT;
|
||||
config.format = ADC_DIGI_FORMAT_11BIT;
|
||||
}
|
||||
TEST_ESP_OK( adc_digi_controller_config(&config) );
|
||||
|
||||
/* ADC-DMA linker init */
|
||||
if (que_adc == NULL) {
|
||||
que_adc = xQueueCreate(5, sizeof(adc_dma_event_t));
|
||||
} else {
|
||||
xQueueReset(que_adc);
|
||||
}
|
||||
uint32_t int_mask = SPI_IN_SUC_EOF_INT_ENA;
|
||||
uint32_t dma_addr = adc_dma_linker_init(adc, false);
|
||||
adc_dac_dma_isr_register(adc_dma_isr, NULL, int_mask);
|
||||
adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
|
||||
|
||||
ESP_LOGI(TAG, "adc IO fake tie middle, test ...");
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
adc_fake_tie_middle(adc, adc_list[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void scope_output(int adc_num, int channel, int data)
|
||||
{
|
||||
/** can replace by uart log.*/
|
||||
#if SCOPE_OUTPUT_UART
|
||||
static int icnt = 0;
|
||||
if (icnt++ % 8 == 0) {
|
||||
esp_rom_printf("\n");
|
||||
}
|
||||
esp_rom_printf("[%d_%d_%04x] ", adc_num, channel, data);
|
||||
return;
|
||||
#endif
|
||||
#if SCOPE_DEBUG_TYPE == 0
|
||||
if (adc_num != 0) {
|
||||
return;
|
||||
}
|
||||
#elif SCOPE_DEBUG_TYPE == 1
|
||||
if (adc_num != 1) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
int i;
|
||||
/* adc Read */
|
||||
for (i = 0; i < adc_test_num; i++) {
|
||||
if (adc_list[i] == channel && scope_temp[i] == 0) {
|
||||
scope_temp[i] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == adc_test_num) {
|
||||
test_tp_print_to_scope(scope_temp, adc_test_num);
|
||||
vTaskDelay(SCOPE_DEBUG_FREQ_MS / portTICK_PERIOD_MS);
|
||||
for (int i = 0; i < adc_test_num; i++) {
|
||||
scope_temp[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual test: Capture ADC-DMA data and display it on the serial oscilloscope. Used to observe the stability of the data.
|
||||
* Use step:
|
||||
* 1. Run this test from the unit test app.
|
||||
* 2. Use `ESP-Tuning Tool`(download from `www.espressif.com`) to capture.
|
||||
* 3. The readings of multiple channels will be displayed on the tool.
|
||||
*/
|
||||
TEST_CASE("test_adc_digi_slope_debug", "[adc_dma][ignore]")
|
||||
{
|
||||
adc_dma_event_t evt;
|
||||
test_tp_scope_debug_init(0, -1, -1, SCOPE_UART_BUADRATE);
|
||||
adc_unit_t adc = ADC_CONV_BOTH_UNIT;
|
||||
test_adc_dig_scope_debug_unit(adc);
|
||||
while (1) {
|
||||
TEST_ESP_OK( adc_digi_start() );
|
||||
TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, portMAX_DELAY), pdTRUE );
|
||||
if (evt.int_msk & SPI_IN_SUC_EOF_INT_ST) {
|
||||
TEST_ESP_OK( adc_digi_stop() );
|
||||
adc_digi_reset();
|
||||
for (int cnt = 0; cnt < 2; cnt++) {
|
||||
esp_rom_printf("cnt%d\n", cnt);
|
||||
for (int i = 0; i < SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM); i += 2) {
|
||||
uint8_t h = link_buf[cnt % 2][i + 1], l = link_buf[cnt % 2][i];
|
||||
uint16_t temp = (h << 8 | l);
|
||||
adc_digi_output_data_t *data = (adc_digi_output_data_t *)&temp;
|
||||
if (adc > ADC_UNIT_2) { //ADC_ENCODE_11BIT
|
||||
scope_output(data->type2.unit, data->type2.channel, data->type2.data);
|
||||
} else { //ADC_ENCODE_12BIT
|
||||
if (adc == ADC_UNIT_1) {
|
||||
scope_output(0, data->type1.channel, data->type1.data);
|
||||
} else if (adc == ADC_UNIT_2) {
|
||||
scope_output(1, data->type1.channel, data->type1.data);
|
||||
}
|
||||
}
|
||||
link_buf[cnt % 2][i] = 0;
|
||||
link_buf[cnt % 2][i + 1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif //#if !DISABLED_FOR_TARGETS(ESP32S2)
|
@ -15,7 +15,6 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/adc.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "unity.h"
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "driver/adc.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
/**@{*/
|
||||
/**
|
||||
|
@ -1,608 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_adc_cal.h"
|
||||
#include "driver/adc_common.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
__attribute__((unused)) static const char *TAG = "ADC";
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2)
|
||||
//TODO: IDF-3160
|
||||
|
||||
#define TEST_COUNT 4096
|
||||
#define MAX_ARRAY_SIZE 4096
|
||||
#define TEST_ATTEN ADC_ATTEN_MAX //Set to ADC_ATTEN_*db to test a single attenuation only
|
||||
|
||||
static int s_adc_count[MAX_ARRAY_SIZE]={};
|
||||
static int s_adc_offset = -1;
|
||||
|
||||
static int insert_point(uint32_t value)
|
||||
{
|
||||
const bool fixed_size = true;
|
||||
|
||||
if (s_adc_offset < 0) {
|
||||
if (fixed_size) {
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(4096, MAX_ARRAY_SIZE);
|
||||
s_adc_offset = 0; //Fixed to 0 because the array can hold all the data in 12 bits
|
||||
} else {
|
||||
s_adc_offset = MAX((int)value - MAX_ARRAY_SIZE/2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fixed_size && (value < s_adc_offset || value >= s_adc_offset + MAX_ARRAY_SIZE)) {
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(s_adc_offset, value);
|
||||
TEST_ASSERT_LESS_THAN(s_adc_offset + MAX_ARRAY_SIZE, value);
|
||||
}
|
||||
|
||||
s_adc_count[value - s_adc_offset] ++;
|
||||
return value - s_adc_offset;
|
||||
}
|
||||
|
||||
static void reset_array(void)
|
||||
{
|
||||
memset(s_adc_count, 0, sizeof(s_adc_count));
|
||||
s_adc_offset = -1;
|
||||
}
|
||||
|
||||
static uint32_t get_average(void)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_ARRAY_SIZE; i++) {
|
||||
sum += s_adc_count[i] * (s_adc_offset+i);
|
||||
count += s_adc_count[i];
|
||||
}
|
||||
return sum/count;
|
||||
}
|
||||
|
||||
static void print_summary(bool figure)
|
||||
{
|
||||
const int MAX_WIDTH=20;
|
||||
int max_count = 0;
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
uint32_t sum = 0;
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_ARRAY_SIZE; i++) {
|
||||
if (s_adc_count[i] > max_count) {
|
||||
max_count = s_adc_count[i];
|
||||
}
|
||||
if (s_adc_count[i] > 0 && start < 0) {
|
||||
start = i;
|
||||
}
|
||||
if (s_adc_count[i] > 0) {
|
||||
end = i;
|
||||
}
|
||||
count += s_adc_count[i];
|
||||
sum += s_adc_count[i] * (s_adc_offset+i);
|
||||
}
|
||||
|
||||
if (figure) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
printf("%4d ", i+s_adc_offset);
|
||||
int count = s_adc_count[i] * MAX_WIDTH / max_count;
|
||||
for (int j = 0; j < count; j++) {
|
||||
putchar('|');
|
||||
}
|
||||
printf(" %d\n", s_adc_count[i]);
|
||||
}
|
||||
}
|
||||
float average = (float)sum/count;
|
||||
|
||||
float variation_square = 0;
|
||||
for (int i = start; i <= end; i ++) {
|
||||
if (s_adc_count[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
float delta = i + s_adc_offset - average;
|
||||
variation_square += (delta * delta) * s_adc_count[i];
|
||||
}
|
||||
|
||||
printf("%d points.\n", count);
|
||||
printf("average: %.1f\n", (float)sum/count);
|
||||
printf("std: %.2f\n", sqrt(variation_square/count));
|
||||
}
|
||||
|
||||
static void continuous_adc_init(uint16_t adc1_chan_mask, uint16_t adc2_chan_mask, adc_channel_t *channel, uint8_t channel_num, adc_atten_t atten)
|
||||
{
|
||||
adc_digi_init_config_t adc_dma_config = {
|
||||
.max_store_buf_size = TEST_COUNT*2,
|
||||
.conv_num_each_intr = 128,
|
||||
.adc1_chan_mask = adc1_chan_mask,
|
||||
.adc2_chan_mask = adc2_chan_mask,
|
||||
};
|
||||
TEST_ESP_OK(adc_digi_initialize(&adc_dma_config));
|
||||
|
||||
adc_digi_pattern_table_t adc_pattern[10] = {0};
|
||||
adc_digi_config_t dig_cfg = {
|
||||
.conv_limit_en = 0,
|
||||
.conv_limit_num = 250,
|
||||
.sample_freq_hz = 83333,
|
||||
};
|
||||
|
||||
dig_cfg.adc_pattern_len = channel_num;
|
||||
for (int i = 0; i < channel_num; i++) {
|
||||
uint8_t unit = ((channel[i] >> 3) & 0x1);
|
||||
uint8_t ch = channel[i] & 0x7;
|
||||
adc_pattern[i].atten = atten;
|
||||
adc_pattern[i].channel = ch;
|
||||
adc_pattern[i].unit = unit;
|
||||
}
|
||||
dig_cfg.adc_pattern = adc_pattern;
|
||||
TEST_ESP_OK(adc_digi_controller_config(&dig_cfg));
|
||||
}
|
||||
|
||||
TEST_CASE("test_adc_dma", "[adc][ignore][manual]")
|
||||
{
|
||||
uint16_t adc1_chan_mask = BIT(2);
|
||||
uint16_t adc2_chan_mask = 0;
|
||||
adc_channel_t channel[1] = {ADC1_CHANNEL_2};
|
||||
adc_atten_t target_atten = TEST_ATTEN;
|
||||
|
||||
const int output_data_size = sizeof(adc_digi_output_data_t);
|
||||
|
||||
int buffer_size = TEST_COUNT*output_data_size;
|
||||
uint8_t* read_buf = malloc(buffer_size);
|
||||
TEST_ASSERT_NOT_NULL(read_buf);
|
||||
|
||||
adc_atten_t atten;
|
||||
bool print_figure;
|
||||
if (target_atten == ADC_ATTEN_MAX) {
|
||||
atten = ADC_ATTEN_DB_0;
|
||||
target_atten = ADC_ATTEN_DB_11;
|
||||
print_figure = false;
|
||||
} else {
|
||||
atten = target_atten;
|
||||
print_figure = true;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ESP_LOGI("TEST_ADC", "Test with atten: %d", atten);
|
||||
memset(read_buf, 0xce, buffer_size);
|
||||
|
||||
bool do_calibration = false;
|
||||
|
||||
esp_adc_cal_characteristics_t chan1_char = {};
|
||||
esp_adc_cal_value_t cal_ret = esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_12Bit, 0, &chan1_char);
|
||||
if (cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
do_calibration = true;
|
||||
}
|
||||
|
||||
continuous_adc_init(adc1_chan_mask, adc2_chan_mask, channel, sizeof(channel) / sizeof(adc_channel_t), atten);
|
||||
adc_digi_start();
|
||||
|
||||
int remain_count = TEST_COUNT;
|
||||
while (remain_count) {
|
||||
int already_got = TEST_COUNT - remain_count;
|
||||
uint32_t ret_num;
|
||||
TEST_ESP_OK(adc_digi_read_bytes(read_buf + already_got*output_data_size,
|
||||
remain_count*output_data_size, &ret_num, ADC_MAX_DELAY));
|
||||
|
||||
TEST_ASSERT((ret_num % output_data_size) == 0);
|
||||
remain_count -= ret_num / output_data_size;
|
||||
}
|
||||
|
||||
adc_digi_output_data_t *p = (void*)read_buf;
|
||||
reset_array();
|
||||
for (int i = 0; i < TEST_COUNT; i++) {
|
||||
insert_point(p[i].type2.data);
|
||||
}
|
||||
|
||||
print_summary(print_figure);
|
||||
|
||||
if (do_calibration) {
|
||||
uint32_t raw = get_average();
|
||||
uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char);
|
||||
printf("Voltage = %d mV\n", voltage_mv);
|
||||
}
|
||||
|
||||
adc_digi_stop();
|
||||
TEST_ESP_OK(adc_digi_deinitialize());
|
||||
|
||||
if (atten == target_atten) {
|
||||
break;
|
||||
}
|
||||
|
||||
atten++;
|
||||
}
|
||||
|
||||
free(read_buf);
|
||||
}
|
||||
|
||||
TEST_CASE("test_adc_single", "[adc][ignore][manual]")
|
||||
{
|
||||
adc_atten_t target_atten = TEST_ATTEN;
|
||||
adc_atten_t atten;
|
||||
bool print_figure;
|
||||
if (target_atten == ADC_ATTEN_MAX) {
|
||||
atten = ADC_ATTEN_DB_0;
|
||||
target_atten = ADC_ATTEN_DB_11;
|
||||
print_figure = false;
|
||||
} else {
|
||||
atten = target_atten;
|
||||
print_figure = true;
|
||||
}
|
||||
|
||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||
|
||||
|
||||
while (1) {
|
||||
ESP_LOGI("TEST_ADC", "Test with atten: %d", atten);
|
||||
|
||||
adc1_config_channel_atten(ADC1_CHANNEL_2, atten);
|
||||
|
||||
bool do_calibration = false;
|
||||
|
||||
esp_adc_cal_characteristics_t chan1_char = {};
|
||||
esp_adc_cal_value_t cal_ret = esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_12Bit, 0, &chan1_char);
|
||||
if (cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
do_calibration = true;
|
||||
}
|
||||
|
||||
|
||||
const int test_count = TEST_COUNT;
|
||||
adc1_channel_t channel = ADC1_CHANNEL_2;
|
||||
while (1) {
|
||||
|
||||
reset_array();
|
||||
|
||||
for (int i = 0; i < test_count; i++) {
|
||||
uint32_t raw = adc1_get_raw(channel);
|
||||
insert_point(raw);
|
||||
}
|
||||
print_summary(print_figure);
|
||||
break;
|
||||
}
|
||||
|
||||
if (do_calibration) {
|
||||
uint32_t raw = get_average();
|
||||
uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char);
|
||||
printf("Voltage = %d mV\n", voltage_mv);
|
||||
}
|
||||
|
||||
|
||||
if (atten == target_atten) {
|
||||
break;
|
||||
}
|
||||
atten++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2)
|
||||
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2) //TODO IDF-3908
|
||||
|
||||
/********************************************************************************
|
||||
* ADC Speed Related Tests
|
||||
********************************************************************************/
|
||||
|
||||
#define RECORD_TIME_PREPARE() uint32_t __t1, __t2
|
||||
#define RECORD_TIME_START() do {__t1 = esp_cpu_get_ccount();}while(0)
|
||||
#define RECORD_TIME_END(p_time) do{__t2 = esp_cpu_get_ccount(); *p_time = (__t2-__t1);}while(0)
|
||||
#define GET_US_BY_CCOUNT(t) ((double)t/CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ)
|
||||
|
||||
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_CALI_TEST_CHAN0 ADC1_CHANNEL_6
|
||||
#define ADC2_CALI_TEST_CHAN0 ADC2_CHANNEL_0
|
||||
#else
|
||||
#define ADC1_CALI_TEST_CHAN0 ADC1_CHANNEL_2
|
||||
#define ADC2_CALI_TEST_CHAN0 ADC2_CHANNEL_0
|
||||
#endif
|
||||
|
||||
//ADC Calibration
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT
|
||||
#endif
|
||||
|
||||
#define TIMES_PER_ATTEN 10
|
||||
|
||||
static esp_adc_cal_characteristics_t adc1_chars;
|
||||
static esp_adc_cal_characteristics_t adc2_chars;
|
||||
|
||||
static void adc_single_cali_init(adc_unit_t adc_n, adc_channel_t chan, uint32_t atten)
|
||||
{
|
||||
esp_err_t ret;
|
||||
esp_adc_cal_value_t ret_val = ESP_ADC_CAL_VAL_NOT_SUPPORTED;
|
||||
|
||||
ret = esp_adc_cal_check_efuse(ADC_TEST_CALI_SCHEME);
|
||||
if (ret == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGE(TAG, "Cali scheme not supported!");
|
||||
TEST_ASSERT(ret != ESP_ERR_NOT_SUPPORTED);
|
||||
} else if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "No cali eFuse, but will run the test");
|
||||
}
|
||||
|
||||
if (adc_n == ADC_UNIT_1) {
|
||||
ret_val = esp_adc_cal_characterize(adc_n, atten, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars);
|
||||
TEST_ESP_OK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT));
|
||||
TEST_ESP_OK(adc1_config_channel_atten((adc1_channel_t)chan, atten));
|
||||
} else if (adc_n == ADC_UNIT_2) {
|
||||
TEST_ESP_OK(adc2_config_channel_atten((adc2_channel_t)chan, atten));
|
||||
ret_val = esp_adc_cal_characterize(adc_n, atten, ADC_WIDTH_BIT_DEFAULT, 0, &adc2_chars);
|
||||
}
|
||||
if (ret_val == ESP_ADC_CAL_VAL_NOT_SUPPORTED) {
|
||||
ESP_LOGW(TAG, "No cali eFuse, or invalid arg, but will run the test");
|
||||
}
|
||||
ESP_LOGI(TAG, "ADC%d, channel%d, atten%d", adc_n, chan, atten);
|
||||
}
|
||||
|
||||
static IRAM_ATTR NOINLINE_ATTR uint32_t get_cali_time_in_ccount(uint32_t adc_raw, esp_adc_cal_characteristics_t *chars)
|
||||
{
|
||||
uint32_t time;
|
||||
|
||||
RECORD_TIME_PREPARE();
|
||||
RECORD_TIME_START();
|
||||
esp_adc_cal_raw_to_voltage(adc_raw, chars);
|
||||
RECORD_TIME_END(&time);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
TEST_CASE("test_adc_single_cali_time", "[adc][ignore][manual]")
|
||||
{
|
||||
ESP_LOGI(TAG, "CPU FREQ is %dMHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
|
||||
uint32_t adc1_time_record[4][TIMES_PER_ATTEN] = {};
|
||||
uint32_t adc2_time_record[4][TIMES_PER_ATTEN] = {};
|
||||
int adc1_raw = 0;
|
||||
int adc2_raw = 0;
|
||||
|
||||
//atten0 ~ atten3
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ESP_LOGI(TAG, "----------------atten%d----------------", i);
|
||||
adc_single_cali_init(ADC_UNIT_1, ADC1_CALI_TEST_CHAN0, i);
|
||||
adc_single_cali_init(ADC_UNIT_2, ADC2_CALI_TEST_CHAN0, i);
|
||||
|
||||
for (int j = 0; j < TIMES_PER_ATTEN; j++) {
|
||||
|
||||
adc1_raw = adc1_get_raw(ADC1_CALI_TEST_CHAN0);
|
||||
TEST_ESP_OK(adc2_get_raw(ADC2_CALI_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc2_raw));
|
||||
|
||||
adc1_time_record[i][j] = get_cali_time_in_ccount(adc1_raw, &adc1_chars);
|
||||
adc2_time_record[i][j] = get_cali_time_in_ccount(adc2_raw, &adc2_chars);
|
||||
|
||||
IDF_LOG_PERFORMANCE("ADC1 Cali time", "%d us", (int)GET_US_BY_CCOUNT(adc1_time_record[i][j]));
|
||||
IDF_LOG_PERFORMANCE("ADC2 Cali time", "%d us", (int)GET_US_BY_CCOUNT(adc2_time_record[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* ADC Single with Light Sleep
|
||||
********************************************************************************/
|
||||
#include <inttypes.h>
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#if REGI2C_ANA_CALI_PD_WORKAROUND
|
||||
#include "soc/regi2c_saradc.h"
|
||||
#endif
|
||||
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_SLEEP_TEST_CHAN ADC1_CHANNEL_6
|
||||
#define ADC2_SLEEP_TEST_CHAN ADC2_CHANNEL_0
|
||||
static const char *TAG_CH[2][10] = {{"ADC1_CH6"}, {"ADC2_CH0"}};
|
||||
#else
|
||||
#define ADC1_SLEEP_TEST_CHAN ADC1_CHANNEL_2
|
||||
#define ADC2_SLEEP_TEST_CHAN ADC2_CHANNEL_0
|
||||
static const char *TAG_CH[2][10] = {{"ADC1_CH2"}, {"ADC2_CH0"}};
|
||||
#endif
|
||||
|
||||
//ADC Attenuation
|
||||
#define ADC_SLEEP_TEST_ATTEN ADC_ATTEN_DB_6
|
||||
|
||||
//ADC Calibration
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT
|
||||
#endif
|
||||
|
||||
static esp_adc_cal_characteristics_t adc1_chars;
|
||||
static esp_adc_cal_characteristics_t adc2_chars;
|
||||
|
||||
|
||||
static bool adc_calibration_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
bool cali_enable = false;
|
||||
|
||||
ret = esp_adc_cal_check_efuse(ADC_SLEEP_TEST_CALI_SCHEME);
|
||||
if (ret == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGW(TAG, "Calibration scheme not supported, skip software calibration");
|
||||
} else if (ret == ESP_ERR_INVALID_VERSION) {
|
||||
ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
|
||||
} else if (ret == ESP_OK) {
|
||||
cali_enable = true;
|
||||
esp_adc_cal_characterize(ADC_UNIT_1, ADC_SLEEP_TEST_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars);
|
||||
esp_adc_cal_characterize(ADC_UNIT_2, ADC_SLEEP_TEST_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc2_chars);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid arg");
|
||||
}
|
||||
|
||||
return cali_enable;
|
||||
}
|
||||
|
||||
#define TEST_REGI2C_ANA_CALI_BYTE_NUM 8
|
||||
|
||||
TEST_CASE("test ADC1 Single Read with Light Sleep", "[adc][manul][ignore]")
|
||||
{
|
||||
//ADC1 config
|
||||
TEST_ESP_OK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT));
|
||||
TEST_ESP_OK(adc1_config_channel_atten(ADC1_SLEEP_TEST_CHAN, ADC_SLEEP_TEST_ATTEN));
|
||||
|
||||
//ADC config calibration
|
||||
bool cali_en = adc_calibration_init();
|
||||
|
||||
int raw_expected = 0;
|
||||
uint32_t cali_expected = 0;
|
||||
uint8_t regi2c_cali_val_before[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {};
|
||||
|
||||
int raw_after_sleep = 0;
|
||||
uint32_t cali_after_sleep = 0;
|
||||
uint8_t regi2c_cali_val_after[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {};
|
||||
|
||||
//---------------------------------Before Sleep-----------------------------------//
|
||||
ESP_LOGI("Before", "Light Sleep");
|
||||
|
||||
//Read
|
||||
raw_expected = adc1_get_raw(ADC1_SLEEP_TEST_CHAN);
|
||||
if (cali_en) {
|
||||
cali_expected = esp_adc_cal_raw_to_voltage(raw_expected, &adc1_chars);
|
||||
}
|
||||
|
||||
#if REGI2C_ANA_CALI_PD_WORKAROUND
|
||||
//Print regi2c
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
regi2c_cali_val_before[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i);
|
||||
printf("regi2c cali val is 0x%x", regi2c_cali_val_before[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
//Print result
|
||||
ESP_LOGI(TAG_CH[0][0], "ADC1 raw data: %d", raw_expected);
|
||||
if (cali_en) {
|
||||
ESP_LOGI(TAG_CH[0][0], "ADC1 cali data: %d", cali_expected);
|
||||
}
|
||||
|
||||
//---------------------------------After Sleep-----------------------------------//
|
||||
ESP_LOGI("After", "Light Sleep");
|
||||
esp_sleep_enable_timer_wakeup(30 * 1000);
|
||||
esp_light_sleep_start();
|
||||
ESP_LOGI(TAG, "Wakeup from light sleep.");
|
||||
|
||||
#if REGI2C_ANA_CALI_PD_WORKAROUND
|
||||
//Print regi2c
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
regi2c_cali_val_after[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i);
|
||||
printf("regi2c cali val is 0x%x", regi2c_cali_val_after[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
//Read
|
||||
raw_after_sleep = adc1_get_raw(ADC1_SLEEP_TEST_CHAN);
|
||||
if (cali_en) {
|
||||
cali_after_sleep = esp_adc_cal_raw_to_voltage(raw_after_sleep, &adc1_chars);
|
||||
}
|
||||
|
||||
//Print result
|
||||
ESP_LOGI(TAG_CH[0][0], "after light sleep, ADC1 cali data: %d", raw_after_sleep);
|
||||
if (cali_en) {
|
||||
ESP_LOGI(TAG_CH[0][0], "after light sleep, ADC1 cali data: %d", cali_after_sleep);
|
||||
}
|
||||
|
||||
//Compare
|
||||
int32_t raw_diff = raw_expected - raw_after_sleep;
|
||||
IDF_LOG_PERFORMANCE("ADC1 raw diff after sleep", "%d", raw_diff);
|
||||
if (cali_en) {
|
||||
int32_t cali_diff = cali_expected - cali_after_sleep;
|
||||
IDF_LOG_PERFORMANCE("ADC1 cali diff after sleep", "%d mV", cali_diff);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
TEST_ASSERT_EQUAL(regi2c_cali_val_before[i], regi2c_cali_val_after[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("test ADC2 Single Read with Light Sleep", "[adc][manul][ignore]")
|
||||
{
|
||||
//ADC2 config
|
||||
ESP_ERROR_CHECK(adc2_config_channel_atten(ADC2_SLEEP_TEST_CHAN, ADC_SLEEP_TEST_ATTEN));
|
||||
//ADC config calibration
|
||||
bool cali_en = adc_calibration_init();
|
||||
|
||||
int raw_expected = 0;
|
||||
uint32_t cali_expected = 0;
|
||||
uint8_t regi2c_cali_val_before[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {};
|
||||
|
||||
int raw_after_sleep = 0;
|
||||
uint32_t cali_after_sleep = 0;
|
||||
uint8_t regi2c_cali_val_after[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {};
|
||||
|
||||
//---------------------------------Before Sleep-----------------------------------//
|
||||
ESP_LOGI("Before", "Light Sleep");
|
||||
|
||||
//Read
|
||||
TEST_ESP_OK(adc2_get_raw(ADC2_SLEEP_TEST_CHAN, ADC_WIDTH_BIT_DEFAULT, &raw_expected));
|
||||
if (cali_en) {
|
||||
cali_expected = esp_adc_cal_raw_to_voltage(raw_expected, &adc2_chars);
|
||||
}
|
||||
|
||||
#if REGI2C_ANA_CALI_PD_WORKAROUND
|
||||
//Print regi2c
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
regi2c_cali_val_before[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i);
|
||||
printf("regi2c cali val is 0x%x", regi2c_cali_val_before[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
//Print result
|
||||
ESP_LOGI(TAG_CH[1][0], "ADC2 raw data: %d", raw_expected);
|
||||
if (cali_en) {
|
||||
ESP_LOGI(TAG_CH[1][0], "ADC2 cali data: %d", cali_expected);
|
||||
}
|
||||
|
||||
//---------------------------------After Sleep-----------------------------------//
|
||||
ESP_LOGI("After", "Light Sleep");
|
||||
esp_sleep_enable_timer_wakeup(30 * 1000);
|
||||
esp_light_sleep_start();
|
||||
ESP_LOGI(TAG, "Wakeup from light sleep.");
|
||||
|
||||
#if REGI2C_ANA_CALI_PD_WORKAROUND
|
||||
//Print regi2c
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
regi2c_cali_val_after[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i);
|
||||
printf("regi2c cali val is 0x%x", regi2c_cali_val_after[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
//Read
|
||||
TEST_ESP_OK(adc2_get_raw(ADC2_SLEEP_TEST_CHAN, ADC_WIDTH_BIT_DEFAULT, &raw_after_sleep));
|
||||
if (cali_en) {
|
||||
cali_after_sleep += esp_adc_cal_raw_to_voltage(raw_after_sleep, &adc2_chars);
|
||||
}
|
||||
|
||||
//Print result
|
||||
ESP_LOGI(TAG_CH[1][0], "after light sleep, ADC2 cali data: %d", raw_after_sleep);
|
||||
if (cali_en) {
|
||||
ESP_LOGI(TAG_CH[1][0], "after light sleep, ADC2 cali data: %d", cali_after_sleep);
|
||||
}
|
||||
|
||||
//Compare
|
||||
int32_t raw_diff = raw_expected - raw_after_sleep;
|
||||
IDF_LOG_PERFORMANCE("ADC2 raw diff after sleep", "%d", raw_diff);
|
||||
if (cali_en) {
|
||||
int32_t cali_diff = cali_expected - cali_after_sleep;
|
||||
IDF_LOG_PERFORMANCE("ADC2 cali diff after sleep", "%d mV", cali_diff);
|
||||
}
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
TEST_ASSERT_EQUAL(regi2c_cali_val_before[i], regi2c_cali_val_after[i]);
|
||||
}
|
||||
}
|
||||
#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2) //TODO IDF-3908
|
@ -15,12 +15,13 @@
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/adc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#define CONFIG_ADC_SUPPRESS_DEPRECATE_WARN 1
|
||||
#include "driver/adc.h"
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3, ESP32S3, ESP32C2)
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3, ESP32C2)
|
||||
|
||||
static const char* TAG = "test_adc2";
|
||||
|
||||
@ -149,7 +150,7 @@ TEST_CASE("adc2 work with wifi","[adc]")
|
||||
bool test_list[TEST_NUM] ={1, 1, 0, 0, 1, 0, 1, 0};
|
||||
|
||||
adc2_pad_get_io_num(ADC2_CHAN1, &test_adc_io);
|
||||
TEST_ESP_OK(adc2_config_channel_atten(ADC2_CHAN1, ADC_ATTEN_0db));
|
||||
TEST_ESP_OK(adc2_config_channel_atten(ADC2_CHAN1, ADC_ATTEN_DB_0));
|
||||
printf("test_adc_io is %d\n", test_adc_io);
|
||||
|
||||
//---------------------------------GPIO init-----------------------------------//
|
||||
|
@ -1,394 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/*
|
||||
Tests for the adc device driver
|
||||
*/
|
||||
#include "esp_system.h"
|
||||
#include "driver/adc.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "unity.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "soc/adc_periph.h"
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3,ESP32C3, ESP32C2)
|
||||
#include "driver/dac.h"
|
||||
|
||||
static const char *TAG = "test_adc";
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_TEST_WIDTH ADC_WIDTH_BIT_12
|
||||
#define ADC2_TEST_WIDTH ADC_WIDTH_BIT_12
|
||||
#elif defined CONFIG_IDF_TARGET_ESP32S2
|
||||
#define ADC1_TEST_WIDTH ADC_WIDTH_BIT_13 //ESP32S2 only support 13 bit width
|
||||
#define ADC2_TEST_WIDTH ADC_WIDTH_BIT_13 //ESP32S2 only support 13 bit width
|
||||
#endif
|
||||
|
||||
#define ADC1_TEST_ATTEN ADC_ATTEN_DB_11
|
||||
#define ADC2_TEST_ATTEN ADC_ATTEN_DB_11
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_TEST_CHANNEL_NUM 8
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define ADC1_TEST_CHANNEL_NUM 10
|
||||
#endif
|
||||
#define ADC2_TEST_CHANNEL_NUM 6
|
||||
|
||||
static const int adc1_ch[ADC1_TEST_CHANNEL_NUM] = {
|
||||
ADC1_CHANNEL_0,
|
||||
ADC1_CHANNEL_1,
|
||||
ADC1_CHANNEL_2,
|
||||
ADC1_CHANNEL_3,
|
||||
ADC1_CHANNEL_4,
|
||||
ADC1_CHANNEL_5,
|
||||
ADC1_CHANNEL_6,
|
||||
ADC1_CHANNEL_7,
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
ADC1_CHANNEL_8,
|
||||
ADC1_CHANNEL_9,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const int adc2_ch[ADC2_TEST_CHANNEL_NUM] = {
|
||||
ADC2_CHANNEL_0,
|
||||
ADC2_CHANNEL_1,
|
||||
ADC2_CHANNEL_2,
|
||||
ADC2_CHANNEL_3,
|
||||
ADC2_CHANNEL_4,
|
||||
ADC2_CHANNEL_5,
|
||||
};
|
||||
|
||||
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
|
||||
|
||||
void adc_fake_tie_middle(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
gpio_num_t gpio_num = 0;
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
gpio_num = ADC_GET_IO_NUM(0, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_PULLDOWN));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED));
|
||||
}
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
gpio_num = ADC_GET_IO_NUM(1, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_PULLDOWN));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED));
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void adc_fake_tie_high(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
gpio_num_t gpio_num = 0;
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
gpio_num = ADC_GET_IO_NUM(0, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 1));
|
||||
}
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
gpio_num = ADC_GET_IO_NUM(1, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 1));
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void adc_fake_tie_low(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
gpio_num_t gpio_num = 0;
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
gpio_num = ADC_GET_IO_NUM(0, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLDOWN_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 0));
|
||||
}
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
gpio_num = ADC_GET_IO_NUM(1, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLDOWN_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY));
|
||||
TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 0));
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void adc_io_normal(adc_unit_t adc_unit, adc_channel_t channel)
|
||||
{
|
||||
gpio_num_t gpio_num = 0;
|
||||
if (adc_unit == ADC_UNIT_1) {
|
||||
gpio_num = ADC_GET_IO_NUM(0, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_FLOATING));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED));
|
||||
}
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
gpio_num = ADC_GET_IO_NUM(1, channel);
|
||||
TEST_ESP_OK(rtc_gpio_init(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num));
|
||||
TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num));
|
||||
TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_FLOATING));
|
||||
TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED));
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
TEST_CASE("ADC1 rtc read", "[adc1]")
|
||||
{
|
||||
int adc1_val[ADC1_TEST_CHANNEL_NUM] = {0};
|
||||
|
||||
/* adc1 Configure */
|
||||
adc1_config_width(ADC1_TEST_WIDTH);
|
||||
ESP_LOGI(TAG, "ADC1 [CH - GPIO]:");
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc1_config_channel_atten(adc1_ch[i], ADC1_TEST_ATTEN) );
|
||||
ESP_LOGI(TAG, "[CH%d - IO%d]:", adc1_ch[i], ADC_GET_IO_NUM(0, adc1_ch[i]));
|
||||
}
|
||||
printf("ADC tie normal read: ");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
/* adc Read */
|
||||
printf("ADC1: ");
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]);
|
||||
printf("CH%d-%d ", adc1_ch[i], adc1_val[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* tie high */
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_high(ADC_UNIT_1, adc1_ch[i]);
|
||||
}
|
||||
printf("ADC tie high read: ");
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
/* adc Read */
|
||||
printf("ADC1: ");
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]);
|
||||
printf("CH%d-%d ", adc1_ch[i], adc1_val[i]);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
TEST_ASSERT_EQUAL( adc1_val[i], 0x1fff );
|
||||
#endif
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* tie low */
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_low(ADC_UNIT_1, adc1_ch[i]);
|
||||
}
|
||||
printf("ADC tie low read: ");
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
/* adc Read */
|
||||
printf("ADC1: ");
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]);
|
||||
printf("CH%d-%d ", adc1_ch[i], adc1_val[i]);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
TEST_ASSERT_INT_WITHIN( 100, 0, adc1_val[i] );
|
||||
#endif
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* tie midedle */
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_middle(ADC_UNIT_1, adc1_ch[i]);
|
||||
}
|
||||
printf("ADC tie mid read: ");
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
/* adc Read */
|
||||
printf("ADC1: ");
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]);
|
||||
printf("CH%d-%d ", adc1_ch[i], adc1_val[i]);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
TEST_ASSERT_NOT_EQUAL( adc1_val[i], 0x1fff );
|
||||
TEST_ASSERT_NOT_EQUAL( adc1_val[i], 0 );
|
||||
#endif
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc_io_normal(ADC_UNIT_1, adc1_ch[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("ADC2 rtc read", "[adc2]")
|
||||
{
|
||||
int adc2_val[ADC2_TEST_CHANNEL_NUM] = {0};
|
||||
|
||||
/* adc2 Configure */
|
||||
ESP_LOGI(TAG, "ADC2 [CH - GPIO]:");
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc2_config_channel_atten(adc2_ch[i], ADC2_TEST_ATTEN) );
|
||||
ESP_LOGI(TAG, "[CH%d - IO%d]:", adc2_ch[i], ADC_GET_IO_NUM(1, adc2_ch[i]));
|
||||
}
|
||||
printf("ADC float read: ");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
/* adc Read */
|
||||
printf("ADC2: ");
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) );
|
||||
printf("CH%d-%d ", adc2_ch[i], adc2_val[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* tie high */
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_high(ADC_UNIT_2, adc2_ch[i]);
|
||||
}
|
||||
printf("ADC tie high read: ");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
/* adc Read */
|
||||
printf("ADC2: ");
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) );
|
||||
printf("CH%d-%d ", adc2_ch[i], adc2_val[i]);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
TEST_ASSERT_EQUAL( adc2_val[i], 0x1fff );
|
||||
#endif
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* tie low */
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_low(ADC_UNIT_2, adc2_ch[i]);
|
||||
}
|
||||
printf("ADC tie low read: ");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
/* adc Read */
|
||||
printf("ADC2: ");
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) );
|
||||
printf("CH%d-%d ", adc2_ch[i], adc2_val[i]);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
TEST_ASSERT_INT_WITHIN( 100, 0, adc2_val[i] );
|
||||
#endif
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* tie midedle */
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_middle(ADC_UNIT_2, adc2_ch[i]);
|
||||
}
|
||||
printf("ADC tie middle read: ");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
/* adc Read */
|
||||
printf("ADC2: ");
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) );
|
||||
printf("CH%d-%d ", adc2_ch[i], adc2_val[i]);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
TEST_ASSERT_NOT_EQUAL( 0, adc2_val[i] );
|
||||
TEST_ASSERT_NOT_EQUAL( 0x1fff, adc2_val[i] );
|
||||
#endif
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc_io_normal(ADC_UNIT_1, adc1_ch[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#include "touch_scope.h"
|
||||
/**
|
||||
* 0: ADC1 channels raw data debug.
|
||||
* 1: ADC2 channels raw data debug.
|
||||
*/
|
||||
#define SCOPE_DEBUG_TYPE 1
|
||||
#define SCOPE_DEBUG_CHANNEL_MAX (10)
|
||||
#define SCOPE_DEBUG_ENABLE (0)
|
||||
#define SCOPE_UART_BUADRATE (256000)
|
||||
#define SCOPE_DEBUG_FREQ_MS (50)
|
||||
|
||||
/**
|
||||
* Manual test: Capture ADC-DMA data and display it on the serial oscilloscope. Used to observe the stability of the data.
|
||||
* Use step:
|
||||
* 1. Call this function in `esp-idf/tools/unit-test-app/main/app_main.c`.
|
||||
* 2. Use `ESP-Tuning Tool`(download from `www.espressif.com`) to capture.
|
||||
* 3. The readings of multiple channels will be displayed on the tool.
|
||||
*/
|
||||
void test_adc_slope_debug(void)
|
||||
{
|
||||
float scope_temp[SCOPE_DEBUG_CHANNEL_MAX] = {0}; // max scope channel is 10.
|
||||
test_tp_scope_debug_init(0, -1, -1, SCOPE_UART_BUADRATE);
|
||||
|
||||
#if SCOPE_DEBUG_TYPE == 0
|
||||
/* adc1 Configure */
|
||||
adc1_config_width(ADC1_TEST_WIDTH);
|
||||
ESP_LOGI(TAG, "ADC1 [CH - GPIO] atten %d:", ADC1_TEST_ATTEN);
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc1_config_channel_atten(adc1_ch[i], ADC1_TEST_ATTEN) );
|
||||
ESP_LOGI(TAG, "[CH%d - IO%d]", adc1_ch[i], ADC_GET_IO_NUM(0, adc1_ch[i]));
|
||||
}
|
||||
/* tie midedle */
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_middle(ADC_UNIT_1, adc1_ch[i]);
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
while (1) {
|
||||
/* adc Read */
|
||||
for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) {
|
||||
scope_temp[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]);
|
||||
}
|
||||
test_tp_print_to_scope(scope_temp, ADC1_TEST_CHANNEL_NUM);
|
||||
vTaskDelay(SCOPE_DEBUG_FREQ_MS / portTICK_PERIOD_MS);
|
||||
}
|
||||
#elif SCOPE_DEBUG_TYPE == 1
|
||||
int adc2_val[ADC2_TEST_CHANNEL_NUM] = {0};
|
||||
|
||||
/* adc2 Configure */
|
||||
ESP_LOGI(TAG, "ADC2 [CH - GPIO] atten %d:", ADC2_TEST_ATTEN);
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
TEST_ESP_OK( adc2_config_channel_atten(adc2_ch[i], ADC2_TEST_ATTEN) );
|
||||
ESP_LOGI(TAG, "[CH%d - IO%d]:", adc2_ch[i], ADC_GET_IO_NUM(1, adc2_ch[i]));
|
||||
}
|
||||
/* tie midedle */
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
adc_fake_tie_middle(ADC_UNIT_2, adc2_ch[i]);
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
while (1) {
|
||||
/* adc Read */
|
||||
printf("ADC2: ");
|
||||
for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) {
|
||||
adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]);
|
||||
scope_temp[i] = adc2_val[i];
|
||||
}
|
||||
|
||||
test_tp_print_to_scope(scope_temp, ADC2_TEST_CHANNEL_NUM);
|
||||
vTaskDelay(SCOPE_DEBUG_FREQ_MS / portTICK_PERIOD_MS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
@ -8,7 +8,6 @@
|
||||
*/
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "driver/adc.h"
|
||||
#include "unity.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
@ -17,6 +16,8 @@
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#define CONFIG_ADC_SUPPRESS_DEPRECATE_WARN 1
|
||||
#include "driver/adc.h"
|
||||
|
||||
#if SOC_DAC_SUPPORTED
|
||||
#include "driver/dac.h"
|
||||
|
@ -13,7 +13,6 @@
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "driver/adc.h"
|
||||
#include "unity.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_I2S_ENABLE_DEBUG_LOG=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
@ -1,3 +1,4 @@
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_I2S_ENABLE_DEBUG_LOG=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
@ -0,0 +1,5 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(legacy_adc_driver_test)
|
2
components/driver/test_apps/legacy_adc_driver/README.md
Normal file
2
components/driver/test_apps/legacy_adc_driver/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- |
|
@ -0,0 +1,5 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_legacy_adc.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
WHOLE_ARCHIVE)
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/adc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "soc/adc_periph.h"
|
||||
|
||||
#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel])
|
||||
|
||||
/**
|
||||
* We use weak pulldown, `ADC_TEST_LOW_THRESH` may vary.
|
||||
* If connect to GND, `ADC_TEST_LOW_THRESH` will usually within 10
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 10
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_THRESH 10
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 25
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 8191
|
||||
#define ADC_TEST_HIGH_THRESH 10
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 30
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_THRESH 10
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 15
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_THRESH 0
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
#define ADC_TEST_LOW_VAL 2147
|
||||
#define ADC_TEST_LOW_THRESH 50
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_THRESH 0
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#define ADC_TEST_LOW_VAL 2147
|
||||
#define ADC_TEST_LOW_THRESH 50
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_THRESH 0
|
||||
#endif
|
||||
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_TEST_CHAN0 ADC1_CHANNEL_4
|
||||
#define ADC2_TEST_CHAN0 ADC2_CHANNEL_0
|
||||
#elif (SOC_ADC_PERIPH_NUM >= 2)
|
||||
#define ADC1_TEST_CHAN0 ADC1_CHANNEL_2
|
||||
#define ADC2_TEST_CHAN0 ADC2_CHANNEL_0
|
||||
#else
|
||||
#define ADC1_TEST_CHAN0 ADC1_CHANNEL_2
|
||||
#endif
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "TEST_ADC_LEGACY";
|
||||
|
||||
|
||||
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 SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_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
|
||||
}
|
||||
|
||||
TEST_CASE("Legacy ADC oneshot high/low test", "[legacy_adc_oneshot]")
|
||||
{
|
||||
int adc_raw = 0;
|
||||
//ADC1 config
|
||||
TEST_ESP_OK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT));
|
||||
TEST_ESP_OK(adc1_config_channel_atten(ADC1_TEST_CHAN0, ADC_ATTEN_DB_11));
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
//ADC2 config
|
||||
TEST_ESP_OK(adc2_config_channel_atten(ADC2_TEST_CHAN0, ADC_ATTEN_DB_11));
|
||||
#endif
|
||||
|
||||
test_adc_set_io_level(ADC_UNIT_1, (adc1_channel_t)ADC1_TEST_CHAN0, 0);
|
||||
adc_raw = adc1_get_raw(ADC1_TEST_CHAN0);
|
||||
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_1, ADC1_TEST_CHAN0, adc_raw);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw);
|
||||
|
||||
test_adc_set_io_level(ADC_UNIT_1, (adc1_channel_t)ADC1_TEST_CHAN0, 1);
|
||||
adc_raw = adc1_get_raw(ADC1_TEST_CHAN0);
|
||||
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_1, ADC1_TEST_CHAN0, adc_raw);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw);
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
test_adc_set_io_level(ADC_UNIT_2, (adc2_channel_t)ADC2_TEST_CHAN0, 0);
|
||||
TEST_ESP_OK(adc2_get_raw(ADC2_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw));
|
||||
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_2, ADC2_TEST_CHAN0, adc_raw);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw);
|
||||
|
||||
test_adc_set_io_level(ADC_UNIT_2, (adc2_channel_t)ADC2_TEST_CHAN0, 1);
|
||||
TEST_ESP_OK(adc2_get_raw(ADC2_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw));
|
||||
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_2, ADC2_TEST_CHAN0, adc_raw);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.esp32c2
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'release',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_legacy_adc(dut: Dut) -> None:
|
||||
dut.expect_exact('Press ENTER to see the list of tests')
|
||||
dut.write('*')
|
||||
dut.expect_unity_test_output(timeout=240)
|
@ -0,0 +1,5 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
@ -0,0 +1,3 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
|
@ -39,8 +39,9 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a
|
||||
return init_code + 1000; // version 1 logic
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv)
|
||||
esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, uint32_t adc_unit, int atten, uint32_t* out_digi, uint32_t* out_vol_mv)
|
||||
{
|
||||
(void)adc_unit; //On esp32c3, V1 we don't have calibration data for ADC2, using the efuse data of ADC1
|
||||
const esp_efuse_desc_t** cal_vol_efuse;
|
||||
uint32_t calib_vol_expected_mv;
|
||||
if (version != 1) {
|
||||
|
@ -35,6 +35,7 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a
|
||||
* @brief Get the calibration digits stored in the efuse, and the corresponding voltage.
|
||||
*
|
||||
* @param version Version of the stored efuse
|
||||
* @param adc_unit ADC unit (not used on ESP32C3, for compatibility)
|
||||
* @param atten Attenuation to use
|
||||
* @param out_digi Output buffer of the digits
|
||||
* @param out_vol_mv Output of the voltage, in mV
|
||||
@ -42,7 +43,7 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a
|
||||
* - ESP_ERR_INVALID_ARG: If efuse version or attenuation is invalid
|
||||
* - ESP_OK: if success
|
||||
*/
|
||||
esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv);
|
||||
esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, uint32_t adc_unit, int atten, uint32_t* out_digi, uint32_t* out_vol_mv);
|
||||
|
||||
/**
|
||||
* @brief Get the temperature sensor calibration number delta_T stored in the efuse.
|
||||
|
39
components/esp_adc/CMakeLists.txt
Normal file
39
components/esp_adc/CMakeLists.txt
Normal file
@ -0,0 +1,39 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
set(includes "include" "interface" "${target}/include" "deprecated/include")
|
||||
|
||||
set(srcs "adc_cali.c"
|
||||
"adc_cali_curve_fitting.c"
|
||||
"adc_oneshot.c"
|
||||
"adc_common.c"
|
||||
"adc_lock.c"
|
||||
"deprecated/esp_adc_cal_common_legacy.c")
|
||||
|
||||
if(CONFIG_SOC_ADC_DMA_SUPPORTED)
|
||||
list(APPEND srcs "adc_continuous.c")
|
||||
endif()
|
||||
|
||||
# init constructor for wifi
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/adc2_init_cal.c")
|
||||
list(APPEND srcs "${target}/adc2_init_cal.c")
|
||||
endif()
|
||||
|
||||
# line fitting scheme
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/adc_cali_line_fitting.c")
|
||||
list(APPEND srcs "${target}/adc_cali_line_fitting.c")
|
||||
endif()
|
||||
|
||||
# curve fitting scheme coefficients
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/curve_fitting_coefficients.c")
|
||||
list(APPEND srcs "${target}/curve_fitting_coefficients.c")
|
||||
endif()
|
||||
|
||||
# legacy calibration driver
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deprecated/${target}/esp_adc_cal_legacy.c")
|
||||
list(APPEND srcs "deprecated/${target}/esp_adc_cal_legacy.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
PRIV_REQUIRES driver efuse
|
||||
LDFRAGMENTS linker.lf)
|
47
components/esp_adc/Kconfig
Normal file
47
components/esp_adc/Kconfig
Normal file
@ -0,0 +1,47 @@
|
||||
menu "ADC and ADC Calibration"
|
||||
|
||||
config ADC_ONESHOT_CTRL_FUNC_IN_IRAM
|
||||
bool "Place ISR version ADC oneshot mode read function into IRAM"
|
||||
default n
|
||||
help
|
||||
Place ISR version ADC oneshot mode read function into IRAM.
|
||||
|
||||
config ADC_CONTINUOUS_ISR_IRAM_SAFE
|
||||
depends on SOC_ADC_DMA_SUPPORTED
|
||||
bool "ADC continuous mode driver ISR IRAM-Safe"
|
||||
default n
|
||||
select GDMA_ISR_IRAM_SAFE if SOC_ADC_DMA_SUPPORTED && SOC_GDMA_SUPPORTED
|
||||
help
|
||||
Ensure the ADC continuous mode ISR is IRAM-Safe. When enabled, the ISR handler
|
||||
will be available when the cache is disabled.
|
||||
|
||||
menu "ADC Calibration Configurations"
|
||||
depends on IDF_TARGET_ESP32
|
||||
|
||||
config ADC_CALI_EFUSE_TP_ENABLE
|
||||
bool "Use Two Point Values"
|
||||
default "y"
|
||||
help
|
||||
Some ESP32s have Two Point calibration values burned into eFuse BLOCK3.
|
||||
This option will allow the ADC calibration component to characterize the
|
||||
ADC-Voltage curve using Two Point values if they are available.
|
||||
|
||||
config ADC_CALI_EFUSE_VREF_ENABLE
|
||||
bool "Use eFuse Vref"
|
||||
default "y"
|
||||
help
|
||||
Some ESP32s have Vref burned into eFuse BLOCK0. This option will allow
|
||||
the ADC calibration component to characterize the ADC-Voltage curve using
|
||||
eFuse Vref if it is available.
|
||||
|
||||
config ADC_CALI_LUT_ENABLE
|
||||
bool "Use Lookup Tables"
|
||||
default "y"
|
||||
help
|
||||
This option will allow the ADC calibration component to use Lookup Tables
|
||||
to correct for non-linear behavior in 11db attenuation. Other attenuations
|
||||
do not exhibit non-linear behavior hence will not be affected by this option.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
45
components/esp_adc/adc_cali.c
Normal file
45
components/esp_adc/adc_cali.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "esp_types.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "adc_cali_interface.h"
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "adc_cali";
|
||||
|
||||
|
||||
esp_err_t adc_cali_check_scheme(adc_cali_scheme_ver_t *scheme_mask)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(scheme_mask, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
*scheme_mask = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
*scheme_mask |= ADC_CALI_SCHEME_VER_LINE_FITTING;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
||||
*scheme_mask |= ADC_CALI_SCHEME_VER_CURVE_FITTING;
|
||||
#endif
|
||||
|
||||
//Add your custom ADC calibration scheme here
|
||||
|
||||
ESP_RETURN_ON_FALSE((*scheme_mask) != 0, ESP_ERR_NOT_SUPPORTED, TAG, "no supported calibration scheme yet");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_cali_raw_to_voltage(adc_cali_handle_t handle, int raw, int *voltage)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle && voltage, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->ctx, ESP_ERR_INVALID_STATE, TAG, "no calibration scheme, create a scheme first");
|
||||
|
||||
return handle->raw_to_voltage(handle->ctx, raw, voltage);
|
||||
}
|
247
components/esp_adc/adc_cali_curve_fitting.c
Normal file
247
components/esp_adc/adc_cali_curve_fitting.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
#include "adc_cali_interface.h"
|
||||
#include "curve_fitting_coefficients.h"
|
||||
|
||||
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
#include "esp_efuse_rtc_calib.h"
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "adc_cali";
|
||||
|
||||
|
||||
// coeff_a is actually a float number
|
||||
// it is scaled to put them into uint32_t so that the headers do not have to be changed
|
||||
static const int coeff_a_scaling = 65536;
|
||||
|
||||
|
||||
/* -------------------- Characterization Helper Data Types ------------------ */
|
||||
typedef struct {
|
||||
uint32_t voltage;
|
||||
uint32_t digi;
|
||||
} adc_calib_data_ver1_t;
|
||||
|
||||
typedef struct {
|
||||
char version_num;
|
||||
adc_unit_t unit_id;
|
||||
adc_atten_t atten;
|
||||
union {
|
||||
adc_calib_data_ver1_t ver1;
|
||||
} ref_data;
|
||||
} adc_calib_info_t;
|
||||
|
||||
|
||||
/* ------------------------ Context Structure--------------------------- */
|
||||
typedef struct {
|
||||
uint32_t coeff_a; ///< Gradient of ADC-Voltage curve
|
||||
uint32_t coeff_b; ///< Offset of ADC-Voltage curve
|
||||
} cali_chars_first_step_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t term_num; ///< Term number of the algorithm formula
|
||||
const uint64_t (*coeff)[COEFF_GROUP_NUM][TERM_MAX][2]; ///< Coeff of each term. See `adc_error_coef_atten` for details (and the magic number 2)
|
||||
const int32_t (*sign)[COEFF_GROUP_NUM][TERM_MAX]; ///< Sign of each term
|
||||
} cali_chars_second_step_t;
|
||||
|
||||
typedef struct {
|
||||
adc_unit_t unit_id; ///< ADC unit
|
||||
adc_atten_t atten; ///< ADC attenuation
|
||||
cali_chars_first_step_t chars_first_step; ///< Calibration first step characteristics
|
||||
cali_chars_second_step_t chars_second_step; ///< Calibration second step characteristics
|
||||
} cali_chars_curve_fitting_t;
|
||||
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
static void get_first_step_reference_point(int version_num, adc_unit_t unit_id, adc_atten_t atten, adc_calib_info_t *calib_info);
|
||||
static void calc_first_step_coefficients(const adc_calib_info_t *parsed_data, cali_chars_curve_fitting_t *chars);
|
||||
static void calc_second_step_coefficients(const adc_cali_curve_fitting_config_t *config, cali_chars_curve_fitting_t *ctx);
|
||||
static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param, adc_atten_t atten);
|
||||
static esp_err_t check_valid(const adc_cali_curve_fitting_config_t *config);
|
||||
|
||||
|
||||
/* ------------------------ Interface Functions --------------------------- */
|
||||
static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage);
|
||||
|
||||
/* ------------------------- Public API ------------------------------------- */
|
||||
esp_err_t adc_cali_create_scheme_curve_fitting(const adc_cali_curve_fitting_config_t *config, adc_cali_handle_t *ret_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
|
||||
ret = check_valid(config);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
// current version only accepts encoding ver 1.
|
||||
uint8_t adc_encoding_version = esp_efuse_rtc_calib_get_ver();
|
||||
ESP_RETURN_ON_FALSE(adc_encoding_version == 1, ESP_ERR_NOT_SUPPORTED, TAG, "Calibration required eFuse bits not burnt");
|
||||
|
||||
adc_cali_scheme_t *scheme = (adc_cali_scheme_t *)heap_caps_calloc(1, sizeof(adc_cali_scheme_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for adc calibration scheme");
|
||||
|
||||
cali_chars_curve_fitting_t *chars = (cali_chars_curve_fitting_t *)heap_caps_calloc(1, sizeof(cali_chars_curve_fitting_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_GOTO_ON_FALSE(chars, ESP_ERR_NO_MEM, err, TAG, "no memory for the calibration characteristics");
|
||||
|
||||
scheme->raw_to_voltage = cali_raw_to_voltage;
|
||||
scheme->ctx = chars;
|
||||
|
||||
//Prepare calibration characteristics
|
||||
adc_calib_info_t calib_info = {0};
|
||||
//Set first step calibration context
|
||||
get_first_step_reference_point(adc_encoding_version, config->unit_id, config->atten, &calib_info);
|
||||
calc_first_step_coefficients(&calib_info, chars);
|
||||
//Set second step calibration context
|
||||
calc_second_step_coefficients(config, chars);
|
||||
chars->unit_id = config->unit_id;
|
||||
chars->atten = config->atten;
|
||||
|
||||
*ret_handle = scheme;
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (scheme) {
|
||||
free(scheme);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_cali_delete_scheme_curve_fitting(adc_cali_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
free(handle->ctx);
|
||||
handle->ctx = NULL;
|
||||
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------ Interface Functions --------------------------- */
|
||||
static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage)
|
||||
{
|
||||
//pointers are checked in the upper layer
|
||||
|
||||
cali_chars_curve_fitting_t *ctx = arg;
|
||||
uint64_t v_cali_1 = raw * ctx->chars_first_step.coeff_a / coeff_a_scaling + ctx->chars_first_step.coeff_b;
|
||||
int32_t error = get_reading_error(v_cali_1, &(ctx->chars_second_step), ctx->atten);
|
||||
|
||||
*voltage = (int32_t)v_cali_1 - error;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
//To get the reference point (Dout, Vin)
|
||||
static void get_first_step_reference_point(int version_num, adc_unit_t unit_id, adc_atten_t atten, adc_calib_info_t *calib_info)
|
||||
{
|
||||
assert(version_num == 1);
|
||||
esp_err_t ret;
|
||||
|
||||
calib_info->version_num = version_num;
|
||||
calib_info->unit_id = unit_id;
|
||||
calib_info->atten = atten;
|
||||
|
||||
uint32_t voltage = 0;
|
||||
uint32_t digi = 0;
|
||||
ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, unit_id, atten, &digi, &voltage);
|
||||
assert(ret == ESP_OK);
|
||||
calib_info->ref_data.ver1.voltage = voltage;
|
||||
calib_info->ref_data.ver1.digi = digi;
|
||||
}
|
||||
|
||||
/*
|
||||
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
|
||||
* with the previously done measurement when the chip was manufactured.
|
||||
*/
|
||||
static void calc_first_step_coefficients(const adc_calib_info_t *parsed_data, cali_chars_curve_fitting_t *ctx)
|
||||
{
|
||||
ctx->chars_first_step.coeff_a = coeff_a_scaling * parsed_data->ref_data.ver1.voltage / parsed_data->ref_data.ver1.digi;
|
||||
ctx->chars_first_step.coeff_b = 0;
|
||||
ESP_LOGV(TAG, "Calib V1, Cal Voltage = %d, Digi out = %d, Coef_a = %d\n", parsed_data->ref_data.ver1.voltage, parsed_data->ref_data.ver1.digi, ctx->chars_first_step.coeff_a);
|
||||
}
|
||||
|
||||
static void calc_second_step_coefficients(const adc_cali_curve_fitting_config_t *config, cali_chars_curve_fitting_t *ctx)
|
||||
{
|
||||
ctx->chars_second_step.term_num = (config->atten == 3) ? 5 : 3;
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
//On esp32c3, ADC1 and ADC2 share the second step coefficients
|
||||
ctx->chars_second_step.coeff = &adc1_error_coef_atten;
|
||||
ctx->chars_second_step.sign = &adc1_error_sign;
|
||||
#else
|
||||
ctx->chars_second_step.coeff = (config->unit_id == ADC_UNIT_1) ? &adc1_error_coef_atten : &adc2_error_coef_atten;
|
||||
ctx->chars_second_step.sign = (config->unit_id == ADC_UNIT_1) ? &adc1_error_sign : &adc2_error_sign;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param, adc_atten_t atten)
|
||||
{
|
||||
if (v_cali_1 == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t term_num = param->term_num;
|
||||
int32_t error = 0;
|
||||
uint64_t coeff = 0;
|
||||
uint64_t variable[term_num];
|
||||
uint64_t term[term_num];
|
||||
memset(variable, 0, term_num * sizeof(uint64_t));
|
||||
memset(term, 0, term_num * sizeof(uint64_t));
|
||||
|
||||
/**
|
||||
* For atten0 ~ 2:
|
||||
* error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2);
|
||||
*
|
||||
* For atten3:
|
||||
* error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
|
||||
*/
|
||||
variable[0] = 1;
|
||||
coeff = (*param->coeff)[atten][0][0];
|
||||
term[0] = variable[0] * coeff / (*param->coeff)[atten][0][1];
|
||||
error = (int32_t)term[0] * (*param->sign)[atten][0];
|
||||
|
||||
for (int i = 1; i < term_num; i++) {
|
||||
variable[i] = variable[i-1] * v_cali_1;
|
||||
coeff = (*param->coeff)[atten][i][0];
|
||||
term[i] = variable[i] * coeff;
|
||||
ESP_LOGV(TAG, "big coef is %llu, big term%d is %llu, coef_id is %d", coeff, i, term[i], i);
|
||||
|
||||
term[i] = term[i] / (*param->coeff)[atten][i][1];
|
||||
error += (int32_t)term[i] * (*param->sign)[atten][i];
|
||||
ESP_LOGV(TAG, "term%d is %llu, error is %d", i, term[i], error);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static esp_err_t check_valid(const adc_cali_curve_fitting_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit");
|
||||
ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation");
|
||||
|
||||
bool available_oneshot_bitwidth = (config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH);
|
||||
bool available_dma_bitwidth = (config->bitwidth >= SOC_ADC_DIGI_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_DIGI_MAX_BITWIDTH);
|
||||
bool default_bitwidth_mark = (config->bitwidth == ADC_BITWIDTH_DEFAULT);
|
||||
bool available_bitwidth = (available_oneshot_bitwidth || available_dma_bitwidth || default_bitwidth_mark);
|
||||
ESP_RETURN_ON_FALSE(available_bitwidth, ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif //#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
208
components/esp_adc/adc_common.c
Normal file
208
components/esp_adc/adc_common.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/adc_hal_common.h"
|
||||
#include "hal/adc_hal_conf.h"
|
||||
#include "soc/adc_periph.h"
|
||||
|
||||
//For calibration
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp_efuse_rtc_table.h"
|
||||
#elif SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
#include "esp_efuse_rtc_calib.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "adc_common";
|
||||
static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
extern portMUX_TYPE rtc_spinlock;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* For those who use APB_SARADC periph
|
||||
*----------------------------------------------------------------------------*/
|
||||
static int s_adc_digi_ctrlr_cnt;
|
||||
|
||||
void adc_apb_periph_claim(void)
|
||||
{
|
||||
portENTER_CRITICAL(&s_spinlock);
|
||||
s_adc_digi_ctrlr_cnt++;
|
||||
if (s_adc_digi_ctrlr_cnt == 1) {
|
||||
//enable ADC digital part
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
//reset ADC digital part
|
||||
periph_module_reset(PERIPH_SARADC_MODULE);
|
||||
}
|
||||
|
||||
portEXIT_CRITICAL(&s_spinlock);
|
||||
}
|
||||
|
||||
void adc_apb_periph_free(void)
|
||||
{
|
||||
portENTER_CRITICAL(&s_spinlock);
|
||||
s_adc_digi_ctrlr_cnt--;
|
||||
if (s_adc_digi_ctrlr_cnt == 0) {
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
} else if (s_adc_digi_ctrlr_cnt < 0) {
|
||||
portEXIT_CRITICAL(&s_spinlock);
|
||||
ESP_LOGE(TAG, "%s called, but `s_adc_digi_ctrlr_cnt == 0`", __func__);
|
||||
abort();
|
||||
}
|
||||
|
||||
portEXIT_CRITICAL(&s_spinlock);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* ADC Power
|
||||
*----------------------------------------------------------------------------*/
|
||||
// This gets incremented when adc_power_acquire() is called, and decremented when
|
||||
// adc_power_release() is called. ADC is powered down when the value reaches zero.
|
||||
// Should be modified within critical section (ADC_ENTER/EXIT_CRITICAL).
|
||||
static int s_adc_power_on_cnt;
|
||||
|
||||
static void adc_power_on_internal(void)
|
||||
{
|
||||
/* Set the power always on to increase precision. */
|
||||
adc_hal_set_power_manage(ADC_POWER_SW_ON);
|
||||
}
|
||||
|
||||
void adc_power_acquire(void)
|
||||
{
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
s_adc_power_on_cnt++;
|
||||
if (s_adc_power_on_cnt == 1) {
|
||||
adc_power_on_internal();
|
||||
}
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
static void adc_power_off_internal(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
adc_hal_set_power_manage(ADC_POWER_SW_OFF);
|
||||
#else
|
||||
adc_hal_set_power_manage(ADC_POWER_BY_FSM);
|
||||
#endif
|
||||
}
|
||||
|
||||
void adc_power_release(void)
|
||||
{
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
s_adc_power_on_cnt--;
|
||||
/* Sanity check */
|
||||
if (s_adc_power_on_cnt < 0) {
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
ESP_LOGE(TAG, "%s called, but s_adc_power_on_cnt == 0", __func__);
|
||||
abort();
|
||||
} else if (s_adc_power_on_cnt == 0) {
|
||||
adc_power_off_internal();
|
||||
}
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC IOs
|
||||
---------------------------------------------------------------*/
|
||||
esp_err_t adc_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(io_num), ESP_ERR_INVALID_ARG, TAG, "invalid gpio number");
|
||||
ESP_RETURN_ON_FALSE(unit_id && channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
bool found = false;
|
||||
for (int i = 0; i < SOC_ADC_PERIPH_NUM; i++) {
|
||||
for (int j = 0; j < SOC_ADC_MAX_CHANNEL_NUM; j++) {
|
||||
if (adc_channel_io_map[i][j] == io_num) {
|
||||
*channel = j;
|
||||
*unit_id = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (found) ? ESP_OK : ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t adc_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid unit");
|
||||
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
|
||||
ESP_RETURN_ON_FALSE(io_num, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
*io_num = adc_channel_io_map[unit_id][channel];
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
ADC Hardware Calibration
|
||||
---------------------------------------------------------------*/
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#define esp_efuse_rtc_calib_get_ver() esp_efuse_rtc_table_read_calib_version()
|
||||
|
||||
static inline uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten)
|
||||
{
|
||||
int tag = esp_efuse_rtc_table_get_tag(version, adc_unit + 1, atten, RTCCALIB_V2_PARAM_VINIT);
|
||||
return esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t s_adc_cali_param[SOC_ADC_PERIPH_NUM][SOC_ADC_ATTEN_NUM] = {};
|
||||
|
||||
void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten)
|
||||
{
|
||||
if (s_adc_cali_param[adc_n][atten]) {
|
||||
ESP_EARLY_LOGV(TAG, "Use calibrated val ADC%d atten=%d: %04X", adc_n + 1, atten, s_adc_cali_param[adc_n][atten]);
|
||||
return ;
|
||||
}
|
||||
|
||||
// check if we can fetch the values from eFuse.
|
||||
int version = esp_efuse_rtc_calib_get_ver();
|
||||
|
||||
uint32_t init_code = 0;
|
||||
|
||||
if (version == ESP_EFUSE_ADC_CALIB_VER) {
|
||||
init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten);
|
||||
} else {
|
||||
ESP_EARLY_LOGD(TAG, "Calibration eFuse is not configured, use self-calibration for ICode");
|
||||
adc_power_acquire();
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
adc_ll_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT);
|
||||
const bool internal_gnd = true;
|
||||
init_code = adc_hal_self_calibration(adc_n, atten, internal_gnd);
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
adc_power_release();
|
||||
}
|
||||
|
||||
s_adc_cali_param[adc_n][atten] = init_code;
|
||||
ESP_EARLY_LOGV(TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n + 1, atten, init_code);
|
||||
}
|
||||
|
||||
void IRAM_ATTR adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten)
|
||||
{
|
||||
adc_hal_set_calibration_param(adc_n, s_adc_cali_param[adc_n][atten]);
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void adc_hw_calibration(void)
|
||||
{
|
||||
//Calculate all ICode
|
||||
for (int i = 0; i < SOC_ADC_PERIPH_NUM; i++) {
|
||||
adc_hal_calibration_init(i);
|
||||
for (int j = 0; j < SOC_ADC_ATTEN_NUM; j++) {
|
||||
/**
|
||||
* This may get wrong when attenuations are NOT consecutive on some chips,
|
||||
* update this when bringing up the calibration on that chip
|
||||
*/
|
||||
adc_calc_hw_calibration_code(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
630
components/esp_adc/adc_continuous.c
Normal file
630
components/esp_adc/adc_continuous.c
Normal file
@ -0,0 +1,630 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "esp_private/adc_lock.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_adc/adc_continuous.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/dma_types.h"
|
||||
//For DMA
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
#include "esp_private/gdma.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "hal/spi_types.h"
|
||||
#include "esp_private/spi_common_internal.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
#include "hal/i2s_types.h"
|
||||
#include "driver/i2s_types.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "esp_private/i2s_platform.h"
|
||||
#endif
|
||||
|
||||
static const char *ADC_TAG = "adc_continuous";
|
||||
|
||||
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
|
||||
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
#define INTERNAL_BUF_NUM 5
|
||||
|
||||
typedef enum {
|
||||
ADC_FSM_INIT,
|
||||
ADC_FSM_STARTED,
|
||||
} adc_fsm_t;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Continuous Mode Driverr Context
|
||||
---------------------------------------------------------------*/
|
||||
typedef struct adc_continuous_ctx_t {
|
||||
uint8_t *rx_dma_buf; //dma buffer
|
||||
adc_hal_dma_ctx_t hal; //hal context
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
gdma_channel_handle_t rx_dma_channel; //dma rx channel handle
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
spi_host_device_t spi_host; //ADC uses this SPI DMA
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
i2s_port_t i2s_host; //ADC uses this I2S DMA
|
||||
#endif
|
||||
intr_handle_t dma_intr_hdl; //DMA Interrupt handler
|
||||
RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler
|
||||
void* ringbuf_storage; //Ringbuffer storage buffer
|
||||
void* ringbuf_struct; //Ringbuffer structure buffer
|
||||
intptr_t rx_eof_desc_addr; //eof descriptor address of RX channel
|
||||
adc_fsm_t fsm; //ADC continuous mode driver internal states
|
||||
bool use_adc1; //1: ADC unit1 will be used; 0: ADC unit1 won't be used.
|
||||
bool use_adc2; //1: ADC unit2 will be used; 0: ADC unit2 won't be used. This determines whether to acquire sar_adc2_mutex lock or not.
|
||||
adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation.
|
||||
adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation.
|
||||
adc_hal_digi_ctrlr_cfg_t hal_digi_ctrlr_cfg; //Hal digital controller configuration
|
||||
adc_continuous_evt_cbs_t cbs; //Callbacks
|
||||
void *user_data; //User context
|
||||
esp_pm_lock_handle_t pm_lock; //For power management
|
||||
} adc_continuous_ctx_t;
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
//Only for deprecated API
|
||||
extern esp_pm_lock_handle_t adc_digi_arbiter_lock;
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Continuous Read Mode (via DMA)
|
||||
---------------------------------------------------------------*/
|
||||
//Function to address transaction
|
||||
static bool s_adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx);
|
||||
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
static bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
|
||||
#else
|
||||
static void adc_dma_intr_handler(void *arg);
|
||||
#endif
|
||||
|
||||
static int8_t adc_digi_get_io_num(adc_unit_t adc_unit, uint8_t adc_channel)
|
||||
{
|
||||
assert(adc_unit <= SOC_ADC_PERIPH_NUM);
|
||||
uint8_t adc_n = (adc_unit == ADC_UNIT_1) ? 0 : 1;
|
||||
return adc_channel_io_map[adc_n][adc_channel];
|
||||
}
|
||||
|
||||
static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint64_t gpio_mask = 0;
|
||||
uint32_t n = 0;
|
||||
int8_t io = 0;
|
||||
|
||||
while (channel_mask) {
|
||||
if (channel_mask & 0x1) {
|
||||
io = adc_digi_get_io_num(adc_unit, n);
|
||||
if (io < 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gpio_mask |= BIT64(io);
|
||||
}
|
||||
channel_mask = channel_mask >> 1;
|
||||
n++;
|
||||
}
|
||||
|
||||
gpio_config_t cfg = {
|
||||
.pin_bit_mask = gpio_mask,
|
||||
.mode = GPIO_MODE_DISABLE,
|
||||
};
|
||||
ret = gpio_config(&cfg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_config, adc_continuous_handle_t *ret_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE((hdl_config->conv_frame_size % SOC_ADC_DIGI_DATA_BYTES_PER_CONV == 0), ESP_ERR_INVALID_ARG, ADC_TAG, "conv_frame_size should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`");
|
||||
|
||||
adc_continuous_ctx_t *adc_ctx = heap_caps_calloc(1, sizeof(adc_continuous_ctx_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
if (adc_ctx == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//ringbuffer storage/struct buffer
|
||||
adc_ctx->ringbuf_storage = heap_caps_calloc(1, hdl_config->max_store_buf_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
adc_ctx->ringbuf_struct = heap_caps_calloc(1, sizeof(StaticRingbuffer_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
if (!adc_ctx->ringbuf_storage || !adc_ctx->ringbuf_struct) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//ringbuffer
|
||||
adc_ctx->ringbuf_hdl = xRingbufferCreateStatic(hdl_config->max_store_buf_size, RINGBUF_TYPE_BYTEBUF, adc_ctx->ringbuf_storage, adc_ctx->ringbuf_struct);
|
||||
if (!adc_ctx->ringbuf_hdl) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//malloc internal buffer used by DMA
|
||||
adc_ctx->rx_dma_buf = heap_caps_calloc(1, hdl_config->conv_frame_size * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
||||
if (!adc_ctx->rx_dma_buf) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//malloc dma descriptor
|
||||
adc_ctx->hal.rx_desc = heap_caps_calloc(1, (sizeof(dma_descriptor_t)) * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
||||
if (!adc_ctx->hal.rx_desc) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//malloc pattern table
|
||||
adc_ctx->hal_digi_ctrlr_cfg.adc_pattern = calloc(1, SOC_ADC_PATT_LEN_MAX * sizeof(adc_digi_pattern_config_t));
|
||||
if (!adc_ctx->hal_digi_ctrlr_cfg.adc_pattern) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &adc_ctx->pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
//alloc rx gdma channel
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
};
|
||||
ret = gdma_new_channel(&rx_alloc_config, &adc_ctx->rx_dma_channel);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
gdma_connect(adc_ctx->rx_dma_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_ADC, 0));
|
||||
|
||||
gdma_strategy_config_t strategy_config = {
|
||||
.auto_update_desc = true,
|
||||
.owner_check = true
|
||||
};
|
||||
gdma_apply_strategy(adc_ctx->rx_dma_channel, &strategy_config);
|
||||
|
||||
gdma_rx_event_callbacks_t cbs = {
|
||||
.on_recv_eof = adc_dma_in_suc_eof_callback
|
||||
};
|
||||
gdma_register_rx_event_callbacks(adc_ctx->rx_dma_channel, &cbs, adc_ctx);
|
||||
|
||||
int dma_chan;
|
||||
gdma_get_channel_id(adc_ctx->rx_dma_channel, &dma_chan);
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
//ADC utilises SPI3 DMA on ESP32S2
|
||||
bool spi_success = false;
|
||||
uint32_t dma_chan = 0;
|
||||
|
||||
spi_success = spicommon_periph_claim(SPI3_HOST, "adc");
|
||||
ret = spicommon_dma_chan_alloc(SPI3_HOST, SPI_DMA_CH_AUTO, &dma_chan, &dma_chan);
|
||||
if (ret == ESP_OK) {
|
||||
adc_ctx->spi_host = SPI3_HOST;
|
||||
}
|
||||
if (!spi_success || (adc_ctx->spi_host != SPI3_HOST)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = esp_intr_alloc(spicommon_irqdma_source_for_host(adc_ctx->spi_host), ESP_INTR_FLAG_IRAM, adc_dma_intr_handler,
|
||||
(void *)adc_ctx, &adc_ctx->dma_intr_hdl);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
//ADC utilises I2S0 DMA on ESP32
|
||||
uint32_t dma_chan = 0;
|
||||
ret = i2s_platform_acquire_occupation(I2S_NUM_0, "adc");
|
||||
if (ret != ESP_OK) {
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
adc_ctx->i2s_host = I2S_NUM_0;
|
||||
ret = esp_intr_alloc(i2s_periph_signal[adc_ctx->i2s_host].irq, ESP_INTR_FLAG_IRAM, adc_dma_intr_handler,
|
||||
(void *)adc_ctx, &adc_ctx->dma_intr_hdl);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
adc_hal_dma_config_t config = {
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
.dev = (void *)GDMA_LL_GET_HW(0),
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
.dev = (void *)SPI_LL_GET_HW(adc_ctx->spi_host),
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
.dev = (void *)I2S_LL_GET_HW(adc_ctx->i2s_host),
|
||||
#endif
|
||||
.desc_max_num = INTERNAL_BUF_NUM,
|
||||
.dma_chan = dma_chan,
|
||||
.eof_num = hdl_config->conv_frame_size / SOC_ADC_DIGI_DATA_BYTES_PER_CONV
|
||||
};
|
||||
adc_hal_dma_ctx_config(&adc_ctx->hal, &config);
|
||||
|
||||
adc_ctx->fsm = ADC_FSM_INIT;
|
||||
*ret_handle = adc_ctx;
|
||||
|
||||
//enable ADC digital part
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
//reset ADC digital part
|
||||
periph_module_reset(PERIPH_SARADC_MODULE);
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_hal_calibration_init(ADC_UNIT_1);
|
||||
adc_hal_calibration_init(ADC_UNIT_2);
|
||||
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
return ret;
|
||||
|
||||
cleanup:
|
||||
adc_continuous_deinit(adc_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
|
||||
{
|
||||
assert(event_data);
|
||||
adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)user_data;
|
||||
ctx->rx_eof_desc_addr = event_data->rx_eof_desc_addr;
|
||||
return s_adc_dma_intr(user_data);
|
||||
}
|
||||
#else
|
||||
static IRAM_ATTR void adc_dma_intr_handler(void *arg)
|
||||
{
|
||||
adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)arg;
|
||||
bool need_yield = false;
|
||||
|
||||
bool conversion_finish = adc_hal_check_event(&ctx->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
if (conversion_finish) {
|
||||
adc_hal_digi_clr_intr(&ctx->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
|
||||
intptr_t desc_addr = adc_hal_get_desc_addr(&ctx->hal);
|
||||
|
||||
ctx->rx_eof_desc_addr = desc_addr;
|
||||
need_yield = s_adc_dma_intr(ctx);
|
||||
}
|
||||
|
||||
if (need_yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static IRAM_ATTR bool s_adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx)
|
||||
{
|
||||
portBASE_TYPE taskAwoken = 0;
|
||||
bool need_yield = false;
|
||||
BaseType_t ret;
|
||||
adc_hal_dma_desc_status_t status = false;
|
||||
dma_descriptor_t *current_desc = NULL;
|
||||
|
||||
while (1) {
|
||||
status = adc_hal_get_reading_result(&adc_digi_ctx->hal, adc_digi_ctx->rx_eof_desc_addr, ¤t_desc);
|
||||
if (status != ADC_HAL_DMA_DESC_VALID) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, current_desc->buffer, current_desc->dw0.length, &taskAwoken);
|
||||
need_yield |= (taskAwoken == pdTRUE);
|
||||
|
||||
if (adc_digi_ctx->cbs.on_conv_done) {
|
||||
adc_continuous_evt_data_t edata = {
|
||||
.conv_frame_buffer = current_desc->buffer,
|
||||
.size = current_desc->dw0.length,
|
||||
};
|
||||
if (adc_digi_ctx->cbs.on_conv_done(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) {
|
||||
need_yield |= true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == pdFALSE) {
|
||||
//ringbuffer overflow
|
||||
if (adc_digi_ctx->cbs.on_pool_ovf) {
|
||||
adc_continuous_evt_data_t edata = {};
|
||||
if (adc_digi_ctx->cbs.on_conv_done(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) {
|
||||
need_yield |= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == ADC_HAL_DMA_DESC_NULL) {
|
||||
//start next turns of dma operation
|
||||
adc_hal_digi_start(&adc_digi_ctx->hal, adc_digi_ctx->rx_dma_buf);
|
||||
}
|
||||
|
||||
return need_yield;
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_start(adc_continuous_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised");
|
||||
ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "ADC continuous mode isn't in the init state, it's started already");
|
||||
|
||||
if (handle->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(handle->pm_lock), ADC_TAG, "acquire pm_lock failed");
|
||||
}
|
||||
|
||||
handle->fsm = ADC_FSM_STARTED;
|
||||
adc_power_acquire();
|
||||
//reset flags
|
||||
if (handle->use_adc1) {
|
||||
adc_lock_acquire(ADC_UNIT_1);
|
||||
}
|
||||
if (handle->use_adc2) {
|
||||
adc_lock_acquire(ADC_UNIT_2);
|
||||
}
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
if (handle->use_adc1) {
|
||||
adc_set_hw_calibration_code(ADC_UNIT_1, handle->adc1_atten);
|
||||
}
|
||||
if (handle->use_adc2) {
|
||||
adc_set_hw_calibration_code(ADC_UNIT_2, handle->adc2_atten);
|
||||
}
|
||||
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
#if SOC_ADC_ARBITER_SUPPORTED
|
||||
if (handle->use_adc2) {
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_arbiter_config(&config);
|
||||
}
|
||||
#endif //#if SOC_ADC_ARBITER_SUPPORTED
|
||||
|
||||
if (handle->use_adc1) {
|
||||
adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE);
|
||||
}
|
||||
if (handle->use_adc2) {
|
||||
adc_hal_set_controller(ADC_UNIT_2, ADC_HAL_CONTINUOUS_READ_MODE);
|
||||
}
|
||||
|
||||
adc_hal_digi_init(&handle->hal);
|
||||
adc_hal_digi_controller_config(&handle->hal, &handle->hal_digi_ctrlr_cfg);
|
||||
|
||||
//start conversion
|
||||
adc_hal_digi_start(&handle->hal, handle->rx_dma_buf);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_stop(adc_continuous_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised");
|
||||
ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_STARTED, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver is already stopped");
|
||||
|
||||
handle->fsm = ADC_FSM_INIT;
|
||||
//disable the in suc eof intrrupt
|
||||
adc_hal_digi_dis_intr(&handle->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
//clear the in suc eof interrupt
|
||||
adc_hal_digi_clr_intr(&handle->hal, ADC_HAL_DMA_INTR_MASK);
|
||||
//stop ADC
|
||||
adc_hal_digi_stop(&handle->hal);
|
||||
|
||||
adc_hal_digi_deinit(&handle->hal);
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (handle->pm_lock) {
|
||||
esp_pm_lock_release(handle->pm_lock);
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
if (handle->use_adc2) {
|
||||
adc_lock_release(ADC_UNIT_2);
|
||||
}
|
||||
if (handle->use_adc1) {
|
||||
adc_lock_release(ADC_UNIT_1);
|
||||
}
|
||||
adc_power_release();
|
||||
|
||||
//release power manager lock
|
||||
if (handle->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR(esp_pm_lock_release(handle->pm_lock), ADC_TAG, "release pm_lock failed");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_read(adc_continuous_handle_t handle, uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised");
|
||||
ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_STARTED, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver is already stopped");
|
||||
|
||||
TickType_t ticks_to_wait;
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t *data = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
ticks_to_wait = timeout_ms / portTICK_PERIOD_MS;
|
||||
if (timeout_ms == ADC_MAX_DELAY) {
|
||||
ticks_to_wait = portMAX_DELAY;
|
||||
}
|
||||
|
||||
data = xRingbufferReceiveUpTo(handle->ringbuf_hdl, &size, ticks_to_wait, length_max);
|
||||
if (!data) {
|
||||
ESP_LOGV(ADC_TAG, "No data, increase timeout");
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
*out_length = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(buf, data, size);
|
||||
vRingbufferReturnItem(handle->ringbuf_hdl, data);
|
||||
assert((size % 4) == 0);
|
||||
*out_length = size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_deinit(adc_continuous_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised");
|
||||
ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver is still running");
|
||||
|
||||
if (handle->ringbuf_hdl) {
|
||||
vRingbufferDelete(handle->ringbuf_hdl);
|
||||
handle->ringbuf_hdl = NULL;
|
||||
free(handle->ringbuf_storage);
|
||||
free(handle->ringbuf_struct);
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (handle->pm_lock) {
|
||||
esp_pm_lock_delete(handle->pm_lock);
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
free(handle->rx_dma_buf);
|
||||
free(handle->hal.rx_desc);
|
||||
free(handle->hal_digi_ctrlr_cfg.adc_pattern);
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
gdma_disconnect(handle->rx_dma_channel);
|
||||
gdma_del_channel(handle->rx_dma_channel);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
esp_intr_free(handle->dma_intr_hdl);
|
||||
spicommon_dma_chan_free(handle->spi_host);
|
||||
spicommon_periph_free(handle->spi_host);
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
esp_intr_free(handle->dma_intr_hdl);
|
||||
i2s_platform_release_occupation(handle->i2s_host);
|
||||
#endif
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
---------------------------------------------------------------*/
|
||||
esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_continuous_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised");
|
||||
ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "ADC continuous mode isn't in the init state, it's started already");
|
||||
|
||||
//Pattern related check
|
||||
ESP_RETURN_ON_FALSE(config->pattern_num <= SOC_ADC_PATT_LEN_MAX, ESP_ERR_INVALID_ARG, ADC_TAG, "Max pattern num is %d", SOC_ADC_PATT_LEN_MAX);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
for (int i = 0; i < config->pattern_num; i++) {
|
||||
ESP_RETURN_ON_FALSE((config->adc_pattern[i].bit_width >= SOC_ADC_DIGI_MIN_BITWIDTH && config->adc_pattern->bit_width <= SOC_ADC_DIGI_MAX_BITWIDTH), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC bitwidth not supported");
|
||||
ESP_RETURN_ON_FALSE(config->adc_pattern[i].unit == 0, ESP_ERR_INVALID_ARG, ADC_TAG, "Only support using ADC1 DMA mode");
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < config->pattern_num; i++) {
|
||||
ESP_RETURN_ON_FALSE((config->adc_pattern[i].bit_width == SOC_ADC_DIGI_MAX_BITWIDTH), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC bitwidth not supported");
|
||||
}
|
||||
#endif
|
||||
ESP_RETURN_ON_FALSE(config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC sampling frequency out of range");
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1");
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
if (config->conv_mode == ADC_CONV_BOTH_UNIT || config->conv_mode == ADC_CONV_ALTER_UNIT) {
|
||||
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2");
|
||||
} else if (config->conv_mode == ADC_CONV_SINGLE_UNIT_1 || config->conv_mode == ADC_CONV_SINGLE_UNIT_2) {
|
||||
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1");
|
||||
}
|
||||
#else
|
||||
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2");
|
||||
#endif
|
||||
|
||||
handle->hal_digi_ctrlr_cfg.adc_pattern_len = config->pattern_num;
|
||||
handle->hal_digi_ctrlr_cfg.sample_freq_hz = config->sample_freq_hz;
|
||||
handle->hal_digi_ctrlr_cfg.conv_mode = config->conv_mode;
|
||||
memcpy(handle->hal_digi_ctrlr_cfg.adc_pattern, config->adc_pattern, config->pattern_num * sizeof(adc_digi_pattern_config_t));
|
||||
|
||||
const int atten_uninitialized = 999;
|
||||
handle->adc1_atten = atten_uninitialized;
|
||||
handle->adc2_atten = atten_uninitialized;
|
||||
handle->use_adc1 = 0;
|
||||
handle->use_adc2 = 0;
|
||||
uint32_t adc1_chan_mask = 0;
|
||||
uint32_t adc2_chan_mask = 0;
|
||||
for (int i = 0; i < config->pattern_num; i++) {
|
||||
const adc_digi_pattern_config_t *pat = &config->adc_pattern[i];
|
||||
if (pat->unit == ADC_UNIT_1) {
|
||||
handle->use_adc1 = 1;
|
||||
adc1_chan_mask |= BIT(pat->channel);
|
||||
|
||||
if (handle->adc1_atten == atten_uninitialized) {
|
||||
handle->adc1_atten = pat->atten;
|
||||
} else if (handle->adc1_atten != pat->atten) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
} else if (pat->unit == ADC_UNIT_2) {
|
||||
handle->use_adc2 = 1;
|
||||
adc2_chan_mask |= BIT(pat->channel);
|
||||
|
||||
if (handle->adc2_atten == atten_uninitialized) {
|
||||
handle->adc2_atten = pat->atten;
|
||||
} else if (handle->adc2_atten != pat->atten) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->use_adc1) {
|
||||
adc_digi_gpio_init(ADC_UNIT_1, adc1_chan_mask);
|
||||
}
|
||||
if (handle->use_adc2) {
|
||||
adc_digi_gpio_init(ADC_UNIT_2, adc2_chan_mask);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_register_event_callbacks(adc_continuous_handle_t handle, const adc_continuous_evt_cbs_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, ADC_TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "ADC continuous mode isn't in the init state, it's started already");
|
||||
|
||||
#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE
|
||||
if (cbs->on_conv_done) {
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_conv_done), ESP_ERR_INVALID_ARG, ADC_TAG, "on_conv_done callback not in IRAM");
|
||||
}
|
||||
if (cbs->on_pool_ovf) {
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_pool_ovf), ESP_ERR_INVALID_ARG, ADC_TAG, "on_pool_ovf callback not in IRAM");
|
||||
}
|
||||
#endif
|
||||
|
||||
handle->cbs.on_conv_done = cbs->on_conv_done;
|
||||
handle->cbs.on_pool_ovf = cbs->on_pool_ovf;
|
||||
handle->user_data = user_data;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel)
|
||||
{
|
||||
return adc_io_to_channel(io_num, unit_id, channel);
|
||||
}
|
||||
|
||||
esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num)
|
||||
{
|
||||
return adc_channel_to_io(unit_id, channel, io_num);
|
||||
}
|
87
components/esp_adc/adc_lock.c
Normal file
87
components/esp_adc/adc_lock.c
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "sys/lock.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#include "esp_private/adc_lock.h"
|
||||
#include "esp_private/adc2_wifi.h"
|
||||
|
||||
|
||||
static const char *TAG = "adc_lock";
|
||||
|
||||
static _lock_t adc1_lock;
|
||||
static _lock_t adc2_lock;
|
||||
|
||||
esp_err_t adc_lock_acquire(adc_unit_t unit_mask)
|
||||
{
|
||||
if (unit_mask & ADC_UNIT_1) {
|
||||
_lock_acquire(&adc1_lock);
|
||||
}
|
||||
|
||||
if (unit_mask & ADC_UNIT_2) {
|
||||
_lock_acquire(&adc2_lock);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_lock_release(adc_unit_t unit_mask)
|
||||
{
|
||||
if (unit_mask & ADC_UNIT_2) {
|
||||
ESP_RETURN_ON_FALSE(((uint32_t *)adc2_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc2 lock release without acquiring");
|
||||
_lock_release(&adc2_lock);
|
||||
}
|
||||
|
||||
if (unit_mask & ADC_UNIT_1) {
|
||||
ESP_RETURN_ON_FALSE(((uint32_t *)adc1_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc1 lock release without acquiring");
|
||||
_lock_release(&adc1_lock);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_lock_try_acquire(adc_unit_t unit_mask)
|
||||
{
|
||||
if (unit_mask & ADC_UNIT_1) {
|
||||
if (_lock_try_acquire(&adc1_lock) == -1) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (unit_mask & ADC_UNIT_2) {
|
||||
if (_lock_try_acquire(&adc2_lock) == -1) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc2_wifi_acquire(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/* Wi-Fi module will use adc2. Use locks to avoid conflicts. */
|
||||
adc_lock_acquire(ADC_UNIT_2);
|
||||
ESP_LOGD(TAG, "Wi-Fi takes adc2 lock.");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc2_wifi_release(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
return adc_lock_release(ADC_UNIT_2);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
260
components/esp_adc/adc_oneshot.c
Normal file
260
components/esp_adc/adc_oneshot.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <sys/lock.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "stdatomic.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "esp_private/adc_lock.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_oneshot_hal.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_hal_conf.h"
|
||||
#include "soc/adc_periph.h"
|
||||
|
||||
|
||||
#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM
|
||||
#define ADC_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define ADC_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock;
|
||||
static const char *TAG = "adc_oneshot";
|
||||
|
||||
|
||||
typedef struct adc_oneshot_unit_ctx_t {
|
||||
adc_oneshot_hal_ctx_t hal;
|
||||
uint32_t unit_id;
|
||||
adc_ulp_mode_t ulp_mode;
|
||||
} adc_oneshot_unit_ctx_t;
|
||||
|
||||
typedef struct adc_oneshot_ctx_t {
|
||||
_lock_t mutex;
|
||||
adc_oneshot_unit_ctx_t *units[SOC_ADC_PERIPH_NUM];
|
||||
int apb_periph_ref_cnts; //For the chips that ADC oneshot mode using APB_SARADC periph
|
||||
} adc_oneshot_ctx_t;
|
||||
|
||||
|
||||
static adc_oneshot_ctx_t s_ctx; //ADC oneshot mode context
|
||||
static atomic_bool s_adc_unit_claimed[SOC_ADC_PERIPH_NUM] = {ATOMIC_VAR_INIT(false),
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
ATOMIC_VAR_INIT(false)
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static bool s_adc_unit_claim(adc_unit_t unit);
|
||||
static bool s_adc_unit_free(adc_unit_t unit);
|
||||
static esp_err_t s_adc_io_init(adc_unit_t unit, adc_channel_t channel);
|
||||
|
||||
|
||||
esp_err_t adc_oneshot_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel)
|
||||
{
|
||||
return adc_io_to_channel(io_num, unit_id, channel);
|
||||
}
|
||||
|
||||
esp_err_t adc_oneshot_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num)
|
||||
{
|
||||
return adc_channel_to_io(unit_id, channel, io_num);
|
||||
}
|
||||
|
||||
esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, adc_oneshot_unit_handle_t *ret_unit)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
adc_oneshot_unit_ctx_t *unit = NULL;
|
||||
ESP_GOTO_ON_FALSE(init_config && ret_unit, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument: null pointer");
|
||||
ESP_GOTO_ON_FALSE(init_config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, err, TAG, "invalid unit");
|
||||
|
||||
unit = heap_caps_calloc(1, sizeof(adc_oneshot_unit_ctx_t), ADC_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, TAG, "no mem for unit");
|
||||
|
||||
bool success_claim = s_adc_unit_claim(init_config->unit_id);
|
||||
ESP_GOTO_ON_FALSE(success_claim, ESP_ERR_NOT_FOUND, err, TAG, "adc%d is already in use", init_config->unit_id + 1);
|
||||
_lock_acquire(&s_ctx.mutex);
|
||||
s_ctx.units[init_config->unit_id] = unit;
|
||||
_lock_release(&s_ctx.mutex);
|
||||
unit->unit_id = init_config->unit_id;
|
||||
unit->ulp_mode = init_config->ulp_mode;
|
||||
|
||||
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,
|
||||
};
|
||||
adc_oneshot_hal_init(&(unit->hal), &config);
|
||||
|
||||
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
//To enable the APB_SARADC periph if needed
|
||||
_lock_acquire(&s_ctx.mutex);
|
||||
s_ctx.apb_periph_ref_cnts++;
|
||||
if (s_ctx.apb_periph_ref_cnts == 1) {
|
||||
adc_apb_periph_claim();
|
||||
}
|
||||
_lock_release(&s_ctx.mutex);
|
||||
#endif
|
||||
|
||||
adc_power_acquire();
|
||||
|
||||
ESP_LOGD(TAG, "new adc unit%d is created", unit->unit_id);
|
||||
*ret_unit = unit;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (unit) {
|
||||
free(unit);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_channel_t channel, const adc_oneshot_chan_cfg_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid attenuation");
|
||||
ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth");
|
||||
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
|
||||
|
||||
s_adc_io_init(handle->unit_id, channel);
|
||||
|
||||
adc_oneshot_hal_ctx_t *hal = &(handle->hal);
|
||||
adc_oneshot_hal_chan_cfg_t cfg = {
|
||||
.atten = config->atten,
|
||||
.bitwidth = (config->bitwidth == ADC_BITWIDTH_DEFAULT) ? SOC_ADC_RTC_MAX_BITWIDTH : config->bitwidth,
|
||||
};
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
adc_oneshot_hal_channel_config(hal, &cfg, channel);
|
||||
if (handle->ulp_mode) {
|
||||
adc_oneshot_hal_setup(hal, channel);
|
||||
}
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle && out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(chan < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
|
||||
|
||||
if (adc_lock_try_acquire(handle->unit_id) != ESP_OK) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
|
||||
adc_oneshot_hal_setup(&(handle->hal), chan);
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan);
|
||||
adc_hal_calibration_init(handle->unit_id);
|
||||
adc_set_hw_calibration_code(handle->unit_id, atten);
|
||||
#endif
|
||||
bool valid = false;
|
||||
valid = adc_oneshot_hal_convert(&(handle->hal), out_raw);
|
||||
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
adc_lock_release(handle->unit_id);
|
||||
|
||||
return valid ? ESP_OK : ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
esp_err_t adc_oneshot_read_isr(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(handle && out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE_ISR(out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE_ISR(chan < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
|
||||
|
||||
portENTER_CRITICAL_SAFE(&rtc_spinlock);
|
||||
|
||||
adc_oneshot_hal_setup(&(handle->hal), chan);
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan);
|
||||
adc_hal_calibration_init(handle->unit_id);
|
||||
adc_set_hw_calibration_code(handle->unit_id, atten);
|
||||
#endif
|
||||
|
||||
adc_oneshot_hal_convert(&(handle->hal), out_raw);
|
||||
|
||||
portEXIT_CRITICAL_SAFE(&rtc_spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
bool success_free = s_adc_unit_free(handle->unit_id);
|
||||
ESP_RETURN_ON_FALSE(success_free, ESP_ERR_NOT_FOUND, TAG, "adc%d isn't in use", handle->unit_id + 1);
|
||||
|
||||
_lock_acquire(&s_ctx.mutex);
|
||||
s_ctx.units[handle->unit_id] = NULL;
|
||||
_lock_release(&s_ctx.mutex);
|
||||
|
||||
ESP_LOGD(TAG, "adc unit%d is deleted", handle->unit_id);
|
||||
free(handle);
|
||||
|
||||
adc_power_release();
|
||||
|
||||
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
//To free the APB_SARADC periph if needed
|
||||
_lock_acquire(&s_ctx.mutex);
|
||||
s_ctx.apb_periph_ref_cnts--;
|
||||
assert(s_ctx.apb_periph_ref_cnts >= 0);
|
||||
if (s_ctx.apb_periph_ref_cnts == 0) {
|
||||
adc_apb_periph_free();
|
||||
}
|
||||
_lock_release(&s_ctx.mutex);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel])
|
||||
|
||||
static esp_err_t s_adc_io_init(adc_unit_t unit, adc_channel_t channel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(unit), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
|
||||
|
||||
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
|
||||
uint32_t io_num = ADC_GET_IO_NUM(unit, channel);
|
||||
gpio_config_t cfg = {
|
||||
.pin_bit_mask = BIT64(io_num),
|
||||
.mode = GPIO_MODE_DISABLE,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&cfg), TAG, "IO config fail");
|
||||
#else
|
||||
gpio_num_t io_num = ADC_GET_IO_NUM(unit, channel);
|
||||
ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), TAG, "IO config fail");
|
||||
ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_DISABLED), TAG, "IO config fail");
|
||||
ESP_RETURN_ON_ERROR(rtc_gpio_pulldown_dis(io_num), TAG, "IO config fail");
|
||||
ESP_RETURN_ON_ERROR(rtc_gpio_pullup_dis(io_num), TAG, "IO config fail");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static bool s_adc_unit_claim(adc_unit_t unit)
|
||||
{
|
||||
bool false_var = false;
|
||||
return atomic_compare_exchange_strong(&s_adc_unit_claimed[unit], &false_var, true);
|
||||
}
|
||||
|
||||
static bool s_adc_unit_free(adc_unit_t unit)
|
||||
{
|
||||
bool true_var = true;
|
||||
return atomic_compare_exchange_strong(&s_adc_unit_claimed[unit], &true_var, false);
|
||||
}
|
33
components/esp_adc/curve_fitting_coefficients.h
Normal file
33
components/esp_adc/curve_fitting_coefficients.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#define COEFF_GROUP_NUM 4
|
||||
#define TERM_MAX 5
|
||||
|
||||
/**
|
||||
* @note Error Calculation
|
||||
* Coefficients for calculating the reading voltage error.
|
||||
* Four sets of coefficients for atten0 ~ atten3 respectively.
|
||||
*
|
||||
* For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient.
|
||||
*
|
||||
* @note {0,0} stands for unused item
|
||||
* @note In case of the overflow, these coeffcients are recorded as Absolute Value
|
||||
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
|
||||
* @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered.
|
||||
* @note ADC1 and ADC2 use same coeffients
|
||||
*/
|
||||
extern const uint64_t adc1_error_coef_atten[COEFF_GROUP_NUM][TERM_MAX][2];
|
||||
extern const uint64_t adc2_error_coef_atten[COEFF_GROUP_NUM][TERM_MAX][2];
|
||||
|
||||
/**
|
||||
* Term sign
|
||||
*/
|
||||
extern const int32_t adc1_error_sign[COEFF_GROUP_NUM][TERM_MAX];
|
||||
extern const int32_t adc2_error_sign[COEFF_GROUP_NUM][TERM_MAX];
|
@ -6,12 +6,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_types.h"
|
||||
#include "driver/adc.h"
|
||||
#include "hal/efuse_ll.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "assert.h"
|
||||
#include "esp_adc_cal.h"
|
||||
#include "hal/efuse_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
#include "esp_adc_cal_types_legacy.h"
|
||||
|
||||
/* ----------------------------- Configuration ------------------------------ */
|
||||
#ifdef CONFIG_ADC_CAL_EFUSE_TP_ENABLE
|
@ -11,11 +11,12 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/adc.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "esp_efuse_rtc_calib.h"
|
||||
#include "esp_adc_cal.h"
|
||||
#include "../esp_adc_cal_internal.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
#include "esp_adc_cal_types_legacy.h"
|
||||
#include "../esp_adc_cal_internal_legacy.h"
|
||||
|
||||
const static char LOG_TAG[] = "ADC_CALI";
|
||||
|
||||
@ -79,9 +80,12 @@ static esp_err_t prepare_calib_data_for(int version_num, adc_unit_t adc_num, adc
|
||||
parsed_data_storage->version_num = version_num;
|
||||
parsed_data_storage->adc_num = adc_num;
|
||||
parsed_data_storage->atten_level = atten;
|
||||
// V1 we don't have calibration data for ADC2, using the efuse data of ADC1
|
||||
uint32_t voltage, digi;
|
||||
ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, atten, &digi, &voltage);
|
||||
/**
|
||||
* V1 we don't have calibration data for ADC2, using the efuse data of ADC1.
|
||||
* Here passing the `adc_num` is just for compatibility
|
||||
*/
|
||||
ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, adc_num, atten, &digi, &voltage);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
@ -129,7 +133,7 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
|
||||
ESP_RETURN_ON_FALSE(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid unit num");
|
||||
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Ivalid characteristic");
|
||||
ESP_RETURN_ON_FALSE(bit_width == ADC_WIDTH_BIT_12, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid bit_width");
|
||||
ESP_RETURN_ON_FALSE(atten < 4, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid attenuation");
|
||||
ESP_RETURN_ON_FALSE(atten < SOC_ADC_ATTEN_NUM, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid attenuation");
|
||||
|
||||
int version_num = esp_efuse_rtc_calib_get_ver();
|
||||
ESP_RETURN_ON_FALSE(version_num == 1, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "No calibration efuse burnt");
|
@ -6,16 +6,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_types.h"
|
||||
#include "driver/adc.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "assert.h"
|
||||
#include "esp_adc_cal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_efuse_rtc_table.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
#include "esp_adc_cal_types_legacy.h"
|
||||
|
||||
const static char LOG_TAG[] = "adc_calib";
|
||||
|
@ -11,11 +11,12 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/adc.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "esp_efuse_rtc_calib.h"
|
||||
#include "esp_adc_cal.h"
|
||||
#include "../esp_adc_cal_internal.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
#include "esp_adc_cal_types_legacy.h"
|
||||
#include "../esp_adc_cal_internal_legacy.h"
|
||||
|
||||
const static char LOG_TAG[] = "ADC_CALI";
|
||||
|
@ -6,14 +6,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/adc.h"
|
||||
#include "hal/adc_types.h"
|
||||
#define CONFIG_ADC_SUPPRESS_DEPRECATE_WARN 1
|
||||
#include "esp_adc_cal.h"
|
||||
#include "esp_adc_cal_internal.h"
|
||||
#include "esp_adc_cal_internal_legacy.h"
|
||||
#include "driver/adc.h"
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "ADC_CALI";
|
||||
|
||||
@ -41,6 +45,7 @@ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
|
||||
/*------------------------------------------------------------------------------
|
||||
* Private API
|
||||
@ -86,3 +91,5 @@ int32_t esp_adc_cal_get_reading_error(const esp_adc_error_calc_param_t *param, u
|
||||
return error;
|
||||
}
|
||||
#endif //#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
|
||||
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
@ -4,46 +4,24 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_ADC_CAL_H__
|
||||
#define __ESP_ADC_CAL_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "driver/adc.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
#include "esp_adc_cal_types_legacy.h"
|
||||
|
||||
#if !CONFIG_ADC_SUPPRESS_DEPRECATE_WARN
|
||||
#warning "legacy adc calibration driver is deprecated, please migrate to use esp_adc/adc_cali.h and esp_adc/adc_cali_scheme.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of calibration value used in characterization
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_ADC_CAL_VAL_EFUSE_VREF = 0, /**< Characterization based on reference voltage stored in eFuse*/
|
||||
ESP_ADC_CAL_VAL_EFUSE_TP = 1, /**< Characterization based on Two Point values stored in eFuse*/
|
||||
ESP_ADC_CAL_VAL_DEFAULT_VREF = 2, /**< Characterization based on default reference voltage*/
|
||||
ESP_ADC_CAL_VAL_EFUSE_TP_FIT = 3, /**< Characterization based on Two Point values and fitting curve coefficients stored in eFuse */
|
||||
ESP_ADC_CAL_VAL_MAX,
|
||||
ESP_ADC_CAL_VAL_NOT_SUPPORTED = ESP_ADC_CAL_VAL_MAX,
|
||||
} esp_adc_cal_value_t;
|
||||
|
||||
/**
|
||||
* @brief Structure storing characteristics of an ADC
|
||||
*
|
||||
* @note Call esp_adc_cal_characterize() to initialize the structure
|
||||
*/
|
||||
typedef struct {
|
||||
adc_unit_t adc_num; /**< ADC unit*/
|
||||
adc_atten_t atten; /**< ADC attenuation*/
|
||||
adc_bits_width_t bit_width; /**< ADC bit width */
|
||||
uint32_t coeff_a; /**< Gradient of ADC-Voltage curve*/
|
||||
uint32_t coeff_b; /**< Offset of ADC-Voltage curve*/
|
||||
uint32_t vref; /**< Vref used by lookup table*/
|
||||
const uint32_t *low_curve; /**< Pointer to low Vref curve of lookup table (NULL if unused)*/
|
||||
const uint32_t *high_curve; /**< Pointer to high Vref curve of lookup table (NULL if unused)*/
|
||||
uint8_t version; /**< ADC Calibration */
|
||||
} esp_adc_cal_characteristics_t;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
||||
/**
|
||||
* @brief Checks if ADC calibration values are burned into eFuse
|
||||
*
|
||||
@ -128,8 +106,8 @@ uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_char
|
||||
*/
|
||||
esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, const esp_adc_cal_characteristics_t *chars, uint32_t *voltage);
|
||||
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_ADC_CAL_H__ */
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "driver/adc_types_legacy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
||||
/**
|
||||
* @brief Type of calibration value used in characterization
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_ADC_CAL_VAL_EFUSE_VREF = 0, /**< Characterization based on reference voltage stored in eFuse*/
|
||||
ESP_ADC_CAL_VAL_EFUSE_TP = 1, /**< Characterization based on Two Point values stored in eFuse*/
|
||||
ESP_ADC_CAL_VAL_DEFAULT_VREF = 2, /**< Characterization based on default reference voltage*/
|
||||
ESP_ADC_CAL_VAL_EFUSE_TP_FIT = 3, /**< Characterization based on Two Point values and fitting curve coefficients stored in eFuse */
|
||||
ESP_ADC_CAL_VAL_MAX,
|
||||
ESP_ADC_CAL_VAL_NOT_SUPPORTED = ESP_ADC_CAL_VAL_MAX,
|
||||
} esp_adc_cal_value_t;
|
||||
|
||||
/**
|
||||
* @brief Structure storing characteristics of an ADC
|
||||
*
|
||||
* @note Call esp_adc_cal_characterize() to initialize the structure
|
||||
*/
|
||||
typedef struct {
|
||||
adc_unit_t adc_num; /**< ADC unit*/
|
||||
adc_atten_t atten; /**< ADC attenuation*/
|
||||
adc_bits_width_t bit_width; /**< ADC bit width */
|
||||
uint32_t coeff_a; /**< Gradient of ADC-Voltage curve*/
|
||||
uint32_t coeff_b; /**< Offset of ADC-Voltage curve*/
|
||||
uint32_t vref; /**< Vref used by lookup table*/
|
||||
const uint32_t *low_curve; /**< Pointer to low Vref curve of lookup table (NULL if unused)*/
|
||||
const uint32_t *high_curve; /**< Pointer to high Vref curve of lookup table (NULL if unused)*/
|
||||
uint8_t version; /**< ADC Calibration */
|
||||
} esp_adc_cal_characteristics_t;
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
435
components/esp_adc/esp32/adc_cali_line_fitting.c
Normal file
435
components/esp_adc/esp32/adc_cali_line_fitting.c
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "assert.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/efuse_ll.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
#include "adc_cali_interface.h"
|
||||
|
||||
/* ----------------------------- Configuration ------------------------------ */
|
||||
#ifdef CONFIG_ADC_CALI_EFUSE_TP_ENABLE
|
||||
#define EFUSE_TP_ENABLED 1
|
||||
#else
|
||||
#define EFUSE_TP_ENABLED 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ADC_CALI_EFUSE_VREF_ENABLE
|
||||
#define EFUSE_VREF_ENABLED 1
|
||||
#else
|
||||
#define EFUSE_VREF_ENABLED 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ADC_CALI_LUT_ENABLE
|
||||
#define LUT_ENABLED 1
|
||||
#else
|
||||
#define LUT_ENABLED 0
|
||||
#endif
|
||||
|
||||
/* ESP32s with both Two Point Values and Vref burned into eFuse are required to
|
||||
* also burn the EFUSE_BLK3_PART_RESERVE flag. A limited set of ESP32s
|
||||
* (not available through regular sales channel) DO NOT have the
|
||||
* EFUSE_BLK3_PART_RESERVE burned. Moreover, this set of ESP32s represents Vref
|
||||
* in Two's Complement format. If this is the case, modify the preprocessor
|
||||
* definitions below as follows...
|
||||
* #define CHECK_BLK3_FLAG 0 //Do not check BLK3 flag as it is not burned
|
||||
* #define VREF_FORMAT 1 //eFuse Vref is in Two's Complement format
|
||||
*/
|
||||
#define CHECK_BLK3_FLAG 1
|
||||
#define VREF_FORMAT 0
|
||||
|
||||
/* ------------------------------ eFuse Access ----------------------------- */
|
||||
#define VREF_MASK 0x1F
|
||||
#define VREF_STEP_SIZE 7
|
||||
#define VREF_OFFSET 1100
|
||||
|
||||
#define TP_LOW1_OFFSET 278
|
||||
#define TP_LOW2_OFFSET 421
|
||||
#define TP_LOW_MASK 0x7F
|
||||
#define TP_LOW_VOLTAGE 150
|
||||
#define TP_HIGH1_OFFSET 3265
|
||||
#define TP_HIGH2_OFFSET 3406
|
||||
#define TP_HIGH_MASK 0x1FF
|
||||
#define TP_HIGH_VOLTAGE 850
|
||||
#define TP_STEP_SIZE 4
|
||||
|
||||
/* ----------------------- Raw to Voltage Constants ------------------------- */
|
||||
#define LIN_COEFF_A_SCALE 65536
|
||||
#define LIN_COEFF_A_ROUND (LIN_COEFF_A_SCALE/2)
|
||||
|
||||
#define LUT_VREF_LOW 1000
|
||||
#define LUT_VREF_HIGH 1200
|
||||
#define LUT_ADC_STEP_SIZE 64
|
||||
#define LUT_POINTS 20
|
||||
#define LUT_LOW_THRESH 2880
|
||||
#define LUT_HIGH_THRESH (LUT_LOW_THRESH + LUT_ADC_STEP_SIZE)
|
||||
#define ADC_12_BIT_RES 4096
|
||||
|
||||
/* ------------------------ Characterization Constants ---------------------- */
|
||||
static const uint32_t adc1_tp_atten_scale[4] = {65504, 86975, 120389, 224310};
|
||||
static const uint32_t adc2_tp_atten_scale[4] = {65467, 86861, 120416, 224708};
|
||||
static const uint32_t adc1_tp_atten_offset[4] = {0, 1, 27, 54};
|
||||
static const uint32_t adc2_tp_atten_offset[4] = {0, 9, 26, 66};
|
||||
|
||||
static const uint32_t adc1_vref_atten_scale[4] = {57431, 76236, 105481, 196602};
|
||||
static const uint32_t adc2_vref_atten_scale[4] = {57236, 76175, 105678, 197170};
|
||||
static const uint32_t adc1_vref_atten_offset[4] = {75, 78, 107, 142};
|
||||
static const uint32_t adc2_vref_atten_offset[4] = {63, 66, 89, 128};
|
||||
|
||||
//20 Point lookup tables, covering ADC readings from 2880 to 4096, step size of 64
|
||||
static const uint32_t lut_adc1_low[LUT_POINTS] = {2240, 2297, 2352, 2405, 2457, 2512, 2564, 2616, 2664, 2709,
|
||||
2754, 2795, 2832, 2868, 2903, 2937, 2969, 3000, 3030, 3060};
|
||||
static const uint32_t lut_adc1_high[LUT_POINTS] = {2667, 2706, 2745, 2780, 2813, 2844, 2873, 2901, 2928, 2956,
|
||||
2982, 3006, 3032, 3059, 3084, 3110, 3135, 3160, 3184, 3209};
|
||||
static const uint32_t lut_adc2_low[LUT_POINTS] = {2238, 2293, 2347, 2399, 2451, 2507, 2561, 2613, 2662, 2710,
|
||||
2754, 2792, 2831, 2869, 2904, 2937, 2968, 2999, 3029, 3059};
|
||||
static const uint32_t lut_adc2_high[LUT_POINTS] = {2657, 2698, 2738, 2774, 2807, 2838, 2867, 2894, 2921, 2946,
|
||||
2971, 2996, 3020, 3043, 3067, 3092, 3116, 3139, 3162, 3185};
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "adc_cali";
|
||||
|
||||
|
||||
/* ----------------------- EFuse Access Functions --------------------------- */
|
||||
static bool check_efuse_vref(void);
|
||||
static bool check_efuse_tp(void);
|
||||
static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl);
|
||||
static uint32_t read_efuse_vref(void);
|
||||
static uint32_t read_efuse_tp_low(adc_unit_t unit_id);
|
||||
static uint32_t read_efuse_tp_high(adc_unit_t unit_id);
|
||||
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
static void characterize_using_two_point(adc_unit_t unit_id,
|
||||
adc_atten_t atten,
|
||||
uint32_t high,
|
||||
uint32_t low,
|
||||
uint32_t *coeff_a,
|
||||
uint32_t *coeff_b);
|
||||
static void characterize_using_vref(adc_unit_t unit_id,
|
||||
adc_atten_t atten,
|
||||
uint32_t vref,
|
||||
uint32_t *coeff_a,
|
||||
uint32_t *coeff_b);
|
||||
|
||||
|
||||
/* ------------------------ Conversion Functions --------------------------- */
|
||||
static uint32_t calculate_voltage_linear(uint32_t adc_reading, uint32_t coeff_a, uint32_t coeff_b);
|
||||
//Only call when ADC reading is above threshold
|
||||
static uint32_t calculate_voltage_lut(uint32_t adc, uint32_t vref, const uint32_t *low_vref_curve, const uint32_t *high_vref_curve);
|
||||
|
||||
static inline uint32_t interpolate_two_points(uint32_t y1, uint32_t y2, uint32_t x_step, uint32_t x)
|
||||
{
|
||||
//Interpolate between two points (x1,y1) (x2,y2) between 'lower' and 'upper' separated by 'step'
|
||||
return ((y1 * x_step) + (y2 * x) - (y1 * x) + (x_step / 2)) / x_step;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------ Interface Functions --------------------------- */
|
||||
static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage);
|
||||
|
||||
|
||||
/* ------------------------ Context Structure--------------------------- */
|
||||
typedef struct {
|
||||
adc_unit_t unit_id; ///< ADC unit
|
||||
adc_atten_t atten; ///< ADC attenuation
|
||||
adc_bitwidth_t bitwidth; ///< ADC bit width
|
||||
uint32_t coeff_a; ///< Gradient of ADC-Voltage curve
|
||||
uint32_t coeff_b; ///< Offset of ADC-Voltage curve
|
||||
uint32_t vref; ///< Vref used by lookup table
|
||||
const uint32_t *low_curve; ///< Pointer to low Vref curve of lookup table (NULL if unused)
|
||||
const uint32_t *high_curve; ///< Pointer to high Vref curve of lookup table (NULL if unused)
|
||||
adc_cali_line_fitting_efuse_val_t efuse_val; ///< Type of calibration value used in characterization
|
||||
} cali_chars_line_fitting_t;
|
||||
|
||||
|
||||
/* ------------------------- Public API ------------------------------------- */
|
||||
esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(config && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit");
|
||||
ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation");
|
||||
ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth");
|
||||
|
||||
adc_cali_scheme_t *scheme = (adc_cali_scheme_t *)heap_caps_calloc(1, sizeof(adc_cali_scheme_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for adc calibration scheme");
|
||||
|
||||
cali_chars_line_fitting_t *chars = (cali_chars_line_fitting_t *)heap_caps_calloc(1, sizeof(cali_chars_line_fitting_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_GOTO_ON_FALSE(chars, ESP_ERR_NO_MEM, err, TAG, "no memory for the calibration characteristics");
|
||||
|
||||
//Check eFuse if enabled to do so
|
||||
if (check_efuse_tp() && EFUSE_TP_ENABLED) {
|
||||
//Characterize based on Two Point values
|
||||
chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP;
|
||||
//Characterize based on Two Point values
|
||||
uint32_t high = read_efuse_tp_high(config->unit_id);
|
||||
uint32_t low = read_efuse_tp_low(config->unit_id);
|
||||
characterize_using_two_point(config->unit_id, config->atten, high, low, &chars->coeff_a, &chars->coeff_b);
|
||||
} else if (check_efuse_vref() && EFUSE_VREF_ENABLED) {
|
||||
//Characterize based on eFuse Vref
|
||||
chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF;
|
||||
chars->vref = read_efuse_vref();
|
||||
characterize_using_vref(config->unit_id, config->atten, chars->vref, &chars->coeff_a, &chars->coeff_b);
|
||||
} else {
|
||||
//Characterized based on default Vref
|
||||
chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF;
|
||||
ESP_GOTO_ON_FALSE(config->default_vref, ESP_ERR_INVALID_ARG, err, TAG, "default vref didn't set");
|
||||
chars->vref = config->default_vref;
|
||||
characterize_using_vref(config->unit_id, config->atten, chars->vref, &chars->coeff_a, &chars->coeff_b);
|
||||
}
|
||||
|
||||
chars->unit_id = config->unit_id;
|
||||
chars->atten = config->atten;
|
||||
chars->bitwidth = (config->bitwidth == ADC_BITWIDTH_DEFAULT) ? ADC_BITWIDTH_12 : config->bitwidth;
|
||||
//Initialize fields for lookup table if necessary
|
||||
if (LUT_ENABLED && config->atten == ADC_ATTEN_DB_11) {
|
||||
chars->low_curve = (config->unit_id == ADC_UNIT_1) ? lut_adc1_low : lut_adc2_low;
|
||||
chars->high_curve = (config->unit_id == ADC_UNIT_1) ? lut_adc1_high : lut_adc2_high;
|
||||
} else {
|
||||
chars->low_curve = NULL;
|
||||
chars->high_curve = NULL;
|
||||
}
|
||||
scheme->raw_to_voltage = cali_raw_to_voltage;
|
||||
scheme->ctx = chars;
|
||||
*ret_handle = scheme;
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (scheme) {
|
||||
free(scheme);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_cali_scheme_line_fitting_check_efuse(adc_cali_line_fitting_efuse_val_t *cali_val)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(cali_val, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
if (check_efuse_tp()) {
|
||||
*cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP;
|
||||
} else if (check_efuse_vref()) {
|
||||
*cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF;
|
||||
} else {
|
||||
*cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
free(handle->ctx);
|
||||
handle->ctx = NULL;
|
||||
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* ------------------------ Interface Functions --------------------------- */
|
||||
static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage)
|
||||
{
|
||||
//pointers are checked in the upper layer
|
||||
|
||||
cali_chars_line_fitting_t *ctx = arg;
|
||||
|
||||
//Scale adc_rading if not 12 bits wide
|
||||
raw = (raw << (ADC_BITWIDTH_12 - ctx->bitwidth));
|
||||
if (raw > ADC_12_BIT_RES - 1) {
|
||||
raw = ADC_12_BIT_RES - 1; //Set to 12bit res max
|
||||
}
|
||||
|
||||
if (LUT_ENABLED && (ctx->atten == ADC_ATTEN_DB_11) && (raw >= LUT_LOW_THRESH)) { //Check if in non-linear region
|
||||
//Use lookup table to get voltage in non linear portion of ADC_ATTEN_DB_11
|
||||
uint32_t lut_voltage = calculate_voltage_lut(raw, ctx->vref, ctx->low_curve, ctx->high_curve);
|
||||
if (raw <= LUT_HIGH_THRESH) { //If ADC is transitioning from linear region to non-linear region
|
||||
//Linearly interpolate between linear voltage and lut voltage
|
||||
uint32_t linear_voltage = calculate_voltage_linear(raw, ctx->coeff_a, ctx->coeff_b);
|
||||
*voltage = interpolate_two_points(linear_voltage, lut_voltage, LUT_ADC_STEP_SIZE, (raw - LUT_LOW_THRESH));
|
||||
} else {
|
||||
*voltage = lut_voltage;
|
||||
}
|
||||
} else {
|
||||
*voltage = calculate_voltage_linear(raw, ctx->coeff_a, ctx->coeff_b);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* ----------------------- EFuse Access Functions --------------------------- */
|
||||
static bool check_efuse_vref(void)
|
||||
{
|
||||
//Check if Vref is burned in eFuse
|
||||
return (efuse_ll_get_adc_vref() != 0) ? true : false;
|
||||
}
|
||||
|
||||
static bool check_efuse_tp(void)
|
||||
{
|
||||
//Check if Two Point values are burned in eFuse
|
||||
if (CHECK_BLK3_FLAG && (efuse_ll_get_blk3_part_reserve() == 0)) {
|
||||
return false;
|
||||
}
|
||||
//All TP cal values must be non zero
|
||||
return efuse_ll_get_adc1_tp_low() &&
|
||||
efuse_ll_get_adc2_tp_low() &&
|
||||
efuse_ll_get_adc1_tp_high() &&
|
||||
efuse_ll_get_adc2_tp_high();
|
||||
}
|
||||
|
||||
static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl)
|
||||
{
|
||||
int ret;
|
||||
if (bits & (~(mask >> 1) & mask)) { //Check sign bit (MSB of mask)
|
||||
//Negative
|
||||
if (is_twos_compl) {
|
||||
ret = -(((~bits) + 1) & (mask >> 1)); //2's complement
|
||||
} else {
|
||||
ret = -(bits & (mask >> 1)); //Sign-magnitude
|
||||
}
|
||||
} else {
|
||||
//Positive
|
||||
ret = bits & (mask >> 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t read_efuse_vref(void)
|
||||
{
|
||||
//eFuse stores deviation from ideal reference voltage
|
||||
uint32_t ret = VREF_OFFSET; //Ideal vref
|
||||
uint32_t bits = efuse_ll_get_adc_vref();
|
||||
ret += decode_bits(bits, VREF_MASK, VREF_FORMAT) * VREF_STEP_SIZE;
|
||||
return ret; //ADC Vref in mV
|
||||
}
|
||||
|
||||
static uint32_t read_efuse_tp_low(adc_unit_t unit_id)
|
||||
{
|
||||
//ADC reading at 150mV stored in two's complement format
|
||||
uint32_t ret;
|
||||
uint32_t bits;
|
||||
|
||||
if (unit_id == ADC_UNIT_1) {
|
||||
ret = TP_LOW1_OFFSET;
|
||||
bits = efuse_ll_get_adc1_tp_low();
|
||||
} else {
|
||||
ret = TP_LOW2_OFFSET;
|
||||
bits = efuse_ll_get_adc2_tp_low();
|
||||
}
|
||||
ret += decode_bits(bits, TP_LOW_MASK, true) * TP_STEP_SIZE;
|
||||
return ret; //Reading of ADC at 150mV
|
||||
}
|
||||
|
||||
static uint32_t read_efuse_tp_high(adc_unit_t unit_id)
|
||||
{
|
||||
//ADC reading at 850mV stored in two's complement format
|
||||
uint32_t ret;
|
||||
uint32_t bits;
|
||||
|
||||
if (unit_id == ADC_UNIT_1) {
|
||||
ret = TP_HIGH1_OFFSET;
|
||||
bits = efuse_ll_get_adc1_tp_high();
|
||||
} else {
|
||||
ret = TP_HIGH2_OFFSET;
|
||||
bits = efuse_ll_get_adc2_tp_high();
|
||||
}
|
||||
ret += decode_bits(bits, TP_HIGH_MASK, true) * TP_STEP_SIZE;
|
||||
return ret; //Reading of ADC at 850mV
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
static void characterize_using_two_point(adc_unit_t unit_id,
|
||||
adc_atten_t atten,
|
||||
uint32_t high,
|
||||
uint32_t low,
|
||||
uint32_t *coeff_a,
|
||||
uint32_t *coeff_b)
|
||||
{
|
||||
const uint32_t *atten_scales;
|
||||
const uint32_t *atten_offsets;
|
||||
|
||||
if (unit_id == ADC_UNIT_1) { //Using ADC 1
|
||||
atten_scales = adc1_tp_atten_scale;
|
||||
atten_offsets = adc1_tp_atten_offset;
|
||||
} else { //Using ADC 2
|
||||
atten_scales = adc2_tp_atten_scale;
|
||||
atten_offsets = adc2_tp_atten_offset;
|
||||
}
|
||||
//Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
|
||||
uint32_t delta_x = high - low;
|
||||
uint32_t delta_v = TP_HIGH_VOLTAGE - TP_LOW_VOLTAGE;
|
||||
//Where coeff_a = (delta_v/delta_x) * atten_scale
|
||||
*coeff_a = (delta_v * atten_scales[atten] + (delta_x / 2)) / delta_x; //+(delta_x/2) for rounding
|
||||
//Where coeff_b = high_v - ((delta_v/delta_x) * high_x) + atten_offset
|
||||
*coeff_b = TP_HIGH_VOLTAGE - ((delta_v * high + (delta_x / 2)) / delta_x) + atten_offsets[atten];
|
||||
}
|
||||
|
||||
static void characterize_using_vref(adc_unit_t unit_id,
|
||||
adc_atten_t atten,
|
||||
uint32_t vref,
|
||||
uint32_t *coeff_a,
|
||||
uint32_t *coeff_b)
|
||||
{
|
||||
const uint32_t *atten_scales;
|
||||
const uint32_t *atten_offsets;
|
||||
|
||||
if (unit_id == ADC_UNIT_1) { //Using ADC 1
|
||||
atten_scales = adc1_vref_atten_scale;
|
||||
atten_offsets = adc1_vref_atten_offset;
|
||||
} else { //Using ADC 2
|
||||
atten_scales = adc2_vref_atten_scale;
|
||||
atten_offsets = adc2_vref_atten_offset;
|
||||
}
|
||||
//Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
|
||||
//Where coeff_a = (vref/4096) * atten_scale
|
||||
*coeff_a = (vref * atten_scales[atten]) / (ADC_12_BIT_RES);
|
||||
*coeff_b = atten_offsets[atten];
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------ Conversion Functions --------------------------- */
|
||||
static uint32_t calculate_voltage_linear(uint32_t adc_reading, uint32_t coeff_a, uint32_t coeff_b)
|
||||
{
|
||||
//Where voltage = coeff_a * adc_reading + coeff_b
|
||||
return (((coeff_a * adc_reading) + LIN_COEFF_A_ROUND) / LIN_COEFF_A_SCALE) + coeff_b;
|
||||
}
|
||||
|
||||
//Only call when ADC reading is above threshold
|
||||
static uint32_t calculate_voltage_lut(uint32_t adc, uint32_t vref, const uint32_t *low_vref_curve, const uint32_t *high_vref_curve)
|
||||
{
|
||||
//Get index of lower bound points of LUT
|
||||
uint32_t i = (adc - LUT_LOW_THRESH) / LUT_ADC_STEP_SIZE;
|
||||
|
||||
//Let the X Axis be Vref, Y axis be ADC reading, and Z be voltage
|
||||
int x2dist = LUT_VREF_HIGH - vref; //(x2 - x)
|
||||
int x1dist = vref - LUT_VREF_LOW; //(x - x1)
|
||||
int y2dist = ((i + 1) * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH - adc; //(y2 - y)
|
||||
int y1dist = adc - ((i * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH); //(y - y1)
|
||||
|
||||
//For points for bilinear interpolation
|
||||
int q11 = low_vref_curve[i]; //Lower bound point of low_vref_curve
|
||||
int q12 = low_vref_curve[i + 1]; //Upper bound point of low_vref_curve
|
||||
int q21 = high_vref_curve[i]; //Lower bound point of high_vref_curve
|
||||
int q22 = high_vref_curve[i + 1]; //Upper bound point of high_vref_curve
|
||||
|
||||
//Bilinear interpolation
|
||||
//Where z = 1/((x2-x1)*(y2-y1)) * ( (q11*x2dist*y2dist) + (q21*x1dist*y2dist) + (q12*x2dist*y1dist) + (q22*x1dist*y1dist) )
|
||||
int voltage = (q11 * x2dist * y2dist) + (q21 * x1dist * y2dist) + (q12 * x2dist * y1dist) + (q22 * x1dist * y1dist);
|
||||
voltage += ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE) / 2; //Integer division rounding
|
||||
voltage /= ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE); //Divide by ((x2-x1)*(y2-y1))
|
||||
return (uint32_t)voltage;
|
||||
}
|
15
components/esp_adc/esp32/include/adc_cali_schemes.h
Normal file
15
components/esp_adc/esp32/include/adc_cali_schemes.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file adc_cali_schemes.h
|
||||
*
|
||||
* @brief Supported calibration schemes
|
||||
*/
|
||||
|
||||
#define ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED 1
|
15
components/esp_adc/esp32c2/include/adc_cali_schemes.h
Normal file
15
components/esp_adc/esp32c2/include/adc_cali_schemes.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file adc_cali_schemes.h
|
||||
*
|
||||
* @brief Supported calibration schemes
|
||||
*/
|
||||
|
||||
//No scheme supported
|
@ -8,9 +8,13 @@
|
||||
The linker will link constructor (adc2_init_code_calibration) only when any sections inside the same file (adc2_cal_include) is used.
|
||||
Don't put any other code into this file. */
|
||||
|
||||
#include "hal/adc_hal.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal_common.h"
|
||||
#include "esp_private/adc2_wifi.h"
|
||||
#include "esp_private/adc_cali.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock;
|
||||
|
||||
/**
|
||||
* @brief Set initial code to ADC2 after calibration. ADC2 RTC and ADC2 PWDET controller share the initial code.
|
||||
@ -18,9 +22,11 @@ Don't put any other code into this file. */
|
||||
*/
|
||||
static __attribute__((constructor)) void adc2_init_code_calibration(void)
|
||||
{
|
||||
const adc_unit_t adc_n = ADC_UNIT_2;
|
||||
const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||
adc_cal_offset(adc_n, atten);
|
||||
adc_hal_calibration_init(ADC_UNIT_2);
|
||||
adc_calc_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11);
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
adc_set_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11);
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
/** Don't call `adc2_cal_include` in user code. */
|
36
components/esp_adc/esp32c3/curve_fitting_coefficients.c
Normal file
36
components/esp_adc/esp32c3/curve_fitting_coefficients.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @note Error Calculation
|
||||
* Coefficients for calculating the reading voltage error.
|
||||
* Four sets of coefficients for atten0 ~ atten3 respectively.
|
||||
*
|
||||
* For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient.
|
||||
*
|
||||
* @note {0,0} stands for unused item
|
||||
* @note In case of the overflow, these coeffcients are recorded as Absolute Value
|
||||
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
|
||||
* @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered.
|
||||
* @note ADC1 and ADC2 use same coeffients
|
||||
*/
|
||||
const uint64_t adc1_error_coef_atten[4][5][2] = {
|
||||
{{225966470500043, 1e15}, {7265418501948, 1e16}, {109410402681, 1e16}, {0, 0}, {0, 0}}, //atten0
|
||||
{{4229623392600516, 1e16}, {731527490903, 1e16}, {88166562521, 1e16}, {0, 0}, {0, 0}}, //atten1
|
||||
{{1017859239236435, 1e15}, {97159265299153, 1e16}, {149794028038, 1e16}, {0, 0}, {0, 0}}, //atten2
|
||||
{{14912262772850453, 1e16}, {228549975564099, 1e16}, {356391935717, 1e16}, {179964582, 1e16}, {42046, 1e16}} //atten3
|
||||
};
|
||||
/**
|
||||
* Term sign
|
||||
*/
|
||||
const int32_t adc1_error_sign[4][5] = {
|
||||
{-1, -1, 1, 0, 0}, //atten0
|
||||
{ 1, -1, 1, 0, 0}, //atten1
|
||||
{-1, -1, 1, 0, 0}, //atten2
|
||||
{-1, -1, 1, -1, 1} //atten3
|
||||
};
|
15
components/esp_adc/esp32c3/include/adc_cali_schemes.h
Normal file
15
components/esp_adc/esp32c3/include/adc_cali_schemes.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file adc_cali_schemes.h
|
||||
*
|
||||
* @brief Supported calibration schemes
|
||||
*/
|
||||
|
||||
#define ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED 1
|
15
components/esp_adc/esp32h2/include/adc_cali_schemes.h
Normal file
15
components/esp_adc/esp32h2/include/adc_cali_schemes.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file adc_cali_schemes.h
|
||||
*
|
||||
* @brief Supported calibration schemes
|
||||
*/
|
||||
|
||||
//Now no scheme supported
|
@ -8,9 +8,13 @@
|
||||
The linker will link constructor (adc2_init_code_calibration) only when any sections inside the same file (adc2_cal_include) is used.
|
||||
Don't put any other code into this file. */
|
||||
|
||||
#include "hal/adc_hal.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal_common.h"
|
||||
#include "esp_private/adc2_wifi.h"
|
||||
#include "esp_private/adc_cali.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock;
|
||||
|
||||
/**
|
||||
* @brief Set initial code to ADC2 after calibration. ADC2 RTC and ADC2 PWDET controller share the initial code.
|
||||
@ -18,9 +22,11 @@ Don't put any other code into this file. */
|
||||
*/
|
||||
static __attribute__((constructor)) void adc2_init_code_calibration(void)
|
||||
{
|
||||
const adc_unit_t adc_n = ADC_UNIT_2;
|
||||
const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||
adc_cal_offset(adc_n, atten);
|
||||
adc_hal_calibration_init(ADC_UNIT_2);
|
||||
adc_calc_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11);
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
adc_set_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11);
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
/** Don't call `adc2_cal_include` in user code. */
|
255
components/esp_adc/esp32s2/adc_cali_line_fitting.c
Normal file
255
components/esp_adc/esp32s2/adc_cali_line_fitting.c
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "assert.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_efuse_rtc_table.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
#include "adc_cali_interface.h"
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "adc_cali";
|
||||
|
||||
/* ------------------------ Characterization Constants ---------------------- */
|
||||
// coeff_a and coeff_b are actually floats
|
||||
// they are scaled to put them into uint32_t so that the headers do not have to be changed
|
||||
static const int coeff_a_scaling = 65536;
|
||||
static const int coeff_b_scaling = 1024;
|
||||
|
||||
|
||||
/* -------------------- Characterization Helper Data Types ------------------ */
|
||||
typedef struct {
|
||||
int adc_calib_high;
|
||||
int adc_calib_low;
|
||||
} adc_calib_data_ver1_t;
|
||||
|
||||
typedef struct {
|
||||
int adc_calib_high; // the reading of adc ...
|
||||
int adc_calib_high_voltage; // ... at this voltage (mV)
|
||||
} adc_calib_data_ver2_t;
|
||||
|
||||
typedef struct {
|
||||
char version_num;
|
||||
adc_unit_t unit_id;
|
||||
adc_atten_t atten_level;
|
||||
union {
|
||||
adc_calib_data_ver1_t ver1;
|
||||
adc_calib_data_ver2_t ver2;
|
||||
} efuse_data;
|
||||
} adc_calib_parsed_info_t;
|
||||
|
||||
|
||||
/* ------------------------ Context Structure--------------------------- */
|
||||
typedef struct {
|
||||
adc_unit_t unit_id; ///< ADC unit
|
||||
adc_atten_t atten; ///< ADC attenuation
|
||||
uint32_t coeff_a; ///< Gradient of ADC-Voltage curve
|
||||
uint32_t coeff_b; ///< Offset of ADC-Voltage curve
|
||||
} cali_chars_line_fitting_t;
|
||||
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
static bool prepare_calib_data_for(adc_unit_t unit_id, adc_atten_t atten, adc_calib_parsed_info_t *parsed_data_storage);
|
||||
/**
|
||||
* (Used in V1 of calibration scheme)
|
||||
* The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation
|
||||
* between input voltage and ADC response. (Response = A * Vinput + B)
|
||||
* A and B are scaled ints.
|
||||
* @param high The ADC response at the higher voltage of the corresponding attenuation (600mV, 800mV, 1000mV, 2000mV).
|
||||
* @param low The ADC response at the lower voltage of the corresponding attenuation (all 250mV).
|
||||
*
|
||||
*/
|
||||
static void characterize_using_two_point(adc_unit_t unit_id,
|
||||
adc_atten_t atten,
|
||||
uint32_t high,
|
||||
uint32_t low,
|
||||
uint32_t *coeff_a,
|
||||
uint32_t *coeff_b);
|
||||
/*
|
||||
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
|
||||
* with the previously done measurement when the chip was manufactured.
|
||||
* */
|
||||
static bool calculate_characterization_coefficients(const adc_calib_parsed_info_t *parsed_data, cali_chars_line_fitting_t *ctx);
|
||||
|
||||
|
||||
/* ------------------------ Interface Functions --------------------------- */
|
||||
static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage);
|
||||
|
||||
|
||||
/* ------------------------- Public API ------------------------------------- */
|
||||
esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
|
||||
ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit");
|
||||
ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation");
|
||||
//S2 Oneshot read only supports 13 bits, DMA read only supports 12 bits
|
||||
ESP_RETURN_ON_FALSE(((config->bitwidth == SOC_ADC_RTC_MAX_BITWIDTH || config->bitwidth == SOC_ADC_DIGI_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth");
|
||||
// current version only accepts encoding ver 1 and ver 2.
|
||||
uint8_t adc_encoding_version = esp_efuse_rtc_table_read_calib_version();
|
||||
ESP_RETURN_ON_FALSE(((adc_encoding_version == 1) || (adc_encoding_version == 2)), ESP_ERR_NOT_SUPPORTED, TAG, "Calibration required eFuse bits not burnt");
|
||||
|
||||
adc_cali_scheme_t *scheme = (adc_cali_scheme_t *)heap_caps_calloc(1, sizeof(adc_cali_scheme_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for adc calibration scheme");
|
||||
|
||||
cali_chars_line_fitting_t *chars = (cali_chars_line_fitting_t *)heap_caps_calloc(1, sizeof(cali_chars_line_fitting_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_GOTO_ON_FALSE(chars, ESP_ERR_NO_MEM, err, TAG, "no memory for the calibration characteristics");
|
||||
|
||||
scheme->raw_to_voltage = cali_raw_to_voltage;
|
||||
scheme->ctx = chars;
|
||||
|
||||
adc_calib_parsed_info_t efuse_parsed_data = {0};
|
||||
bool success = prepare_calib_data_for(config->unit_id, config->atten, &efuse_parsed_data);
|
||||
assert(success);
|
||||
success = calculate_characterization_coefficients(&efuse_parsed_data, chars);
|
||||
assert(success);
|
||||
ESP_LOGD(TAG, "adc%d (atten leven %d) calibration done: A:%d B:%d\n", config->unit_id, config->atten, chars->coeff_a, chars->coeff_b);
|
||||
chars->unit_id = config->unit_id;
|
||||
chars->atten = config->atten;
|
||||
|
||||
*ret_handle = scheme;
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (scheme) {
|
||||
free(scheme);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
free(handle->ctx);
|
||||
handle->ctx = NULL;
|
||||
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------ Interface Functions --------------------------- */
|
||||
static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage)
|
||||
{
|
||||
//pointers are checked in the upper layer
|
||||
|
||||
cali_chars_line_fitting_t *ctx = arg;
|
||||
*voltage = raw * ctx->coeff_a / coeff_a_scaling + ctx->coeff_b / coeff_b_scaling;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------- Characterization Functions ----------------------- */
|
||||
static bool prepare_calib_data_for(adc_unit_t unit_id, adc_atten_t atten, adc_calib_parsed_info_t *parsed_data_storage)
|
||||
{
|
||||
int version_num = esp_efuse_rtc_table_read_calib_version();
|
||||
int tag;
|
||||
parsed_data_storage->version_num = version_num;
|
||||
parsed_data_storage->unit_id = unit_id;
|
||||
parsed_data_storage->atten_level = atten;
|
||||
switch (version_num) {
|
||||
case 1:
|
||||
// note: use the unit_id as in hal, which start from 0.
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VLOW);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VHIGH);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
break;
|
||||
case 2:
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V2_PARAM_VHIGH);
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
|
||||
switch (parsed_data_storage->atten_level) {
|
||||
case ADC_ATTEN_DB_0:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 600;
|
||||
break;
|
||||
case ADC_ATTEN_DB_2_5:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 800;
|
||||
break;
|
||||
case ADC_ATTEN_DB_6:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 1000;
|
||||
break;
|
||||
case ADC_ATTEN_DB_11:
|
||||
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 2000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// fall back to case 1 with zeros as params.
|
||||
parsed_data_storage->version_num = 1;
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VLOW);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
|
||||
tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VHIGH);
|
||||
parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Used in V1 of calibration scheme)
|
||||
* The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation
|
||||
* between input voltage and ADC response. (Response = A * Vinput + B)
|
||||
* A and B are scaled ints.
|
||||
* @param high The ADC response at the higher voltage of the corresponding attenuation (600mV, 800mV, 1000mV, 2000mV).
|
||||
* @param low The ADC response at the lower voltage of the corresponding attenuation (all 250mV).
|
||||
*
|
||||
*/
|
||||
static void characterize_using_two_point(adc_unit_t unit_id,
|
||||
adc_atten_t atten,
|
||||
uint32_t high,
|
||||
uint32_t low,
|
||||
uint32_t *coeff_a,
|
||||
uint32_t *coeff_b)
|
||||
{
|
||||
// once we have recovered the reference high(Dhigh) and low(Dlow) readings, we can calculate a and b from
|
||||
// the measured high and low readings
|
||||
static const uint32_t v_high[] = {600, 800, 1000, 2000};
|
||||
static const uint32_t v_low = 250;
|
||||
*coeff_a = coeff_a_scaling * (v_high[atten] - v_low) / (high - low);
|
||||
*coeff_b = coeff_b_scaling * (v_low * high - v_high[atten] * low) / (high - low);
|
||||
}
|
||||
|
||||
/*
|
||||
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
|
||||
* with the previously done measurement when the chip was manufactured.
|
||||
* */
|
||||
static bool calculate_characterization_coefficients(const adc_calib_parsed_info_t *parsed_data, cali_chars_line_fitting_t *ctx)
|
||||
{
|
||||
switch (parsed_data->version_num) {
|
||||
case 1:
|
||||
ESP_LOGD(TAG, "Calib V1, low%dmV, high%dmV\n", parsed_data->efuse_data.ver1.adc_calib_low, parsed_data->efuse_data.ver1.adc_calib_high);
|
||||
|
||||
characterize_using_two_point(parsed_data->unit_id, parsed_data->atten_level,
|
||||
parsed_data->efuse_data.ver1.adc_calib_high, parsed_data->efuse_data.ver1.adc_calib_low,
|
||||
&(ctx->coeff_a), &(ctx->coeff_b));
|
||||
break;
|
||||
case 2:
|
||||
ESP_LOGD(TAG, "Calib V2, volt%dmV\n", parsed_data->efuse_data.ver2.adc_calib_high);
|
||||
ctx->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver2.adc_calib_high_voltage /
|
||||
parsed_data->efuse_data.ver2.adc_calib_high;
|
||||
ctx->coeff_b = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
15
components/esp_adc/esp32s2/include/adc_cali_schemes.h
Normal file
15
components/esp_adc/esp32s2/include/adc_cali_schemes.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file adc_cali_schemes.h
|
||||
*
|
||||
* @brief Supported calibration schemes
|
||||
*/
|
||||
|
||||
#define ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED 1
|
48
components/esp_adc/esp32s3/curve_fitting_coefficients.c
Normal file
48
components/esp_adc/esp32s3/curve_fitting_coefficients.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @note Error Calculation
|
||||
* Coefficients for calculating the reading voltage error.
|
||||
* Four sets of coefficients for atten0 ~ atten3 respectively.
|
||||
*
|
||||
* For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient.
|
||||
*
|
||||
* @note {0,0} stands for unused item
|
||||
* @note In case of the overflow, these coeffcients are recorded as Absolute Value
|
||||
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
|
||||
* @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered.
|
||||
*/
|
||||
const uint64_t adc1_error_coef_atten[4][5][2] = {
|
||||
{{27856531419538344, 1e16}, {50871540569528, 1e16}, {9798249589, 1e15}, {0, 0}, {0, 0}}, //ADC1 atten0
|
||||
{{29831022915028695, 1e16}, {49393185868806, 1e16}, {101379430548, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten1
|
||||
{{23285545746296417, 1e16}, {147640181047414, 1e16}, {208385525314, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten2
|
||||
{{644403418269478, 1e15}, {644334888647536, 1e16}, {1297891447611, 1e16}, {70769718, 1e15}, {13515, 1e15}} //ADC1 atten3
|
||||
};
|
||||
const uint64_t adc2_error_coef_atten[4][5][2] = {
|
||||
{{25668651654328927, 1e16}, {1353548869615, 1e16}, {36615265189, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten0
|
||||
{{23690184690298404, 1e16}, {66319894226185, 1e16}, {118964995959, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten1
|
||||
{{9452499397020617, 1e16}, {200996773954387, 1e16}, {259011467956, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten2
|
||||
{{12247719764336924,1e16}, {755717904943462, 1e16}, {1478791187119, 1e16}, {79672528, 1e15}, {15038, 1e15}} //ADC2 atten3
|
||||
};
|
||||
/**
|
||||
* Term sign
|
||||
*/
|
||||
const int32_t adc1_error_sign[4][5] = {
|
||||
{-1, -1, 1, 0, 0}, //ADC1 atten0
|
||||
{-1, -1, 1, 0, 0}, //ADC1 atten1
|
||||
{-1, -1, 1, 0, 0}, //ADC1 atten2
|
||||
{-1, -1, 1, -1, 1} //ADC1 atten3
|
||||
};
|
||||
const int32_t adc2_error_sign[4][5] = {
|
||||
{-1, 1, 1, 0, 0}, //ADC2 atten0
|
||||
{-1, -1, 1, 0, 0}, //ADC2 atten1
|
||||
{-1, -1, 1, 0, 0}, //ADC2 atten2
|
||||
{ 1, -1, 1, -1, 1} //ADC2 atten3
|
||||
};
|
15
components/esp_adc/esp32s3/include/adc_cali_schemes.h
Normal file
15
components/esp_adc/esp32s3/include/adc_cali_schemes.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file adc_cali_schemes.h
|
||||
*
|
||||
* @brief Supported calibration schemes
|
||||
*/
|
||||
|
||||
#define ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED 1
|
59
components/esp_adc/include/esp_adc/adc_cali.h
Normal file
59
components/esp_adc/include/esp_adc/adc_cali.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADC calibration handle
|
||||
*/
|
||||
typedef struct adc_cali_scheme_t *adc_cali_handle_t;
|
||||
|
||||
/**
|
||||
* @brief ADC calibration scheme
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_CALI_SCHEME_VER_LINE_FITTING = BIT(0), ///< Line fitting scheme
|
||||
ADC_CALI_SCHEME_VER_CURVE_FITTING = BIT(1), ///< Curve fitting scheme
|
||||
} adc_cali_scheme_ver_t;
|
||||
|
||||
/**
|
||||
* @brief Check the supported ADC calibration scheme
|
||||
*
|
||||
* @param[out] scheme_mask Supported ADC calibration scheme(s)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NOT_SUPPORTED: No supported calibration scheme
|
||||
*/
|
||||
esp_err_t adc_cali_check_scheme(adc_cali_scheme_ver_t *scheme_mask);
|
||||
|
||||
/**
|
||||
* @brief Convert ADC raw data to calibrated voltage
|
||||
*
|
||||
* @param[in] handle ADC calibration handle
|
||||
* @param[in] raw ADC raw data
|
||||
* @param[out] voltage Calibrated ADC voltage (in mV)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state, scheme didn't registered
|
||||
*/
|
||||
esp_err_t adc_cali_raw_to_voltage(adc_cali_handle_t handle, int raw, int *voltage);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
135
components/esp_adc/include/esp_adc/adc_cali_scheme.h
Normal file
135
components/esp_adc/include/esp_adc/adc_cali_scheme.h
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "adc_cali_schemes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
Curve Fitting Calibration Scheme
|
||||
---------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
adc_unit_t unit_id; ///< ADC unit
|
||||
adc_atten_t atten; ///< ADC attenuation
|
||||
adc_bitwidth_t bitwidth; ///< ADC raw output bitwidth
|
||||
} adc_cali_curve_fitting_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create a Curve Fitting calibration scheme
|
||||
*
|
||||
* After creating, you'll get a handle to this scheme. Then you can use the driver APIS in `esp_adc/adc_cali.h` to do the
|
||||
* ADC calibration via the handle you get.
|
||||
*
|
||||
* @param[in] config Initial configurations
|
||||
* @param[out] handle ADC calibration handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NO_MEM: No enough memory
|
||||
* - ESP_ERR_NOT_SUPPORTED: Scheme required eFuse bits not burnt
|
||||
*/
|
||||
esp_err_t adc_cali_create_scheme_curve_fitting(const adc_cali_curve_fitting_config_t *config, adc_cali_handle_t *ret_handle);
|
||||
|
||||
/**
|
||||
* @brief Delete the Curve Fitting calibration scheme handle
|
||||
*
|
||||
* @param[in] handle ADC calibration handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
*/
|
||||
esp_err_t adc_cali_delete_scheme_curve_fitting(adc_cali_handle_t handle);
|
||||
#endif // #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
|
||||
|
||||
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
Line Fitting Calibration Scheme
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Type of calibration value used in line fitting scheme characterization
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF = 0, ///< Characterization based on reference voltage stored in eFuse
|
||||
ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP = 1, ///< Characterization based on Two Point values stored in eFuse
|
||||
ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF = 2, ///< Characterization based on default reference voltage
|
||||
} adc_cali_line_fitting_efuse_val_t;
|
||||
|
||||
typedef struct {
|
||||
adc_unit_t unit_id; ///< ADC unit
|
||||
adc_atten_t atten; ///< ADC attenuation
|
||||
adc_bitwidth_t bitwidth; ///< ADC raw output bitwidth
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/**
|
||||
* @brief Default ADC reference voltage in mV.
|
||||
*
|
||||
* Use this when the ADC calibration value is `ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF`.
|
||||
* If others, driver will use the calibration code burnt in the eFuse for calibration.
|
||||
*/
|
||||
uint32_t default_vref;
|
||||
#endif
|
||||
} adc_cali_line_fitting_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create a Line Fitting calibration scheme
|
||||
*
|
||||
* After creating, you'll get a handle to this scheme. Then you can use the driver APIS in `esp_adc/adc_cali.h` to do the
|
||||
* ADC calibration via the handle you get.
|
||||
*
|
||||
* @param[in] config Initial configurations
|
||||
* @param[out] handle ADC calibration handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NO_MEM: No enough memory
|
||||
* - ESP_ERR_NOT_SUPPORTED: Scheme required eFuse bits not burnt
|
||||
*/
|
||||
esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle);
|
||||
|
||||
/**
|
||||
* @brief Delete the Line Fitting calibration scheme handle
|
||||
*
|
||||
* @param[in] handle ADC calibration handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
*/
|
||||
esp_err_t adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/**
|
||||
* @brief Helper function to quickly check the ADC calibration code burnt on your eFuse
|
||||
*
|
||||
* @note If `cali_val` equals to `ESP_ADC_CALI_VAL_DEFAULT_VREF`, please set the `default_vref`
|
||||
* when creating this scheme (See `ESP_ADC_CALI_SCHEME_VER_LINE_FITTING_init_t`)
|
||||
*
|
||||
* @param[out] cali_val See `esp_adc_cali_value_t`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NOT_SUPPORTED: Scheme required eFuse bits not burnt
|
||||
*/
|
||||
esp_err_t adc_cali_scheme_line_fitting_check_efuse(adc_cali_line_fitting_efuse_val_t *cali_val);
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
#endif // #if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
232
components/esp_adc/include/esp_adc/adc_continuous.h
Normal file
232
components/esp_adc/include/esp_adc/adc_continuous.h
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_ADC_DMA_SUPPORTED
|
||||
|
||||
/**
|
||||
* @brief Driver Backgrounds
|
||||
*
|
||||
* --------------------------------------------------------------------------------------------------------
|
||||
* | Conversion Frame |
|
||||
* --------------------------------------------------------------------------------------------------------
|
||||
* | Conversion Result | Conversion Result | Conversion Result | Conversion Result | ... |
|
||||
* --------------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* ADC continuous mode conversion is made up with multiple Conversion Frames.
|
||||
* - Conversion Frame: One Conversion Frame contains multiple Conversion Results.
|
||||
* Conversion Frame size is configured in `adc_continuous_handle_cfg_t:conv_frame_size`, in bytes.
|
||||
* Each time driver see an interrupt event, this means one Conversion Frame is generated by the hardware.
|
||||
* - Conversion Result: One Conversion Result contains multiple bytes (see `SOC_ADC_DIGI_RESULT_BYTES`). Its
|
||||
* structure is `adc_digi_output_data_t`, including ADC Unit, ADC Channel and Raw Data.
|
||||
*
|
||||
* For example:
|
||||
* conv_frame_size = 100,
|
||||
* then one Conversion Frame contains (100 / `SOC_ADC_DIGI_RESULT_BYTES`) pieces of Conversion Results
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief ADC read max timeout value, it may make the ``adc_continuous_read`` block forever if the OS supports
|
||||
*/
|
||||
#define ADC_MAX_DELAY UINT32_MAX
|
||||
|
||||
/**
|
||||
* @brief Type of adc continuous mode driver handle
|
||||
*/
|
||||
typedef struct adc_continuous_ctx_t *adc_continuous_handle_t;
|
||||
|
||||
/**
|
||||
* @brief ADC continuous mode driver initial configurations
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t max_store_buf_size; ///< Max length of the conversion Results that driver can store, in bytes.
|
||||
uint32_t conv_frame_size; ///< Conversion frame size, in bytes. This should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`.
|
||||
} adc_continuous_handle_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief ADC continuous mode driver configurations
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t pattern_num; ///< Number of ADC channels that will be used
|
||||
adc_digi_pattern_config_t *adc_pattern; ///< List of configs for each ADC channel that will be used
|
||||
uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Please refer to `soc/soc_caps.h` to know available sampling frequency range*/
|
||||
adc_digi_convert_mode_t conv_mode; ///< ADC DMA conversion mode, see `adc_digi_convert_mode_t`.
|
||||
adc_digi_output_format_t format; ///< ADC DMA conversion output format, see `adc_digi_output_format_t`.
|
||||
} adc_continuous_config_t;
|
||||
|
||||
/**
|
||||
* @brief Event data structure
|
||||
* @note The `conv_frame_buffer` is maintained by the driver itself, so never free this piece of memory.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *conv_frame_buffer; ///< Pointer to conversion result buffer for one conversion frame
|
||||
uint32_t size; ///< Conversion frame size
|
||||
} adc_continuous_evt_data_t;
|
||||
|
||||
/**
|
||||
* @brief Prototype of ADC continuous mode event callback
|
||||
*
|
||||
* @param[in] handle ADC continuous mode driver handle
|
||||
* @param[in] edata Pointer to ADC contunuous mode event data
|
||||
* @param[in] user_data User registered context, registered when in `adc_continuous_register_event_callbacks()`
|
||||
*
|
||||
* @return Whether a high priority task is woken up by this function
|
||||
*/
|
||||
typedef bool (*adc_continuous_callback_t)(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Group of ADC continuous mode callbacks
|
||||
*
|
||||
* @note These callbacks are all running in an ISR environment.
|
||||
* @note When CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||
* Involved variables should be in internal RAM as well.
|
||||
*/
|
||||
typedef struct {
|
||||
adc_continuous_callback_t on_conv_done; ///< Event callback, invoked when one conversion frame is done. See `@brief Driver Backgrounds` to konw `conversion frame` concept.
|
||||
adc_continuous_callback_t on_pool_ovf; ///< Event callback, invoked when the internal pool is full.
|
||||
} adc_continuous_evt_cbs_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize ADC continuous driver and get a handle to it
|
||||
*
|
||||
* @param[in] hdl_config Pointer to ADC initilization config. Refer to ``adc_continuous_handle_cfg_t``.
|
||||
* @param[out] ret_handle ADC continuous mode driver handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
|
||||
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
|
||||
* - ESP_ERR_NO_MEM If out of memory
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_config, adc_continuous_handle_t *ret_handle);
|
||||
|
||||
/**
|
||||
* @brief Set ADC continuous mode required configurations
|
||||
*
|
||||
* @param[in] handle ADC continuous mode driver handle
|
||||
* @param[in] config Refer to ``adc_digi_config_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
|
||||
* - ESP_ERR_INVALID_ARG: If the combination of arguments is invalid.
|
||||
* - ESP_OK: On success
|
||||
*/
|
||||
esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_continuous_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Register callbacks
|
||||
*
|
||||
* @note User can deregister a previously registered callback by calling this function and setting the to-be-deregistered callback member int
|
||||
* the `cbs` structure to NULL.
|
||||
* @note When CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||
* Involved variables (including `user_data`) should be in internal RAM as well.
|
||||
* @note You should only call this API when the ADC continuous mode driver isn't started. Check return value to know this.
|
||||
*
|
||||
* @param[in] handle ADC continuous mode driver handle
|
||||
* @param[in] cbs Group of callback functions
|
||||
* @param[in] user_data User data, which will be delivered to the callback functions directly
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
|
||||
*/
|
||||
esp_err_t adc_continuous_register_event_callbacks(adc_continuous_handle_t handle, const adc_continuous_evt_cbs_t *cbs, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Start the ADC under continuous mode. After this, the hardware starts working.
|
||||
*
|
||||
* @param[in] handle ADC continuous mode driver handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t adc_continuous_start(adc_continuous_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Read bytes from ADC under continuous mode.
|
||||
*
|
||||
* @param[in] handle ADC continuous mode driver handle
|
||||
* @param[out] buf Conversion result buffer to read from ADC. Suggest convert to `adc_digi_output_data_t` for `ADC Conversion Results`.
|
||||
* See `@brief Driver Backgrounds` to know this concept.
|
||||
* @param[in] length_max Expected length of the Conversion Results read from the ADC, in bytes.
|
||||
* @param[out] out_length Real length of the Conversion Results read from the ADC via this API, in bytes.
|
||||
* @param[in] timeout_ms Time to wait for data via this API, in millisecond.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid. Usually it means the ADC sampling rate is faster than the task processing rate.
|
||||
* - ESP_ERR_TIMEOUT Operation timed out
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t adc_continuous_read(adc_continuous_handle_t handle, uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Stop the ADC. After this, the hardware stops working.
|
||||
*
|
||||
* @param[in] handle ADC continuous mode driver handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t adc_continuous_stop(adc_continuous_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the ADC continuous driver.
|
||||
*
|
||||
* @param[in] handle ADC continuous mode driver handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t adc_continuous_deinit(adc_continuous_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Get ADC channel from the given GPIO number
|
||||
*
|
||||
* @param[in] io_num GPIO number
|
||||
* @param[out] unit_id ADC unit
|
||||
* @param[out] channel ADC channel
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NOT_FOUND: The IO is not a valid ADC pad
|
||||
*/
|
||||
esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel);
|
||||
|
||||
/**
|
||||
* @brief Get GPIO number from the given ADC channel
|
||||
*
|
||||
* @param[in] unit_id ADC unit
|
||||
* @param[in] channel ADC channel
|
||||
* @param[out] io_num GPIO number
|
||||
*
|
||||
* @param
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
*/
|
||||
esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num);
|
||||
|
||||
#endif // #if SOC_ADC_DMA_SUPPORTED
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
130
components/esp_adc/include/esp_adc/adc_oneshot.h
Normal file
130
components/esp_adc/include/esp_adc/adc_oneshot.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of ADC unit handle for oneshot mode
|
||||
*/
|
||||
typedef struct adc_oneshot_unit_ctx_t *adc_oneshot_unit_handle_t;
|
||||
|
||||
/**
|
||||
* @brief ADC oneshot driver initial configurations
|
||||
*/
|
||||
typedef struct {
|
||||
adc_unit_t unit_id; ///< ADC unit
|
||||
adc_ulp_mode_t ulp_mode; ///< ADC controlled by ULP, see `adc_ulp_mode_t`
|
||||
} adc_oneshot_unit_init_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief ADC channel configurations
|
||||
*/
|
||||
typedef struct {
|
||||
adc_atten_t atten; ///< ADC attenuation
|
||||
adc_bitwidth_t bitwidth; ///< ADC conversion result bits
|
||||
} adc_oneshot_chan_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief Create a handle to a specific ADC unit
|
||||
*
|
||||
* @note This API is thread-safe. For more details, see ADC programming guide
|
||||
*
|
||||
* @param[in] init_config Driver initial configurations
|
||||
* @param[out] ret_unit ADC unit handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||
* - ESP_ERR_NO_MEM: No memory
|
||||
* - ESP_ERR_NOT_FOUND: The ADC peripheral to be claimed is already in use
|
||||
*/
|
||||
esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, adc_oneshot_unit_handle_t *ret_unit);
|
||||
|
||||
/**
|
||||
* @brief Set ADC oneshot mode required configurations
|
||||
*
|
||||
* @note This API is thread-safe. For more details, see ADC programming guide
|
||||
*
|
||||
* @param[in] handle ADC handle
|
||||
* @param[in] channel ADC channel to be configured
|
||||
* @param[in] config ADC configurations
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||
*/
|
||||
esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_channel_t channel, const adc_oneshot_chan_cfg_t *config);
|
||||
|
||||
/**
|
||||
* @brief Get one ADC conversion raw result
|
||||
*
|
||||
* @note This API is thread-safe. For more details, see ADC programming guide
|
||||
* @note This API should NOT be called in an ISR context
|
||||
*
|
||||
* @param[in] handle ADC handle
|
||||
* @param[in] chan ADC channel
|
||||
* @param[out] out_raw ADC conversion raw result
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||
* - ESP_ERR_TIMEOUT: Timeout, the ADC result is invalid
|
||||
*/
|
||||
esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw);
|
||||
|
||||
/**
|
||||
* @brief Delete the ADC unit handle
|
||||
*
|
||||
* @note This API is thread-safe. For more details, see ADC programming guide
|
||||
*
|
||||
* @param[in] handle ADC handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||
* - ESP_ERR_NOT_FOUND: The ADC peripheral to be disclaimed isn't in use
|
||||
*/
|
||||
esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Get ADC channel from the given GPIO number
|
||||
*
|
||||
* @param[in] io_num GPIO number
|
||||
* @param[out] unit_id ADC unit
|
||||
* @param[out] channel ADC channel
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NOT_FOUND: The IO is not a valid ADC pad
|
||||
*/
|
||||
esp_err_t adc_oneshot_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel);
|
||||
|
||||
/**
|
||||
* @brief Get GPIO number from the given ADC channel
|
||||
*
|
||||
* @param[in] unit_id ADC unit
|
||||
* @param[in] channel ADC channel
|
||||
* @param[out] io_num GPIO number
|
||||
*
|
||||
* @param
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
*/
|
||||
esp_err_t adc_oneshot_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -21,19 +21,20 @@ extern "C" {
|
||||
* The WIFI module may have to wait for a short time for the current conversion (if exist) to finish.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
|
||||
*/
|
||||
esp_err_t adc2_wifi_acquire(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief For WIFI module to let other tasks use the ADC2 when WIFI is not work.
|
||||
*
|
||||
* Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``.
|
||||
* Call this function to release the occupation of ADC2 by WIFI.
|
||||
*
|
||||
* @return always return ESP_OK.
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet
|
||||
*/
|
||||
esp_err_t adc2_wifi_release(void);
|
||||
|
60
components/esp_adc/include/esp_private/adc_lock.h
Normal file
60
components/esp_adc/include/esp_private/adc_lock.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Acquire ADC lock by unit
|
||||
*
|
||||
* The lock acquiring sequence will be: ADC1, ADC2, ...
|
||||
*
|
||||
* @note If any of the locks are taken, this API will wait until the lock is successfully acquired.
|
||||
*
|
||||
* @param[in] unit_mask ADC unit mask
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
*/
|
||||
esp_err_t adc_lock_acquire(adc_unit_t unit_mask);
|
||||
|
||||
/**
|
||||
* @brief Release ADC lock by unit
|
||||
*
|
||||
* The lock releasing sequence will be: ..., ADC2, ADC1
|
||||
*
|
||||
* @param[in] unit_mask ADC unit mask
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet
|
||||
*/
|
||||
esp_err_t adc_lock_release(adc_unit_t unit_mask);
|
||||
|
||||
/**
|
||||
* @brief Try to acquire ADC lock by unit
|
||||
*
|
||||
* The lock acquiring sequence will be: ADC1, ADC2, ...
|
||||
*
|
||||
* @note If any of the locks are taken, this API will return immediately with an error `ESP_ERR_TIMEOUT`
|
||||
*
|
||||
* @param[in] unit_mask ADC unit mask
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_TIMEOUT: Lock(s) is taken already
|
||||
*/
|
||||
esp_err_t adc_lock_try_acquire(adc_unit_t unit_mask);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
130
components/esp_adc/include/esp_private/adc_private.h
Normal file
130
components/esp_adc/include/esp_private/adc_private.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// DO NOT USE THESE APIS IN ANY APPLICATIONS
|
||||
|
||||
#pragma once
|
||||
#include "esp_err.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* For those who use APB_SARADC periph
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Claim the usage of the APB_SARADC periph
|
||||
*
|
||||
* Reference count inside
|
||||
*/
|
||||
void adc_apb_periph_claim(void);
|
||||
|
||||
/**
|
||||
* @brief Free the usage of the APB_SARADC periph
|
||||
*
|
||||
* Reference count inside
|
||||
*/
|
||||
void adc_apb_periph_free(void);
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* ADC Power
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Acquire the ADC Power
|
||||
*/
|
||||
void adc_power_acquire(void);
|
||||
|
||||
/**
|
||||
* @brief Release the ADC Power
|
||||
*/
|
||||
void adc_power_release(void);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC IOs
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Get ADC channel from the given GPIO number
|
||||
*
|
||||
* @param[in] io_num GPIO number
|
||||
* @param[out] unit_id ADC unit
|
||||
* @param[out] channel ADC channel
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NOT_FOUND: The IO is not a valid ADC pad
|
||||
*/
|
||||
esp_err_t adc_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel);
|
||||
|
||||
/**
|
||||
* @brief Get GPIO number from the given ADC channel
|
||||
*
|
||||
* @param[in] unit_id ADC unit
|
||||
* @param[in] channel ADC channel
|
||||
* @param[out] io_num GPIO number
|
||||
*
|
||||
* @param
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
*/
|
||||
esp_err_t adc_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num);
|
||||
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
ADC Hardware Calibration
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Calculate the ADC HW calibration code. (Based on the pre-stored efuse or actual calibration)
|
||||
*
|
||||
* @param adc_n ADC unit to calibrate
|
||||
* @param atten Attenuation to use
|
||||
*/
|
||||
void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten);
|
||||
|
||||
/**
|
||||
* @brief Set the ADC HW calibration code.
|
||||
*
|
||||
* @param adc_n ADC unit to calibrate
|
||||
* @param atten Attenuation to use
|
||||
*/
|
||||
void adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten);
|
||||
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Oneshot Read API ISR Version
|
||||
---------------------------------------------------------------*/
|
||||
typedef struct adc_oneshot_unit_ctx_t *adc_oneshot_unit_handle_t;
|
||||
/**
|
||||
* @brief ISR version to get one ADC conversion raw result
|
||||
*
|
||||
* @note This API only provide atomic register settings, without hardware resources protection. When other drivers are using
|
||||
* SAR-ADCs, calling this API may get wrong ADC result.
|
||||
* @note This API can be called in an ISR context.
|
||||
* @note Strongly suggest using this function when there's no concurrent hardware usage to the ADC. You can refer to ADC Oneshot
|
||||
* Programming Guide to know ADC Hardware Limitations
|
||||
*
|
||||
* @param[in] handle ADC handle
|
||||
* @param[in] chan ADC channel
|
||||
* @param[out] out_raw ADC conversion raw result
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state, the ADC result is invalid
|
||||
*/
|
||||
esp_err_t adc_oneshot_read_isr(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
46
components/esp_adc/interface/adc_cali_interface.h
Normal file
46
components/esp_adc/interface/adc_cali_interface.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct adc_cali_scheme_t adc_cali_scheme_t;
|
||||
|
||||
/**
|
||||
* @brief ADC Calibration Scheme Interface and Context
|
||||
*/
|
||||
struct adc_cali_scheme_t {
|
||||
|
||||
/**
|
||||
* @brief Convert ADC raw data to calibrated voltage
|
||||
*
|
||||
* @param[in] arg ///< ADC calibration scheme specific context
|
||||
* @param[in] raw ///< ADC raw data
|
||||
* @param[out] voltage ///< Calibrated ADC voltage (in mV)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state, scheme didn't registered
|
||||
*/
|
||||
esp_err_t (*raw_to_voltage)(void *arg, int raw, int *voltage);
|
||||
|
||||
/**
|
||||
* @brief ADC calibration specific contexts
|
||||
* Can be customized to difference calibration schemes
|
||||
*/
|
||||
void *ctx;
|
||||
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
5
components/esp_adc/linker.lf
Normal file
5
components/esp_adc/linker.lf
Normal file
@ -0,0 +1,5 @@
|
||||
[mapping:esp_adc]
|
||||
archive: libesp_adc.a
|
||||
entries:
|
||||
if ADC_ONESHOT_CTRL_FUNC_IN_IRAM = y:
|
||||
adc_oneshot: adc_oneshot_read_isr (noflash)
|
20
components/esp_adc/test_apps/adc/CMakeLists.txt
Normal file
20
components/esp_adc/test_apps/adc/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(adc_test)
|
||||
|
||||
if(CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||
add_custom_target(check_test_app_sections ALL
|
||||
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
|
||||
--rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/esp_adc/
|
||||
--elf-file ${CMAKE_BINARY_DIR}/adc_test.elf
|
||||
find-refs
|
||||
--from-sections=.iram0.text
|
||||
--to-sections=.flash.text,.flash.rodata
|
||||
--exit-code
|
||||
DEPENDS ${elf}
|
||||
)
|
||||
endif()
|
2
components/esp_adc/test_apps/adc/README.md
Normal file
2
components/esp_adc/test_apps/adc/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- |
|
11
components/esp_adc/test_apps/adc/main/CMakeLists.txt
Normal file
11
components/esp_adc/test_apps/adc/main/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_adc.c"
|
||||
"test_adc_performance.c"
|
||||
"test_adc_driver.c"
|
||||
"test_adc_driver_iram.c"
|
||||
"test_common_adc.c")
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
WHOLE_ARCHIVE)
|
260
components/esp_adc/test_apps/adc/main/test_adc.c
Normal file
260
components/esp_adc/test_apps/adc/main/test_adc.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/adc_periph.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "test_common_adc.h"
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "TEST_ADC";
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC General Macros
|
||||
---------------------------------------------------------------*/
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_TEST_CHAN0 ADC_CHANNEL_4
|
||||
#define ADC1_TEST_CHAN1 ADC_CHANNEL_5
|
||||
#define ADC2_TEST_CHAN0 ADC_CHANNEL_0
|
||||
static const char *TAG_CH[2][10] = {{"ADC1_CH4", "ADC1_CH5"}, {"ADC2_CH0"}};
|
||||
#else
|
||||
#define ADC1_TEST_CHAN0 ADC_CHANNEL_2
|
||||
#define ADC1_TEST_CHAN1 ADC_CHANNEL_3
|
||||
#define ADC2_TEST_CHAN0 ADC_CHANNEL_0
|
||||
static const char *TAG_CH[2][10] = {{"ADC1_CH2", "ADC1_CH3"}, {"ADC2_CH0"}};
|
||||
#endif
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Oneshot High / Low test
|
||||
---------------------------------------------------------------*/
|
||||
TEST_CASE("ADC oneshot high/low test", "[adc_oneshot]")
|
||||
{
|
||||
static int adc_raw[2][10];
|
||||
|
||||
//-------------ADC1 Init---------------//
|
||||
adc_oneshot_unit_handle_t adc1_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config1 = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
//-------------ADC2 Init---------------//
|
||||
adc_oneshot_unit_handle_t adc2_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config2 = {
|
||||
.unit_id = ADC_UNIT_2,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_new_unit(&init_config2, &adc2_handle));
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
|
||||
//-------------ADC1 TEST Channel 0 Config---------------//
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, ADC1_TEST_CHAN0, &config));
|
||||
|
||||
//-------------ADC1 TEST Channel 1 Config---------------//
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, ADC1_TEST_CHAN1, &config));
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
//-------------ADC2 TEST Channel 0 Config---------------//
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(adc2_handle, ADC2_TEST_CHAN0, &config));
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0);
|
||||
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN0, &adc_raw[0][0]));
|
||||
ESP_LOGI(TAG_CH[0][0], "raw data: %d", adc_raw[0][0]);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[0][0]);
|
||||
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN1, 1);
|
||||
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN1, &adc_raw[0][1]));
|
||||
ESP_LOGI(TAG_CH[0][1], "raw data: %d", adc_raw[0][1]);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[0][1]);
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
test_adc_set_io_level(ADC_UNIT_2, ADC2_TEST_CHAN0, 0);
|
||||
TEST_ESP_OK(adc_oneshot_read(adc2_handle, ADC2_TEST_CHAN0, &adc_raw[1][0]));
|
||||
ESP_LOGI(TAG_CH[1][0], "raw data: %d", adc_raw[1][0]);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[1][0]);
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
|
||||
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1);
|
||||
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN0, &adc_raw[0][0]));
|
||||
ESP_LOGI(TAG_CH[0][0], "raw data: %d", adc_raw[0][0]);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[0][0]);
|
||||
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN1, 0);
|
||||
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN1, &adc_raw[0][1]));
|
||||
ESP_LOGI(TAG_CH[0][1], "raw data: %d", adc_raw[0][1]);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[0][1]);
|
||||
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
test_adc_set_io_level(ADC_UNIT_2, ADC2_TEST_CHAN0, 1);
|
||||
TEST_ESP_OK(adc_oneshot_read(adc2_handle, ADC2_TEST_CHAN0, &adc_raw[1][0]));
|
||||
ESP_LOGI(TAG_CH[1][0], "raw data: %d", adc_raw[1][0]);
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[1][0]);
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
|
||||
|
||||
TEST_ESP_OK(adc_oneshot_del_unit(adc1_handle));
|
||||
#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
TEST_ESP_OK(adc_oneshot_del_unit(adc2_handle));
|
||||
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
ADC Oneshot with Light Sleep
|
||||
---------------------------------------------------------------*/
|
||||
#include <inttypes.h>
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "soc/regi2c_saradc.h"
|
||||
|
||||
#define TEST_REGI2C_ANA_CALI_BYTE_NUM 8
|
||||
|
||||
static void s_adc_oneshot_with_sleep(adc_unit_t unit_id, adc_channel_t channel)
|
||||
{
|
||||
adc_atten_t atten[SOC_ADC_ATTEN_NUM] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_2_5, ADC_ATTEN_DB_6, ADC_ATTEN_DB_11};
|
||||
//-------------ADC Init---------------//
|
||||
adc_oneshot_unit_handle_t adc_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config = {
|
||||
.unit_id = unit_id,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_new_unit(&init_config, &adc_handle));
|
||||
|
||||
//-------------ADC Channel Config---------------//
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = SOC_ADC_RTC_MAX_BITWIDTH,
|
||||
};
|
||||
|
||||
//-------------ADC Calibration Init---------------//
|
||||
bool do_calibration = false;
|
||||
adc_cali_handle_t cali_handle[SOC_ADC_ATTEN_NUM] = {};
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
do_calibration = test_adc_calibration_init(unit_id, i, SOC_ADC_RTC_MAX_BITWIDTH, &cali_handle[i]);
|
||||
}
|
||||
if (!do_calibration) {
|
||||
ESP_LOGW(TAG, "No efuse bits burnt, only test the regi2c analog register values");
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
|
||||
//-------------ADC Channel Config---------------//
|
||||
config.atten = atten[i];
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(adc_handle, channel, &config));
|
||||
printf("Test with atten: %d\n", atten[i]);
|
||||
|
||||
//---------------------------------Before Sleep-----------------------------------//
|
||||
printf("Before Light Sleep\n");
|
||||
int raw_expected = 0;
|
||||
int cali_expected = 0;
|
||||
uint8_t regi2c_cali_val_before[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {};
|
||||
|
||||
//Read
|
||||
TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &raw_expected));
|
||||
if (do_calibration) {
|
||||
TEST_ESP_OK(adc_cali_raw_to_voltage(cali_handle[i], raw_expected, &cali_expected));
|
||||
}
|
||||
|
||||
//Print regi2c
|
||||
printf("regi2c cali val is: ");
|
||||
for (int j = 0; j < TEST_REGI2C_ANA_CALI_BYTE_NUM; j++) {
|
||||
regi2c_cali_val_before[j] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, j);
|
||||
printf("0x%x ", regi2c_cali_val_before[j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
//Print result
|
||||
ESP_LOGI(TAG, "ADC%d Chan%d: raw data: %d", unit_id + 1, channel, raw_expected);
|
||||
ESP_LOGI(TAG, "ADC%d Chan%d: cali data: %d", unit_id + 1, channel, cali_expected);
|
||||
|
||||
//---------------------------------Sleep-----------------------------------//
|
||||
esp_sleep_enable_timer_wakeup(30 * 1000);
|
||||
esp_light_sleep_start();
|
||||
|
||||
//---------------------------------After Sleep-----------------------------------//
|
||||
printf("After Light Sleep\n");
|
||||
int raw_after_sleep = 0;
|
||||
int cali_after_sleep = 0;
|
||||
uint8_t regi2c_cali_val_after[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {};
|
||||
|
||||
//Print regi2c
|
||||
printf("regi2c cali val is: ");
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
regi2c_cali_val_after[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i);
|
||||
printf("0x%x ", regi2c_cali_val_after[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
//Read
|
||||
TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &raw_after_sleep));
|
||||
if (do_calibration) {
|
||||
TEST_ESP_OK(adc_cali_raw_to_voltage(cali_handle[i], raw_after_sleep, &cali_after_sleep));
|
||||
}
|
||||
|
||||
//Print result
|
||||
ESP_LOGI(TAG, "ADC%d Chan%d: raw data: %d", unit_id + 1, channel, raw_after_sleep);
|
||||
if (do_calibration) {
|
||||
ESP_LOGI(TAG, "ADC%d Chan%d: cali data: %d", unit_id + 1, channel, cali_after_sleep);
|
||||
}
|
||||
|
||||
//Compare
|
||||
int32_t raw_diff = raw_expected - raw_after_sleep;
|
||||
ESP_LOGI(TAG, "ADC%d Chan%d: raw difference: %d", unit_id + 1, channel, raw_diff);
|
||||
|
||||
if (do_calibration) {
|
||||
int32_t cali_diff = cali_expected - cali_after_sleep;
|
||||
ESP_LOGI(TAG, "ADC%d Chan%d: cali difference: %d", unit_id + 1, channel, cali_diff);
|
||||
}
|
||||
|
||||
//Test Calibration registers
|
||||
for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) {
|
||||
TEST_ASSERT_EQUAL(regi2c_cali_val_before[i], regi2c_cali_val_after[i]);
|
||||
}
|
||||
ESP_LOGI(TAG, "Cali register settings unchanged\n");
|
||||
|
||||
}
|
||||
TEST_ESP_OK(adc_oneshot_del_unit(adc_handle));
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
if (cali_handle[i]) {
|
||||
test_adc_calibration_deinit(cali_handle[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_SLEEP_TEST_CHAN ADC_CHANNEL_6
|
||||
#define ADC2_SLEEP_TEST_CHAN ADC_CHANNEL_0
|
||||
#else
|
||||
#define ADC1_SLEEP_TEST_CHAN ADC_CHANNEL_2
|
||||
#define ADC2_SLEEP_TEST_CHAN ADC_CHANNEL_0
|
||||
#endif
|
||||
|
||||
TEST_CASE("test ADC1 Single Read with Light Sleep", "[adc][manul][ignore]")
|
||||
{
|
||||
s_adc_oneshot_with_sleep(ADC_UNIT_1, ADC1_SLEEP_TEST_CHAN);
|
||||
}
|
||||
|
||||
TEST_CASE("test ADC2 Single Read with Light Sleep", "[adc][manul][ignore]")
|
||||
{
|
||||
s_adc_oneshot_with_sleep(ADC_UNIT_2, ADC2_SLEEP_TEST_CHAN);
|
||||
}
|
||||
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
|
128
components/esp_adc/test_apps/adc/main/test_adc_driver.c
Normal file
128
components/esp_adc/test_apps/adc/main/test_adc_driver.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "test_common_adc.h"
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "TEST_ADC";
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC General Macros
|
||||
---------------------------------------------------------------*/
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_TEST_CHAN0 ADC_CHANNEL_4
|
||||
#else
|
||||
#define ADC1_TEST_CHAN0 ADC_CHANNEL_2
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC work with ISR
|
||||
---------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
TaskHandle_t task_handle; //Task handle
|
||||
adc_oneshot_unit_handle_t adc_handle; //ADC handle
|
||||
bool level; //ADC level
|
||||
} test_adc_isr_ctx_t;
|
||||
|
||||
static bool IRAM_ATTR s_alarm_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
test_adc_isr_ctx_t *test_ctx = (test_adc_isr_ctx_t *)user_data;
|
||||
BaseType_t high_task_wakeup;
|
||||
int adc_raw = 0;
|
||||
|
||||
/**
|
||||
* This test won't disable the cache, so having some code on Flash is OK.
|
||||
* If you copy this test callback with cache disabled, do remeber to put all code in internal RAM.
|
||||
*/
|
||||
|
||||
esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value);
|
||||
TEST_ESP_OK(adc_oneshot_read_isr(test_ctx->adc_handle, ADC1_TEST_CHAN0, &adc_raw));
|
||||
esp_rom_printf("adc raw: %d\r\n", adc_raw);
|
||||
if (test_ctx->level) {
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw);
|
||||
} else {
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw);
|
||||
}
|
||||
|
||||
|
||||
// check the count value at alarm event
|
||||
vTaskNotifyGiveFromISR(test_ctx->task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("ADC oneshot fast work with ISR", "[adc_oneshot]")
|
||||
{
|
||||
static test_adc_isr_ctx_t isr_test_ctx = {};
|
||||
isr_test_ctx.adc_handle = NULL;
|
||||
isr_test_ctx.task_handle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
//-------------ADC1 Init---------------//
|
||||
adc_oneshot_unit_init_cfg_t init_config1 = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &isr_test_ctx.adc_handle));
|
||||
|
||||
//-------------ADC1 TEST Channel 0 Config---------------//
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(isr_test_ctx.adc_handle, ADC1_TEST_CHAN0, &config));
|
||||
|
||||
//-------------GPTimer Init & Config---------------//
|
||||
gptimer_handle_t timer = NULL;
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timer));
|
||||
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = s_alarm_callback,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 0,
|
||||
.alarm_count = 100000, // 100ms
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timer, &cbs, &isr_test_ctx));
|
||||
|
||||
//ADC IO tile low
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0);
|
||||
isr_test_ctx.level = 0;
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(timer));
|
||||
TEST_ESP_OK(gptimer_start(timer));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ESP_OK(gptimer_stop(timer));
|
||||
|
||||
|
||||
//ADC IO tile high
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1);
|
||||
isr_test_ctx.level = 1;
|
||||
//Reset counter value to zero
|
||||
TEST_ESP_OK(gptimer_set_raw_count(timer, 0));
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_start(timer));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
|
||||
//Tear Down
|
||||
TEST_ESP_OK(gptimer_disable(timer));
|
||||
TEST_ESP_OK(gptimer_del_timer(timer));
|
||||
TEST_ESP_OK(adc_oneshot_del_unit(isr_test_ctx.adc_handle));
|
||||
}
|
266
components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c
Normal file
266
components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "test_common_adc.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
|
||||
const __attribute__((unused)) static char *TAG = "TEST_ADC";
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC General Macros
|
||||
---------------------------------------------------------------*/
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_TEST_CHAN0 ADC_CHANNEL_4
|
||||
#else
|
||||
#define ADC1_TEST_CHAN0 ADC_CHANNEL_2
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void *adc_handle; //ADC handle, could be oneshot / continuous handle
|
||||
bool level; //ADC level
|
||||
int adc_raw_high; //ADC reading raw when IO tie high
|
||||
int cb_exe_times_high; //Callback running times when IO tie high and $ disabled
|
||||
int adc_raw_low; //ADC reading raw when IO tie low
|
||||
int cb_exe_times_low; //Callback running times when IO tie low and $ disabled
|
||||
bool cache_disable_flag; //Indicating cache is disabled
|
||||
} test_adc_iram_ctx_t;
|
||||
|
||||
extern void spi_flash_disable_interrupts_caches_and_other_cpu(void);
|
||||
extern void spi_flash_enable_interrupts_caches_and_other_cpu(void);
|
||||
__attribute__((unused))
|
||||
static void s_test_cache_disable_period_us(test_adc_iram_ctx_t *ctx, uint32_t period_us);
|
||||
|
||||
|
||||
#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE
|
||||
/*---------------------------------------------------------------
|
||||
ADC oneshot work with cache safe ISR
|
||||
---------------------------------------------------------------*/
|
||||
static bool IRAM_ATTR NOINLINE_ATTR s_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
test_adc_iram_ctx_t *test_ctx = (test_adc_iram_ctx_t *)user_data;
|
||||
adc_oneshot_unit_handle_t oneshot_handle = *(adc_oneshot_unit_handle_t *)(test_ctx->adc_handle);
|
||||
|
||||
if (test_ctx->cache_disable_flag) {
|
||||
|
||||
if (test_ctx->level) {
|
||||
adc_oneshot_read_isr(oneshot_handle, ADC1_TEST_CHAN0, &test_ctx->adc_raw_high);
|
||||
esp_rom_printf(DRAM_STR("adc raw: %d\n"), test_ctx->adc_raw_high);
|
||||
test_ctx->cb_exe_times_high++;
|
||||
} else {
|
||||
adc_oneshot_read_isr(oneshot_handle, ADC1_TEST_CHAN0, &test_ctx->adc_raw_low);
|
||||
esp_rom_printf(DRAM_STR("adc raw: %d\n"), test_ctx->adc_raw_low);
|
||||
test_ctx->cb_exe_times_low++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]")
|
||||
{
|
||||
adc_oneshot_unit_handle_t oneshot_handle;
|
||||
static DRAM_ATTR test_adc_iram_ctx_t isr_test_ctx = {};
|
||||
isr_test_ctx.adc_handle = &oneshot_handle;
|
||||
|
||||
//-------------ADC1 Init---------------//
|
||||
adc_oneshot_unit_init_cfg_t init_config1 = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &oneshot_handle));
|
||||
|
||||
//-------------ADC1 TEST Channel 0 Config---------------//
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(oneshot_handle, ADC1_TEST_CHAN0, &config));
|
||||
|
||||
//-------------GPTimer Init & Config---------------//
|
||||
gptimer_handle_t timer = NULL;
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timer));
|
||||
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = s_alarm_cb,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 0,
|
||||
.alarm_count = 100000, // 100ms
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timer, &cbs, &isr_test_ctx));
|
||||
|
||||
//ADC IO tile low
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0);
|
||||
isr_test_ctx.level = 0;
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(timer));
|
||||
TEST_ESP_OK(gptimer_start(timer));
|
||||
s_test_cache_disable_period_us(&isr_test_ctx, 100 * 1000);
|
||||
TEST_ESP_OK(gptimer_stop(timer));
|
||||
//Checks
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, isr_test_ctx.adc_raw_low);
|
||||
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_low);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_low);
|
||||
|
||||
//ADC IO tile high
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1);
|
||||
isr_test_ctx.level = 1;
|
||||
//Reset counter value to zero
|
||||
TEST_ESP_OK(gptimer_set_raw_count(timer, 0));
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(gptimer_start(timer));
|
||||
s_test_cache_disable_period_us(&isr_test_ctx, 100 * 1000);
|
||||
TEST_ESP_OK(gptimer_stop(timer));
|
||||
//Checks
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, isr_test_ctx.adc_raw_high);
|
||||
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_high);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_high);
|
||||
|
||||
//Tear Down
|
||||
TEST_ESP_OK(gptimer_disable(timer));
|
||||
TEST_ESP_OK(gptimer_del_timer(timer));
|
||||
TEST_ESP_OK(adc_oneshot_del_unit(oneshot_handle));
|
||||
}
|
||||
#endif //#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE
|
||||
|
||||
|
||||
#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE
|
||||
#include "esp_adc/adc_continuous.h"
|
||||
/*---------------------------------------------------------------
|
||||
ADC continuous work with cache safe ISR
|
||||
---------------------------------------------------------------*/
|
||||
#if (SOC_ADC_DIGI_RESULT_BYTES == 2)
|
||||
#define ADC_TEST_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1
|
||||
#else
|
||||
#define ADC_TEST_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2
|
||||
#endif
|
||||
|
||||
#define ADC_TEST_FREQ_HZ (50 * 1000)
|
||||
#define ADC_TEST_PKG_SIZE 100
|
||||
static bool IRAM_ATTR NOINLINE_ATTR s_conv_done_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
|
||||
{
|
||||
test_adc_iram_ctx_t *test_ctx = (test_adc_iram_ctx_t *)user_data;
|
||||
|
||||
if (test_ctx->cache_disable_flag) {
|
||||
int raw = 0;
|
||||
|
||||
for (int i = 0; i < edata->size; i += SOC_ADC_DIGI_RESULT_BYTES) {
|
||||
adc_digi_output_data_t *p = (void*)&(edata->conv_frame_buffer[i]);
|
||||
#if (SOC_ADC_DIGI_RESULT_BYTES == 2)
|
||||
raw += p->type1.data;
|
||||
#else
|
||||
raw += p->type2.data;
|
||||
#endif
|
||||
}
|
||||
if (test_ctx->level) {
|
||||
test_ctx->adc_raw_high = raw / (edata->size / SOC_ADC_DIGI_RESULT_BYTES);
|
||||
test_ctx->cb_exe_times_high++;
|
||||
} else {
|
||||
test_ctx->adc_raw_low = raw / (edata->size / SOC_ADC_DIGI_RESULT_BYTES);
|
||||
test_ctx->cb_exe_times_low++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("ADC continuous work with ISR and Flash", "[adc_oneshot]")
|
||||
{
|
||||
adc_continuous_handle_t handle = NULL;
|
||||
adc_continuous_handle_cfg_t adc_config = {
|
||||
.max_store_buf_size = 1024,
|
||||
.conv_frame_size = ADC_TEST_PKG_SIZE,
|
||||
};
|
||||
TEST_ESP_OK(adc_continuous_new_handle(&adc_config, &handle));
|
||||
|
||||
adc_continuous_config_t dig_cfg = {
|
||||
.sample_freq_hz = ADC_TEST_FREQ_HZ,
|
||||
.conv_mode = ADC_CONV_SINGLE_UNIT_1,
|
||||
.format = ADC_TEST_OUTPUT_TYPE,
|
||||
};
|
||||
adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
|
||||
adc_pattern[0].atten = ADC_ATTEN_DB_0;
|
||||
adc_pattern[0].channel = ADC1_TEST_CHAN0;
|
||||
adc_pattern[0].unit = ADC_UNIT_1;
|
||||
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
|
||||
dig_cfg.adc_pattern = adc_pattern;
|
||||
dig_cfg.pattern_num = 1;
|
||||
TEST_ESP_OK(adc_continuous_config(handle, &dig_cfg));
|
||||
|
||||
static DRAM_ATTR test_adc_iram_ctx_t isr_test_ctx = {};
|
||||
isr_test_ctx.adc_handle = &handle;
|
||||
adc_continuous_evt_cbs_t cbs = {
|
||||
.on_conv_done = s_conv_done_cb,
|
||||
};
|
||||
TEST_ESP_OK(adc_continuous_register_event_callbacks(handle, &cbs, &isr_test_ctx));
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//This may need to be bigger, when the sampling freq is low
|
||||
uint32_t overhead_us = 150;
|
||||
#else
|
||||
uint32_t overhead_us = 0;
|
||||
#endif
|
||||
uint32_t wait_time_us = (1000 * 1000 / ADC_TEST_FREQ_HZ * ADC_TEST_PKG_SIZE / SOC_ADC_DIGI_RESULT_BYTES) + overhead_us;
|
||||
printf("period is %d us\n", wait_time_us);
|
||||
|
||||
//ADC IO tile low
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0);
|
||||
isr_test_ctx.level = 0;
|
||||
TEST_ESP_OK(adc_continuous_start(handle));
|
||||
s_test_cache_disable_period_us(&isr_test_ctx, wait_time_us);
|
||||
TEST_ESP_OK(adc_continuous_stop(handle));
|
||||
//Checks
|
||||
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, isr_test_ctx.adc_raw_low);
|
||||
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_low);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_low);
|
||||
|
||||
vTaskDelay(10);
|
||||
|
||||
printf("to set high\n");
|
||||
//ADC IO tile high
|
||||
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1);
|
||||
isr_test_ctx.level = 1;
|
||||
TEST_ESP_OK(adc_continuous_start(handle));
|
||||
s_test_cache_disable_period_us(&isr_test_ctx, wait_time_us);
|
||||
TEST_ESP_OK(adc_continuous_stop(handle));
|
||||
//Checks
|
||||
// TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL_DMA, isr_test_ctx.adc_raw_high);
|
||||
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_high);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_high);
|
||||
|
||||
TEST_ESP_OK(adc_continuous_deinit(handle));
|
||||
|
||||
}
|
||||
#endif //#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE
|
||||
|
||||
static void IRAM_ATTR NOINLINE_ATTR s_test_cache_disable_period_us(test_adc_iram_ctx_t *ctx, uint32_t period_us)
|
||||
{
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
ctx->cache_disable_flag = 1;
|
||||
|
||||
esp_rom_delay_us(period_us);
|
||||
|
||||
ctx->cache_disable_flag = 0;
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
}
|
298
components/esp_adc/test_apps/adc/main/test_adc_performance.c
Normal file
298
components/esp_adc/test_apps/adc/main/test_adc_performance.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/adc_periph.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "test_common_adc.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || SOC_ADC_CALIBRATION_V1_SUPPORTED
|
||||
|
||||
__attribute__((unused)) static const char *TAG = "TEST_ADC";
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Oneshot Average / STD_Deviation Test
|
||||
---------------------------------------------------------------*/
|
||||
#define TEST_COUNT (1<<SOC_ADC_RTC_MAX_BITWIDTH)
|
||||
#define MAX_ARRAY_SIZE (1<<SOC_ADC_RTC_MAX_BITWIDTH)
|
||||
|
||||
static int s_adc_count[MAX_ARRAY_SIZE]={};
|
||||
static int s_adc_offset = -1;
|
||||
|
||||
static int s_insert_point(uint32_t value)
|
||||
{
|
||||
const bool fixed_size = true;
|
||||
|
||||
if (s_adc_offset < 0) {
|
||||
if (fixed_size) {
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(4096, MAX_ARRAY_SIZE);
|
||||
s_adc_offset = 0; //Fixed to 0 because the array can hold all the data in 12 bits
|
||||
} else {
|
||||
s_adc_offset = MAX((int)value - MAX_ARRAY_SIZE/2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fixed_size && (value < s_adc_offset || value >= s_adc_offset + MAX_ARRAY_SIZE)) {
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(s_adc_offset, value);
|
||||
TEST_ASSERT_LESS_THAN(s_adc_offset + MAX_ARRAY_SIZE, value);
|
||||
}
|
||||
|
||||
s_adc_count[value - s_adc_offset] ++;
|
||||
return value - s_adc_offset;
|
||||
}
|
||||
|
||||
static void s_reset_array(void)
|
||||
{
|
||||
memset(s_adc_count, 0, sizeof(s_adc_count));
|
||||
s_adc_offset = -1;
|
||||
}
|
||||
|
||||
static uint32_t s_get_average(void)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_ARRAY_SIZE; i++) {
|
||||
sum += s_adc_count[i] * (s_adc_offset+i);
|
||||
count += s_adc_count[i];
|
||||
}
|
||||
return sum/count;
|
||||
}
|
||||
|
||||
static void s_print_summary(bool figure)
|
||||
{
|
||||
const int MAX_WIDTH=20;
|
||||
int max_count = 0;
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
uint32_t sum = 0;
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_ARRAY_SIZE; i++) {
|
||||
if (s_adc_count[i] > max_count) {
|
||||
max_count = s_adc_count[i];
|
||||
}
|
||||
if (s_adc_count[i] > 0 && start < 0) {
|
||||
start = i;
|
||||
}
|
||||
if (s_adc_count[i] > 0) {
|
||||
end = i;
|
||||
}
|
||||
count += s_adc_count[i];
|
||||
sum += s_adc_count[i] * (s_adc_offset+i);
|
||||
}
|
||||
|
||||
if (figure) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
printf("%4d ", i+s_adc_offset);
|
||||
int count = s_adc_count[i] * MAX_WIDTH / max_count;
|
||||
for (int j = 0; j < count; j++) {
|
||||
putchar('|');
|
||||
}
|
||||
printf(" %d\n", s_adc_count[i]);
|
||||
}
|
||||
}
|
||||
float average = (float)sum/count;
|
||||
|
||||
float variation_square = 0;
|
||||
for (int i = start; i <= end; i ++) {
|
||||
if (s_adc_count[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
float delta = i + s_adc_offset - average;
|
||||
variation_square += (delta * delta) * s_adc_count[i];
|
||||
}
|
||||
|
||||
printf("%d points.\n", count);
|
||||
printf("average: %.1f\n", (float)sum/count);
|
||||
printf("std: %.2f\n", sqrt(variation_square/count));
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_6
|
||||
#else
|
||||
#define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_2
|
||||
#endif
|
||||
|
||||
TEST_CASE("ADC1 oneshot raw average / std_deviation", "[adc_oneshot][ignore][manual]")
|
||||
{
|
||||
adc_atten_t atten[SOC_ADC_ATTEN_NUM] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_2_5, ADC_ATTEN_DB_6, ADC_ATTEN_DB_11};
|
||||
adc_channel_t channel = TEST_STD_ADC1_CHANNEL0;
|
||||
int raw = 0;
|
||||
bool print_figure = false;
|
||||
|
||||
//-------------ADC1 Init---------------//
|
||||
adc_oneshot_unit_handle_t adc1_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config1 = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
|
||||
|
||||
//-------------ADC Channel Config---------------//
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = SOC_ADC_RTC_MAX_BITWIDTH,
|
||||
};
|
||||
|
||||
//-------------ADC Calibration Init---------------//
|
||||
bool do_calibration = false;
|
||||
adc_cali_handle_t cali_handle[SOC_ADC_ATTEN_NUM] = {};
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
do_calibration = test_adc_calibration_init(ADC_UNIT_1, i, ADC_BITWIDTH_DEFAULT, &cali_handle[i]);
|
||||
}
|
||||
if (!do_calibration) {
|
||||
ESP_LOGW(TAG, "calibration fail, jump calibration\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
|
||||
//-------------ADC1 Channel Config---------------//
|
||||
config.atten = atten[i];
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, channel, &config));
|
||||
ESP_LOGI("TEST_ADC", "Test with atten: %d", atten[i]);
|
||||
|
||||
while (1) {
|
||||
|
||||
s_reset_array();
|
||||
|
||||
for (int i = 0; i < TEST_COUNT; i++) {
|
||||
TEST_ESP_OK(adc_oneshot_read(adc1_handle, channel, &raw));
|
||||
s_insert_point(raw);
|
||||
}
|
||||
s_print_summary(print_figure);
|
||||
break;
|
||||
}
|
||||
|
||||
if (do_calibration) {
|
||||
uint32_t raw = s_get_average();
|
||||
int voltage_mv = 0;
|
||||
TEST_ESP_OK(adc_cali_raw_to_voltage(cali_handle[i], raw, &voltage_mv));
|
||||
printf("Voltage = %d mV\n", voltage_mv);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ESP_OK(adc_oneshot_del_unit(adc1_handle));
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
if (cali_handle[i]) {
|
||||
test_adc_calibration_deinit(cali_handle[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Calibration Speed
|
||||
---------------------------------------------------------------*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define CPU_FREQ_MHZ CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define CPU_FREQ_MHZ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define CPU_FREQ_MHZ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define CPU_FREQ_MHZ CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ
|
||||
#endif
|
||||
|
||||
#define RECORD_TIME_PREPARE() uint32_t __t1, __t2
|
||||
#define RECORD_TIME_START() do {__t1 = esp_cpu_get_ccount();}while(0)
|
||||
#define RECORD_TIME_END(p_time) do{__t2 = esp_cpu_get_ccount(); *p_time = (__t2-__t1);}while(0)
|
||||
#define GET_US_BY_CCOUNT(t) ((double)t/CPU_FREQ_MHZ)
|
||||
|
||||
|
||||
//ADC Channels
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC1_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_6
|
||||
#define ADC2_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_0
|
||||
#else
|
||||
#define ADC1_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_2
|
||||
#define ADC2_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_0
|
||||
#endif
|
||||
|
||||
#define TIMES_PER_ATTEN 10
|
||||
|
||||
|
||||
static IRAM_ATTR NOINLINE_ATTR uint32_t get_cali_time_in_ccount(adc_cali_handle_t cali_handle, int adc_raw)
|
||||
{
|
||||
uint32_t time;
|
||||
int voltage = 0;
|
||||
RECORD_TIME_PREPARE();
|
||||
RECORD_TIME_START();
|
||||
adc_cali_raw_to_voltage(cali_handle, adc_raw, &voltage);
|
||||
RECORD_TIME_END(&time);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
static void s_adc_cali_speed(adc_unit_t unit_id, adc_channel_t channel)
|
||||
{
|
||||
//-------------ADC Calibration Init---------------//
|
||||
bool do_calibration = false;
|
||||
adc_cali_handle_t cali_handle[SOC_ADC_ATTEN_NUM] = {};
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
do_calibration = test_adc_calibration_init(unit_id, i, SOC_ADC_RTC_MAX_BITWIDTH, &cali_handle[i]);
|
||||
}
|
||||
|
||||
if (!do_calibration) {
|
||||
ESP_LOGW(TAG, "no efuse burnt, jump test");
|
||||
} else {
|
||||
|
||||
ESP_LOGI(TAG, "CPU FREQ is %dMHz", CPU_FREQ_MHZ);
|
||||
adc_atten_t atten[SOC_ADC_ATTEN_NUM] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_2_5, ADC_ATTEN_DB_6, ADC_ATTEN_DB_11};
|
||||
uint32_t adc_time_record[4][TIMES_PER_ATTEN] = {};
|
||||
int adc_raw = 0;
|
||||
|
||||
//-------------ADC Init---------------//
|
||||
adc_oneshot_unit_handle_t adc_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config = {
|
||||
.unit_id = unit_id,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
TEST_ESP_OK(adc_oneshot_new_unit(&init_config, &adc_handle));
|
||||
|
||||
//-------------ADC Channel Config---------------//
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = SOC_ADC_RTC_MAX_BITWIDTH,
|
||||
};
|
||||
|
||||
//atten0 ~ atten3
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
|
||||
//-------------ADC Channel Config---------------//
|
||||
config.atten = atten[i];
|
||||
TEST_ESP_OK(adc_oneshot_config_channel(adc_handle, channel, &config));
|
||||
ESP_LOGI("TEST_ADC", "Test with atten: %d", atten[i]);
|
||||
|
||||
for (int j = 0; j < TIMES_PER_ATTEN; j++) {
|
||||
TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &adc_raw));
|
||||
adc_time_record[i][j] = get_cali_time_in_ccount(cali_handle[i], adc_raw);
|
||||
IDF_LOG_PERFORMANCE("ADC1 Cali time", "%d us", (int)GET_US_BY_CCOUNT(adc_time_record[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ESP_OK(adc_oneshot_del_unit(adc_handle));
|
||||
for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) {
|
||||
if (cali_handle[i]) {
|
||||
test_adc_calibration_deinit(cali_handle[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("ADC1 Calibration Speed", "[adc][ignore][manual]")
|
||||
{
|
||||
s_adc_cali_speed(ADC_UNIT_1, ADC1_CALI_SPEED_TEST_CHAN0);
|
||||
}
|
||||
|
||||
TEST_CASE("ADC2 Calibration Speed", "[adc][ignore][manual]")
|
||||
{
|
||||
s_adc_cali_speed(ADC_UNIT_2, ADC2_CALI_SPEED_TEST_CHAN0);
|
||||
}
|
||||
#endif //#if CONFIG_IDF_TARGET_ESP32 || SOC_ADC_CALIBRATION_V1_SUPPORTED
|
40
components/esp_adc/test_apps/adc/main/test_app_main.c
Normal file
40
components/esp_adc/test_apps/adc/main/test_app_main.c
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-600)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
94
components/esp_adc/test_apps/adc/main/test_common_adc.c
Normal file
94
components/esp_adc/test_apps/adc/main/test_common_adc.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "soc/adc_periph.h"
|
||||
#include "test_common_adc.h"
|
||||
|
||||
__attribute__((unused)) static const char *TAG = "TEST_ADC";
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Calibration
|
||||
---------------------------------------------------------------*/
|
||||
bool test_adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_bitwidth_t bitwidth, adc_cali_handle_t *out_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
adc_cali_handle_t handle = NULL;
|
||||
bool calibrated = false;
|
||||
|
||||
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.atten = atten,
|
||||
.bitwidth = bitwidth,
|
||||
};
|
||||
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
|
||||
|
||||
#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting");
|
||||
adc_cali_line_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.atten = atten,
|
||||
.bitwidth = bitwidth,
|
||||
};
|
||||
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
|
||||
#endif
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
calibrated = true;
|
||||
} else if (ret == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGW(TAG, "calibration fail due to lack of eFuse bits");
|
||||
} else {
|
||||
TEST_ASSERT(false);
|
||||
}
|
||||
|
||||
*out_handle = handle;
|
||||
|
||||
return calibrated;
|
||||
}
|
||||
|
||||
void test_adc_calibration_deinit(adc_cali_handle_t handle)
|
||||
{
|
||||
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
ESP_LOGI(TAG, "deregister %s calibration scheme", "Curve Fitting");
|
||||
TEST_ESP_OK(adc_cali_delete_scheme_curve_fitting(handle));
|
||||
|
||||
#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
ESP_LOGI(TAG, "deregister %s calibration scheme", "Line Fitting");
|
||||
TEST_ESP_OK(adc_cali_delete_scheme_line_fitting(handle));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC GPIO
|
||||
---------------------------------------------------------------*/
|
||||
#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel])
|
||||
|
||||
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 SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_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));
|
||||
}
|
||||
TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY: GPIO_PULLDOWN_ONLY)));
|
||||
#endif
|
||||
}
|
107
components/esp_adc/test_apps/adc/main/test_common_adc.h
Normal file
107
components/esp_adc/test_apps/adc/main/test_common_adc.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Calibration
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Initialise ADC Calibration
|
||||
*
|
||||
* @param[out] out_handle ADC calibration handle
|
||||
*
|
||||
* @return
|
||||
* - True Calibration success
|
||||
* - False Calibration fail
|
||||
*/
|
||||
bool test_adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_bitwidth_t bitwidth, adc_cali_handle_t *out_handle);
|
||||
|
||||
/**
|
||||
* @brief De-initialise ADC Calibration
|
||||
*
|
||||
* @param[in] handle ADC calibration handle
|
||||
*/
|
||||
void test_adc_calibration_deinit(adc_cali_handle_t handle);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC GPIO
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* We use weak pulldown, `ADC_TEST_LOW_THRESH` may vary.
|
||||
* If connect to GND, `ADC_TEST_LOW_THRESH` can be smaller
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 10
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_VAL_DMA 4095
|
||||
#define ADC_TEST_HIGH_THRESH 10
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 35
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 8191
|
||||
#define ADC_TEST_HIGH_VAL_DMA 4095
|
||||
#define ADC_TEST_HIGH_THRESH 10
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 60
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_VAL_DMA 4095
|
||||
#define ADC_TEST_HIGH_THRESH 10
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define ADC_TEST_LOW_VAL 0
|
||||
#define ADC_TEST_LOW_THRESH 15
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_VAL_DMA 4095
|
||||
#define ADC_TEST_HIGH_THRESH 0
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
#define ADC_TEST_LOW_VAL 2147
|
||||
#define ADC_TEST_LOW_THRESH 50
|
||||
|
||||
#define ADC_TEST_HIGH_VAL 4095
|
||||
#define ADC_TEST_HIGH_THRESH 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set ADC IO level
|
||||
*
|
||||
* @param[in] unit ADC unit
|
||||
* @param[in] channel ADC channel
|
||||
* @param[in] level IO level. True: high; False: low
|
||||
*/
|
||||
void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
21
components/esp_adc/test_apps/adc/pytest_adc.py
Normal file
21
components/esp_adc/test_apps/adc/pytest_adc.py
Normal file
@ -0,0 +1,21 @@
|
||||
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32c2
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize('config', [
|
||||
'iram_safe',
|
||||
'release',
|
||||
], indirect=True)
|
||||
def test_adc(dut: Dut) -> None:
|
||||
dut.expect_exact('Press ENTER to see the list of tests')
|
||||
dut.write('*')
|
||||
dut.expect_unity_test_output(timeout=120)
|
6
components/esp_adc/test_apps/adc/sdkconfig.ci.iram_safe
Normal file
6
components/esp_adc/test_apps/adc/sdkconfig.ci.iram_safe
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||
CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM=y
|
||||
CONFIG_GPTIMER_ISR_IRAM_SAFE=y
|
||||
CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y
|
||||
# silent the error check, as the error string are stored in rodata, causing RTL check failure
|
||||
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
3
components/esp_adc/test_apps/adc/sdkconfig.ci.release
Normal file
3
components/esp_adc/test_apps/adc/sdkconfig.ci.release
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
2
components/esp_adc/test_apps/adc/sdkconfig.defaults
Normal file
2
components/esp_adc/test_apps/adc/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
@ -1,12 +0,0 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
set(srcs "esp_adc_cal_common.c")
|
||||
set(src_target "${target}/esp_adc_cal.c")
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${src_target}")
|
||||
list(APPEND srcs ${src_target})
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES driver
|
||||
PRIV_REQUIRES efuse)
|
@ -1,31 +0,0 @@
|
||||
menu "ADC-Calibration"
|
||||
|
||||
config ADC_CAL_EFUSE_TP_ENABLE
|
||||
depends on IDF_TARGET_ESP32
|
||||
bool "Use Two Point Values"
|
||||
default "y"
|
||||
help
|
||||
Some ESP32s have Two Point calibration values burned into eFuse BLOCK3.
|
||||
This option will allow the ADC calibration component to characterize the
|
||||
ADC-Voltage curve using Two Point values if they are available.
|
||||
|
||||
config ADC_CAL_EFUSE_VREF_ENABLE
|
||||
depends on IDF_TARGET_ESP32
|
||||
bool "Use eFuse Vref"
|
||||
default "y"
|
||||
help
|
||||
Some ESP32s have Vref burned into eFuse BLOCK0. This option will allow
|
||||
the ADC calibration component to characterize the ADC-Voltage curve using
|
||||
eFuse Vref if it is available.
|
||||
|
||||
config ADC_CAL_LUT_ENABLE
|
||||
depends on IDF_TARGET_ESP32
|
||||
bool "Use Lookup Tables"
|
||||
default "y"
|
||||
help
|
||||
This option will allow the ADC calibration component to use Lookup Tables
|
||||
to correct for non-linear behavior in 11db attenuation. Other attenuations
|
||||
do not exhibit non-linear behavior hence will not be affected by this option.
|
||||
|
||||
|
||||
endmenu # ADC-Calibration
|
@ -31,7 +31,7 @@ endif()
|
||||
# [refactor-todo]: requires "driver" component for periph_ctrl header file
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "include" "${idf_target}/include"
|
||||
PRIV_REQUIRES nvs_flash driver efuse esp_timer
|
||||
PRIV_REQUIRES nvs_flash driver efuse esp_timer esp_adc
|
||||
LDFRAGMENTS "${ldfragments}"
|
||||
EMBED_FILES ${embed_files}
|
||||
)
|
||||
|
@ -5,8 +5,9 @@
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "esp_private/regi2c_ctrl.h"
|
||||
#include "driver/adc.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
|
||||
/*
|
||||
* This file is used to override the hooks provided by the PHY lib for some system features.
|
||||
|
@ -30,7 +30,7 @@ endif()
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES esp_event esp_phy
|
||||
PRIV_REQUIRES driver esptool_py esp_netif esp_pm esp_timer nvs_flash
|
||||
PRIV_REQUIRES driver esptool_py esp_netif esp_pm esp_timer nvs_flash esp_adc
|
||||
wpa_supplicant hal lwip ${extra_priv_requires}
|
||||
LDFRAGMENTS "${ldfragments}")
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "esp_wpa.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_private/adc_private.h"
|
||||
#include "esp_coexist_internal.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "phy.h"
|
||||
|
@ -44,7 +44,7 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"spi_flash_encrypt_hal_iram.c"
|
||||
"sha_hal.c"
|
||||
"adc_hal_common.c"
|
||||
"adc_hal.c")
|
||||
"adc_oneshot_hal.c")
|
||||
|
||||
if(CONFIG_SOC_SYSTIMER_SUPPORTED AND NOT CONFIG_HAL_SYSTIMER_USE_ROM_IMPL)
|
||||
list(APPEND srcs "systimer_hal.c")
|
||||
@ -82,6 +82,10 @@ if(NOT BOOTLOADER_BUILD)
|
||||
list(APPEND srcs "emac_hal.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_ADC_DMA_SUPPORTED)
|
||||
list(APPEND srcs "adc_hal.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LCDCAM_SUPPORTED)
|
||||
list(APPEND srcs "lcd_hal.c")
|
||||
endif()
|
||||
@ -96,7 +100,6 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"sdio_slave_hal.c"
|
||||
"touch_sensor_hal.c"
|
||||
"aes_hal.c"
|
||||
"esp32/adc_hal.c"
|
||||
"esp32/brownout_hal.c"
|
||||
"esp32/touch_sensor_hal.c"
|
||||
"esp32/gpio_hal_workaround.c")
|
||||
@ -143,7 +146,6 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"spi_slave_hd_hal.c"
|
||||
"xt_wdt_hal.c"
|
||||
"aes_hal.c"
|
||||
"esp32c3/adc_hal.c"
|
||||
"esp32c3/brownout_hal.c"
|
||||
"esp32c3/hmac_hal.c"
|
||||
"esp32c3/rtc_cntl_hal.c")
|
||||
|
@ -25,16 +25,6 @@
|
||||
#include "soc/spi_struct.h"
|
||||
#endif
|
||||
|
||||
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
/*---------------------------------------------------------------
|
||||
Single Read
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* For chips without RTC controller, Digital controller is used to trigger an ADC single read.
|
||||
*/
|
||||
#include "esp_rom_sys.h"
|
||||
#endif //SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Define all ADC DMA required operations here
|
||||
---------------------------------------------------------------*/
|
||||
@ -190,9 +180,12 @@ static void adc_hal_digi_sample_freq_config(adc_hal_dma_ctx_t *hal, uint32_t fre
|
||||
adc_ll_digi_clk_sel(0); //use APB
|
||||
#else
|
||||
i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_SRC_DEFAULT); /*!< Clock from PLL_D2_CLK(160M)*/
|
||||
uint32_t bck = I2S_BASE_CLK / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_B_DEFAULT / ADC_LL_CLKM_DIV_A_DEFAULT) / 2 / freq;
|
||||
i2s_ll_set_raw_mclk_div(hal->dev, ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT);
|
||||
i2s_ll_rx_set_bck_div_num(hal->dev, bck);
|
||||
uint32_t bclk_div = 16;
|
||||
uint32_t bclk = freq * 2;
|
||||
uint32_t mclk = bclk * bclk_div;
|
||||
uint32_t mclk_div = I2S_BASE_CLK / mclk;
|
||||
i2s_ll_rx_set_mclk(hal->dev, I2S_BASE_CLK, mclk, mclk_div);
|
||||
i2s_ll_rx_set_bck_div_num(hal->dev, bclk_div);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -231,13 +224,8 @@ void adc_hal_digi_controller_config(adc_hal_dma_ctx_t *hal, const adc_hal_digi_c
|
||||
|
||||
#endif
|
||||
|
||||
if (cfg->conv_limit_en) {
|
||||
adc_ll_digi_set_convert_limit_num(cfg->conv_limit_num);
|
||||
adc_ll_digi_convert_limit_enable();
|
||||
} else {
|
||||
adc_ll_digi_convert_limit_disable();
|
||||
}
|
||||
|
||||
adc_ll_digi_convert_limit_enable(ADC_LL_DEFAULT_CONV_LIMIT_EN);
|
||||
adc_ll_digi_set_convert_limit_num(ADC_LL_DEFAULT_CONV_LIMIT_NUM);
|
||||
adc_ll_digi_set_convert_mode(get_convert_mode(cfg->conv_mode));
|
||||
|
||||
//clock and sample frequency
|
||||
@ -277,7 +265,7 @@ void adc_hal_digi_start(adc_hal_dma_ctx_t *hal, uint8_t *data_buf)
|
||||
|
||||
//reset the current descriptor address
|
||||
hal->cur_desc_ptr = &hal->desc_dummy_head;
|
||||
adc_hal_digi_dma_link_descriptors(hal->rx_desc, data_buf, hal->eof_num * ADC_HAL_DATA_LEN_PER_CONV, hal->desc_max_num);
|
||||
adc_hal_digi_dma_link_descriptors(hal->rx_desc, data_buf, hal->eof_num * SOC_ADC_DIGI_DATA_BYTES_PER_CONV, hal->desc_max_num);
|
||||
|
||||
//start DMA
|
||||
adc_dma_ll_rx_start(hal->dev, hal->dma_chan, (lldesc_t *)hal->rx_desc);
|
||||
@ -334,67 +322,3 @@ void adc_hal_digi_stop(adc_hal_dma_ctx_t *hal)
|
||||
//disconnect DMA and peripheral
|
||||
adc_ll_digi_dma_disable();
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Single Read
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* For chips without RTC controller, Digital controller is used to trigger an ADC single read.
|
||||
*/
|
||||
|
||||
//--------------------Single Read-------------------------------//
|
||||
static void adc_hal_onetime_start(adc_unit_t adc_n)
|
||||
{
|
||||
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
|
||||
(void)adc_n;
|
||||
/**
|
||||
* There is a hardware limitation. If the APB clock frequency is high, the step of this reg signal: ``onetime_start`` may not be captured by the
|
||||
* ADC digital controller (when its clock frequency is too slow). A rough estimate for this step should be at least 3 ADC digital controller
|
||||
* clock cycle.
|
||||
*
|
||||
* This limitation will be removed in hardware future versions.
|
||||
*
|
||||
*/
|
||||
uint32_t digi_clk = APB_CLK_FREQ / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1);
|
||||
//Convert frequency to time (us). Since decimals are removed by this division operation. Add 1 here in case of the fact that delay is not enough.
|
||||
uint32_t delay = (1000 * 1000) / digi_clk + 1;
|
||||
//3 ADC digital controller clock cycle
|
||||
delay = delay * 3;
|
||||
//This coefficient (8) is got from test. When digi_clk is not smaller than ``APB_CLK_FREQ/8``, no delay is needed.
|
||||
if (digi_clk >= APB_CLK_FREQ/8) {
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
adc_oneshot_ll_start(false);
|
||||
esp_rom_delay_us(delay);
|
||||
adc_oneshot_ll_start(true);
|
||||
|
||||
//No need to delay here. Becuase if the start signal is not seen, there won't be a done intr.
|
||||
#else
|
||||
adc_oneshot_ll_start(adc_n);
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw)
|
||||
{
|
||||
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_hal_onetime_start(adc_n);
|
||||
while (adc_oneshot_ll_get_event(event) != true) {
|
||||
;
|
||||
}
|
||||
*out_raw = adc_oneshot_ll_get_raw_result(adc_n);
|
||||
if (adc_oneshot_ll_raw_check_valid(adc_n, *out_raw) == false) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
//HW workaround: when enabling periph clock, this should be false
|
||||
adc_oneshot_ll_disable_all_unit();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user