Copyright ©

Mongoose OS Forum

ATTENTION! This forum has moved to:

Do not post any new messages.

Confusion with ESP32 ADC calibration

jstevewoodjstevewood California
edited April 2018 in Mongoose OS

I am doing the most basic of AD testing on ESP32 in Mongoose. I have power (3.288V) and ground connected to two ADC1 channels, and I do two types of reads (with mgos_adc_read_voltage and with mgos_adc_read). Here is my code and results:

#include "mgos.h"
#include "mgos_pwm.h"
#include "mgos_adc.h"
//#include "esp32_adc.h"
#include <xtensa/hal.h>
#include <math.h>

int kread=0; int lread=0;

static IRAM void led_timer_cb(void *arg) {
    printf ("k with mgos_adc_read_voltage (connected to Ground): %d \r\n",kread); 
    printf ("l with mgos_adc_read_voltage (connected to 3.288V): %d \r\n",lread); 
    printf ("k with mgos_adc_read (connected to Ground): %d \r\n",kread); 
    printf ("l with mgos_adc_read (connected to 3.288V): %d \r\n\r\n",lread); 
    (void) arg;

enum mgos_app_init_result mgos_app_init(void) {
  mgos_set_timer(2000, MGOS_TIMER_REPEAT, led_timer_cb, NULL);
[Apr 29 16:00:47.988] k with mgos_adc_read_voltage (connected to Ground): 142
[Apr 29 16:00:48.011] l with mgos_adc_read_voltage (connected to 3.288V): 3134
[Apr 29 16:00:48.024] k with mgos_adc_read (connected to Ground): 0
[Apr 29 16:00:48.038] l with mgos_adc_read (connected to 3.288V): 4095
[Apr 29 16:00:48.052]
[Apr 29 16:00:49.999] k with mgos_adc_read_voltage (connected to Ground): 142
[Apr 29 16:00:50.010] l with mgos_adc_read_voltage (connected to 3.288V): 3134
[Apr 29 16:00:50.024] k with mgos_adc_read (connected to Ground): 0
[Apr 29 16:00:50.038] l with mgos_adc_read (connected to 3.288V): 4095
[Apr 29 16:00:50.055]

As I understand, there are two different ways to get ADC calibration data from the eFuse information in each ESP32 (two point calibration at 150 mV and 850 mV, and actual recorded reference voltage information). Yet, the esp32_adc_set_vref seems to require a known input value (the reference voltage expressed as millivolts in an integer). If I leave esp32_adc_set_vref out of the code, I get identical results. If I change the integer from 1100 to 1200, the lread value (power rail) changes to 3209, while the kread value (sampling GND) remains the same at 142.

Several questions come out of this:
1) Why doesn't esp32_adc_set_vref deal directly with the eFuse reference voltage data without requiring input? (If each ESP32's internal reference voltage must be externally measured, then esp32_adc_set_vref has very little value).
2) Why are the recorded values for measurements of 3.288 V and 0.0 V so strange?
3) Why is the measurement of 0.0 V so far away from 0?
4) Is there some other offset parameter that needs to be adjusted?
5) Or am I completely missing the point, and there is some other way to achieve a calibrated EPS32 ADC read?

As a related question, is there any plan to address the linearity of ESP32 ADCs?

Thanks for your assistance, JSW


  • jstevewoodjstevewood California

    Anyone interested in precise A/D? I can't be the only one that has questions or requirements on this topic. It looks like a significant amount of work has been done by Mongoose in this area, but I can't find any how to use information. Any info greatly appreciated, Thanks JSW

  • ddrennanddrennan South Africa

    From my reading of the code there is nothing that accesses the ESP32 factory calibration in the Mongoose code. You have to know what the VREF value is before calling esp32_adc_set_vref(). It is possible to use the esp32 functions to access the factory calibration values, but we found (assuming we're doing this correctly) that our devices had no factory calibration in them.

    Our code for checking if the calibration values are set in the eFuses (still to confirm that this is correct):

    #include "driver/adc.h"
    #include "esp_adc_cal.h"
    static void check_efuse()
      //Check TP is burned into eFuse
      if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
          LOG(LL_INFO, ("eFuse Two Point: Supported\n"));
      } else {
          LOG(LL_INFO, ("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) {
        LOG(LL_INFO, ("eFuse Vref: Supported\n"));
      } else {
        LOG(LL_INFO, ("eFuse Vref: NOT supported\n"));

    This should at least help you to identify if the factory calibration is stored in the eFuses of your devices. If it is, you could read it out and then call esp32_adc_set_vref() based on the factory calibration VREF value.

  • jstevewoodjstevewood California

    Thanks ddrennan for weighing in on this. After studying this question for several weeks, I can add a little more definition to this issue

    According to Expressif, compensation has been added to ESP-32 starting in early 2018. Using the ESPFUSE python tool, I have not been able to find any compensation in my ESP-32s either. However since my module was received by me in March of this year, its production probably pre-dates Expressif’s correction measures. I can find lots of references in the Internet wisdom on this topic, but no specifics. There are two proposed Expressif compensation actions (as you mention) which would place A/D compensation information respectively in two different areas of Efuse. The first method adds the reference voltage to Block 0 (although there is no information on where or how to retrieve and use this information). The second method would perform a 2 point calibration that would actually eliminate the need for the first method by providing total characterization of gain and offset. The two points are reported to be loaded into the third (User Block) of the Efuses. I can find no format or location data specifics on how these two numbers would appear or be used; perhaps I can find this out by looking at the details of esp_adc_cal_check_check_efuse(). Expressif indicates that the two point method would be suitable for all attenuations except for 11dB (where non-linear effects are the worst). Cesanta indicates that ADC compensation will be automatically supported as soon as it appears in the ESP-32, however with no data on how the Efuses are to be programmed and no ability to program attenuation, I don’t see how this can be done. Cesanta has also considered adding software control of the ADC attenuation (it appears as a possible to do item in the ADC source code). Please do this. Mongoose's current default and only attenuation setting is the worst performing setting in the ADC. Also, please address the issue of ADC calibration with newly available ESP-32 parts. The ESP-32 ADC has been given thoroughly bad press, and subjected to slander and superstition, however if the 11 dB attenuation setting is avoided AND the promised calibration is implemented and accessible through mgos_adc_read_voltage, the ESP-32 ADC is completely usable.

    Thanks all,


Sign In or Register to comment.