Merge branch 'feature/sync_adc_changes_from_c3_to_master_last' into 'master'

adc: sync adc changes from c3 to master (last time)

Closes IDF-2694

See merge request espressif/esp-idf!12134
This commit is contained in:
Michael (XIAO Xufeng) 2021-01-26 12:52:20 +08:00
commit c99e891201
18 changed files with 322 additions and 192 deletions

View File

@ -308,6 +308,10 @@ esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
adc_hal_set_atten(ADC_NUM_1, channel, atten);
ADC_EXIT_CRITICAL();
#if SOC_ADC_HW_CALIBRATION_V1
adc_hal_calibration_init(ADC_NUM_1);
#endif
return ESP_OK;
}
@ -472,6 +476,10 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
ADC2_WIFI_LOCK_RELEASE();
ADC2_EXIT_CRITICAL();
#if SOC_ADC_HW_CALIBRATION_V1
adc_hal_calibration_init(ADC_NUM_2);
#endif
return ESP_OK;
}

View File

@ -201,6 +201,9 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
periph_module_enable(PERIPH_SARADC_MODULE);
periph_module_enable(PERIPH_GDMA_MODULE);
adc_hal_calibration_init(ADC_NUM_1);
adc_hal_calibration_init(ADC_NUM_2);
return ret;
cleanup:
@ -268,8 +271,6 @@ esp_err_t adc_digi_start(void)
ADC_DIGI_LOCK_ACQUIRE();
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
adc_hal_init();
if (s_adc_digi_ctx->use_adc1) {
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_1, ADC_CHANNEL_MAX, s_adc_digi_ctx->adc1_atten);
adc_hal_set_calibration_param(ADC_NUM_1, cal_val);
@ -279,6 +280,8 @@ esp_err_t adc_digi_start(void)
adc_hal_set_calibration_param(ADC_NUM_2, cal_val);
}
adc_hal_init();
adc_hal_arbiter_config(&config);
adc_hal_digi_init(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
adc_hal_digi_controller_config(&s_adc_digi_ctx->digi_controller_config);
@ -418,6 +421,8 @@ esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
s_atten1_single[channel] = atten;
ret = adc_digi_gpio_init(ADC_NUM_1, BIT(channel));
adc_hal_calibration_init(ADC_NUM_1);
return ret;
}
@ -441,18 +446,19 @@ int adc1_get_raw(adc1_channel_t channel)
adc_hal_digi_controller_config(&dig_cfg);
adc_hal_intr_clear(ADC_EVENT_ADC1_DONE);
adc_hal_adc1_onetime_sample_enable(true);
adc_hal_onetime_channel(ADC_NUM_1, channel);
adc_hal_set_onetime_atten(atten);
//Trigger single read.
adc_hal_adc1_onetime_sample_enable(true);
adc_hal_onetime_start(&dig_cfg);
while (!adc_hal_intr_get_raw(ADC_EVENT_ADC1_DONE));
adc_hal_single_read(ADC_NUM_1, &raw_out);
adc_hal_intr_clear(ADC_EVENT_ADC1_DONE);
adc_hal_adc1_onetime_sample_enable(false);
adc_hal_single_read(ADC_NUM_1, &raw_out);
adc_hal_digi_deinit();
periph_module_disable(PERIPH_SARADC_MODULE);
@ -470,6 +476,8 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
s_atten2_single[channel] = atten;
ret = adc_digi_gpio_init(ADC_NUM_2, BIT(channel));
adc_hal_calibration_init(ADC_NUM_2);
return ret;
}
@ -498,28 +506,26 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
adc_hal_digi_controller_config(&dig_cfg);
adc_hal_intr_clear(ADC_EVENT_ADC2_DONE);
adc_hal_adc2_onetime_sample_enable(true);
adc_hal_onetime_channel(ADC_NUM_2, channel);
adc_hal_set_onetime_atten(atten);
//Trigger single read.
adc_hal_adc2_onetime_sample_enable(true);
adc_hal_onetime_start(&dig_cfg);
while (!adc_hal_intr_get_raw(ADC_EVENT_ADC2_DONE));
ret = adc_hal_single_read(ADC_NUM_2, raw_out);
adc_hal_intr_clear(ADC_EVENT_ADC2_DONE);
adc_hal_adc2_onetime_sample_enable(false);
ret = adc_hal_single_read(ADC_NUM_2, raw_out);
if (ret != ESP_OK) {
return ret;
}
adc_hal_digi_deinit();
periph_module_disable(PERIPH_SARADC_MODULE);
ADC_DIGI_LOCK_RELEASE();
SAC_ADC2_LOCK_RELEASE();
return ESP_OK;
return ret;
}
@ -794,7 +800,7 @@ esp_err_t adc_digi_isr_deregister(void)
RTC controller setting
---------------------------------------------------------------*/
static uint16_t s_adc_cali_param[ADC_ATTEN_MAX] = {};
static uint16_t s_adc_cali_param[ADC_UNIT_MAX][ADC_ATTEN_MAX] = {};
//NOTE: according to calibration version, different types of lock may be taken during the process:
// 1. Semaphore when reading efuse
@ -803,8 +809,8 @@ static uint16_t s_adc_cali_param[ADC_ATTEN_MAX] = {};
static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
const bool no_cal = false;
if (s_adc_cali_param[atten]) {
return (uint32_t)s_adc_cali_param[atten];
if (s_adc_cali_param[adc_n][atten]) {
return (uint32_t)s_adc_cali_param[adc_n][atten];
}
if (no_cal) {
@ -813,17 +819,30 @@ static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t cha
// check if we can fetch the values from eFuse.
int version = esp_efuse_rtc_calib_get_ver();
assert(version == 1);
uint32_t init_code = esp_efuse_rtc_calib_get_init_code(version, atten);
ESP_LOGD(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code);
s_adc_cali_param[atten] = init_code;
uint32_t init_code = 0;
if (version == 1) {
//for calibration v1, both ADC units use the same init code (calibrated by ADC1)
init_code = esp_efuse_rtc_calib_get_init_code(version, atten);
ESP_LOGD(ADC_TAG, "Calib(V%d) ADC0, 1 atten=%d: %04X", version, atten, init_code);
s_adc_cali_param[0][atten] = init_code;
s_adc_cali_param[1][atten] = init_code;
} else {
const bool internal_gnd = true;
ADC_ENTER_CRITICAL();
init_code = adc_hal_self_calibration(adc_n, channel, atten, internal_gnd);
ADC_EXIT_CRITICAL();
ESP_LOGD(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code);
s_adc_cali_param[adc_n][atten] = init_code;
}
return init_code;
}
// Internal function to calibrate PWDET for WiFi
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);
ADC_ENTER_CRITICAL();
adc_hal_set_calibration_param(adc_n, cal_val);

