I believe I have found a bug in the documentation. In the esp32 IDF programming guide for the esp32c3 it states:
"Software Calibration
To convert ADC raw data to calibrated digital data, following steps should be followed:
Check the eFuse to know if the software calibration is supported via esp_adc_cal_check_efuse().
Calculate the ADC calibration characteristics via esp_adc_cal_characterize(). The ADC software calibration characteristics are per ADC module and per attenuation. For example, characteristics of ADC1 channel 0 under 11 dB attenuation are the same as characteristics of ADC1 channel 2 under 11 dB attenuation. But characteristics of ADC1 channel 0 under 11 dB attenuation are different with characteristics of ADC2 channel 0 under 11 dB attenuation. Also characteristics of ADC1 channel 0 under 11 dB attenuation are different with characteristics of ADC1 channel 0 under 6 dB attenuation.
Get the actual voltage value via esp_adc_cal_raw_to_voltage()."
In reality, the esp_adc_cal_characterize() function must be called per ADC, per attenuation
and per channel. it sets up the gpio for ADC operation.
The documentation need to be updated.
The output shows that the gpio is updated each time the cal function is called:
termianl output:
eFuse Vref: NOT supported
I (2070296) gpio: GPIO[0]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
Characterized using Two Point Value
Ch:0 Raw: 1773 Voltage: 1248mV
eFuse Two Point: Supported
eFuse Vref: NOT supported
I (2080296) gpio: GPIO[1]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
Characterized using Two Point Value
Ch:1 Raw: 1164 Voltage: 819mV
eFuse Two Point: Supported
eFuse Vref: NOT supported
I (2090296) gpio: GPIO[2]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
Characterized using Two Point Value
Ch:2 Raw: 582 Voltage: 409mV
here is the code:
Code: Select all
/* 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 "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define DEFAULT_VREF 1100 //Use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES 64 //Multisampling
static esp_adc_cal_characteristics_t *adc_chars;
static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_1;
static adc_channel_t channel0 = ADC_CHANNEL_0;
//static const adc_channel_t channel1 = ADC_CHANNEL_1;
//static const adc_channel_t channel2 = ADC_CHANNEL_2;
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
static void check_efuse(void)
{
//Check if TP is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
printf("eFuse Two Point: Supported\n");
} else {
printf("eFuse Two Point: NOT supported\n");
}
//Check Vref is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
printf("eFuse Vref: Supported\n");
} else {
printf("eFuse Vref: NOT supported\n");
}
}
static void print_char_val_type(esp_adc_cal_value_t val_type)
{
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
printf("Characterized using Two Point Value\n");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
printf("Characterized using eFuse Vref\n");
} else {
printf("Characterized using Default Vref\n");
}
}
void app_main(void)
{
int ii=0;
while (1) {
switch (ii){
case 0: channel0 = ADC_CHANNEL_0;
break;
case 1: channel0 = ADC_CHANNEL_1;
break;
case 2: channel0 = ADC_CHANNEL_2;
}
//Check if Two Point or Vref are burned into eFuse
check_efuse();
//Configure ADC
if (unit == ADC_UNIT_1) {
adc1_config_width(width);
adc1_config_channel_atten(channel0, atten);
} else {
adc2_config_channel_atten((adc2_channel_t)channel0, atten);
}
//Characterize ADC
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars);
print_char_val_type(val_type);
// sample ADC1 ch 0
uint32_t adc_reading = 0;
//Multisampling
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_reading += adc1_get_raw((adc1_channel_t)channel0);
}
adc_reading /= NO_OF_SAMPLES;
//Convert adc_reading to voltage in mV
uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
printf("Ch:%d\t Raw: %d\tVoltage: %dmV\n",ii, adc_reading, voltage);
vTaskDelay(pdMS_TO_TICKS(10000));
ii++;
if(ii==3){
ii=0;
}
}
}