mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
adc: add fallback calibration method
Also: 1. Separate static configuration into init phase to improve performance 2. Add a init code config layer to avoid duplicated configuration 3. Add a HW_CALIBRATION_V1 caps
This commit is contained in:
parent
3d7da2c8ff
commit
2b83418141
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user