How to run ADC two point calibration?

vonnieda
Posts: 145
Joined: Tue Nov 07, 2017 3:42 pm

How to run ADC two point calibration?

Postby vonnieda » Wed Jan 09, 2019 2:30 am

Hi all,

The docs at https://docs.espressif.com/projects/esp ... ion-values say "Two Point values represent each of the ADCs’ readings at 150mV and 850mV. To obtain more accurate calibration results these values should be measured by user and burned into eFuse BLOCK3" but there doesn't seem to be further information on how this is done. Is this documented somewhere, and if not, can someone explain the process?

In particular:
* How do I go about reading the value? Is it simply adc1_get_raw()? Should I do any averaging?
* How should I configure the ADC? Attenuation / bit width?
* How do I burn the values once I know them?

Thanks,
Jason

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

Re: How to run ADC two point calibration?

Postby ESP_Dazz » Wed Jan 09, 2019 3:55 am


vonnieda
Posts: 145
Joined: Tue Nov 07, 2017 3:42 pm

Re: How to run ADC two point calibration?

Postby vonnieda » Wed Jan 09, 2019 3:59 am

ESP_Dazz wrote:
Wed Jan 09, 2019 3:55 am
See the ADC1 example and esp_adc_cal_get_voltage().
Hi ESP_Dazz,

Thanks for the response, but I wasn't asking how to use the calibration. I'm asking how to perform it. I have chips that do not have the two point EFUSE calibration burned in, and I'd like to burn it in. The docs say this can be done by the user, but do not explain how.

Again, I am looking for information on this part from the docs: To obtain more accurate calibration results these values should be measured by user and burned into eFuse BLOCK3

Thanks,
Jason

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

Re: How to run ADC two point calibration?

Postby ESP_Dazz » Thu Jan 10, 2019 4:01 pm

Currently, the support for burning Two Point Calibration is minimal as it'll require manually calculating the encoded values, and burning block 3 using esptool. I would recommend you open an issue on the esptool Github.

However, if you would prefer to do it manually, the Two Point Calibration process is outlined below:

Writing Two Point Calibration values into EFuse Block 3 can be split into the following stages

Measurement
The first step is the measure the readings of ADC1 and ADC2 when given two voltages (150mV and 850mV) at 12-bit preceision and 0db attenuation. adcx_get_raw() can be used to obtain the readings.
  • Sample multiple times (e.g. 128 times) and then average to get a more stable reading
Scaling and Encoding
Two Point calibrations values are allocated 32bits of EFUSE_BLK3_RDATA3_REG. 7 bits are used for the 150mV readings and 9 bits are used for the 850mV readings:

EFUSE_BLK3_RDATA3[6:0] - ADC1 150mV Calibration Value
EFUSE_BLK3_RDATA3[15:7] - ADC1 850mV Calibration Value
EFUSE_BLK3_RDATA3[22:16] - ADC2 150mV Calibration Value
EFUSE_BLK3_RDATA3[32:23] - ADC2 850mV Calibration Value

However, in order to fit a 12 bit ADC reading (i.e. a reading of 0 to 4095) into 7 or 9 bits, the ADC readings must first be scaled and shifted as follows.

A1 = (ADC1 150mV Reading - 279)/4
B1 = (ADC1 850mV Reading - 3265)/4
A2 = (ADC2 150mV Reading - 421)/4
B2 = (ADC2 850mV Reading - 3406)/4

After scaling and shifting, A1 and A2 should be able to fit into 7 bits. Likewise, B1 and B2 should be able to fit into 9 bits. However, the scaled and shifted values could be negative, therefore A1, B1, A2, B2 must all be encoded into 2's complement format.

The 2's complement format must be slightly modified to account by using an all 0 binary to represent uncalibrated efuses, and the most negative value (or -0 in sign magnitude) to represent a calibrated 0 value. Using 7 bits as an example, 7'b0000000 would represent an uncalibrated value, whilst 7'b1000000 would represent a calibrated 0 value.

After encoding into two's complement format, the calibration values should be written to their respective fields within EFUSE_BLK3_RDATA3.

Example
Given the following ADC readings:
ADC1 150mV Reading: 306
ADC1 850mV Reading: 3153
ADC2 150mV Reading: 389
ADC2 850mV Reading: 3206

The scaling and shifting will result in the following:
A1 = (306 - 278)/4 = 7
B1 = (3153 - 3265)/4 = -28
A2 = (389 - 421)/4 = -8
B2 = (3206 - 3406)/4 = -50

Two's complement encoding will result in the following:
EFUSE_BLK3_RDATA3[6:0] = 7'b 0000111
EFUSE_BLK3_RDATA3[15:7] = 9'b 111100100
EFUSE_BLK3_RDATA3[22:16] = 7'b 1111000
EFUSE_BLK3_RDATA3[32:23] = 9'b 111001110

Therefore, EFUSE_BLK3_RDATA3 = 0xE778F207

Verifying Calibration Value Correctness

To verify correctness before burning, I recommend you test your final calculated value of EFUSE_BLK3_RDATA3 on a few chips by running adc1 example with a modified esp_adc_cal.c (see attached). The modified esp_adc_cal.c will read the two point calibration value from a global uint32_t, so define your calculated the following somewhere in example main:

Code: Select all

uint32_t const test_two_point_value = ...;
Burning

