Merge branch 'feature/support_adc_calibration_s3' into 'master'

adc: support adc calibration on s3

Closes IDF-1950, IDF-3730, and IDF-3036

See merge request espressif/esp-idf!15031
This commit is contained in:
Armando (Dou Yiwen) 2021-09-14 08:51:03 +00:00
commit 13b63cd9d2
39 changed files with 1317 additions and 191 deletions

View File

@ -18,16 +18,18 @@
#include "driver/gpio.h"
#include "driver/adc.h"
#include "adc1_private.h"
#include "hal/adc_types.h"
#include "hal/adc_hal.h"
#include "hal/adc_hal_conf.h"
#if SOC_DAC_SUPPORTED
#include "driver/dac.h"
#include "hal/dac_hal.h"
#endif
#include "hal/adc_hal_conf.h"
#if CONFIG_IDF_TARGET_ESP32S3
#include "esp_efuse_rtc_calib.h"
#endif
#define ADC_CHECK_RET(fun_ret) ({ \
if (fun_ret != ESP_OK) { \
@ -123,20 +125,10 @@ static esp_pm_lock_handle_t s_adc2_arbiter_lock;
#endif //CONFIG_PM_ENABLE
#endif // !CONFIG_IDF_TARGET_ESP32
/*---------------------------------------------------------------
ADC Common
---------------------------------------------------------------*/
#if CONFIG_IDF_TARGET_ESP32S2
static uint32_t get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t chan)
{
adc_atten_t atten = adc_hal_get_atten(adc_n, chan);
extern uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool no_cal);
return adc_get_calibration_offset(adc_n, chan, atten, false);
}
#endif
// ADC Power
// This gets incremented when adc_power_acquire() is called, and decremented when
@ -226,7 +218,56 @@ esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
return ESP_OK;
}
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
//------------------------------------------------------------RTC Single Read----------------------------------------------//
#if SOC_ADC_RTC_CTRL_SUPPORTED
/*---------------------------------------------------------------
ADC Calibration
---------------------------------------------------------------*/
#if CONFIG_IDF_TARGET_ESP32S3
/**
* Temporarily put this function here. These are about ADC calibration and will be moved driver/adc.c in !14278.
* Reason for putting calibration functions in driver/adc.c:
* adc_common.c is far too confusing. Before a refactor is applied to adc_common.c, will put definite code in driver/adc.c
*/
static uint16_t s_adc_cali_param[ADC_UNIT_MAX][ADC_ATTEN_MAX] = {};
uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
if (s_adc_cali_param[adc_n][atten]) {
//These value won't exceed UINT16_MAX
return s_adc_cali_param[adc_n][atten];
}
//Get the calibration version
int version = esp_efuse_rtc_calib_get_ver();
uint32_t init_code = 0;
if (version == 1) {
init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten);
s_adc_cali_param[adc_n][atten] = init_code;
} else {
ESP_LOGW(ADC_TAG, "Calibration eFuse is not configured, skip calibration");
}
return s_adc_cali_param[adc_n][atten];
}
#elif CONFIG_IDF_TARGET_ESP32S2
//Temporarily extern this from s2/adc.c. Will be modified in !14278.
extern uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten);
#endif //CONFIG_IDF_TARGET_ESP32S3
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
static uint32_t get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t chan)
{
adc_atten_t atten = adc_hal_get_atten(adc_n, chan);
return adc_get_calibration_offset(adc_n, chan, atten);
}
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
esp_err_t adc_set_clk_div(uint8_t clk_div)
{
DIGI_CONTROLLER_ENTER();
@ -349,7 +390,7 @@ esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
adc_hal_set_atten(ADC_NUM_1, channel, atten);
SARADC1_EXIT();
#if SOC_ADC_HW_CALIBRATION_V1
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(ADC_NUM_1);
#endif
@ -427,11 +468,11 @@ int adc1_get_raw(adc1_channel_t channel)
ADC_CHANNEL_CHECK(ADC_NUM_1, channel);
adc1_rtc_mode_acquire();
#if CONFIG_IDF_TARGET_ESP32S2
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
// Get calibration value before going into critical section
uint32_t cal_val = get_calibration_offset(ADC_NUM_1, channel);
adc_hal_set_calibration_param(ADC_NUM_1, cal_val);
#endif
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
SARADC1_ENTER();
#ifdef CONFIG_IDF_TARGET_ESP32
@ -521,7 +562,7 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
SARADC2_RELEASE();
#if SOC_ADC_HW_CALIBRATION_V1
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(ADC_NUM_2);
#endif
@ -578,11 +619,11 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
ADC_CHECK(width_bit == ADC_WIDTH_MAX - 1, "WIDTH ERR: see `adc_bits_width_t` for supported bit width", ESP_ERR_INVALID_ARG);
#endif
#if CONFIG_IDF_TARGET_ESP32S2
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
// Get calibration value before going into critical section
uint32_t cal_val = get_calibration_offset(ADC_NUM_2, channel);
adc_hal_set_calibration_param(ADC_NUM_2, cal_val);
#endif
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
if ( SARADC2_TRY_ACQUIRE() == -1 ) {
//try the lock, return if failed (wifi using).
@ -679,4 +720,4 @@ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
return ESP_OK;
}
#endif //CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#endif //SOC_ADC_RTC_CTRL_SUPPORTED

View File

@ -437,7 +437,7 @@ static uint16_t s_adc_cali_param[ADC_NUM_MAX][ADC_ATTEN_MAX] = { {0}, {0} };
// 1. Semaphore when reading efuse
// 2. Spinlock when actually doing ADC calibration
//This function shoudn't be called inside critical section or ISR
uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool no_cal)
uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
#ifdef CONFIG_IDF_ENV_FPGA
return 0;
@ -448,10 +448,6 @@ uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, a
return (uint32_t)s_adc_cali_param[adc_n][atten];
}
if (no_cal) {
return 0; //indicating failure
}
uint32_t dout = 0;
// check if we can fetch the values from eFuse.
int version = esp_efuse_rtc_table_read_calib_version();
@ -474,7 +470,7 @@ uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, a
esp_err_t adc_cal_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
adc_hal_calibration_init(adc_n);
uint32_t cal_val = adc_get_calibration_offset(adc_n, channel, atten, false);
uint32_t cal_val = adc_get_calibration_offset(adc_n, channel, atten);
ADC_ENTER_CRITICAL();
adc_hal_set_calibration_param(adc_n, cal_val);
ADC_EXIT_CRITICAL();

View File

@ -4,15 +4,20 @@
* 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"
static const char *TAG = "ADC";
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP32S2, ESP32S3)
//API only supported for C3 now.
#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "esp_log.h"
#define TEST_COUNT 4096
@ -274,4 +279,120 @@ TEST_CASE("test_adc_single", "[adc][ignore][manual]")
}
}
#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP32S2, ESP32S3)
/********************************************************************************
* ADC Speed Related Tests
********************************************************************************/
#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_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", 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]));
}
}
}

View File