View File

@ -74,6 +74,10 @@ esp_err_t adc_digi_init(void)
adc_hal_init();
adc_hal_arbiter_config(&config);
ADC_EXIT_CRITICAL();
adc_hal_calibration_init(ADC_NUM_1);
adc_hal_calibration_init(ADC_NUM_2);
return ESP_OK;
}
@ -472,6 +476,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);
ADC_ENTER_CRITICAL();
adc_hal_set_calibration_param(adc_n, cal_val);

View File

@ -43,14 +43,21 @@ esp_err_t adc2_wifi_acquire(void);
*/
esp_err_t adc2_wifi_release(void);
#if CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
/**
* @brief This API help ADC2 calibration constructor be linked.
*
* @note This is a private function, Don't call `adc2_cal_include` in user code.
*/
void adc2_cal_include(void);
#endif //CONFIG_IDF_TARGET_ESP32S2
#else
/**
* @brief There's no calibration involved on this chip.
*
* @note This is a private function, Don't call `adc2_cal_include` in user code.
*/
#define adc2_cal_include()
#endif //CONFIG_IDF_TARGET_*
#ifdef __cplusplus
}

View File

@ -175,9 +175,13 @@ TEST_CASE("test_adc_dma", "[adc][ignore][manual]")
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);
TEST_ASSERT(cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP);
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();
@ -201,9 +205,11 @@ TEST_CASE("test_adc_dma", "[adc][ignore][manual]")
print_summary(print_figure);
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 (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());
@ -240,9 +246,13 @@ TEST_CASE("test_adc_single", "[adc][ignore][manual]")
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);
TEST_ASSERT(cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP);
if (cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP) {
do_calibration = true;
}
const int test_count = TEST_COUNT;
@ -258,9 +268,13 @@ TEST_CASE("test_adc_single", "[adc][ignore][manual]")
print_summary(print_figure);
break;
}
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 (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;

View File

@ -50,6 +50,10 @@
#define I2C_ULP_BG_O_DONE_FLAG_MSB 3
#define I2C_ULP_BG_O_DONE_FLAG_LSB 3
#define I2C_ULP_OCODE 4
#define I2C_ULP_OCODE_MSB 7
#define I2C_ULP_OCODE_LSB 0
#define I2C_ULP_IR_FORCE_CODE 5
#define I2C_ULP_IR_FORCE_CODE_MSB 6
#define I2C_ULP_IR_FORCE_CODE_LSB 6

View File

@ -247,9 +247,7 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
return result;
}
}
#if CONFIG_IDF_TARGET_ESP32S2
adc2_cal_include(); //This enables the ADC2 calibration constructor at start up.
#endif
esp_wifi_config_info();
return result;
}