See the espefuse wiki regarding burning non-key data. Don't forgot to set also burn the BLK3_PART_RESERVE flag to indicate that Block 3 has been used for two point calibration
Attachments
esp_adc_cal_mod.c
(17.95 KiB) Downloaded 1104 times

vonnieda
Posts: 145
Joined: Tue Nov 07, 2017 3:42 pm

Re: How to run ADC two point calibration?

Postby vonnieda » Thu Jan 10, 2019 4:43 pm

Thank you ESP_Dazz, this is exactly what I was looking for!

Thanks,
Jason

tommag
Posts: 1
Joined: Tue Jun 25, 2019 2:14 pm

Re: How to run ADC two point calibration?

Postby tommag » Tue Jun 25, 2019 2:25 pm

Hi all,

I just wanted to let you know that I have written a small program to assist in measuring and converting the ADC calibration values.
You can find it here : https://github.com/tommag/ESP32_ADC_Calibration_tool

Thanks for the useful and detailed info !
Tom

pgmcbt
Posts: 1
Joined: Mon Sep 14, 2020 6:25 pm

Re: How to run ADC two point calibration?

Postby pgmcbt » Mon Sep 14, 2020 6:37 pm

Hello Tom ,

Please have a look at efuse_blk3.bin file ... ( 29 bytes )
Following steps done :
echo -n -e \\x3b\\xf3\\xa5\\xed > efuse_blk3.bin
espefuse.py burn_block_data --offset 12 BLK3 efuse_blk3.bin , after this I've got the following errors ..

C:\Users\Embed>espefuse.py --port COM4 --baud 115200 burn_block_data --offset 12 BLK3 efuse_blk3.bin
espefuse.py v2.8
Connecting........_____....._____....._____..
Traceback (most recent call last):
File "C:\Users\Embed\.platformio\python37\Scripts\espefuse.py-script.py", line 11, in <module>
load_entry_point('esptool==2.8', 'console_scripts', 'espefuse.py')()
File "c:\users\embed\.platformio\python37\lib\site-packages\espefuse.py", line 967, in _main
main()
File "c:\users\embed\.platformio\python37\lib\site-packages\espefuse.py", line 962, in main
operation_func(esp, efuses, args)
File "c:\users\embed\.platformio\python37\lib\site-packages\espefuse.py", line 656, in burn_block_data
raise RuntimeError("Data will not fit: Key block size %d bytes, data file is %d bytes" % (num_bytes, len(data)))
RuntimeError: Data will not fit: Key block size 32 bytes, data file is 29 bytes

C:\Users\Embed>

Any idea what I'm doing wrong ?
Thank you for your support .
Greetings
Chris
Attachments
efuse_blk3.bin.txt
bin file
(29 Bytes) Downloaded 447 times
calibration 1135.txt
Calibration data esp32
(1.1 KiB) Downloaded 453 times

ma-lalonde
Posts: 3
Joined: Fri Sep 10, 2021 4:36 am

Re: How to run ADC two point calibration?

Postby ma-lalonde » Wed Jan 05, 2022 7:30 am

Since this is pretty much the only documentation on burning the eFuse for Two-Point calibration, here is a code excerpt you can run directly on the ESP32 to burn the eFuse once you have completed your measurements.

Code: Select all

            
            /* Do some measurements here... */
            int16_t A1 = round((A1_mean - 278.0f) / 4.0f);
            int16_t B1 = round((B1_mean - 3265.0f) / 4.0f);
            int16_t A2 = round((A2_mean - 421.0f) / 4.0f);
            int16_t B2 = round((B2_mean - 3406.0f) / 4.0f);

            printf("A1: %i | B1: %i | A2: %i | B2: %i\r\n", A1, B1, A2, B2);

            if (err == ESP_OK) {
                err = esp_efuse_write_field_blob(ESP_EFUSE_ADC1_TP_LOW, &A1, 7);
            }
            if (err == ESP_OK) {
                err = esp_efuse_write_field_blob(ESP_EFUSE_ADC1_TP_HIGH, &B1, 9);
            }
            if (err == ESP_OK) {
                err = esp_efuse_write_field_blob(ESP_EFUSE_ADC2_TP_LOW, &A2, 7);
            }
            if (err == ESP_OK) {
                err = esp_efuse_write_field_blob(ESP_EFUSE_ADC2_TP_HIGH, &B2, 9);
            }
            if (err == ESP_OK) {
                esp_efuse_write_reg(EFUSE_BLK0,
                        (EFUSE_BLK0_RDATA3_REG - DR_REG_EFUSE_BASE) / sizeof(uint32_t),
                        EFUSE_RD_BLK3_PART_RESERVE);
            }
       
before you burn the values, you can edit esp_adc_cal_esp32.c (or the file relevant to your ESP32 version) to fake the EFUSE_RD_BLK3_PART_RESERVE flag and to overwrite the EFUSE_RD_ADCx_TP_LOW bits.

On my end, there is a 10 mV difference between the new Two Point calibration and the previous VREF factory calibration at 850 mV and about 5 mV difference at 150 mV. I did the calibration with an external DAC and ADC (DACx0501 and ADS1119) connected to the ESP32's ADC input pins. This is a lot of trouble, so make sure your sensor has better than 1% accuracy if you want this to be worth it.

Who is online

Users browsing this forum: Google [Bot] and 113 guests