@ -33,7 +33,7 @@ uint8_t esp_efuse_get_chip_ver(void)
uint32_t esp_efuse_get_pkg_ver(void)
{
uint32_t pkg_ver = 0;
esp_efuse_read_field_blob(ESP_EFUSE_PKG_VERSION, &pkg_ver, 4);
esp_efuse_read_field_blob(ESP_EFUSE_PKG_VERSION, &pkg_ver, ESP_EFUSE_PKG_VERSION[0]->bit_count);
return pkg_ver;
}
@ -45,9 +45,9 @@ esp_err_t esp_efuse_disable_rom_download_mode(void)
esp_err_t esp_efuse_set_rom_log_scheme(esp_efuse_rom_log_scheme_t log_scheme)
{
int cur_log_scheme = 0;
esp_efuse_read_field_blob(ESP_EFUSE_UART_PRINT_CONTROL, &cur_log_scheme, 2);
esp_efuse_read_field_blob(ESP_EFUSE_UART_PRINT_CONTROL, &cur_log_scheme, ESP_EFUSE_UART_PRINT_CONTROL[0]->bit_count);
if (!cur_log_scheme) { // not burned yet
return esp_efuse_write_field_blob(ESP_EFUSE_UART_PRINT_CONTROL, &log_scheme, 2);
return esp_efuse_write_field_blob(ESP_EFUSE_UART_PRINT_CONTROL, &log_scheme, ESP_EFUSE_UART_PRINT_CONTROL[0]->bit_count);
} else {
return ESP_ERR_INVALID_STATE;
}

View File

@ -0,0 +1,103 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_bit_defs.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
//Don't introduce new dependency of ADC, keep these macro same as ADC related definations
#define ADC_ATTEN_MAX 4
#define ADC_NUM_MAX 2
#define ADC_NUM_1 0
#define ADC_NUM_2 1
int esp_efuse_rtc_calib_get_ver(void)
{
uint32_t blk1_version = 0;
uint32_t blk2_version = 0;
ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_BLOCK1_VERSION, &blk1_version, ESP_EFUSE_BLOCK1_VERSION[0]->bit_count));
ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &blk2_version, ESP_EFUSE_BLOCK2_VERSION[0]->bit_count));
if (blk1_version == blk2_version) {
return blk1_version;
} else {
blk1_version = 0;
blk2_version = 0;
ESP_LOGW("eFuse", "calibration efuse version does not match, set default version: %d", 0);
}
return blk2_version;
}
uint16_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten)
{
assert(version == 1);
assert(atten < 4);
assert(adc_unit < ADC_NUM_MAX);
const esp_efuse_desc_t **desc[8] = {ESP_EFUSE_ADC1_INIT_CODE_ATTEN0, ESP_EFUSE_ADC1_INIT_CODE_ATTEN1, ESP_EFUSE_ADC1_INIT_CODE_ATTEN2, ESP_EFUSE_ADC1_INIT_CODE_ATTEN3,
ESP_EFUSE_ADC2_INIT_CODE_ATTEN0, ESP_EFUSE_ADC2_INIT_CODE_ATTEN1, ESP_EFUSE_ADC2_INIT_CODE_ATTEN2, ESP_EFUSE_ADC2_INIT_CODE_ATTEN3};
int efuse_icode_bits = 0;
uint32_t adc_icode[4] = {};
uint32_t adc_icode_diff[4] = {};
uint8_t desc_index = (adc_unit == ADC_NUM_1) ? 0 : 4;
for (int diff_index = 0; diff_index < 4; diff_index++) {
efuse_icode_bits = esp_efuse_get_field_size(desc[desc_index]);
ESP_ERROR_CHECK(esp_efuse_read_field_blob(desc[desc_index], &adc_icode_diff[diff_index], efuse_icode_bits));
desc_index++;
}
//Version 1 logic for calculating ADC ICode based on EFUSE burnt value
if (adc_unit == ADC_NUM_1) {
adc_icode[0] = adc_icode_diff[0] + 1850;
adc_icode[1] = adc_icode_diff[1] + adc_icode[0] + 90;
adc_icode[2] = adc_icode_diff[2] + adc_icode[1];
adc_icode[3] = adc_icode_diff[3] + adc_icode[2] + 70;
} else {
adc_icode[0] = adc_icode_diff[0] + 2020;
adc_icode[1] = adc_icode_diff[1] + adc_icode[0];
adc_icode[2] = adc_icode_diff[2] + adc_icode[1];
adc_icode[3] = adc_icode_diff[3] + adc_icode[2];
}
return adc_icode[atten];
}
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)
{
assert(version == 1);
assert(atten < 4);
assert(adc_unit < ADC_NUM_MAX);
int efuse_vol_bits = 0;
uint32_t adc_vol_diff[8] = {};
uint32_t adc1_vol[4] = {};
uint32_t adc2_vol[4] = {};
const esp_efuse_desc_t **desc[8] = {ESP_EFUSE_ADC1_CAL_VOL_ATTEN0, ESP_EFUSE_ADC1_CAL_VOL_ATTEN1, ESP_EFUSE_ADC1_CAL_VOL_ATTEN2, ESP_EFUSE_ADC1_CAL_VOL_ATTEN3,
ESP_EFUSE_ADC2_CAL_VOL_ATTEN0, ESP_EFUSE_ADC2_CAL_VOL_ATTEN1, ESP_EFUSE_ADC2_CAL_VOL_ATTEN2, ESP_EFUSE_ADC2_CAL_VOL_ATTEN3};
for (int i = 0; i < 8; i++) {
efuse_vol_bits = esp_efuse_get_field_size(desc[i]);
ESP_ERROR_CHECK(esp_efuse_read_field_blob(desc[i], &adc_vol_diff[i], efuse_vol_bits));
}
adc1_vol[3] = adc_vol_diff[3] + 900;
adc1_vol[2] = adc_vol_diff[2] + adc1_vol[3] + 800;
adc1_vol[1] = adc_vol_diff[1] + adc1_vol[2] + 700;
adc1_vol[0] = adc_vol_diff[0] + adc1_vol[1] + 800;
adc2_vol[3] = adc1_vol[3] - adc_vol_diff[7] + 15;
adc2_vol[2] = adc1_vol[2] - adc_vol_diff[6] + 20;
adc2_vol[1] = adc1_vol[1] - adc_vol_diff[5] + 10;
adc2_vol[0] = adc1_vol[0] - adc_vol_diff[4] + 40;
*out_digi = (adc_unit == ADC_NUM_1) ? adc1_vol[atten] : adc2_vol[atten];
*out_vol_mv = 850;
return ESP_OK;
}

View File