View File

@ -12,8 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "soc/soc_caps.h"
#include "hal/adc_hal.h"
#include "hal/adc_hal_conf.h"
#include "sdkconfig.h"
#include <sys/param.h>
#if CONFIG_IDF_TARGET_ESP32C3
@ -50,6 +53,159 @@ int adc_hal_convert(adc_ll_num_t adc_n, int channel, int *value)
}
#endif
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
#if SOC_ADC_HW_CALIBRATION_V1
// ESP32-S2 and C3 support HW offset calibration.
void adc_hal_calibration_init(adc_ll_num_t adc_n)
{
adc_ll_calibration_init(adc_n);
}
static uint32_t s_previous_init_code[SOC_ADC_PERIPH_NUM] = {-1, -1};
void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param)
{
if (param != s_previous_init_code[adc_n]) {
adc_ll_set_calibration_param(adc_n, param);
s_previous_init_code[adc_n] = param;
}
}
#if CONFIG_IDF_TARGET_ESP32S2
static void cal_setup(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd)
{
adc_hal_set_controller(adc_n, ADC_CTRL_RTC); //Set controller
/* Enable/disable internal connect GND (for calibration). */
if (internal_gnd) {
adc_ll_rtc_disable_channel(adc_n);
adc_ll_set_atten(adc_n, 0, atten); // Note: when disable all channel, HW auto select channel0 atten param.
} else {
adc_ll_rtc_enable_channel(adc_n, channel);
adc_ll_set_atten(adc_n, channel, atten);
}
}
static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel)
{
adc_ll_rtc_start_convert(adc_n, channel);
while (adc_ll_rtc_convert_is_done(adc_n) != true);
return (uint32_t)adc_ll_rtc_get_convert_value(adc_n);
}
#elif CONFIG_IDF_TARGET_ESP32C3
static void cal_setup(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd)
{
adc_hal_set_controller(adc_n, ADC_CTRL_DIG); //Set controller
adc_digi_config_t dig_cfg = {
.conv_limit_en = 0,
.conv_limit_num = 250,
.sample_freq_hz = SOC_ADC_SAMPLE_FREQ_THRES_HIGH,
};
adc_hal_digi_controller_config(&dig_cfg);
/* Enable/disable internal connect GND (for calibration). */
if (internal_gnd) {
const int esp32c3_invalid_chan = (adc_n == ADC_NUM_1)? 0xF: 0x1;
adc_ll_onetime_set_channel(adc_n, esp32c3_invalid_chan);
} else {
adc_ll_onetime_set_channel(adc_n, channel);
}
adc_ll_onetime_set_atten(atten);
adc_hal_adc1_onetime_sample_enable((adc_n == ADC_NUM_1));
adc_hal_adc2_onetime_sample_enable((adc_n == ADC_NUM_2));
}
static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel)
{
adc_ll_intr_clear(ADC_LL_INTR_ADC1_DONE | ADC_LL_INTR_ADC2_DONE);
adc_ll_onetime_start(false);
esp_rom_delay_us(5);
adc_ll_onetime_start(true);
while(!adc_ll_intr_get_raw(ADC_LL_INTR_ADC1_DONE | ADC_LL_INTR_ADC2_DONE));
uint32_t read_val = -1;
if (adc_n == ADC_NUM_1) {
read_val = adc_ll_adc1_read();
} else if (adc_n == ADC_NUM_2) {
read_val = adc_ll_adc2_read();
if (adc_ll_analysis_raw_data(adc_n, read_val)) {
return -1;
}
}
return read_val;
}
#endif //CONFIG_IDF_TARGET_*
#define ADC_HAL_CAL_TIMES (10)
#define ADC_HAL_CAL_OFFSET_RANGE (4096)
uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd)
{
adc_hal_set_power_manage(ADC_POWER_SW_ON);
if (adc_n == ADC_NUM_2) {
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
adc_hal_arbiter_config(&config);
}
cal_setup(adc_n, channel, atten, internal_gnd);
adc_ll_calibration_prepare(adc_n, channel, internal_gnd);
uint32_t code_list[ADC_HAL_CAL_TIMES] = {0};
uint32_t code_sum = 0;
uint32_t code_h = 0;
uint32_t code_l = 0;
uint32_t chk_code = 0;
for (uint8_t rpt = 0 ; rpt < ADC_HAL_CAL_TIMES ; rpt ++) {
code_h = ADC_HAL_CAL_OFFSET_RANGE;
code_l = 0;
chk_code = (code_h + code_l) / 2;
adc_ll_set_calibration_param(adc_n, chk_code);
uint32_t self_cal = read_cal_channel(adc_n, channel);
while (code_h - code_l > 1) {
if (self_cal == 0) {
code_h = chk_code;
} else {
code_l = chk_code;
}
chk_code = (code_h + code_l) / 2;
adc_ll_set_calibration_param(adc_n, chk_code);
self_cal = read_cal_channel(adc_n, channel);
if ((code_h - code_l == 1)) {
chk_code += 1;
adc_ll_set_calibration_param(adc_n, chk_code);
self_cal = read_cal_channel(adc_n, channel);
}
}
code_list[rpt] = chk_code;
code_sum += chk_code;
}
code_l = code_list[0];
code_h = code_list[0];
for (uint8_t i = 0 ; i < ADC_HAL_CAL_TIMES ; i++) {
code_l = MIN(code_l, code_list[i]);
code_h = MAX(code_h, code_list[i]);
}
chk_code = code_h + code_l;
uint32_t ret = ((code_sum - chk_code) % (ADC_HAL_CAL_TIMES - 2) < 4)
? (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2)
: (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + 1;
adc_ll_calibration_finish(adc_n);
return ret;
}
#endif //SOC_ADC_HW_CALIBRATION_V1
#if CONFIG_IDF_TARGET_ESP32C3
//This feature is currently supported on ESP32C3, will be supported on other chips soon
/*---------------------------------------------------------------
@ -130,6 +286,9 @@ void adc_hal_digi_init(adc_dma_hal_context_t *adc_dma_ctx, adc_dma_hal_config_t
gdma_ll_enable_clock(adc_dma_ctx->dev, true);
gdma_ll_clear_interrupt_status(adc_dma_ctx->dev, dma_config->dma_chan, UINT32_MAX);
gdma_ll_rx_connect_to_periph(adc_dma_ctx->dev, dma_config->dma_chan, SOC_GDMA_TRIG_PERIPH_ADC0);
adc_ll_adc1_onetime_sample_enable(false);
adc_ll_adc2_onetime_sample_enable(false);
}
/*---------------------------------------------------------------
@ -163,20 +322,12 @@ void adc_hal_onetime_start(adc_digi_config_t *adc_digi_config)
void adc_hal_adc1_onetime_sample_enable(bool enable)
{
if (enable) {
adc_ll_adc1_onetime_sample_ena();
} else {
adc_ll_adc1_onetime_sample_dis();
}
adc_ll_adc1_onetime_sample_enable(enable);
}
void adc_hal_adc2_onetime_sample_enable(bool enable)
{
if (enable) {
adc_ll_adc2_onetime_sample_ena();
} else {
adc_ll_adc2_onetime_sample_dis();
}
adc_ll_adc2_onetime_sample_enable(enable);
}
void adc_hal_onetime_channel(adc_ll_num_t unit, adc_channel_t channel)

View File

@ -299,9 +299,8 @@ static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel)
* @note Only one channel can be selected in once measurement.
*
* @param adc_n ADC unit.
* @param channel ADC channel number for each ADCn.
*/
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n, int channel)
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_meas_start1.sar1_en_pad = 0; //only one channel is selected.

