Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

oldndumb
Posts: 21
Joined: Tue May 02, 2023 4:18 pm

Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby oldndumb » Sat Jan 20, 2024 2:54 pm

Hi there,

Anyone know if I can get the value of the reference voltage (vref) burned in efuse through a built in esp-idf function?
I know I can get it "outside of the board" with espefuse.py --port [PORT] adc_info, but I like to use and display the vref value per board. Mostly out of curiosity ;)

oldndumb
Posts: 21
Joined: Tue May 02, 2023 4:18 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby oldndumb » Sun Jan 21, 2024 12:10 am

Alright. I found a way of getting my vref value and for example the mac address in code. I think there should be a way of using esp_efuse_read_field_blob for the vref too... And probably multiple other ways as well. But I wasn't able to adapt it for the vref register yet... perhaps someone else knows? I ended up copying the code that was in esp_adc_cal.c with the function: read_efuse_vref :) :

Code: Select all

#include "esp_efuse.h"
#include "soc/efuse_reg.h"
#include "esp_efuse_table.h"
#include "soc/efuse_periph.h"
#include "esp_err.h"
#include "esp_adc_cal.h"

#define VREF_FORMAT                     0
#define VREF_REG                        EFUSE_BLK0_RDATA4_REG
#define VREF_MASK                       0x1F
#define VREF_STEP_SIZE                  7
#define VREF_OFFSET                     1100

static inline int decode_reg_bits(uint32_t bits, uint32_t mask, bool is_twos_compl)
{
    int ret;
    if (bits & (~(mask >> 1) & mask)) {      //Check sign bit (MSB of mask)
        //Negative
        if (is_twos_compl) {
            ret = -(((~bits) + 1) & (mask >> 1));   //2's complement
        } else {
            ret = -(bits & (mask >> 1));    //Sign-magnitude
        }
    } else {
        //Positive
        ret = bits & (mask >> 1);
    }
    return ret;
}

static uint32_t read_efuse_vref_reg(void)
{
    //eFuse stores deviation from ideal reference voltage
    uint32_t ret = VREF_OFFSET;       //Ideal vref
    uint32_t bits = REG_GET_FIELD(VREF_REG, EFUSE_ADC_VREF);
    ret += decode_reg_bits(bits, VREF_MASK, VREF_FORMAT) * VREF_STEP_SIZE;
    return ret;     //ADC Vref in mV
}


void read_efuse_values(){
    uint8_t mac[6];
    ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8));
    printf("1. read MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    uint32_t efuse_vref = read_efuse_vref_reg();
    printf("2. ADC_VREF from eFuse: %u mV\n", efuse_vref);
}


johann75
Posts: 6
Joined: Tue Feb 20, 2024 12:21 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby johann75 » Tue Feb 20, 2024 1:06 pm

@oldndumb, I love your sketch, but do not yet understand how it works. Could you maybe explain? Below what I was using to read Vref:

Code: Select all

#include "esp_adc_cal.h"

void setup() {
Serial.begin(115200);
while (!Serial) {}

  //Read eFuse Voltage Refference
  esp_adc_cal_characteristics_t adc_chars;                                                        //declaring ADC calibration variable adc_chars
  esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars);      //characterizing the ADC calibration function ADC_UNIT_1 or ADC_UNIT_2
  Serial.println(); Serial.print("eFuse-Vref:"); Serial.print(adc_chars.vref); Serial.println();  //reading the actual internal refference voltage
}

void loop() {
}
Below one return value that different for each device:
eFuse-Vref:1086
And for the MAC, I was reading registers before I found your code:

Code: Select all

#include <soc/efuse_reg.h>

void setup() {
Serial.begin(115200);
while (!Serial) {}

//Read all registers of eFuse Block 0 
uint32_t blk0reg0 = REG_READ(EFUSE_BLK0_RDATA0_REG), blk0reg1 = REG_READ(EFUSE_BLK0_RDATA1_REG), blk0reg2 = REG_READ(EFUSE_BLK0_RDATA2_REG), blk0reg3 = REG_READ(EFUSE_BLK0_RDATA3_REG), 
         blk0reg4 = REG_READ(EFUSE_BLK0_RDATA4_REG), blk0reg5 = REG_READ(EFUSE_BLK0_RDATA5_REG), blk0reg6 = REG_READ(EFUSE_BLK0_RDATA6_REG); //blk0reg7 = REG_READ(EFUSE_BLK0_RDATA7_REG) did not work

  //Print all registers of eFuse Block 0
  Serial.println(); Serial.println();
  Serial.print("Block 0 non HEX: "); Serial.print(blk0reg0); Serial.print(blk0reg1); Serial.print(blk0reg2);
  Serial.print(blk0reg3); Serial.print(blk0reg4); Serial.print(blk0reg5); Serial.print(blk0reg6); Serial.println(); //Serial.print(blk0reg7)

  //HEX Print all registers of eFuse Block 0
  Serial.println("Block 0 HEX:");
  Serial.print("Block 0, Register 0: "); Serial.println(blk0reg0, HEX);
  Serial.print("Block 0, Register 1: "); Serial.println(blk0reg1, HEX);
  Serial.print("Block 0, Register 2: "); Serial.println(blk0reg2, HEX);
  Serial.print("Block 0, Register 3: "); Serial.println(blk0reg3, HEX);
  Serial.print("Block 0, Register 4: "); Serial.println(blk0reg4, HEX);
  Serial.print("Block 0, Register 5: "); Serial.println(blk0reg5, HEX);
  Serial.print("Block 0, Register 6: "); Serial.println(blk0reg6, HEX);
  //Serial.print("Block 0, Register 7: "); Serial.println(blk0reg7, HEX);
}