@ -9,7 +9,7 @@
#include <assert.h>
#include "esp_efuse_table.h"
// md5_digest_table 2b4b79060b04576a3d189a54f42dd462
// md5_digest_table 0f3dc076304dac1cb56cea03c223d26d
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
@ -417,15 +417,15 @@ static const esp_efuse_desc_t WAFER_VERSION[] = {
};
static const esp_efuse_desc_t PKG_VERSION[] = {
{EFUSE_BLK1, 117, 4}, // Package version 0:ESP32-S2 1:ESP32-S2FH16 2:ESP32-S2FH32,
{EFUSE_BLK1, 117, 3}, // Package version,
};
static const esp_efuse_desc_t BLOCK1_VERSION[] = {
{EFUSE_BLK1, 121, 3}, // BLOCK1 efuse version 0:No calibration 1:With calibration,
{EFUSE_BLK1, 120, 3}, // BLOCK1 efuse version 0:No calibration 1:With calibration,
};
static const esp_efuse_desc_t SYS_DATA_PART0[] = {
{EFUSE_BLK1, 126, 66}, // System configuration,
static const esp_efuse_desc_t ADC2_CAL_VOL_ATTEN3[] = {
{EFUSE_BLK1, 186, 6}, // ADC2 calibration voltage at atten3,
};
static const esp_efuse_desc_t OPTIONAL_UNIQUE_ID[] = {
@ -433,7 +433,75 @@ static const esp_efuse_desc_t OPTIONAL_UNIQUE_ID[] = {
};
static const esp_efuse_desc_t BLOCK2_VERSION[] = {
{EFUSE_BLK2, 132, 3}, // Version of BLOCK2,
{EFUSE_BLK2, 128, 4}, // Version of BLOCK2,
};
static const esp_efuse_desc_t TEMP_CALIB[] = {
{EFUSE_BLK2, 132, 9}, // Temperature calibration data,
};
static const esp_efuse_desc_t OCODE[] = {
{EFUSE_BLK2, 141, 8}, // ADC OCode,
};
static const esp_efuse_desc_t ADC1_INIT_CODE_ATTEN0[] = {
{EFUSE_BLK2, 149, 8}, // ADC1 init code at atten0,
};
static const esp_efuse_desc_t ADC1_INIT_CODE_ATTEN1[] = {
{EFUSE_BLK2, 157, 6}, // ADC1 init code at atten1,
};
static const esp_efuse_desc_t ADC1_INIT_CODE_ATTEN2[] = {
{EFUSE_BLK2, 163, 6}, // ADC1 init code at atten2,
};
static const esp_efuse_desc_t ADC1_INIT_CODE_ATTEN3[] = {
{EFUSE_BLK2, 169, 6}, // ADC1 init code at atten3,
};
static const esp_efuse_desc_t ADC2_INIT_CODE_ATTEN0[] = {
{EFUSE_BLK2, 175, 8}, // ADC2 init code at atten0,
};
static const esp_efuse_desc_t ADC2_INIT_CODE_ATTEN1[] = {
{EFUSE_BLK2, 183, 6}, // ADC2 init code at atten1,
};
static const esp_efuse_desc_t ADC2_INIT_CODE_ATTEN2[] = {
{EFUSE_BLK2, 189, 6}, // ADC2 init code at atten2,
};
static const esp_efuse_desc_t ADC2_INIT_CODE_ATTEN3[] = {
{EFUSE_BLK2, 195, 6}, // ADC2 init code at atten3,
};
static const esp_efuse_desc_t ADC1_CAL_VOL_ATTEN0[] = {
{EFUSE_BLK2, 201, 8}, // ADC1 calibration voltage at atten0,
};
static const esp_efuse_desc_t ADC1_CAL_VOL_ATTEN1[] = {
{EFUSE_BLK2, 209, 8}, // ADC1 calibration voltage at atten1,
};
static const esp_efuse_desc_t ADC1_CAL_VOL_ATTEN2[] = {
{EFUSE_BLK2, 217, 8}, // ADC1 calibration voltage at atten2,
};
static const esp_efuse_desc_t ADC1_CAL_VOL_ATTEN3[] = {
{EFUSE_BLK2, 225, 8}, // ADC1 calibration voltage at atten3,
};
static const esp_efuse_desc_t ADC2_CAL_VOL_ATTEN0[] = {
{EFUSE_BLK2, 233, 8}, // ADC2 calibration voltage at atten0,
};
static const esp_efuse_desc_t ADC2_CAL_VOL_ATTEN1[] = {
{EFUSE_BLK2, 241, 7}, // ADC2 calibration voltage at atten1,
};
static const esp_efuse_desc_t ADC2_CAL_VOL_ATTEN2[] = {
{EFUSE_BLK2, 248, 7}, // ADC2 calibration voltage at atten2,
};
static const esp_efuse_desc_t USER_DATA[] = {
@ -977,7 +1045,7 @@ const esp_efuse_desc_t* ESP_EFUSE_WAFER_VERSION[] = {
};
const esp_efuse_desc_t* ESP_EFUSE_PKG_VERSION[] = {
&PKG_VERSION[0], // Package version 0:ESP32-S2 1:ESP32-S2FH16 2:ESP32-S2FH32
&PKG_VERSION[0], // Package version
NULL
};
@ -986,8 +1054,8 @@ const esp_efuse_desc_t* ESP_EFUSE_BLOCK1_VERSION[] = {
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_SYS_DATA_PART0[] = {
&SYS_DATA_PART0[0], // System configuration
const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN3[] = {
&ADC2_CAL_VOL_ATTEN3[0], // ADC2 calibration voltage at atten3
NULL
};
@ -1001,6 +1069,91 @@ const esp_efuse_desc_t* ESP_EFUSE_BLOCK2_VERSION[] = {
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_TEMP_CALIB[] = {
&TEMP_CALIB[0], // Temperature calibration data
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_OCODE[] = {
&OCODE[0], // ADC OCode
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN0[] = {
&ADC1_INIT_CODE_ATTEN0[0], // ADC1 init code at atten0
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN1[] = {
&ADC1_INIT_CODE_ATTEN1[0], // ADC1 init code at atten1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN2[] = {
&ADC1_INIT_CODE_ATTEN2[0], // ADC1 init code at atten2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN3[] = {
&ADC1_INIT_CODE_ATTEN3[0], // ADC1 init code at atten3
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN0[] = {
&ADC2_INIT_CODE_ATTEN0[0], // ADC2 init code at atten0
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN1[] = {
&ADC2_INIT_CODE_ATTEN1[0], // ADC2 init code at atten1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN2[] = {
&ADC2_INIT_CODE_ATTEN2[0], // ADC2 init code at atten2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN3[] = {
&ADC2_INIT_CODE_ATTEN3[0], // ADC2 init code at atten3
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN0[] = {
&ADC1_CAL_VOL_ATTEN0[0], // ADC1 calibration voltage at atten0
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN1[] = {
&ADC1_CAL_VOL_ATTEN1[0], // ADC1 calibration voltage at atten1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN2[] = {
&ADC1_CAL_VOL_ATTEN2[0], // ADC1 calibration voltage at atten2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN3[] = {
&ADC1_CAL_VOL_ATTEN3[0], // ADC1 calibration voltage at atten3
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN0[] = {
&ADC2_CAL_VOL_ATTEN0[0], // ADC2 calibration voltage at atten0
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN1[] = {
&ADC2_CAL_VOL_ATTEN1[0], // ADC2 calibration voltage at atten1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN2[] = {
&ADC2_CAL_VOL_ATTEN2[0], // ADC2 calibration voltage at atten2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_USER_DATA[] = {
&USER_DATA[0], // User data
NULL

View File

@ -130,14 +130,31 @@
SPI_PAD_CONFIG_D6, EFUSE_BLK1, 102, 6, SPI_PAD_configure D6
SPI_PAD_CONFIG_D7, EFUSE_BLK1, 108, 6, SPI_PAD_configure D7
WAFER_VERSION, EFUSE_BLK1, 114, 3, WAFER version 0:A
PKG_VERSION, EFUSE_BLK1, 117, 4, Package version 0:ESP32-S2 1:ESP32-S2FH16 2:ESP32-S2FH32
BLOCK1_VERSION, EFUSE_BLK1, 121, 3, BLOCK1 efuse version 0:No calibration 1:With calibration
SYS_DATA_PART0, EFUSE_BLK1, 126, 66, System configuration
PKG_VERSION, EFUSE_BLK1, 117, 3, Package version
BLOCK1_VERSION, EFUSE_BLK1, 120, 3, BLOCK1 efuse version 0:No calibration 1:With calibration
ADC2_CAL_VOL_ATTEN3, EFUSE_BLK1, 186, 6, ADC2 calibration voltage at atten3
# SYS_DATA_PART1 BLOCK# - System configuration
#######################
OPTIONAL_UNIQUE_ID, EFUSE_BLK2, 0, 128, Optional unique 128-bit ID
BLOCK2_VERSION, EFUSE_BLK2, 132, 3, Version of BLOCK2
BLOCK2_VERSION, EFUSE_BLK2, 128, 4, Version of BLOCK2
TEMP_CALIB, EFUSE_BLK2, 132, 9, Temperature calibration data
OCODE, EFUSE_BLK2, 141, 8, ADC OCode
ADC1_INIT_CODE_ATTEN0, EFUSE_BLK2, 149, 8, ADC1 init code at atten0
ADC1_INIT_CODE_ATTEN1, EFUSE_BLK2, 157, 6, ADC1 init code at atten1
ADC1_INIT_CODE_ATTEN2, EFUSE_BLK2, 163, 6, ADC1 init code at atten2
ADC1_INIT_CODE_ATTEN3, EFUSE_BLK2, 169, 6, ADC1 init code at atten3
ADC2_INIT_CODE_ATTEN0, EFUSE_BLK2, 175, 8, ADC2 init code at atten0
ADC2_INIT_CODE_ATTEN1, EFUSE_BLK2, 183, 6, ADC2 init code at atten1
ADC2_INIT_CODE_ATTEN2, EFUSE_BLK2, 189, 6, ADC2 init code at atten2
ADC2_INIT_CODE_ATTEN3, EFUSE_BLK2, 195, 6, ADC2 init code at atten3
ADC1_CAL_VOL_ATTEN0, EFUSE_BLK2, 201, 8, ADC1 calibration voltage at atten0
ADC1_CAL_VOL_ATTEN1, EFUSE_BLK2, 209, 8, ADC1 calibration voltage at atten1
ADC1_CAL_VOL_ATTEN2, EFUSE_BLK2, 217, 8, ADC1 calibration voltage at atten2
ADC1_CAL_VOL_ATTEN3, EFUSE_BLK2, 225, 8, ADC1 calibration voltage at atten3
ADC2_CAL_VOL_ATTEN0, EFUSE_BLK2, 233, 8, ADC2 calibration voltage at atten0
ADC2_CAL_VOL_ATTEN1, EFUSE_BLK2, 241, 7, ADC2 calibration voltage at atten1
ADC2_CAL_VOL_ATTEN2, EFUSE_BLK2, 248, 7, ADC2 calibration voltage at atten2
################
USER_DATA, EFUSE_BLK3, 0, 256, User data

Can't render this file because it contains an unexpected character in line 8 and column 53.

View File

@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get the RTC calibration efuse version
*
* @return Version of the stored efuse
*/
int esp_efuse_rtc_calib_get_ver(void);
/**
* @brief Get the init code in the efuse, for the corresponding attenuation.
*
* @param version Version of the stored efuse
* @param adc_unit ADC unit
* @param atten Attenuation of the init code
* @return The init code stored in efuse
*/
uint16_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten);
/**
* @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
* @param atten Attenuation to use
* @param out_digi Output buffer of the digits
* @param out_vol_mv Output of the voltage, in mV
* @return
* - 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, 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.
*
* @param version Version of the stored efuse
*
* @return The specification of temperature sensor calibration number in efuse.
*/
float esp_efuse_rtc_calib_get_cal_temp(int version);
#ifdef __cplusplus
}
#endif

View File

@ -9,7 +9,7 @@ extern "C" {
#endif
// md5_digest_table 2b4b79060b04576a3d189a54f42dd462
// md5_digest_table 0f3dc076304dac1cb56cea03c223d26d
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
@ -117,9 +117,26 @@ extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_D7[];
extern const esp_efuse_desc_t* ESP_EFUSE_WAFER_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_PKG_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_BLOCK1_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_SYS_DATA_PART0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN3[];
extern const esp_efuse_desc_t* ESP_EFUSE_OPTIONAL_UNIQUE_ID[];
extern const esp_efuse_desc_t* ESP_EFUSE_BLOCK2_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_TEMP_CALIB[];
extern const esp_efuse_desc_t* ESP_EFUSE_OCODE[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN1[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN2[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN3[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN1[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN2[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_INIT_CODE_ATTEN3[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN1[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN2[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN3[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN1[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_CAL_VOL_ATTEN2[];
extern const esp_efuse_desc_t* ESP_EFUSE_USER_DATA[];
extern const esp_efuse_desc_t* ESP_EFUSE_USER_DATA_MAC_CUSTOM[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY0[];

View File

@ -1,3 +1,4 @@
set(EFUSE_SOC_SRCS "esp_efuse_table.c"
"esp_efuse_fields.c"
"esp_efuse_rtc_calib.c"
"esp_efuse_utility.c")

View File

@ -15,6 +15,12 @@ elseif(${target} STREQUAL "esp32c3")
INCLUDE_DIRS "include"
REQUIRES driver efuse)
elseif(${target} STREQUAL "esp32s3")
idf_component_register(SRCS "esp_adc_cal_esp32s3.c"
INCLUDE_DIRS "include"
REQUIRES driver efuse)
elseif(${target} STREQUAL "esp32h2")
idf_component_register(SRCS "esp_adc_cal_esp32h2.c"
INCLUDE_DIRS "include"

View File

@ -3,4 +3,4 @@
#
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_OBJEXCLUDE += esp_adc_cal_esp32s2.o esp_adc_cal_esp32c3.o esp_adc_cal_esp32h2.o
COMPONENT_OBJEXCLUDE += esp_adc_cal_esp32s2.o esp_adc_cal_esp32c3.o esp_adc_cal_esp32h2.o esp_adc_cal_esp32s3.o

View File

@ -17,6 +17,7 @@
#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"
@ -82,11 +83,7 @@
#define LUT_HIGH_THRESH (LUT_LOW_THRESH + LUT_ADC_STEP_SIZE)
#define ADC_12_BIT_RES 4096
#define ADC_CAL_CHECK(cond, ret) ({ \
if(!(cond)){ \
return ret; \
} \
})
const static char LOG_TAG[] = "ADC_CALI";
/* ------------------------ Characterization Constants ---------------------- */
static const uint32_t adc1_tp_atten_scale[4] = {65504, 86975, 120389, 224310};
@ -372,21 +369,20 @@ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
uint32_t *voltage)
{
//Check parameters
ADC_CAL_CHECK(chars != NULL, ESP_ERR_INVALID_ARG);
ADC_CAL_CHECK(voltage != NULL, ESP_ERR_INVALID_ARG);
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input");
ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer");
esp_err_t ret = ESP_OK;
int adc_reading;
if (chars->adc_num == ADC_UNIT_1) {
//Check channel is valid on ADC1
ADC_CAL_CHECK((adc1_channel_t)channel < ADC1_CHANNEL_MAX, ESP_ERR_INVALID_ARG);
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
adc_reading = adc1_get_raw(channel);
} else {
//Check channel is valid on ADC2
ADC_CAL_CHECK((adc2_channel_t)channel < ADC2_CHANNEL_MAX, ESP_ERR_INVALID_ARG);
if (adc2_get_raw(channel, chars->bit_width, &adc_reading) != ESP_OK) {
return ESP_ERR_TIMEOUT; //Timed out waiting for ADC2
}
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
ret = adc2_get_raw(channel, chars->bit_width, &adc_reading);
}
*voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars);
return ESP_OK;
return ret;
}

View File

@ -18,19 +18,12 @@
#include "esp_types.h"
#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"
#define ADC_CALIB_CHECK(cond, err_msg, ret) do {\
if (!(cond)) { \
ESP_LOGE(LOG_TAG, err_msg); \
return (ret); \
} \
} while(0)
const static char LOG_TAG[] = "adc_calib";
@ -110,13 +103,13 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
esp_err_t ret;
adc_calib_parsed_info efuse_parsed_data = {0};
// Check parameters
ADC_CALIB_CHECK(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, "Invalid unit num", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ADC_CALIB_CHECK(chars != NULL, "Invalid characteristic", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ADC_CALIB_CHECK(bit_width == ADC_WIDTH_BIT_12, "Invalid bit_width", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ADC_CALIB_CHECK(atten < 4, "Invalid attenuation", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
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");
int version_num = esp_efuse_rtc_calib_get_ver();
ADC_CALIB_CHECK(version_num == 1, "No calibration efuse burnt", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ESP_RETURN_ON_FALSE(version_num == 1, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "No calibration efuse burnt");
memset(chars, 0, sizeof(esp_adc_cal_characteristics_t));
@ -140,8 +133,7 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
ADC_CALIB_CHECK(chars != NULL, "No characteristic input.", ESP_ERR_INVALID_ARG);
assert(chars != NULL);
return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling;
}
@ -150,21 +142,20 @@ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
uint32_t *voltage)
{
// Check parameters
ADC_CALIB_CHECK(chars != NULL, "No characteristic input.", ESP_ERR_INVALID_ARG);
ADC_CALIB_CHECK(voltage != NULL, "No output buffer.", ESP_ERR_INVALID_ARG);
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input");
ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer");
esp_err_t ret = ESP_OK;
int adc_reading;
if (chars->adc_num == ADC_UNIT_1) {
//Check if channel is valid on ADC1
ADC_CALIB_CHECK((adc1_channel_t)channel < ADC1_CHANNEL_MAX, "Invalid channel", ESP_ERR_INVALID_ARG);
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
adc_reading = adc1_get_raw(channel);
} else {
//Check if channel is valid on ADC2
ADC_CALIB_CHECK((adc2_channel_t)channel < ADC2_CHANNEL_MAX, "Invalid channel", ESP_ERR_INVALID_ARG);
if (adc2_get_raw(channel, chars->bit_width, &adc_reading) != ESP_OK) {
return ESP_ERR_TIMEOUT; //Timed out waiting for ADC2
}
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
ret = adc2_get_raw(channel, chars->bit_width, &adc_reading);
}
*voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars);
return ESP_OK;
return ret;
}

View File

@ -17,6 +17,7 @@
#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"
@ -24,11 +25,6 @@
#include "esp_efuse_rtc_table.h"
#include "hal/adc_hal.h"
#define ADC_CAL_CHECK(cond, ret) ({ \
if(!(cond)){ \
return ret; \
} \
})
const static char LOG_TAG[] = "adc_calib";
/* ------------------------ Characterization Constants ---------------------- */
@ -207,8 +203,7 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
ADC_CAL_CHECK(chars != NULL, ESP_ERR_INVALID_ARG);
assert(chars != NULL);
return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling;
}
@ -217,21 +212,20 @@ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
uint32_t *voltage)
{
// Check parameters
ADC_CAL_CHECK(chars != NULL, ESP_ERR_INVALID_ARG);
ADC_CAL_CHECK(voltage != NULL, ESP_ERR_INVALID_ARG);
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input");
ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer");
esp_err_t ret = ESP_OK;
int adc_reading;
if (chars->adc_num == ADC_UNIT_1) {
//Check if channel is valid on ADC1
ADC_CAL_CHECK((adc1_channel_t)channel < ADC1_CHANNEL_MAX, ESP_ERR_INVALID_ARG);
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
adc_reading = adc1_get_raw(channel);
} else {
//Check if channel is valid on ADC2
ADC_CAL_CHECK((adc2_channel_t)channel < ADC2_CHANNEL_MAX, ESP_ERR_INVALID_ARG);
if (adc2_get_raw(channel, chars->bit_width, &adc_reading) != ESP_OK) {
return ESP_ERR_TIMEOUT; //Timed out waiting for ADC2
}
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
ret = adc2_get_raw(channel, chars->bit_width, &adc_reading);
}
*voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars);
return ESP_OK;
return ret;
}

View File

@ -0,0 +1,237 @@
/*
* SPDX-FileCopyrightText: 2020-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 "driver/adc.h"
#include "hal/adc_types.h"
#include "esp_efuse_rtc_calib.h"
#include "esp_adc_cal.h"
const static char LOG_TAG[] = "ADC_CALI";
/* ------------------------ Characterization Constants ---------------------- */
//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 = 1000000;
/**
* @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 = a1 * X^2 + a2 * X + a3; For atten3, error = a1 * X^4 + a2 * X^3 + a3 * X^2 + a4 * X + a5;
*/
const static uint64_t adc_error_coef_atten[4][10][2] = {
{{9798249589, 1e15}, {50871540569528, 1e16}, {3, 1}, {0, 0}, {0, 0}, //ADC1 atten0
{36615265189, 1e16}, {1353548869615, 1e16}, {3, 1}, {0, 0}, {0, 0}}, //ADC2 atten0
{{101379430548, 1e16}, {49393185868806, 1e16}, {3, 1}, {0, 0}, {0, 0}, //ADC1 atten1
{118964995959, 1e16}, {66319894226185, 1e16}, {2, 1}, {0, 0}, {0, 0}}, //ADC2 atten1
{{208385525314, 1e16}, {147640181047414, 1e16}, {2, 1}, {0, 0}, {0, 0}, //ADC1 atten2
{259011467956, 1e16}, {200996773954387, 1e16}, {1, 1}, {0, 0}, {0, 0}}, //ADC2 atten2
{{13515, 1e15}, {70769718, 1e15}, {1297891447611, 1e16}, {644334888647536, 1e16}, {1,1}, //ADC1 atten3
{15038, 1e15}, {79672528, 1e15}, {1478791187119, 1e16}, {755717904943462, 1e16}, {1,1}} //ADC2 atten3
};
const static int32_t adc_error_sign[4][10] = {
{1, -1, -1, 0, 0, //ADC1 atten0
1, 1, -1, 0, 0}, //ADC2 atten0
{1, -1, -1, 0, 0, //ADC1 atten1
1, -1, -1, 0, 0}, //ADC2 atten1
{1, -1, -1, 0, 0, //ADC1 atten2
1, -1, -1, 0, 0}, //ADC2 atten2
{1, -1, 1, -1, -1, //ADC1 atten3
1, -1, 1, -1, 1} //ADC2 atten3
};
/* -------------------- 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 adc_num;
adc_atten_t atten_level;
union {
adc_calib_data_ver1_t ver1;
} ref_data;
} adc_calib_info_t;
//To get the reference point (Dout, Vin)
static esp_err_t get_reference_point(int version_num, adc_unit_t adc_num, 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->adc_num = adc_num;
calib_info->atten_level = atten;
uint32_t voltage = 0;
uint32_t digi = 0;
ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, ((adc_num == ADC_UNIT_1) ? 0 : 1), atten, &digi, &voltage);
assert(ret == ESP_OK);
calib_info->ref_data.ver1.voltage = voltage;
calib_info->ref_data.ver1.digi = digi;
return ret;
}
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
{
if (source != ESP_ADC_CAL_VAL_EFUSE_TP_FIT) {
return ESP_ERR_NOT_SUPPORTED;
}
uint8_t adc_encoding_version = esp_efuse_rtc_calib_get_ver();
if (adc_encoding_version != 1) {
// current version only accepts encoding ver 1.
return ESP_ERR_INVALID_VERSION;
}
return ESP_OK;
}
/*
* Get an expected linear relationship btwn Vin and Dout
*/
static void calculate_characterization_coefficients(const adc_calib_info_t *parsed_data, esp_adc_cal_characteristics_t *chars)
{
chars->coeff_a = coeff_a_scaling * parsed_data->ref_data.ver1.voltage / parsed_data->ref_data.ver1.digi;
chars->coeff_b = 0;
ESP_LOGV(LOG_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, chars->coeff_a);
}
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars)
{
(void) default_vref;
// Check parameters
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(atten < ADC_ATTEN_MAX, 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");
memset(chars, 0, sizeof(esp_adc_cal_characteristics_t));
adc_calib_info_t calib_info = {0};
// make sure adc is calibrated.
get_reference_point(version_num, adc_num, atten, &calib_info);
calculate_characterization_coefficients(&calib_info, chars);
// Initialize remaining fields
chars->adc_num = adc_num;
chars->atten = atten;
chars->bit_width = bit_width;
return ESP_ADC_CAL_VAL_EFUSE_TP_FIT;
}
static int32_t get_reading_error(uint64_t v_cali_1, uint8_t adc_num, uint8_t atten)
{
if (v_cali_1 == 0) {
return 0;
}
uint8_t term_max = (atten == 3) ? 5 : 3;
int32_t error = 0;
uint64_t coeff = 0;
uint64_t term[5] = {0};
/**
* For atten0 ~ 2:
* error = a1 * X^2 + a2 * X + a3;
*
* For atten3:
* error = a1 * X^4 + a2 * X^3 + a3 * X^2 + a4 * X + a5;
*/
//Calculate all the power beforehand
term[term_max-1] = 1;
term[term_max-2] = v_cali_1;
for (int term_id = term_max - 3; term_id >= 0; term_id--) {
term[term_id] = term[term_id + 1] * v_cali_1;
}
//Calculate each term
uint8_t coef_id_start = (adc_num == ADC_UNIT_1) ? 0 : 5;
for (int i = 0; i < term_max; i++) {
coeff = adc_error_coef_atten[atten][coef_id_start + i][0];
term[i] = term[i] * coeff;
ESP_LOGV(LOG_TAG, "big coef is %llu, big term%d is %llu, coef_id is %d", coeff, i, term[i], coef_id_start + i);
term[i] = term[i] / adc_error_coef_atten[atten][coef_id_start + i][1];
error += (int32_t)term[i] * adc_error_sign[atten][i];
ESP_LOGV(LOG_TAG, "term%d is %llu, error is %d", i, term[i], error);
}
return error;
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
assert(chars != NULL);
//ADC reading won't exceed 4096. Otherwise the raw reading result is wrong, the next calculation will overflow.
assert(adc_reading < 4096);
uint32_t voltage = 0;
int32_t error = 0;
uint64_t v_cali_1 = 0;
//raw * gradient * 1000000
v_cali_1 = adc_reading * chars->coeff_a;
//convert to real number
v_cali_1 = v_cali_1 / coeff_a_scaling;
ESP_LOGV(LOG_TAG, "v_cali_1 is %llu", v_cali_1);
error = get_reading_error(v_cali_1, chars->adc_num, chars->atten);
voltage = (int32_t)v_cali_1 - error;
return voltage;
}
esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
const esp_adc_cal_characteristics_t *chars,
uint32_t *voltage)
{
// Check parameters
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input");
ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer");
esp_err_t ret = ESP_OK;
int adc_reading;
if (chars->adc_num == ADC_UNIT_1) {
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
adc_reading = adc1_get_raw(channel);
} else {
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel");
ret = adc2_get_raw(channel, chars->bit_width, &adc_reading);
}
*voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars);
return ret;
}

View File

@ -30,6 +30,7 @@ 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;
@ -48,6 +49,7 @@ typedef struct {
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;
/**
@ -129,8 +131,8 @@ uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_char
*
* @return
* - ESP_OK: ADC read and converted to mV
* - ESP_ERR_TIMEOUT: Error, timed out attempting to read ADC
* - ESP_ERR_INVALID_ARG: Error due to invalid arguments
* - ESP_ERR_INVALID_STATE: Reading result is invalid. Try to read again.
*/
esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, const esp_adc_cal_characteristics_t *chars, uint32_t *voltage);

View File

@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/**
* @file regi2c_lp_bias.h
* @brief Register definitions for analog to calibrate o_code for getting a more precise voltage.
*/
#define I2C_ULP_IR_FORCE_CODE 5
#define I2C_ULP_IR_FORCE_CODE_MSB 6
#define I2C_ULP_IR_FORCE_CODE_LSB 6
//register for OCode
#define I2C_ULP_EXT_CODE 6
#define I2C_ULP_EXT_CODE_MSB 7
#define I2C_ULP_EXT_CODE_LSB 0

View File

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/**
* @file regi2c_saradc.h
* @brief Register definitions for analog to calibrate initial code for getting a more precise voltage of SAR ADC.
*
* This file lists register fields of SAR, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
* function in adc_ll.h.
*/
#define I2C_SAR_ADC 0X69
#define I2C_SAR_ADC_HOSTID 0
#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR 0x1
#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB 0x3
#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB 0x0
#define ADC_SAR1_INITIAL_CODE_LOW_ADDR 0x0
#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB 0x7
#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB 0x0
#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR 0x4
#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB 0x3
#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB 0x0
#define ADC_SAR2_INITIAL_CODE_LOW_ADDR 0x3
#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB 0x7
#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB 0x0
#define ADC_SAR1_DREF_ADDR 0x2
#define ADC_SAR1_DREF_ADDR_MSB 0x6
#define ADC_SAR1_DREF_ADDR_LSB 0x4
#define ADC_SAR2_DREF_ADDR 0x5
#define ADC_SAR2_DREF_ADDR_MSB 0x6
#define ADC_SAR2_DREF_ADDR_LSB 0x4
#define ADC_SAR1_SAMPLE_CYCLE_ADDR 0x2
#define ADC_SAR1_SAMPLE_CYCLE_ADDR_MSB 0x2
#define ADC_SAR1_SAMPLE_CYCLE_ADDR_LSB 0x0

View File

@ -9,6 +9,12 @@
#include <stdint.h>
#include "regi2c_bbpll.h"
#include "regi2c_dig_reg.h"
#include "regi2c_lp_bias.h"
#include "regi2c_saradc.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Analog function control register */
#define I2C_MST_ANA_CONF0_REG 0x6000E040
@ -73,3 +79,8 @@ void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add,
#define REGI2C_READ(block, reg_add) \
regi2c_ctrl_read_reg(block, block##_HOSTID, reg_add)
#ifdef __cplusplus
}
#endif

View File

@ -17,11 +17,17 @@
#include "regi2c_ctrl.h"
#include "regi2c_ulp.h"
#include "soc_log.h"
#include "esp_err.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#define RTC_CNTL_MEM_FORCE_NOISO (RTC_CNTL_SLOWMEM_FORCE_NOISO | RTC_CNTL_FASTMEM_FORCE_NOISO)
static const char *TAG = "rtcinit";
static void set_ocode_by_efuse(int calib_version);
static void calibrate_ocode(void);
void rtc_init(rtc_config_t cfg)
{
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_RTC_REG, 0);
@ -59,6 +65,31 @@ void rtc_init(rtc_config_t cfg)
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG_SLEEP, RTC_CNTL_DBIAS_1V10);
REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, RTC_CNTL_DBIAS_1V10);
if (cfg.cali_ocode) {
uint32_t blk1_version = 0;
uint32_t blk2_version = 0;
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_BLOCK1_VERSION, &blk1_version, 3);
if (err != ESP_OK) {
blk1_version = 0;
SOC_LOGW(TAG, "efuse read fail, set default blk1_version: %d\n", blk1_version);
}
err = esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &blk2_version, 4);
if (err != ESP_OK) {
blk2_version = 0;
SOC_LOGW(TAG, "efuse read fail, set default blk2_version: %d\n", blk2_version);
}
if (blk1_version != blk2_version) {
blk1_version = 0;
blk2_version = 0;
SOC_LOGW(TAG, "calibration efuse version does not match, set default version: %d\n", 0);
}
if (blk2_version == 1) {
set_ocode_by_efuse(blk2_version);
} else {
calibrate_ocode();
}
}
if (cfg.clkctl_init) {
//clear CMMU clock force on
CLEAR_PERI_REG_MASK(EXTMEM_CACHE_MMU_POWER_CTRL_REG, EXTMEM_CACHE_MMU_MEM_FORCE_ON);
@ -147,55 +178,6 @@ void rtc_init(rtc_config_t cfg)
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD);
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_NOISO);
}
if (cfg.cali_ocode) {
/*
Bangap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration(must close PLL).
Method:
1. read current cpu config, save in old_config;
2. switch cpu to xtal because PLL will be closed when o-code calibration;
3. begin o-code calibration;
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get();
rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL;
rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256;
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_freq == (rtc_slow_freq_x32k)) {
cal_clk = RTC_CAL_32K_XTAL;
} else if (slow_clk_freq == rtc_slow_freq_8MD256) {
cal_clk = RTC_CAL_8MD256;
}
uint64_t max_delay_time_us = 30000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
uint64_t cycle1 = 0;
rtc_cpu_freq_config_t old_config;
rtc_clk_cpu_freq_get_config(&old_config);
rtc_clk_cpu_freq_set_xtal();
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0);
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1);
bool odone_flag = 0;
bool bg_odone_flag = 0;
while (1) {
odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG);
bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG);
cycle1 = rtc_time_get();
if (odone_flag && bg_odone_flag) {
break;
}
if (cycle1 >= timeout_cycle) {
SOC_LOGW(TAG, "o_code calibration fail\n");
break;
}
}
rtc_clk_cpu_freq_set_config(&old_config);
}
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);
@ -236,3 +218,66 @@ void rtc_vddsdio_set_config(rtc_vddsdio_config_t config)
val |= RTC_CNTL_SDIO_PD_EN;
REG_WRITE(RTC_CNTL_SDIO_CONF_REG, val);
}
static void set_ocode_by_efuse(int calib_version)
{
assert(calib_version == 1);
// use efuse ocode.
uint32_t ocode;
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_OCODE, &ocode, 8);
assert(err == ESP_OK);
(void) err;
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_EXT_CODE, ocode);
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE, 1);
}
static void calibrate_ocode(void)
{
/*
Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL).
Method:
1. read current cpu config, save in old_config;
2. switch cpu to xtal because PLL will be closed when o-code calibration;
3. begin o-code calibration;
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get();
rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL;
rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256;
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_freq == (rtc_slow_freq_x32k)) {
cal_clk = RTC_CAL_32K_XTAL;
} else if (slow_clk_freq == rtc_slow_freq_8MD256) {
cal_clk = RTC_CAL_8MD256;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
uint64_t cycle1 = 0;
rtc_cpu_freq_config_t old_config;
rtc_clk_cpu_freq_get_config(&old_config);
rtc_clk_cpu_freq_set_xtal();
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0);
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1);
bool odone_flag = 0;
bool bg_odone_flag = 0;
while (1) {
odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG);
bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG);
cycle1 = rtc_time_get();
if (odone_flag && bg_odone_flag) {
break;
}
if (cycle1 >= timeout_cycle) {
SOC_LOGW(TAG, "o_code calibration fail\n");
break;
}
}
rtc_clk_cpu_freq_set_config(&old_config);
}

View File

@ -10,7 +10,7 @@
#include "soc/soc_caps.h"
#include "soc/rtc.h"
#include "soc/rtc_periph.h"
#if SOC_ADC_SUPPORT_RTC_CTRL
#if SOC_ADC_RTC_CTRL_SUPPORTED
#include "soc/sens_periph.h"
#endif
#include "soc/gpio_periph.h"

View File

@ -76,6 +76,12 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk);
__attribute__((weak)) void esp_clk_init(void)
{
rtc_config_t cfg = RTC_CONFIG_DEFAULT();
soc_reset_reason_t rst_reas;
rst_reas = esp_rom_get_reset_reason(0);
//When power on, we need to set `cali_ocode` to 1, to do a OCode calibration, which will calibrate the rtc reference voltage to a tested value
if (rst_reas == RESET_REASON_CHIP_POWER_ON) {
cfg.cali_ocode = 1;
}
rtc_init(cfg);
assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M);

View File

@ -55,7 +55,7 @@ void adc_hal_arbiter_config(adc_arbiter_t *config)
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
#if SOC_ADC_HW_CALIBRATION_V1
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
void adc_hal_calibration_init(adc_ll_num_t adc_n)
{
adc_ll_calibration_init(adc_n);
@ -134,6 +134,7 @@ static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel)
#define ADC_HAL_CAL_TIMES (10)
#define ADC_HAL_CAL_OFFSET_RANGE (4096)
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd)
{
if (adc_n == ADC_NUM_2) {
@ -191,7 +192,8 @@ uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc
adc_ll_calibration_finish(adc_n);
return ret;
}
#endif //SOC_ADC_HW_CALIBRATION_V1
#endif //#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
//This feature is currently supported on ESP32C3, will be supported on other chips soon

View File

@ -15,6 +15,8 @@
#include <stdio.h>
#include <stdbool.h>
#include "regi2c_ctrl.h"
#include "soc/adc_periph.h"
#include "hal/adc_types.h"
#include "soc/apb_saradc_struct.h"
@ -703,6 +705,18 @@ static inline void adc_ll_disable_sleep_controller(void)
SENS.sar_meas2_mux.sar2_rtc_force = 0;
}
/**
* @brief Set common calibration configuration. Should be shared with other parts (PWDET).
*/
static inline void adc_ll_calibration_init(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 4);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 4);
}
}
/**
* Configure the registers for ADC calibration. You need to call the ``adc_ll_calibration_finish`` interface to resume after calibration.
*
@ -737,7 +751,15 @@ static inline void adc_ll_calibration_finish(adc_ll_num_t adc_n)
*/
static inline void adc_ll_set_calibration_param(adc_ll_num_t adc_n, uint32_t param)
{
abort();
uint8_t msb = param >> 8;
uint8_t lsb = param & 0xFF;
if (adc_n == ADC_NUM_1) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_HIGH_ADDR, msb);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, lsb);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_HIGH_ADDR, msb);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_LOW_ADDR, lsb);
}
}
/**
@ -1015,6 +1037,22 @@ static inline void adc_ll_set_atten(adc_ll_num_t adc_n, adc_channel_t channel, a
}
}
/**
* Get the attenuation of a particular channel on ADCn.
*
* @param adc_n ADC unit.
* @param channel ADCn channel number.
* @return atten The attenuation option.
*/
static inline adc_atten_t adc_ll_get_atten(adc_ll_num_t adc_n, adc_channel_t channel)
{
if (adc_n == ADC_NUM_1) {
return (adc_atten_t)((SENS.sar_atten1 >> (channel * 2)) & 0x3);
} else {
return (adc_atten_t)((SENS.sar_atten2 >> (channel * 2)) & 0x3);
}
}
static inline uint32_t adc_ll_adc1_read(void)
{
//On ESP32S3, valid data width is 12-bit

View File

@ -276,7 +276,7 @@ esp_err_t adc_hal_convert(adc_ll_num_t adc_n, int channel, int *out_raw);
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
#if SOC_ADC_HW_CALIBRATION_V1
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
// ESP32-S2, C3 and H2 support HW offset calibration.
/**
@ -312,7 +312,7 @@ void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param);
*/
uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd);
#endif //SOC_ADC_HW_CALIBRATION_V1
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
/*---------------------------------------------------------------

View File

@ -75,20 +75,33 @@
#define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 1
/*-------------------------- ADC CAPS ----------------------------------------*/
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_PATT_LEN_MAX (16)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 8: 10)
#define SOC_ADC_MAX_CHANNEL_NUM (10)
#define SOC_ADC_MAX_BITWIDTH (12)
/**
* TO BE REMOVED in !14278
* Check if adc support digital controller (DMA) mode.
* @value
* - 1 : support;
* - 0 : not support;
*/
#define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) ((PERIPH_NUM==0)? 1: 0)
#define SOC_ADC_SUPPORT_RTC_CTRL 1
/*!< SAR ADC Module*/
#define SOC_ADC_RTC_CTRL_SUPPORTED 1
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 8: 10)
#define SOC_ADC_MAX_CHANNEL_NUM (10)
/*!< Digital */
#define SOC_ADC_DIGI_CONTROLLER_NUM (2)
#define SOC_ADC_PATT_LEN_MAX (16) //Two pattern table, each contains 16 items. Each item takes 1 byte. But only support ADC1 using DMA mode
#define SOC_ADC_DIGI_MIN_BITWIDTH (9)
#define SOC_ADC_DIGI_MAX_BITWIDTH (12)
/*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */
#define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333
#define SOC_ADC_SAMPLE_FREQ_THRES_LOW 611
/*!< RTC */
#define SOC_ADC_MAX_BITWIDTH (12)
/*-------------------------- BROWNOUT CAPS -----------------------------------*/
#if SOC_CAPS_ECO_VER >= 1

View File

@ -35,19 +35,30 @@
#define SOC_AES_SUPPORT_AES_256 (1)
/*-------------------------- ADC CAPS -------------------------------*/
/*!< SAR ADC Module*/
#define SOC_ADC_ARBITER_SUPPORTED 1
#define SOC_ADC_FILTER_SUPPORTED 1
#define SOC_ADC_MONITOR_SUPPORTED 1
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_PATT_LEN_MAX (16)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 5 : 1)
#define SOC_ADC_MAX_CHANNEL_NUM (5)
#define SOC_ADC_MAX_BITWIDTH (12)
/*!< Digital */
#define SOC_ADC_DIGI_CONTROLLER_NUM (1)
#define SOC_ADC_PATT_LEN_MAX (8) /*!< One pattern table, each contains 8 items. Each item takes 1 byte */
#define SOC_ADC_DIGI_MAX_BITWIDTH (12)
#define SOC_ADC_DIGI_FILTER_NUM (2)
#define SOC_ADC_DIGI_MONITOR_NUM (2)
#define SOC_ADC_HW_CALIBRATION_V1 (1) /*!< support HW offset calibration */
#define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) 1
//F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095
/*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */
#define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333
#define SOC_ADC_SAMPLE_FREQ_THRES_LOW 611
#define SOC_ADC_ARBITER_SUPPORTED 1
/*!< RTC */
#define SOC_ADC_MAX_BITWIDTH (12)
/*!< Calibration */
#define SOC_ADC_CALIBRATION_V1_SUPPORTED (1) /*!< support HW offset calibration version 1*/
/*-------------------------- APB BACKUP DMA CAPS -------------------------------*/
#define SOC_APB_BACKUP_DMA (1)

View File

@ -38,7 +38,7 @@
#define SOC_ADC_MAX_BITWIDTH (12)
#define SOC_ADC_DIGI_FILTER_NUM (2)
#define SOC_ADC_DIGI_MONITOR_NUM (2)
#define SOC_ADC_HW_CALIBRATION_V1 (1) /*!< support HW offset calibration */
#define SOC_ADC_CALIBRATION_V1_SUPPORTED (1) /*!< support HW offset calibration version 1*/
#define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) 1
//F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095
#define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333

View File

@ -62,23 +62,29 @@
#define SOC_XT_WDT_SUPPORTED 1
/*-------------------------- ADC CAPS ----------------------------------------*/
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_PATT_LEN_MAX (16)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10)
#define SOC_ADC_MAX_CHANNEL_NUM (10)
#define SOC_ADC_MAX_BITWIDTH (13)
#define SOC_ADC_HW_CALIBRATION_V1 (1) /*!< support HW offset calibration */
/*!< SAR ADC Module*/
#define SOC_ADC_RTC_CTRL_SUPPORTED 1
#define SOC_ADC_ARBITER_SUPPORTED 1
#define SOC_ADC_FILTER_SUPPORTED 1
#define SOC_ADC_MONITOR_SUPPORTED 1
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10)
#define SOC_ADC_MAX_CHANNEL_NUM (10)
/*!< Digital */
#define SOC_ADC_DIGI_CONTROLLER_NUM (2)
#define SOC_ADC_PATT_LEN_MAX (32) /*!< Two pattern table, each contains 16 items. Each item takes 1 byte */
#define SOC_ADC_DIGI_MAX_BITWIDTH (12)
/*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */
#define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333
#define SOC_ADC_SAMPLE_FREQ_THRES_LOW 611
/*!< RTC */
#define SOC_ADC_MAX_BITWIDTH (13)
/*!< Calibration */
#define SOC_ADC_CALIBRATION_V1_SUPPORTED (1) /*!< support HW offset calibration version 1*/
/**
* Check if adc support digital controller (DMA) mode.
* @value
* - 1 : support;
* - 0 : not support;
*/
#define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) ((PERIPH_NUM==0)? 1: 1)
#define SOC_ADC_SUPPORT_RTC_CTRL 1
#define SOC_ADC_ARBITER_SUPPORTED 1
/*-------------------------- BROWNOUT CAPS -----------------------------------*/
#define SOC_BROWNOUT_RESET_SUPPORTED 1