View File

@ -206,20 +206,6 @@ void adc_hal_digi_monitor_enable(adc_digi_monitor_idx_t mon_idx, bool enable);
*/
void adc_hal_arbiter_config(adc_arbiter_t *config);
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
/**
* Set the calibration result (initial data) to ADC.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
*/
#define adc_hal_set_calibration_param(adc_n, param) adc_ll_set_calibration_param(adc_n, param);
#ifdef __cplusplus
}
#endif

View File

@ -738,6 +738,17 @@ static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig,
}
/* ADC calibration code. */
/**
* @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, 1);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 1);
}
}
/**
* Configure the registers for ADC calibration. You need to call the ``adc_ll_calibration_finish`` interface to resume after calibration.
@ -751,19 +762,14 @@ static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig,
*/
static inline void adc_ll_calibration_prepare(adc_ll_num_t adc_n, adc_channel_t channel, bool internal_gnd)
{
/* Should be called before writing I2C registers. */
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU);
/* Enable/disable internal connect GND (for calibration). */
if (adc_n == ADC_NUM_1) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 4);
if (internal_gnd) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 1);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0);
}
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 4);
if (internal_gnd) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 1);
} else {
@ -912,14 +918,9 @@ static inline bool adc_ll_intr_get_status(adc_ll_intr_t mask)
}
//--------------------------------adc1------------------------------//
static inline void adc_ll_adc1_onetime_sample_ena(void)
static inline void adc_ll_adc1_onetime_sample_enable(bool enable)
{
APB_SARADC.onetime_sample.adc1_onetime_sample = 1;
}
static inline void adc_ll_adc1_onetime_sample_dis(void)
{
APB_SARADC.onetime_sample.adc1_onetime_sample = 0;
APB_SARADC.onetime_sample.adc1_onetime_sample = enable;
}
static inline uint32_t adc_ll_adc1_read(void)
@ -929,14 +930,9 @@ static inline uint32_t adc_ll_adc1_read(void)
}
//--------------------------------adc2------------------------------//
static inline void adc_ll_adc2_onetime_sample_ena(void)
static inline void adc_ll_adc2_onetime_sample_enable(bool enable)
{
APB_SARADC.onetime_sample.adc2_onetime_sample = 1;
}
static inline void adc_ll_adc2_onetime_sample_dis(void)
{
APB_SARADC.onetime_sample.adc2_onetime_sample = 0;
APB_SARADC.onetime_sample.adc2_onetime_sample = enable;
}
static inline uint32_t adc_ll_adc2_read(void)

