ADC VRef calibration eFuse

ats1080
Posts: 2
Joined: Tue Aug 27, 2019 4:34 pm

ADC VRef calibration eFuse

Postby ats1080 » Tue Aug 27, 2019 5:01 pm

I got a Lolin D32 and I'm trying to read the battery voltage with an Arduino sketch. It's pretty close, but seems like it's a bit more inaccurate than it should be. After hours of reading about the calibration process I came to the conclusion that the board I got came with the ADC VRef calibration eFuse already burnt with the default 1100. Here is how I checked:

Code: Select all

Sketch:
//Check 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");
}

Output:
eFuse Two Point: NOT supported
eFuse Vref: Supported

espefuse.py:
espefuse.py --port COM11 adc_info

Output:
espefuse.py v2.7-dev
Connecting....
ADC VRef calibration: 1100mV
I ran the example sketch to route the VREF to GPIO 25 and I'm reading 1094 so it is close but not exact. It looks to me like Lolin is just writing the default value without testing.

So my questions are:
I read that eFuse burning is a one time process. Is there any way to overwrite them or am I stuck with 1100 for the VREF now?
Is there an easy way to override the fuse value when calling esp_adc_cal_characterize? No matter what I supply for the VREF param it always gets set to 1100 because the fuse takes priority.

ESP_Dazz
Posts: 146
Joined: Fri Jun 02, 2017 6:50 am

Re: ADC VRef calibration eFuse

Postby ESP_Dazz » Wed Aug 28, 2019 8:07 am

ats1080 wrote: Is there an easy way to override the fuse value when calling esp_adc_cal_characterize? No matter what I supply for the VREF param it always gets set to 1100 because the fuse takes priority.
In esp-idf, the simplest way is to modify the esp_adc_cal_characterize() function directly as such:

Code: Select all

    //Check eFuse if enabled to do so
    bool efuse_tp_present = check_efuse_tp();
    bool efuse_vref_present = check_efuse_vref();
    ...
    bool efuse_tp_present = false;
    bool efuse_vref_present = false;
However, this could be more difficult in Arduino. IIRC the esp-idf features used in Arduino come from precompiled libraries. esp_adc_cal.c is a pretty independent component. Most of calibration values and lookup tables are statically defined inside the source file. In theory, what you could do is just copy and rename esp_adc_cal.c and esp_adc_cal.h into your project, then just rename all the public facing API in esp_adc_cal.h to avoid conflicting names.
ats1080 wrote: I read that eFuse burning is a one time process. Is there any way to overwrite them or am I stuck with 1100 for the VREF now?
Once an eFuse bit has been burned to 1, it can never be reverted back to zero. However, since your eFuse Vref is set at 1100, the 5 bit eFuse value should be 5'b10000, so in theory you should be able burn some of the bits to 1, but you'll need to modify espefuse.py to allow you to burn an already burnt eFuse field.

FYI, eFuse Vref is a 5 bit sign-magnitude representation of the chips deviation (in units of 7mV) from the ideal reference voltage of 1100mV, with a calibrated zero deviation as a negative zero in sign-magnitude. For example:
  • A reference voltage of 1149mV would have an eFuse Vref of 5'b00111
  • A reference voltage of 1100mV would have an eFuse Vref of 5'b10000
  • A reference voltage of 1016mV would have an eFuse Vref of 5'b11100

papaluna
Posts: 50
Joined: Tue Jan 30, 2018 11:27 am

Re: ADC VRef calibration eFuse

Postby papaluna » Wed Aug 28, 2019 3:31 pm

No matter what I supply for the VREF param it always gets set to 1100 because the fuse takes priority.
FYI I'm also using the Lolin D32 board intensively. I have always assumed that the fuse takes priority and there is no way around that. But I hope I am wrong.
--
Paul.

ats1080
Posts: 2
Joined: Tue Aug 27, 2019 4:34 pm

Re: ADC VRef calibration eFuse

Postby ats1080 » Wed Aug 28, 2019 4:55 pm

Thanks for the info. I think I'll skip trying to overwrite the eFuse, seems more effort than it's worth. Looks like I can also use the ESP-IDF you disable the eFuse check and force the esp_adc_cal_characterize function to use the VREF parameter, but that also seems like more effort than it's worth. It's pretty disappointing that Arduino offers no way to use menuconfig. I can see many settings that would be advantageous to change.

The easiest route I could come up with was just overwriting the esp_adc_cal_characteristics_t values using the output of the characterize_using_vref function from esp_adc_cal.c:

Code: Select all

...
#include <esp_adc_cal.h>
...
#define ADC_12_BIT_RES         4096
#define VREF                   1090 // Value in mV.  Change this per board.  Use route vref to GPIO function to get this value from a multimeter
...
esp_adc_cal_characteristics_t *adc_chars = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));

static const uint32_t adc1_vref_atten_scale[4] = {57431, 76236, 105481, 196602};
static const uint32_t adc1_vref_atten_offset[4] = {75, 78, 107, 142};
...
  // Setup ADC1
  // 11db range between 150 to 2450mV
  adc1_config_width(ADC_WIDTH_BIT_12);
  // The input voltage of ADC will be reduced to about 1/3.6
  adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11);
  esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1094, adc_chars);
  //Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
  //Where coeff_a = (vref/4096) * atten_scale
  adc_chars->coeff_a = (VREF * adc1_vref_atten_scale[ADC_ATTEN_DB_11]) / (ADC_12_BIT_RES);
  adc_chars->coeff_b = adc1_vref_atten_offset[ADC_ATTEN_DB_11];
  adc_chars->vref;
...
With the right VREF set I'm still off by what appears to be a linear offset. Is this normal? If I lower VREF I can get it to what seems to be dead on. I guess it's possible my multimeter is off. I'll double check with a better one later.

Who is online

Users browsing this forum: No registered users and 5 guests