View File

@ -36,12 +36,29 @@
#define SOC_APPCPU_HAS_CLOCK_GATING_BUG (1)
/*-------------------------- ADC CAPS ----------------------------------------*/
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10)
#define SOC_ADC_MAX_CHANNEL_NUM (10)
#define SOC_ADC_MAX_BITWIDTH (12)
#define SOC_ADC_SUPPORT_RTC_CTRL (1)
#define SOC_ADC_ARBITER_SUPPORTED (1)
/*!< SAR ADC Module*/
#define SOC_ADC_RTC_CTRL_SUPPORTED 1
#define SOC_ADC_ARBITER_SUPPORTED 1
#define SOC_ADC_FILTER_SUPPORTED 1
#define SOC_ADC_MONITOR_SUPPORTED 1
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10)
#define SOC_ADC_MAX_CHANNEL_NUM (10)
/*!< Digital */
#define SOC_ADC_DIGI_CONTROLLER_NUM (2)
#define SOC_ADC_PATT_LEN_MAX (24) //Two pattern table, each contains 12 items. Each item takes 1 byte
#define SOC_ADC_DIGI_MAX_BITWIDTH (13)
/*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */
#define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333
#define SOC_ADC_SAMPLE_FREQ_THRES_LOW 611
/*!< RTC */
#define SOC_ADC_MAX_BITWIDTH (12)
/*!< Calibration */
#define SOC_ADC_CALIBRATION_V1_SUPPORTED (1) /*!< support HW offset calibration version 1*/
/*-------------------------- APB BACKUP DMA CAPS -------------------------------*/
#define SOC_APB_BACKUP_DMA (1)