View File

@ -146,86 +146,3 @@ void adc_hal_arbiter_config(adc_arbiter_t *config)
adc_ll_set_arbiter_work_mode(config->mode);
adc_ll_set_arbiter_priority(config->rtc_pri, config->dig_pri, config->pwdet_pri);
}
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
#define ADC_HAL_CAL_TIMES (10)
#define ADC_HAL_CAL_OFFSET_RANGE (4096)
static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel)
{
adc_ll_rtc_start_convert(adc_n, channel);
while (adc_ll_rtc_convert_is_done(adc_n) != true);
return (uint32_t)adc_ll_rtc_get_convert_value(adc_n);
}
uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd)
{
adc_hal_set_power_manage(ADC_POWER_SW_ON);
if (adc_n == ADC_NUM_2) {
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
adc_hal_arbiter_config(&config);
}
adc_hal_set_controller(adc_n, ADC_CTRL_RTC); //Set controller
adc_ll_calibration_prepare(adc_n, channel, internal_gnd);
/* Enable/disable internal connect GND (for calibration). */
if (internal_gnd) {
adc_ll_rtc_disable_channel(adc_n, channel);
adc_ll_set_atten(adc_n, 0, atten); // Note: when disable all channel, HW auto select channel0 atten param.
} else {
adc_ll_rtc_enable_channel(adc_n, channel);
adc_ll_set_atten(adc_n, channel, atten);
}
uint32_t code_list[ADC_HAL_CAL_TIMES] = {0};
uint32_t code_sum = 0;
uint32_t code_h = 0;
uint32_t code_l = 0;
uint32_t chk_code = 0;
for (uint8_t rpt = 0 ; rpt < ADC_HAL_CAL_TIMES ; rpt ++) {
code_h = ADC_HAL_CAL_OFFSET_RANGE;
code_l = 0;
chk_code = (code_h + code_l) / 2;
adc_ll_set_calibration_param(adc_n, chk_code);
uint32_t self_cal = read_cal_channel(adc_n, channel);
while (code_h - code_l > 1) {
if (self_cal == 0) {
code_h = chk_code;
} else {
code_l = chk_code;
}
chk_code = (code_h + code_l) / 2;
adc_ll_set_calibration_param(adc_n, chk_code);
self_cal = read_cal_channel(adc_n, channel);
if ((code_h - code_l == 1)) {
chk_code += 1;
adc_ll_set_calibration_param(adc_n, chk_code);
self_cal = read_cal_channel(adc_n, channel);
}
}
code_list[rpt] = chk_code;
code_sum += chk_code;
}
code_l = code_list[0];
code_h = code_list[0];
for (uint8_t i = 0 ; i < ADC_HAL_CAL_TIMES ; i++) {
if (code_l > code_list[i]) {
code_l = code_list[i];
}
if (code_h < code_list[i]) {
code_h = code_list[i];
}
}
chk_code = code_h + code_l;
uint32_t ret = ((code_sum - chk_code) % (ADC_HAL_CAL_TIMES - 2) < 4)
? (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2)
: (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + 1;
adc_ll_calibration_finish(adc_n);
return ret;
}

View File

@ -214,35 +214,6 @@ void adc_hal_digi_monitor_config(adc_ll_num_t adc_n, adc_digi_monitor_t *config)
*/
void adc_hal_arbiter_config(adc_arbiter_t *config);
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
/**
* Calibrate the ADC using internal connections.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
* @param channel adc channel number.
* @param atten The attenuation for the channel
* @param internal_gnd true: Disconnect from the IO port and use the internal GND as the calibration voltage.
* false: Use IO external voltage as calibration voltage.
*
* @return
* - The calibration result (initial data) to ADC, use `adc_hal_set_calibration_param` to set.
*/
uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd);
/**
* Set the calibration result (initial data) to ADC.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
*/
#define adc_hal_set_calibration_param(adc_n, param) adc_ll_set_calibration_param(adc_n, param);
#ifdef __cplusplus
}
#endif