void loop() {
}
The return for one of the device:
Block 0, Register 0: 0
Block 0, Register 1: F71DD3B8
Block 0, Register 2: 330C6
Block 0, Register 3: A000
Block 0, Register 4: 1236
Block 0, Register 5: 100000
Block 0, Register 6: 4
Whereby the last 4 digits of Block 0, Register 2 (first one or two is the checksum) + Register 1 is the MAC 30C6F71DD3B8. And I also could not read the last Resister 7 for some reason. Also have lost time with esp_efuse_read_field_blob and could not find a working sample sketch.

oldndumb
Posts: 21
Joined: Tue May 02, 2023 4:18 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby oldndumb » Wed Feb 21, 2024 7:34 am

@johann75
Seems you are using the arduino platform and not esp-idf.
There's no point in explaining. To use these functions you need all the #includes.
Unless you have a very specific question regarding my code, you're better off asking arduino platform questions in the arduino forum. Try to make very clear what you actually want to achieve and why you were unable to so far.

johann75
Posts: 6
Joined: Tue Feb 20, 2024 12:21 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby johann75 » Wed Feb 21, 2024 9:35 am

@oldndumb, I am using your function. All works for me just fine. All ESP-IDF works good for me on Arduino and Platform IO.

Also wondering, why do you need to read the eFuse voltage reference and how do you use it? I have mesured the actual ESP32 internal reference voltage on a few boards and results are not matching with eFuse:

TTGO 1: eFuse: 1086. Actually mesured: 1078
TTGO 2: eFuse: 1100. Actually mesured: 1080

Using the below to route internal voltage reference to a physical GPIO and works fine on ESP-IDF and Arduino:

Code: Select all

#include <driver/adc.h>        //ADC driver or include esp_adc_cal.h Both work

void setup() {
  esp_err_t status = adc_vref_to_gpio(ADC_UNIT_2, GPIO_NUM_26);
  if (status == ESP_OK) {
        printf("\nv_ref routed to desired GPIO\n");
  } else {
        printf("failed to route v_ref\n");
    }
}

void loop() {
}

oldndumb
Posts: 21
Joined: Tue May 02, 2023 4:18 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby oldndumb » Wed Feb 21, 2024 10:17 am

@johann75
What is your actual question? You're requiring me to spend time reading your long posts but, it isn't clear what you actually want. So please be more specific.

//or did you just want to share your solution to find vref? With the struct member adc_chars.vref and the calibration function that populates it. Which is simpler. That wasn't really clear.
Stand by the request for a more specific question if you've got one though. Explaining my whole 'sketch' is more work than writing it ;)

johann75
Posts: 6
Joined: Tue Feb 20, 2024 12:21 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby johann75 » Wed Feb 21, 2024 1:37 pm

@oldndumb, I was wondering, what do you need the voltage refference for and how do you calibrate ADC?

johann75
Posts: 6
Joined: Tue Feb 20, 2024 12:21 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby johann75 » Thu Feb 22, 2024 12:42 pm

@oldndumb , I could not understand how you convert REG_GET_FIELD to human readable values. But at most, for what reason do you read eFuse and how do you use the data. Also, what is you methode to calibrate ADC?

oldndumb
Posts: 21
Joined: Tue May 02, 2023 4:18 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby oldndumb » Thu Feb 22, 2024 5:27 pm

This is done with the decode_reg_bits function.

In it you see a lot of bitwise operations.
>> means right shift, moving a binary number a number of bits to the right.
& means bitwise AND. With it you can set certain regbits to 0.
| means bitwise OR. Which lets you set certain regbits to 1.
~ means NOT. Which lets you invert a number.

The other thing to read up on to grasp the function is two's complient, which tells you how (negative) numbers are stored in memory, where you can only store 1s and 0s. And msb (most significant bit) which tells you how a number is aligned when stored in memory.

Used the vref value to check battery voltage level deviance across devices. I think the value stored in efuse should get you pretty close. Measuring might lead to improvements. But if I remember correctly the value deviates a bt depending on the boards temperature.... So hard to get an absolute value... But for my use case accuracy is not crucial anyway. Keep in mind the esp32 adc's aren't very accurate to begin with.

johann75
Posts: 6
Joined: Tue Feb 20, 2024 12:21 pm

Re: Get efuse vref value in code, "espefuse.py --port [PORT] adc_info" equivalent in onboard code?

Postby johann75 » Thu Feb 29, 2024 7:52 am

@oldndumb, completely agree with you. ESP32 ADC is completely inaccurate. eFuse value is closer to actial voltage refference, but still useless. Not only eFuse, actually red Refference Voltage cannot really be used. The only more or les working ESP32 ADC calibration methode I have found so far is be the below, but I am still exploring other methodes: https://github.com/e-tinkers/esp32-adc-calibrate

But still wandering, how do you user eFuse Vref? Could you share you sketch example?

Who is online

Users browsing this forum: No registered users and 186 guests