View File

@ -18,7 +18,7 @@
#include "soc/soc_caps.h"
#include "soc/syscon_struct.h"
#if SOC_ADC_SUPPORT_RTC_CTRL
#if SOC_ADC_RTC_CTRL_SUPPORTED
#include "soc/sens_reg.h"
#include "soc/sens_struct.h"
#endif

View File

@ -27,7 +27,7 @@
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_cntl_struct.h"
#if SOC_ADC_SUPPORT_RTC_CTRL
#if SOC_ADC_RTC_CTRL_SUPPORTED
#include "soc/sens_struct.h"
#endif

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(single_read)

View File

@ -0,0 +1,8 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := single_read
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,55 @@
# ADC Single Read Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates the following:
- How to obtain a single ADC reading from a GPIO pin using the ADC Driver's Single Read function
- How to use the ADC Calibration functions to obtain a calibrated result (in mV)
## How to use example
### Hardware Required
* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for power supply and programming
In this example, you need to connect a voltage source (e.g. a DC power supply) to the GPIO pins specified in `single_read.c` (see the macros defined on the top of the source file). Feel free to modify the pin setting.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
Running this example, you will see the following log output on the serial monitor:
```
I (302) ADC1_CH2: raw data: 4095
I (302) ADC1_CH2: cali data: 3109 mV
I (1302) ADC2_CH0: raw data: 0
I (1302) ADC2_CH0: cali data: 0 mV
I (2302) ADC1_CH2: raw data: 4095
I (2302) ADC1_CH2: cali data: 3109 mV
I (3302) ADC2_CH0: raw data: 0
I (3302) ADC2_CH0: cali data: 0 mV
I (4302) ADC1_CH2: raw data: 4095
I (4302) ADC1_CH2: cali data: 3109 mV
...
```
## Troubleshooting
If following warning is printed out, it means the calibration required eFuse bits are not burnt correctly on your board. The calibration will be skipped. Only raw data will be printed out.
```
W (300) ADC SINGLE: eFuse not burnt, skip calibration
I (1310) ADC2_CH0: raw data: 2715
```

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "single_read.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#