View File

@ -690,7 +690,7 @@ static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel)
* @param adc_n ADC unit.
* @param channel ADC channel number for each ADCn.
*/
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n, int channel)
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_meas1_ctrl2.sar1_en_pad = 0; //only one channel is selected.
@ -1123,6 +1123,18 @@ static inline void adc_ll_disable_sleep_controller(void)
}
/* ADC calibration code. */
/**
* @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.
*
@ -1143,14 +1155,12 @@ static inline void adc_ll_calibration_prepare(adc_ll_num_t adc_n, adc_channel_t
/* Enable/disable internal connect GND (for calibration). */
if (adc_n == ADC_NUM_1) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 4);
if (internal_gnd) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 1);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0);
}
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 4);
if (internal_gnd) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 1);
} else {

View File

@ -606,7 +606,7 @@ static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel)
* @param adc_n ADC unit.
* @param channel ADC channel number for each ADCn.
*/
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n, int channel)
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_meas1_ctrl2.sar1_en_pad = 0; //only one channel is selected.

View File

@ -1,5 +1,6 @@
#pragma once
#include "soc/soc_caps.h"
#include "hal/adc_types.h"
#include "hal/adc_ll.h"
@ -206,6 +207,47 @@ void adc_hal_digi_controller_config(const adc_digi_config_t *cfg);
*/
#define adc_hal_digi_clear_pattern_table(adc_n) adc_ll_digi_clear_pattern_table(adc_n)
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
#if SOC_ADC_HW_CALIBRATION_V1
// ESP32-S2 and C3 support HW offset calibration.
/**
* @brief Initialize default parameter for the calibration block.
*
* @param adc_n ADC index numer
*/
void adc_hal_calibration_init(adc_ll_num_t adc_n);
/**
* Set the calibration result (initial data) to ADC.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
* @param param the calibration parameter to configure
*/
void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param);
/**
* Calibrate the ADC using internal connections.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
* @param channel adc channel number.
* @param atten The attenuation for the channel
* @param internal_gnd true: Disconnect from the IO port and use the internal GND as the calibration voltage.
* false: Use IO external voltage as calibration voltage.
*
* @return
* - The calibration result (initial data) to ADC, use `adc_hal_set_calibration_param` to set.
*/
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
#if CONFIG_IDF_TARGET_ESP32C3
/*---------------------------------------------------------------
DMA setting

View File

@ -109,6 +109,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_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

@ -58,6 +58,8 @@
#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 */
/**
* Check if adc support digital controller (DMA) mode.