View File

@ -0,0 +1,104 @@
/* ADC1 Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/adc_common.h"
#include "esp_adc_cal.h"
//ADC Channels
#if CONFIG_IDF_TARGET_ESP32
#define ADC1_EXAMPLE_CHAN0 ADC1_CHANNEL_6
#define ADC2_EXAMPLE_CHAN0 ADC2_CHANNEL_0
static const char *TAG_CH[2][10] = {{"ADC1_CH6"}, {"ADC2_CH0"}};
#else
#define ADC1_EXAMPLE_CHAN0 ADC1_CHANNEL_2
#define ADC2_EXAMPLE_CHAN0 ADC2_CHANNEL_0
static const char *TAG_CH[2][10] = {{"ADC1_CH2"}, {"ADC2_CH0"}};
#endif
//ADC Attenuation
#define ADC_EXAMPLE_ATTEN ADC_ATTEN_DB_11
//ADC Calibration
#if CONFIG_IDF_TARGET_ESP32
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF
#elif CONFIG_IDF_TARGET_ESP32S2
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
#elif CONFIG_IDF_TARGET_ESP32C3
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
#elif CONFIG_IDF_TARGET_ESP32S3
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT
#endif
static int adc_raw[2][10];
static const char *TAG = "ADC SINGLE";
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_EXAMPLE_CALI_SCHEME);
if (ret == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGW(TAG, "Calibration scheme not supported, skip calibration");
} else if (ret == ESP_ERR_INVALID_VERSION) {
ESP_LOGW(TAG, "eFuse not burnt, skip calibration");
} else if (ret == ESP_OK) {
cali_enable = true;
esp_adc_cal_characterize(ADC_UNIT_1, ADC_EXAMPLE_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars);
esp_adc_cal_characterize(ADC_UNIT_2, ADC_EXAMPLE_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc2_chars);
} else {
ESP_LOGE(TAG, "Invalid arg");
}
return cali_enable;
}
void app_main(void)
{
esp_err_t ret = ESP_OK;
uint32_t voltage = 0;
bool cali_enable = adc_calibration_init();
//ADC1 config
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT));
ESP_ERROR_CHECK(adc1_config_channel_atten(ADC1_EXAMPLE_CHAN0, ADC_EXAMPLE_ATTEN));
//ADC2 config
ESP_ERROR_CHECK(adc2_config_channel_atten(ADC2_EXAMPLE_CHAN0, ADC_EXAMPLE_ATTEN));
while (1) {
adc_raw[0][0] = adc1_get_raw(ADC1_EXAMPLE_CHAN0);
ESP_LOGI(TAG_CH[0][0], "raw data: %d", adc_raw[0][0]);
if (cali_enable) {
voltage = esp_adc_cal_raw_to_voltage(adc_raw[0][0], &adc1_chars);
ESP_LOGI(TAG_CH[0][0], "cali data: %d mV", voltage);
}
vTaskDelay(pdMS_TO_TICKS(1000));
do {
ret = adc2_get_raw(ADC2_EXAMPLE_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw[1][0]);
} while (ret == ESP_ERR_INVALID_STATE);
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG_CH[1][0], "raw data: %d", adc_raw[1][0]);
if (cali_enable) {
voltage = esp_adc_cal_raw_to_voltage(adc_raw[1][0], &adc2_chars);
ESP_LOGI(TAG_CH[1][0], "cali data: %d mV", voltage);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}