esp_adc_cal/Add eFuse functionality

This commit updates the esp_adc_cal ocmponent to support new calibration methods
which utilize calibratoin values stored in eFuse. This commit includes LUT mode
This commit is contained in:
Darian Leung 2018-01-24 17:22:13 +08:00
parent ca3faa6186
commit 73cdfbfe79
12 changed files with 1018 additions and 339 deletions

View file

@ -0,0 +1,37 @@
menu "ADC-Calibration"
config ADC_CAL_EFUSE_TP_DISABLE
bool "Disable Two Point values"
default "n"
help
Some ESP32s have Two Point calibration values burned into eFuse. Enabling
this option will prevent the ADC calibration component from using Two Point
values if they are available.
config ADC_CAL_EFUSE_VREF_DISABLE
bool "Disable eFuse Vref"
default "n"
help
Some ESP32s have ADC Vref burned into eFuse. Enabling this option will
prevent the ADC calibration component from using eFuse Vref if they are
available.
config ADC_CAL_DEFAULT_VREF_DISABLE
bool "Disable Default Vref"
default "n"
help
The esp_adc_cal_characterize() function requires the user to provide a
vref_default argument to be used if eFuse values are unavailable. Enabling
this option will prevent the ADC calibration component from using the
vref_default argument. Note that if eFuse values are also unavailabe,
the esp_adc_cal_characterize will trigger an abort.
config ADC_CAL_NO_BLK3_RESERVE_FLAG
bool "EFUSE_BLK3_PART_RESERVE not set"
default "n"
help
By default, ESP32s will have the EFUSE_BLK3_PART_RESERVE flag set if it
uses BLK3 of eFuse to store Two Point values. Some ESP32s do not set this
flag. Enable this option if that is the case
endmenu # ADC-Calibration

View file

@ -13,99 +13,444 @@
// limitations under the License.
#include <stdint.h>
#include "esp_types.h"
#include "driver/adc.h"
#include "soc/efuse_reg.h"
#include "esp_err.h"
#include "esp_log.h"
#include "assert.h"
#include "esp_adc_cal_constants.h"
#include "esp_adc_cal.h"
static const esp_adc_cal_lookup_table_t *table_ptrs[4] = {&esp_adc_cal_table_atten_0,
&esp_adc_cal_table_atten_1,
&esp_adc_cal_table_atten_2,
&esp_adc_cal_table_atten_3};
#define CONFIG_ADC_CAL_EFUSE_TP_DISABLE
/* ----------------------------- Configuration ------------------------------ */
uint32_t get_adc_vref_from_efuse()
#ifdef CONFIG_ADC_CAL_EFUSE_TP_DISABLE
#define EFUSE_TP_ENABLED 0
#else
#define EFUSE_TP_ENABLED 1
#endif
#ifdef CONFIG_ADC_CAL_EFUSE_VREF_DISABLE
#define EFUSE_VREF_ENABLED 0
#else
#define EFUSE_VREF_ENABLED 1
#endif
#ifdef CONFIG_ADC_CAL_DEFAULT_VREF_DISABLE
#define DEFAULT_VREF_ENABLED 0
#else
#define DEFAULT_VREF_ENABLED 1
#endif
/* ------------------------------ eFuse Access ----------------------------- */
#define BLK3_RESERVED_REG EFUSE_BLK0_RDATA4_REG
#define VREF_REG EFUSE_BLK0_RDATA4_REG
#define VREF_SIGN_BIT 0x10
#define VREF_MAG_BITS 0x0F
#define VREF_STEP_SIZE 7
#define VREF_OFFSET 1100
#define TP_REG EFUSE_BLK3_RDATA3_REG
#define TP_LOW1_OFFSET 278
#define TP_LOW2_OFFSET 421
#define TP_HIGH1_OFFSET 3265
#define TP_HIGH2_OFFSET 3406
#define TP_LOW_SIGN_BIT 0x40
#define TP_LOW_MAG_BITS 0x3F
#define TP_LOW_VOLTAGE 150
#define TP_HIGH_SIGN_BIT 0x100
#define TP_HIGH_MAG_BITS 0xFF
#define TP_HIGH_VOLTAGE 850
#define TP_STEP_SIZE 4
/* -------------------- Linear and LUT mode constants ----------------------- */
#define LIN_COEFF_A_SCALE 65536
#define LIN_COEFF_A_ROUND (LIN_COEFF_A_SCALE/2)
#define LUT_VREF_IDEAL 1100
#define LUT_VREF_LOW 1000
#define LUT_VREF_HIGH 1200
#define LUT_ADC_STEP_SIZE 128
#define ADC_12_BIT_MAX 4095
#define ADC_CAL_ASSERT(cond, ret) ({ \
if(!(cond)){ \
return ret; \
} \
})
#define ESP_ADC_CAL_ERR_STR "No characterization possible"
static const char* ESP_ADC_CAL_TAG = "esp_adc_cal_log";
extern const uint32_t adc1_lin_tp_atten_scale[4];
extern const uint32_t adc2_lin_tp_atten_scale[4];
extern const uint32_t adc1_lin_tp_atten_offset[4];
extern const uint32_t adc2_lin_tp_atten_offset[4];
extern const uint32_t adc1_lin_vref_atten_scale[4];
extern const uint32_t adc2_lin_vref_atten_scale[4];
extern const uint32_t adc1_lin_vref_atten_offset[4];
extern const uint32_t adc2_lin_vref_atten_offset[4];
extern const esp_adc_cal_lookup_table_t lut_atten0_adc1;
extern const esp_adc_cal_lookup_table_t lut_atten0_adc2;
extern const esp_adc_cal_lookup_table_t lut_atten1_adc1;
extern const esp_adc_cal_lookup_table_t lut_atten1_adc2;
extern const esp_adc_cal_lookup_table_t lut_atten2_adc1;
extern const esp_adc_cal_lookup_table_t lut_atten2_adc2;
extern const esp_adc_cal_lookup_table_t lut_atten3_adc1;
extern const esp_adc_cal_lookup_table_t lut_atten3_adc2;
/* ----------------------- EFuse Access Functions --------------------------- */
//Check if Vref is burned in eFuse
static bool check_efuse_vref()
{
//TODO: Replaced with read to eFuse once ATE confirms location of 5 bits
return 0;
//Check eFuse for vref
return (REG_GET_FIELD(VREF_REG, EFUSE_RD_ADC_VREF) != 0) ? true : false;
}
void esp_adc_cal_get_characteristics(uint32_t v_ref,
//Check if Two Point values are burned in eFuse
static bool check_efuse_tp()
{
#ifndef CONFIG_ADC_CAL_NO_BLK3_RESERVE_FLAG
//BLK3_PART_RESERVE flag must be set
if(REG_GET_FIELD(BLK3_RESERVED_REG, EFUSE_RD_BLK3_PART_RESERVE) == 0){
return false;
}
#endif
//All TP cal values must be non zero
if((REG_GET_FIELD(TP_REG, EFUSE_RD_ADC1_TP_LOW) != 0) &&
(REG_GET_FIELD(TP_REG, EFUSE_RD_ADC2_TP_LOW) != 0) &&
(REG_GET_FIELD(TP_REG, EFUSE_RD_ADC1_TP_HIGH) != 0) &&
(REG_GET_FIELD(TP_REG, EFUSE_RD_ADC2_TP_HIGH) != 0)){
return true;
} else {
return false;
}
}
//Read Vref from eFuse
static uint32_t read_efuse_vref()
{
//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);
if(bits & VREF_SIGN_BIT){ //Negative deviation from ideal Vref
#ifndef CONFIG_ADC_CAL_NO_BLK3_RESERVE_FLAG
//Deviation stored in sign-magnitude format
ret -= (bits & VREF_MAG_BITS) * VREF_STEP_SIZE;
#else
//Deviation stored in two's complement
ret -= (((~bits)+1) & VREF_MAG_BITS) * VREF_STEP_SIZE;
#endif
} else { //Positive deviation from ideal Vref
ret += (bits & VREF_MAG_BITS) * VREF_STEP_SIZE;
}
return ret; //ADC Vref in mV
}
//Read Two Point low reading from eFuse
static uint32_t read_efuse_tp_low(adc_unit_t adc_num)
{
//ADC reading at 150mV stored in two's complement format
uint32_t ret;
uint32_t bits;
if(adc_num == ADC_UNIT_1){
ret = TP_LOW1_OFFSET;
bits = REG_GET_FIELD(TP_REG, EFUSE_RD_ADC1_TP_LOW);
} else {
ret = TP_LOW2_OFFSET;
bits = REG_GET_FIELD(TP_REG, EFUSE_RD_ADC2_TP_LOW);
}
//Represented in two's complement format
if(bits & TP_LOW_SIGN_BIT){ //Negative
ret -= (((~bits) + 1) & TP_LOW_MAG_BITS) * TP_STEP_SIZE;
} else { //Positive
ret += (bits & TP_LOW_MAG_BITS) * TP_STEP_SIZE;
}
return ret; //Reading of ADC at 150mV
}
//Read Two Point high reading from eFuse
static uint32_t read_efuse_tp_high(adc_unit_t adc_num)
{
//ADC reading at 850mV stored in two's complement format
uint32_t ret;
uint32_t bits;
if(adc_num == ADC_UNIT_1){
ret = TP_HIGH1_OFFSET;
bits = REG_GET_FIELD(TP_REG, EFUSE_RD_ADC1_TP_HIGH);
} else {
ret = TP_HIGH2_OFFSET;
bits = REG_GET_FIELD(TP_REG, EFUSE_RD_ADC2_TP_HIGH);
}
//Represented in two's complement format
if(bits & TP_HIGH_SIGN_BIT){ //Negative
ret -= (((~bits) + 1) & TP_HIGH_MAG_BITS) * TP_STEP_SIZE;
} else { //Positive
ret += (bits & TP_HIGH_MAG_BITS) * TP_STEP_SIZE;
}
return ret; //Reading of ADC at 850mV
}
/* ----------------------- Characterization Functions ----------------------- */
//Linear characterization using Two Point values
static void characterize_lin_tp(adc_unit_t adc_num,
adc_atten_t atten,
uint32_t high,
uint32_t low,
uint32_t *coeff_a,
uint32_t *coeff_b)
{
const uint32_t *atten_scales;
const uint32_t *atten_offsets;
if(adc_num == ADC_UNIT_1){ //Using ADC 1
atten_scales = adc1_lin_tp_atten_scale;
atten_offsets = adc1_lin_tp_atten_offset;
} else { //Using ADC 2
atten_scales = adc2_lin_tp_atten_scale;
atten_offsets = adc2_lin_tp_atten_offset;
}
//Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
uint32_t delta_x = high - low;
uint32_t delta_v = TP_HIGH_VOLTAGE - TP_LOW_VOLTAGE;
//coeff_a = (delta_v/delta_x) * atten_scale
*coeff_a = (delta_v * atten_scales[atten] + (delta_x/2)) / delta_x; //+(delta_x/2) for rounding
//coeff_b = high_v - ((delta_v/delta_x) * high_x) + atten_offset
*coeff_b = TP_HIGH_VOLTAGE - ((delta_v * high + (delta_x/2)) / delta_x) + atten_offsets[atten];
}
//Linear characterization using Vref
static void characterize_lin_vref(adc_unit_t adc_num,
adc_atten_t atten,
uint32_t vref,
uint32_t *coeff_a,
uint32_t *coeff_b)
{
const uint32_t *atten_scales;;
const uint32_t *atten_offsets;
if(adc_num == ADC_UNIT_1){ //Using ADC 1
atten_scales = adc1_lin_vref_atten_scale;
atten_offsets = adc1_lin_vref_atten_offset;
} else { //Using ADC 2
atten_scales = adc2_lin_vref_atten_scale;
atten_offsets = adc2_lin_vref_atten_offset;
}
//Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
//coeff_a = (vref/4096) * atten_scale
*coeff_a = (vref * atten_scales[atten]) / (ADC_12_BIT_MAX + 1);
*coeff_b = atten_offsets[atten];
}
//LUT characterization
static void characterize_lut(adc_unit_t adc_num,
adc_atten_t atten,
uint32_t vref,
const esp_adc_cal_lookup_table_t **table_ptr)
{
//Get pointer to the correct lookup table
if(atten == ADC_ATTEN_DB_0){
*table_ptr = (adc_num == ADC_UNIT_1) ? &lut_atten0_adc1 : &lut_atten0_adc2;
} else if (atten == ADC_ATTEN_DB_2_5){
*table_ptr = (adc_num == ADC_UNIT_1) ? &lut_atten1_adc1 : &lut_atten1_adc2;
} else if (atten == ADC_ATTEN_DB_6){
*table_ptr = (adc_num == ADC_UNIT_1) ? &lut_atten2_adc1 : &lut_atten2_adc2;
} else {
*table_ptr = (adc_num == ADC_UNIT_1) ? &lut_atten3_adc1 : &lut_atten3_adc2;
}
}
/* ------------------------ Conversion Functions --------------------------- */
//Calculate voltage using linear characterization of the ADC curve
static uint32_t linear_raw_to_voltage(uint32_t adc,
uint32_t gain,
uint32_t offset)
{
//ADC Curve is characterized as y = coeff_a * adc + coeff_b
//All gains scaled by 65536
return (((gain * adc) + LIN_COEFF_A_ROUND) / LIN_COEFF_A_SCALE) + offset;
}
//Calculate voltage using a lookup table
static uint32_t lut_raw_to_voltage(uint32_t adc, uint32_t vref, const esp_adc_cal_lookup_table_t *table)
{
//Get index of lower bound points of LUT
uint32_t i = (adc / LUT_ADC_STEP_SIZE);
//Let the X Axis be Vref, Y axis be ADC reading, and Z be voltage
int x2dist = LUT_VREF_HIGH - vref; //(x2 - x)
int x1dist = vref - LUT_VREF_LOW; //(x - x1)
int y2dist = ((i+1) * LUT_ADC_STEP_SIZE) - adc; //(y2 - y)
int y1dist = adc - (i * LUT_ADC_STEP_SIZE); //(y - y1)
//For points for bilinear interpolation
int q11 = (int)table->low_vref_curve[i]; //Lower bound point of low_vref_curve
int q12 = (int)table->low_vref_curve[i+1]; //Upper bound point of low_vref_curve
int q21 = (int)table->high_vref_curve[i]; //Lower bound point of high_vref_curve
int q22 = (int)table->high_vref_curve[i+1]; //Upper bound point of high_vref_curve
//Bilinear interpolation
//z = 1/((x2-x1)*(y2-y1)) * ( (q11*x2dist*y2dist) + (q21*x1dist*y2dist) + (q12*x2dist*y1dist) + (q22*x1dist*y1dist) )
int voltage = (q11*x2dist*y2dist) + (q21*x1dist*y2dist) + (q12*x2dist*y1dist) + (q22*x1dist*y1dist);
voltage += ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE)/2; //Integer division rounding
voltage /= ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE); //Divide by ((x2-x1)*(y2-y1))
return (uint32_t)voltage;
}
/* ------------------------- Public API ------------------------------------- */
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
{
if(source == ESP_ADC_CAL_VAL_EFUSE_TP){
return (check_efuse_tp()) ? ESP_OK : ESP_ERR_NOT_SUPPORTED;
} else if (source == ESP_ADC_CAL_VAL_EFUSE_VREF){
return (check_efuse_vref()) ? ESP_OK : ESP_ERR_NOT_SUPPORTED;
} else {
return ESP_ERR_INVALID_ARG;
}
}
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
esp_adc_cal_mode_t mode,
uint32_t vref_default,
esp_adc_cal_characteristics_t *chars)
{
assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2));
assert(chars != NULL);
//Check eFuse if enabled to do so
bool efuse_tp_present = check_efuse_tp();
bool efuse_vref_present = check_efuse_vref();
esp_adc_cal_value_t ret;
if(mode == ESP_ADC_CAL_MODE_LIN){
if(efuse_tp_present && EFUSE_TP_ENABLED){
uint32_t high = read_efuse_tp_high(adc_num);
uint32_t low = read_efuse_tp_low(adc_num);
characterize_lin_tp(adc_num, atten, high, low, &chars->linear_chars.coeff_a, &chars->linear_chars.coeff_b);
ret = ESP_ADC_CAL_VAL_EFUSE_TP;
} else if(efuse_vref_present && EFUSE_VREF_ENABLED){
uint32_t vref = read_efuse_vref();
characterize_lin_vref(adc_num, atten, vref, &chars->linear_chars.coeff_a, &chars->linear_chars.coeff_b);
ret = ESP_ADC_CAL_VAL_EFUSE_VREF;
} else if(DEFAULT_VREF_ENABLED){
characterize_lin_vref(adc_num, atten, vref_default, &chars->linear_chars.coeff_a, &chars->linear_chars.coeff_b);
ret = ESP_ADC_CAL_VAL_DEFAULT_VREF;
} else {
goto err;
}
} else if (mode == ESP_ADC_CAL_MODE_LUT){
if(efuse_vref_present && EFUSE_VREF_ENABLED){
uint32_t vref = read_efuse_vref();
chars->lut_chars.vref = vref;
characterize_lut(adc_num, atten, vref, &chars->lut_chars.table);
ret = ESP_ADC_CAL_VAL_EFUSE_VREF;
} else if(DEFAULT_VREF_ENABLED){
chars->lut_chars.vref = vref_default;
characterize_lut(adc_num, atten, vref_default, &chars->lut_chars.table);
ret = ESP_ADC_CAL_VAL_DEFAULT_VREF;
} else{
goto err;
}
} else {
goto err;
}
chars->mode = mode;
chars->adc_num = adc_num;
return ret;
err: //No possible characterization
// usually only occurs if users manually disable calibration values and modes in menuconfig
ESP_LOGE(ESP_ADC_CAL_TAG, ESP_ADC_CAL_ERR_STR);
abort();
return ESP_ADC_CAL_VAL_DEFAULT_VREF; //Should not reach this point, added to suppress Eclipse warnings
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading,
adc_bits_width_t bit_width,
const esp_adc_cal_characteristics_t *chars)
{
assert(chars != NULL);
//Scale adc_rading if not 12 bits wide
if(bit_width != ADC_WIDTH_BIT_12){
adc_reading = (adc_reading << (ADC_WIDTH_BIT_12 - bit_width));
//If adc_reading is out of 12bit range
if(adc_reading > ADC_12_BIT_MAX){
adc_reading = ADC_12_BIT_MAX; //Set to 12bit max
}
}
//Convert ADC reading to voltage in mV
if(chars->mode == ESP_ADC_CAL_MODE_LUT){ //Lookup Table
assert(chars->lut_chars.table != NULL);
return lut_raw_to_voltage(adc_reading, chars->lut_chars.vref, chars->lut_chars.table);
} else {
return linear_raw_to_voltage(adc_reading, chars->linear_chars.coeff_a, chars->linear_chars.coeff_b);
}
}
esp_err_t adc_to_voltage(adc_channel_t channel,
adc_bits_width_t bit_width,
const esp_adc_cal_characteristics_t *chars,
uint32_t *voltage)
{
//Check parameters
ADC_CAL_ASSERT(chars != NULL, ESP_ERR_INVALID_ARG);
ADC_CAL_ASSERT(voltage != NULL, ESP_ERR_INVALID_ARG);
if(chars->adc_num == ADC_UNIT_1){
//Check channel is valid on ADC1
ADC_CAL_ASSERT((adc1_channel_t)channel < ADC1_CHANNEL_MAX, ESP_ERR_INVALID_ARG);
uint32_t adc_reading = (uint32_t)adc1_get_raw(channel); //Todo: get_raw function to change
*voltage = esp_adc_cal_raw_to_voltage(adc_reading, bit_width, chars);
} else {
//Check channel is valid on ADC2
ADC_CAL_ASSERT((adc2_channel_t)channel < ADC2_CHANNEL_MAX, ESP_ERR_INVALID_ARG);
int adc_reading;
if(adc2_get_raw(channel, bit_width, &adc_reading) != ESP_OK){
//Timed out waiting for ADC2
return ESP_ERR_TIMEOUT;
}
*voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, bit_width, chars);
}
return ESP_OK;
}
/* ------------------------ Deprecated API --------------------------------- */
void esp_adc_cal_get_characteristics(uint32_t vref,
adc_atten_t atten,
adc_bits_width_t bit_width,
esp_adc_cal_characteristics_t *chars)
{
chars->v_ref = v_ref;
chars->table = table_ptrs[atten];
chars->bit_width = bit_width;
if (v_ref >= ADC_CAL_LOW_V_REF) {
chars->gain = ((chars->v_ref - ADC_CAL_LOW_V_REF)
* chars->table->gain_m)
+ chars->table->gain_c;
chars->offset = (((chars->v_ref - ADC_CAL_LOW_V_REF)
* chars->table->offset_m)
+ chars->table->offset_c
+ ((1 << ADC_CAL_OFFSET_SCALE) / 2))
>> ADC_CAL_OFFSET_SCALE; //Bit shift to cancel 2^10 multiplier
chars->ideal_offset = (((ADC_CAL_IDEAL_V_REF - ADC_CAL_LOW_V_REF)
* chars->table->offset_m)
+ chars->table->offset_c
+ ((1 << ADC_CAL_OFFSET_SCALE) / 2)) //Rounding
>> ADC_CAL_OFFSET_SCALE;
} else { //For case where v_ref is smaller than low bound resulting in negative
chars->gain = chars->table->gain_c
- ((ADC_CAL_LOW_V_REF - chars->v_ref)
* chars->table->gain_m);
chars->offset = (chars->table->offset_c
- ((chars->v_ref - ADC_CAL_LOW_V_REF)
* chars->table->offset_m)
+ ((1 << ADC_CAL_OFFSET_SCALE) / 2)) //Rounding
>> ADC_CAL_OFFSET_SCALE; //Bit shift to cancel 2^10 multiplier
chars->ideal_offset = (chars->table->offset_c
- ((ADC_CAL_IDEAL_V_REF - ADC_CAL_LOW_V_REF)
* chars->table->offset_m)
+ ((1 << ADC_CAL_OFFSET_SCALE) / 2)) //Rounding
>> ADC_CAL_OFFSET_SCALE;
}
}
//Default to ADC1 and LUT mode
assert(chars != NULL);
static uint32_t esp_adc_cal_interpolate_round(uint32_t lower, uint32_t upper,
uint32_t step, uint32_t point)
{
//Interpolate 'point' between 'lower' and 'upper' seperated by 'step'
return ((lower * step) - (lower * point) + (upper * point) + (step / 2)) / step;
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc,
const esp_adc_cal_characteristics_t *chars)
{
//Scale ADC to 12 bit width (0 to 4095)
adc <<= (ADC_WIDTH_BIT_12 - chars->bit_width);
uint32_t i = (adc >> chars->table->bit_shift); //find index for lut voltages
//Refernce LUT to obtain voltage using index
uint32_t voltage = esp_adc_cal_interpolate_round(chars->table->voltage[i],
chars->table->voltage[i + 1],
(1 << chars->table->bit_shift),
adc - (i << chars->table->bit_shift));
/*
* Apply Gain, scaling(bit shift) and offset to interpolated voltage
* v_true = (((v_id - off_id)*gain)*scaling) + off_true
*/
if (voltage > chars->ideal_offset) {
voltage = (voltage - chars->ideal_offset) * chars->gain;
voltage += (1 << ADC_CAL_GAIN_SCALE) / 2; //For rounding when scaled
voltage >>= ADC_CAL_GAIN_SCALE;
voltage += chars->offset;
} else { //For case where voltage is less than ideal offset leading to negative value
voltage = ((chars->ideal_offset - voltage) * chars->gain);
voltage += (1 << ADC_CAL_GAIN_SCALE) / 2; //For rounding when scaled
voltage >>= ADC_CAL_GAIN_SCALE;
voltage = chars->offset - voltage;
}
return voltage;
//bit_width parameter unused, kept due to legacy API
chars->mode = ESP_ADC_CAL_MODE_LUT;
chars->lut_chars.vref = vref;
characterize_lut(ADC_UNIT_1, atten, vref, &chars->lut_chars.table);
chars->adc_num = ADC_UNIT_1;
}
uint32_t adc1_to_voltage(adc1_channel_t channel, const esp_adc_cal_characteristics_t *chars)
{
return esp_adc_cal_raw_to_voltage((uint32_t)adc1_get_raw(channel), chars);
assert(chars != NULL);
uint32_t voltage = 0;
adc_to_voltage((adc_channel_t) channel, ADC_WIDTH_BIT_12, chars, &voltage);
return voltage;
}

View file

@ -0,0 +1,222 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_adc_cal.h"
#include "esp_adc_cal_constants.h"
/* ------------------------- Lookup Tables ---------------------------------- */
/**
* Mean error of 70 modules: 2.674297mV
* Max error of 70 modules: 12.176238mV
* Mean of max errors of 70 modules: 7.079913mV
*/
const esp_adc_cal_lookup_table_t lut_atten0_adc1 = {
.low_vref_curve = {
58, 84, 114, 142, 168, 196, 224, 252,
281, 308, 335, 363, 390, 417, 445, 473,
501, 528, 556, 583, 611, 637, 665, 692,
720, 747, 775, 802, 830, 856, 883, 910,
937
},
.high_vref_curve = {
86, 106, 152, 184, 218, 251, 283, 316,
348, 381, 415, 447, 480, 513, 546, 579,
612, 644, 677, 710, 742, 775, 808, 841,
874, 906, 938, 971, 1003, 1035, 1068, 1100,
1133
}
};
/**
* Mean error of 70 modules: 3.950325mV
* Max error of 70 modules: 20.975788mV
* Mean of max errors of 70 modules: 6.629054mV
*/
const esp_adc_cal_lookup_table_t lut_atten0_adc2 = {
.low_vref_curve = {
49, 75, 105, 132, 160, 187, 214, 241,
268, 296, 324, 352, 380, 407, 434, 461,
488, 516, 545, 572, 600, 627, 654, 681,
708, 735, 763, 791, 818, 845, 872, 899,
927
},
.high_vref_curve = {
72, 103, 137, 170, 202, 235, 268, 302,
335, 367, 399, 432, 464, 497, 530, 563,
596, 628, 661, 693, 725, 758, 791, 824,
857, 889, 921, 954, 986, 1018, 1051, 1084,
1116
}
};
/**
* Mean error of 70 modules: 3.339671mV
* Max error of 70 modules: 13.476428mV
* Mean of max errors of 70 modules: 5.818235mV
*/
const esp_adc_cal_lookup_table_t lut_atten1_adc1 = {
.low_vref_curve = {
57, 87, 130, 168, 204, 240, 277, 313,
349, 387, 424, 461, 498, 534, 571, 607,
644, 680, 717, 753, 789, 826, 862, 898,
934, 970, 1007, 1043, 1078, 1115, 1151, 1187,
1223
},
.high_vref_curve = {
89, 128, 178, 221, 264, 309, 353, 397,
442, 484, 528, 572, 616, 659, 703, 747,
790, 833, 877, 921, 964, 1006, 1050, 1094,
1137, 1179, 1222, 1266, 1309, 1351, 1394, 1437,
1481
}
};
/**
* Mean error of 70 modules: 5.319836mV
* Max error of 70 modules: 29.034477mV
* Mean of max errors of 70 modules: 9.226072mV
*/
const esp_adc_cal_lookup_table_t lut_atten1_adc2 = {
.low_vref_curve = {
47, 86, 122, 159, 196, 232, 268, 305,
340, 377, 415, 452, 487, 525, 562, 598,
635, 671, 708, 745, 782, 817, 853, 890,
926, 962, 999, 1035, 1071, 1107, 1144, 1180,
1215
},
.high_vref_curve = {
78, 113, 165, 209, 251, 295, 339, 383,
427, 470, 514, 558, 602, 644, 688, 732,
775, 818, 862, 905, 948, 992, 1036, 1079,
1122, 1164, 1208, 1252, 1295, 1338, 1381, 1424,
1468
}
};
/**
* Mean error of 70 modules: 4.943406mV
* Max error of 70 modules: 19.203104mV
* Mean of max errors of 70 modules: 9.462435mV
*/
const esp_adc_cal_lookup_table_t lut_atten2_adc1 = {
.low_vref_curve = {
72, 117, 177, 228, 281, 330, 382, 434,
483, 536, 587, 639, 690, 740, 791, 842,
892, 942, 992, 1042, 1092, 1141, 1191, 1241,
1290, 1339, 1391, 1441, 1490, 1540, 1591, 1642,
1692
},
.high_vref_curve = {
120, 175, 243, 305, 364, 426, 488, 550,
612, 671, 732, 793, 852, 912, 973, 1033,
1092, 1151, 1211, 1272, 1331, 1390, 1450, 1511,
1571, 1631, 1691, 1752, 1812, 1872, 1933, 1994,
2056
}
};
/**
* Mean error of 70 modules: 7.782408mV
* Max error of 70 modules: 45.327423mV
* Mean of max errors of 70 modules: 13.569581mV
*/
const esp_adc_cal_lookup_table_t lut_atten2_adc2 = {
.low_vref_curve = {
61, 119, 164, 216, 267, 317, 369, 420,
471, 522, 574, 625, 676, 726, 777, 828,
878, 928, 979, 1030, 1080, 1130, 1180, 1230,
1280, 1330, 1381, 1432, 1483, 1532, 1583, 1634,
1685
},
.high_vref_curve = {
102, 152, 225, 286, 347, 407, 469, 530,
590, 651, 712, 773, 832, 892, 953, 1013,
1073, 1132, 1192, 1253, 1313, 1372, 1432, 1494,
1554, 1613, 1675, 1735, 1795, 1856, 1917, 1978,
2039
}
};
/**
* Mean error of 70 modules: 9.568297mV
* Max error of 70 modules: 44.480817mV
* Mean of max errors of 70 modules: 20.165069mV
*/
const esp_adc_cal_lookup_table_t lut_atten3_adc1 = {
.low_vref_curve = {
88, 185, 285, 380, 473, 568, 664, 759,
853, 945, 1039, 1133, 1224, 1316, 1410, 1505,
1599, 1692, 1788, 1886, 1983, 2081, 2186, 2297,
2405, 2511, 2615, 2710, 2793, 2868, 2937, 3000,
3061
},
.high_vref_curve = {
173, 271, 399, 515, 628, 740, 853, 965,
1075, 1186, 1299, 1411, 1523, 1634, 1749, 1863,
1975, 2087, 2201, 2314, 2422, 2525, 2622, 2707,
2779, 2844, 2901, 2956, 3008, 3059, 3110, 3160,
3210
}
};
/**
* Mean error of 70 modules: 12.799173mV
* Max error of 70 modules: 60.129227mV
* Mean of max errors of 70 modules: 23.334659mV
*/
const esp_adc_cal_lookup_table_t lut_atten3_adc2 = {
.low_vref_curve = {
83, 177, 274, 370, 465, 559, 655, 751,
844, 937, 1031, 1126, 1218, 1312, 1407, 1502,
1597, 1691, 1787, 1885, 1983, 2081, 2185, 2293,
2400, 2506, 2612, 2709, 2793, 2868, 2937, 2999,
3059
},
.high_vref_curve = {
155, 257, 383, 498, 610, 722, 836, 947,
1058, 1170, 1283, 1396, 1507, 1619, 1733, 1848,
1960, 2073, 2188, 2300, 2408, 2513, 2611, 2698,
2773, 2838, 2895, 2946, 2996, 3044, 3092, 3139,
3186
}
};
/* ---------------- Constants for linear calibration using TP --------------- */
// (0.999518539509928, 1.32714033039721, 1.83698541693337, 3.42269475397192) * 65536
const uint32_t adc1_lin_tp_atten_scale[4] = {65504, 86975, 120389, 224310};
// (0.99895306551877194, 1.3253993908658808, 1.8373986067502703, 3.4287787961634124) * 65536
const uint32_t adc2_lin_tp_atten_scale[4] = {65467, 86861, 120416, 224708};
// (0.369882210218334, 1.33352056600476, 26.5266258898132, 54.2706443679156)
const uint32_t adc1_lin_tp_atten_offset[4] = {0, 1, 27, 54};
// (0.0, 3.59737421, 26.3951927, 64.738429)
const uint32_t adc2_lin_tp_atten_offset[4] = {0, 9, 26, 66};
/* ------------- Constants for linear calibration using Vref ---------------- */
// (0.87632707, 1.16327136, 1.60951523, 2.99991113) * 65536
const uint32_t adc1_lin_vref_atten_scale[4] = {57431, 76236, 105481, 196602};
// (0.87335934, 1.16233322, 1.61251264, 3.00858015) * 65536
const uint32_t adc2_lin_vref_atten_scale[4] = {57236, 76175, 105678, 197170};
// (74.97079, 77.67434785, 106.58843993, 142.18959459)
const uint32_t adc1_lin_vref_atten_offset[4] = {75, 78, 107, 142};
// (62.73368574, 66.33498527, 89.23584218, 127.69820652)
const uint32_t adc2_lin_vref_atten_offset[4] = {63, 66, 89, 128};

View file

@ -1,96 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_adc_cal.h"
/**
* Mean error of 219 modules: 3.756418mV
* Max error of 219 modules: 26.314087mV
* Mean of max errors of 219 modules: 7.387282mV
*/
const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_0 = {
.gain_m = 56,
.gain_c = 59928,
.offset_m = 91,
.offset_c = 52798,
.bit_shift = 7,
.voltage = {
54, 90, 120, 150, 180, 209, 241, 271,
301, 330, 360, 391, 421, 450, 480, 511,
541, 571, 601, 630, 660, 690, 720, 750,
780, 809, 839, 870, 900, 929, 959, 988,
1018
}
};
/**
* Mean error of 219 modules: 4.952441mV
* Max error of 219 modules: 38.235321mV
* Mean of max errors of 219 modules: 9.718749mV
*/
const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_1 = {
.gain_m = 57,
.gain_c = 59834,
.offset_m = 108,
.offset_c = 54733,
.bit_shift = 7,
.voltage = {
60, 102, 143, 184, 223, 262, 303, 343,
383, 423, 463, 503, 543, 583, 623, 663,
703, 742, 782, 823, 862, 901, 942, 981,
1022, 1060, 1101, 1141, 1180, 1219, 1259, 1298,
1338
}
};
/**
* Mean error of 219 modules: 6.793558mV
* Max error of 219 modules: 51.435440mV
* Mean of max errors of 219 modules: 13.083121mV
*/
const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_2 = {
.gain_m = 56,
.gain_c = 59927,
.offset_m = 154,
.offset_c = 71995,
.bit_shift = 7,
.voltage = {
82, 138, 194, 250, 305, 360, 417, 473,
529, 584, 639, 696, 751, 806, 861, 917,
971, 1026, 1081, 1136, 1192, 1246, 1301, 1356,
1411, 1466, 1522, 1577, 1632, 1687, 1743, 1799,
1855
}
};
/**
* Mean error of 219 modules: 13.149460mV
* Max error of 219 modules: 97.102951mV
* Mean of max errors of 219 modules: 35.538924mV
*/
const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_3 = {
.gain_m = 33,
.gain_c = 62214,
.offset_m = 610,
.offset_c = 108422,
.bit_shift = 7,
.voltage = {
110, 221, 325, 430, 534, 637, 741, 845,
947, 1049, 1153, 1256, 1358, 1461, 1565, 1670,
1774, 1878, 1983, 2088, 2192, 2293, 2393, 2490,
2580, 2665, 2746, 2820, 2885, 2947, 3007, 3060,
3107
}
};

View file

@ -20,131 +20,171 @@ extern "C" {
#endif
#include <stdint.h>
#include "esp_err.h"
#include "driver/adc.h"
#include "esp_adc_cal_constants.h"
/** @cond */
#define ADC_CAL_GAIN_SCALE 16
#define ADC_CAL_OFFSET_SCALE 10
/**
* @brief ADC characterization mode
*/
typedef enum {
ESP_ADC_CAL_MODE_LIN = 0, /**< Characterize the ADC as a linear curve*/
ESP_ADC_CAL_MODE_LUT= 1, /**< Characterize the ADC using a lookup table*/
} esp_adc_cal_mode_t;
#define ADC_CAL_IDEAL_V_REF 1100 //In mV
#define ADC_CAL_LOW_V_REF 1000
#define ADC_CAL_HIGH_V_REF 1200
#define ADC_CAL_MIN 0
#define ADC_CAL_MAX 4095
/** @endcond */
/**
* @brief Type of calibration value used in characterization
*/
typedef enum {
ESP_ADC_CAL_VAL_EFUSE_VREF = 0, /**< Characterization based on reference voltage stored in eFuse*/
ESP_ADC_CAL_VAL_EFUSE_TP = 1, /**< Characterization based on Two Point values stored in eFuse*/
ESP_ADC_CAL_VAL_DEFAULT_VREF = 2, /**< Characterization based on default reference voltage*/
} esp_adc_cal_value_t;
/**
* @brief Structure storing Lookup Table
*
* The Lookup Tables (LUT) of a given attenuation contains 33 equally spaced
* points. The Gain and Offset curves are used to find the appopriate gain and
* offset factor given a reference voltage v_ref.
* A Lookup Table (LUT) of a given ADC and attenuation contains two curves
* mapping ADC readings to a voltage in mV. Each curve contains 33 equally spaced
* points separated by a step size of 128. The low_vref_curve represents the ADC
* voltage curve of a module with a reference voltage of 1000mV, whilst the
* high_vref_curve represents a reference voltage of 1200mV.
*
* @note A seperate LUT is provided for each attenuation and are defined in
* esp_adc_cal_lookup_tables.c
* @note Separate LUTs are provided for each ADC at each attenuation
*/
typedef struct {
uint32_t gain_m; /**<Gradient of Gain Curve */
uint32_t gain_c; /**<Offset of Gain Curve */
uint32_t offset_m; /**<Gradient of Offset Curve */
uint32_t offset_c; /**<Offset of Offset Curve */
uint32_t bit_shift; /**<Bit shift used find corresponding LUT points
given an ADC reading*/
uint32_t voltage[]; /**<Array of voltages in mV representing the
ADC-Voltage curve */
uint32_t low_vref_curve[33]; /**< Voltage curve at a reference voltage of 1000mV*/
uint32_t high_vref_curve[33]; /**< Voltage curve at a reference voltage of 1200mV*/
} esp_adc_cal_lookup_table_t;
/**
* @brief Structure storing ADC characteristics of given v_ref
*
* The ADC Characteristics structure stores the gain and offset factors of an
* ESP32 module's ADC. These factors are calculated using the reference voltage,
* and the Gain and Offset curves provided in the lookup tables.
* @brief Structure storing characteristics of an ADC
*
* @note Call esp_adc_cal_get_characteristics() to initialize the structure
*
*/
typedef struct {
uint32_t v_ref; /**<Reference Voltage of current ESP32 Module in mV*/
uint32_t gain; /**<Scaling factor used to correct LUT voltages to
current v_ref. Bit shifted by << ADC_CAL_GAIN_SCALE
for uint32 arithmetic */
uint32_t offset; /**<Offset in mV used to correct LUT Voltages to current v_ref */
uint32_t ideal_offset; /**<Offset in mV at the ideal reference voltage */
adc_bits_width_t bit_width; /**<Bit width of ADC e.g. ADC_WIDTH_BIT_12 */
const esp_adc_cal_lookup_table_t *table; /**<Pointer to LUT */
esp_adc_cal_mode_t mode; /**< Characterization mode*/
adc_unit_t adc_num; /**< ADC number*/
union {
struct {
uint32_t coeff_a; /**< 1st order coefficient of linear characteristics curve*/
uint32_t coeff_b; /**< 0th order coefficient of linear characteristics curve*/
} linear_chars;
struct {
uint32_t vref; /**< Reference voltage*/
const esp_adc_cal_lookup_table_t *table; /**< Pointer to lookup table*/
} lut_chars;
};
} esp_adc_cal_characteristics_t;
extern const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_0; /**<LUT for atten0 */
extern const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_1; /**<LUT for atten1 */
extern const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_2; /**<LUT for atten2 */
extern const esp_adc_cal_lookup_table_t esp_adc_cal_table_atten_3; /**<LUT for atten3 */
/**
* @brief Calculate characteristics of ADC
* @brief Checks if ADC calibration values are stored in eFuse
*
* This function will calculate the gain and offset factors based on the
* reference voltage parameter and the Gain and Offset curve provided in the LUT.
* This function checks if ADC reference voltage or Two Point calibration voltages
* have been burned to the eFuse of the current ESP32
*
* @note reference voltage of the ADCs can be routed to GPIO using
* adc2_vref_to_gpio() from the ADC driver
* @param value_type Type of calibration value (ESP_ADC_CAL_VAL_EFUSE_VREF or ESP_ADC_CAL_VAL_EFUSE_TP)
*
* @note The LUT members have been bit shifted by ADC_CAL_GAIN_SCALE or
* ADC_CAL_OFFSET_SCALE to make them uint32_t compatible. This bit shifting will
* accounted for in this function
*
* @param[in] v_ref true reference voltage of the ADC in mV (1000 to 1200mV). Nominal
* value for reference voltage is 1100mV.
* @param[in] atten attenuation setting used to select the corresponding lookup table
* @param[in] bit_width bit width of ADC
* @param[out] chars pointer to structure used to store ADC characteristics of module
* @return
* - ESP_OK: The calibration mode is supported in eFuse
* - ESP_ERR_NOT_SUPPORTED: Error, eFuse values are not burned
* - ESP_ERR_INVALID_ARG: Error, invalid argument (ESP_ADC_CAL_VAL_DEFAULT_VREF)
*/
void esp_adc_cal_get_characteristics(uint32_t v_ref,
adc_atten_t atten,
adc_bits_width_t bit_width,
esp_adc_cal_characteristics_t *chars);
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t value_type);
/**
* @brief Convert raw ADC reading to voltage in mV
* @brief Characterize an ADC at a particular attenuation under Linear or LUT Mode
*
* This function converts a raw ADC reading to a voltage in mV. This conversion
* is based on the ADC's characteristics. The raw ADC reading is referenced
* against the LUT (pointed to inside characteristics struct) to obtain a voltage.
* Gain and offset factors are then applied to the voltage in order to obtain
* the final result.
* This function will generate the characteristics curve of one of the ADCs at a
* particular attenuation. This characteristics curve will be stored in a
* characteristics structure. Linear Mode will be characterize the ADC-Voltage
* curve as a linear curve. LUT Mode will characterize the ADC-Voltage curve
* using a lookup table. Calibration values in eFuse will be used to generate
* the characteristics curve if available, and vref_default will be used if they
* are not.
*
* @param[in] adc ADC reading (different bit widths will be handled)
* @param[in] chars pointer to structure containing ADC characteristics of
* the module. Structure also contains pointer to the
* corresponding LUT
* @note This function will abort if there are no available options for
* characterization (characterization modes and calibration value types
* can be enabled and disabled in menuconfig)
*
* @return Calculated voltage in mV
* @param[in] adc_num ADC to characterize (ADC_UNIT_1 or ADC_UNIT_2)
* @param[in] atten Attenuation to characterize
* @param[in] mode Characterization mode (Linear or LUT)
* @param[in] vref_default Default ADC reference voltage in mV (used if eFuse is not available)
* @param[out] chars Pointer to empty structure used to store ADC characteristics
*
* @note characteristics structure must be initialized using
* esp_adc_cal_get_characteristics() before this function is used
* @return
* - ESP_ADC_CAL_VAL_EFUSE_VREF: eFuse Vref used for characterization
* - ESP_ADC_CAL_VAL_EFUSE_TP: Two Point value used for characterization (only in Linear Mode)
* - ESP_ADC_CAL_VAL_DEFAULT_VREF: Default Vref used for characterization
*/
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc,
const esp_adc_cal_characteristics_t *chars);
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
esp_adc_cal_mode_t mode,
uint32_t vref_default,
esp_adc_cal_characteristics_t *chars);
/**
* @brief Reads ADC1 and returns voltage in mV
* @brief Convert an ADC reading to voltage in mV
*
* This function reads the ADC1 using adc1_get_raw() to obtain a raw ADC
* reading. The reading is then converted into a voltage value using
* esp_adc_cal_raw_to_voltage().
* This function converts a an ADC reading to a voltage in mV based on the
* ADC characteristics curve provided.
*
* @param[in] channel Channel of ADC1 to measure
* @param[in] chars Pointer to ADC characteristics struct
* @param[in] adc_reading ADC reading
* @param[in] bit_width Bit width of the ADC reading
* @param[in] chars Pointer to initialized structure containing ADC characteristics curve
*
* @return voltage Calculated voltage in mV
* @return Voltage in mV
*
* @note ADC must be initialized using adc1_config_width() and
* adc1_config_channel_atten() before this function is used
*
* @note characteristics structure must be initialized using
* esp_adc_cal_get_characteristics() before this function is used
* @note characteristics structure must be initialized first using esp_adc_cal_characterize()
*/
uint32_t adc1_to_voltage(adc1_channel_t channel, const esp_adc_cal_characteristics_t *chars);
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, adc_bits_width_t bit_width, const esp_adc_cal_characteristics_t *chars);
/**
* @brief Reads an ADC and returns a voltage in mV
*
* This function reads an ADC then converts the raw reading to a voltage in mV
* using the characteristics curve provided. The ADC that is read is also
* determined by the characteristics.
*
* @param[in] channel ADC Channel to read
* @param[in] bit_width Bit width of ADC reading (must be same as ADC configuration)
* @param[in] chars Pointer to initialized ADC characteristics structure
* @param[out] voltage Pointer to store converted voltage
*
* @return
* - ESP_OK: ADC read and converted
* - ESP_ERR_TIMEOUT: Error, could not read ADC
* - ESP_ERR_INVALID_ARG: Error due to invalid arguments
*
* @note The ADC must be initialized before calling this function. The
* bit_width parameter must be the same as the bit width used in
* configuration
*
* @note Characteristics structure must be initialized using before calling
* this function
*/
esp_err_t adc_to_voltage(adc_channel_t channel, adc_bits_width_t bit_width, const esp_adc_cal_characteristics_t *chars, uint32_t *voltage);
/* -------------------------- Deprecated API ------------------------------- */
/** @cond */ //Doxygen command to hide deprecated function from API Reference
/**
* @deprecated ADC1 characterization function. Deprecated in order to accommodate
* new characterization functions. Use esp_adc_cal_characterize() instead
*/
void esp_adc_cal_get_characteristics(uint32_t vref, adc_atten_t atten, adc_bits_width_t bit_width, esp_adc_cal_characteristics_t *chars) __attribute__((deprecated));
/*
* @deprecated This function reads ADC1 and returns the corrected voltage. This
* has been deprecated in order to accommodate ADC2 support and new
* ADC calibration methods. Use the new function adc_to_voltage() instead
*/
uint32_t adc1_to_voltage(adc1_channel_t channel, const esp_adc_cal_characteristics_t *chars) __attribute__((deprecated));
/** @endcond */
#ifdef __cplusplus
}

View file

@ -79,17 +79,23 @@
#define EFUSE_RD_WIFI_MAC_CRC_HIGH_S 0
#define EFUSE_BLK0_RDATA3_REG (DR_REG_EFUSE_BASE + 0x00c)
/* EFUSE_RD_CHIP_VER_REV1 : R/W ;bitpos:[16] ;default: 1'b0 ; */
/* EFUSE_RD_CHIP_VER_REV1 : R/W ;bitpos:[15] ;default: 1'b0 ; */
/*description: bit is set to 1 for rev1 silicon*/
#define EFUSE_RD_CHIP_VER_REV1 (BIT(15))
#define EFUSE_RD_CHIP_VER_REV1_M ((EFUSE_RD_CHIP_VER_REV1_V)<<(EFUSE_RD_CHIP_VER_REV1_S))
#define EFUSE_RD_CHIP_VER_REV1_V 0x1
#define EFUSE_RD_CHIP_VER_REV1_S 15
/* EFUSE_RD_CHIP_VER_RESERVE : R/W ;bitpos:[15:12] ;default: 3'b0 ; */
/* EFUSE_RD_BLK3_PART_RESERVE : R/W ; bitpos:[14] ; default: 1'b0; */
/*description: If set, this bit indicates that BLOCK3[143:96] is reserved for calibration purposes and BLOCK1/2/3 uses 3/4 encoding*/
#define EFUSE_RD_BLK3_PART_RESERVE (BIT(14))
#define EFUSE_RD_BLK3_PART_RESERVE_M ((EFUSE_RD_BLK3_PART_RESERVE_V)<<(EFUSE_RD_BLK3_PART_RESERVE_S))
#define EFUSE_RD_BLK3_PART_RESERVE_V 0x1
#define EFUSE_RD_BLK3_PART_RESERVE_S 14
/* EFUSE_RD_CHIP_VER_RESERVE : R/W ;bitpos:[13:12] ;default: 2'b0 ; */
/*description: */
#define EFUSE_RD_CHIP_VER_RESERVE 0x00000007
#define EFUSE_RD_CHIP_VER_RESERVE 0x00000003
#define EFUSE_RD_CHIP_VER_RESERVE_M ((EFUSE_RD_CHIP_VER_RESERVE_V)<<(EFUSE_RD_CHIP_VER_RESERVE_S))
#define EFUSE_RD_CHIP_VER_RESERVE_V 0x7
#define EFUSE_RD_CHIP_VER_RESERVE_V 0x3
#define EFUSE_RD_CHIP_VER_RESERVE_S 12
/* EFUSE_RD_CHIP_VER : R/W ;bitpos:[11:9] ;default: 3'b0 ; */
/*description: chip package */
@ -152,6 +158,15 @@
#define EFUSE_RD_XPD_SDIO_REG_M (BIT(14))
#define EFUSE_RD_XPD_SDIO_REG_V 0x1
#define EFUSE_RD_XPD_SDIO_REG_S 14
/* EFUSE_RD_ADC_VREF : R/W ;bitpos:[12:8] ;default: 5'b0 ; */
/*description: True ADC reference voltage */
#define EFUSE_RD_ADC_VREF 0x0000001F
#define EFUSE_RD_ADC_VREF_M ((EFUSE_RD_ADC_VREF_V)<<(EFUSE_RD_ADC_VREF_S))
#define EFUSE_RD_ADC_VREF_V 0x1F
#define EFUSE_RD_ADC_VREF_S 8
/* Note: EFUSE_ADC_VREF and SDIO_DREFH/M/L share the same address space. Newer
* versions of ESP32 come with EFUSE_ADC_VREF already burned, therefore
* SDIO_DREFH/M/L is only available in older versions of ESP32 */
/* EFUSE_RD_SDIO_DREFL : RO ;bitpos:[13:12] ;default: 2'b0 ; */
/*description: */
#define EFUSE_RD_SDIO_DREFL 0x00000003
@ -314,17 +329,23 @@
#define EFUSE_WIFI_MAC_CRC_HIGH_S 0
#define EFUSE_BLK0_WDATA3_REG (DR_REG_EFUSE_BASE + 0x028)
/* EFUSE_CHIP_VER_REV1 : R/W ;bitpos:[16] ;default: 1'b0 ; */
/* EFUSE_CHIP_VER_REV1 : R/W ;bitpos:[15] ;default: 1'b0 ; */
/*description: */
#define EFUSE_CHIP_VER_REV1 (BIT(15))
#define EFUSE_CHIP_VER_REV1_M ((EFUSE_CHIP_VER_REV1_V)<<(EFUSE_CHIP_VER_REV1_S))
#define EFUSE_CHIP_VER_REV1_V 0x1
#define EFUSE_CHIP_VER_REV1_S 15
/* EFUSE_CHIP_VER_RESERVE : R/W ;bitpos:[15:12] ;default: 3'b0 ; */
/* EFUSE_BLK3_PART_RESERVE : R/W ; bitpos:[14] ; default: 1'b0; */
/*description: If set, this bit indicates that BLOCK3[143:96] is reserved for calibration purposes and BLOCK1/2/3 uses 3/4 encoding*/
#define EFUSE_BLK3_PART_RESERVE (BIT(14))
#define EFUSE_BLK3_PART_RESERVE_M ((EFUSE_BLK3_PART_RESERVE_V)<<(EFUSE_BLK3_PART_RESERVE_S))
#define EFUSE_BLK3_PART_RESERVE_V 0x1
#define EFUSE_BLK3_PART_RESERVE_S 14
/* EFUSE_CHIP_VER_RESERVE : R/W ;bitpos:[13:12] ;default: 2'b0 ; */
/*description: */
#define EFUSE_CHIP_VER_RESERVE 0x00000007
#define EFUSE_CHIP_VER_RESERVE 0x00000003
#define EFUSE_CHIP_VER_RESERVE_M ((EFUSE_CHIP_VER_RESERVE_V)<<(EFUSE_CHIP_VER_RESERVE_S))
#define EFUSE_CHIP_VER_RESERVE_V 0x7
#define EFUSE_CHIP_VER_RESERVE_V 0x3
#define EFUSE_CHIP_VER_RESERVE_S 12
/* EFUSE_CHIP_VER : R/W ;bitpos:[11:9] ;default: 3'b0 ; */
/*description: */
@ -382,6 +403,15 @@
#define EFUSE_XPD_SDIO_REG_M (BIT(14))
#define EFUSE_XPD_SDIO_REG_V 0x1
#define EFUSE_XPD_SDIO_REG_S 14
/* EFUSE_ADC_VREF : R/W ;bitpos:[12:8] ;default: 5'b0 ; */
/*description: True ADC reference voltage */
#define EFUSE_ADC_VREF 0x0000001F
#define EFUSE_ADC_VREF_M ((EFUSE_ADC_VREF_V)<<(EFUSE_ADC_VREF_S))
#define EFUSE_ADC_VREF_V 0x1F
#define EFUSE_ADC_VREF_S 8
/* Note: EFUSE_ADC_VREF and SDIO_DREFH/M/L share the same address space. Newer
* versions of ESP32 come with EFUSE_ADC_VREF already burned, therefore
* SDIO_DREFH/M/L is only available in older versions of ESP32 */
/* EFUSE_SDIO_DREFL : R/W ;bitpos:[13:12] ;default: 2'b0 ; */
/*description: */
#define EFUSE_SDIO_DREFL 0x00000003
@ -659,6 +689,8 @@
#define EFUSE_BLK3_DOUT2_V 0xFFFFFFFF
#define EFUSE_BLK3_DOUT2_S 0
/* Note: Newer ESP32s utilize BLK3_DATA3 and parts of BLK3_DATA4 for calibration
* purposes. This usage is indicated by the EFUSE_RD_BLK3_PART_RESERVE bit.*/
#define EFUSE_BLK3_RDATA3_REG (DR_REG_EFUSE_BASE + 0x084)
/* EFUSE_BLK3_DOUT3 : RO ;bitpos:[31:0] ;default: 32'h0 ; */
/*description: read for BLOCK3*/
@ -666,6 +698,30 @@
#define EFUSE_BLK3_DOUT3_M ((EFUSE_BLK3_DOUT3_V)<<(EFUSE_BLK3_DOUT3_S))
#define EFUSE_BLK3_DOUT3_V 0xFFFFFFFF
#define EFUSE_BLK3_DOUT3_S 0
/* EFUSE_RD_ADC2_TP_HIGH : R/W ;bitpos:[31:23] ;default: 9'b0 ; */
/*description: ADC2 Two Point calibration high point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_RD_ADC2_TP_HIGH 0x1FF
#define EFUSE_RD_ADC2_TP_HIGH_M ((EFUSE_RD_ADC2_TP_HIGH_V)<<(EFUSE_RD_ADC2_TP_HIGH_S))
#define EFUSE_RD_ADC2_TP_HIGH_V 0x1FF
#define EFUSE_RD_ADC2_TP_HIGH_S 23
/* EFUSE_RD_ADC2_TP_LOW : R/W ;bitpos:[22:16] ;default: 7'b0 ; */
/*description: ADC2 Two Point calibration low point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_RD_ADC2_TP_LOW 0x7F
#define EFUSE_RD_ADC2_TP_LOW_M ((EFUSE_RD_ADC2_TP_LOW_V)<<(EFUSE_RD_ADC2_TP_LOW_S))
#define EFUSE_RD_ADC2_TP_LOW_V 0x7F
#define EFUSE_RD_ADC2_TP_LOW_S 16
/* EFUSE_RD_ADC1_TP_HIGH : R/W ;bitpos:[15:7] ;default: 9'b0 ; */
/*description: ADC1 Two Point calibration high point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_RD_ADC1_TP_HIGH 0x1FF
#define EFUSE_RD_ADC1_TP_HIGH_M ((EFUSE_RD_ADC1_TP_HIGH_V)<<(EFUSE_RD_ADC1_TP_HIGH_S))
#define EFUSE_RD_ADC1_TP_HIGH_V 0x1FF
#define EFUSE_RD_ADC1_TP_HIGH_S 7
/* EFUSE_RD_ADC1_TP_LOW : R/W ;bitpos:[6:0] ;default: 7'b0 ; */
/*description: ADC1 Two Point calibration low point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_RD_ADC1_TP_LOW 0x7F
#define EFUSE_RD_ADC1_TP_LOW_M ((EFUSE_RD_ADC1_TP_LOW_V)<<(EFUSE_RD_ADC1_TP_LOW_S))
#define EFUSE_RD_ADC1_TP_LOW_V 0x7F
#define EFUSE_RD_ADC1_TP_LOW_S 0
#define EFUSE_BLK3_RDATA4_REG (DR_REG_EFUSE_BASE + 0x088)
/* EFUSE_BLK3_DOUT4 : RO ;bitpos:[31:0] ;default: 32'h0 ; */
@ -674,6 +730,12 @@
#define EFUSE_BLK3_DOUT4_M ((EFUSE_BLK3_DOUT4_V)<<(EFUSE_BLK3_DOUT4_S))
#define EFUSE_BLK3_DOUT4_V 0xFFFFFFFF
#define EFUSE_BLK3_DOUT4_S 0
/* EFUSE_RD_CAL_RESERVED: R/W ; bitpos:[0:15] ; default : 16'h0 ; */
/*description: Reserved for future calibration use. Indicated by EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_RD_CAL_RESERVED 0x0000FFFF
#define EFUSE_RD_CAL_RESERVED_M ((EFUSE_RD_CAL_RESERVED_V)<<(EFUSE_RD_CAL_RESERVED_S))
#define EFUSE_RD_CAL_RESERVED_V 0xFFFF
#define EFUSE_RD_CAL_RESERVED_S 0
#define EFUSE_BLK3_RDATA5_REG (DR_REG_EFUSE_BASE + 0x08c)
/* EFUSE_BLK3_DOUT5 : RO ;bitpos:[31:0] ;default: 32'h0 ; */
@ -851,6 +913,8 @@
#define EFUSE_BLK3_DIN2_V 0xFFFFFFFF
#define EFUSE_BLK3_DIN2_S 0
/* Note: Newer ESP32s utilize BLK3_DATA3 and parts of BLK3_DATA4 for calibration
* purposes. This usage is indicated by the EFUSE_RD_BLK3_PART_RESERVE bit.*/
#define EFUSE_BLK3_WDATA3_REG (DR_REG_EFUSE_BASE + 0x0e4)
/* EFUSE_BLK3_DIN3 : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
/*description: program for BLOCK3*/
@ -858,6 +922,30 @@
#define EFUSE_BLK3_DIN3_M ((EFUSE_BLK3_DIN3_V)<<(EFUSE_BLK3_DIN3_S))
#define EFUSE_BLK3_DIN3_V 0xFFFFFFFF
#define EFUSE_BLK3_DIN3_S 0
/* EFUSE_ADC2_TP_HIGH : R/W ;bitpos:[31:23] ;default: 9'b0 ; */
/*description: ADC2 Two Point calibration high point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_ADC2_TP_HIGH 0x1FF
#define EFUSE_ADC2_TP_HIGH_M ((EFUSE_ADC2_TP_HIGH_V)<<(EFUSE_ADC2_TP_HIGH_S))
#define EFUSE_ADC2_TP_HIGH_V 0x1FF
#define EFUSE_ADC2_TP_HIGH_S 23
/* EFUSE_ADC2_TP_LOW : R/W ;bitpos:[22:16] ;default: 7'b0 ; */
/*description: ADC2 Two Point calibration low point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_ADC2_TP_LOW 0x7F
#define EFUSE_ADC2_TP_LOW_M ((EFUSE_ADC2_TP_LOW_V)<<(EFUSE_ADC2_TP_LOW_S))
#define EFUSE_ADC2_TP_LOW_V 0x7F
#define EFUSE_ADC2_TP_LOW_S 16
/* EFUSE_ADC1_TP_HIGH : R/W ;bitpos:[15:7] ;default: 9'b0 ; */
/*description: ADC1 Two Point calibration high point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_ADC1_TP_HIGH 0x1FF
#define EFUSE_ADC1_TP_HIGH_M ((EFUSE_ADC1_TP_HIGH_V)<<(EFUSE_ADC1_TP_HIGH_S))
#define EFUSE_ADC1_TP_HIGH_V 0x1FF
#define EFUSE_ADC1_TP_HIGH_S 7
/* EFUSE_ADC1_TP_LOW : R/W ;bitpos:[6:0] ;default: 7'b0 ; */
/*description: ADC1 Two Point calibration low point. Only valid if EFUSE_RD_BLK3_PART_RESERVE */
#define EFUSE_ADC1_TP_LOW 0x7F
#define EFUSE_ADC1_TP_LOW_M ((EFUSE_ADC1_TP_LOW_V)<<(EFUSE_ADC1_TP_LOW_S))
#define EFUSE_ADC1_TP_LOW_V 0x7F
#define EFUSE_ADC1_TP_LOW_S 0
#define EFUSE_BLK3_WDATA4_REG (DR_REG_EFUSE_BASE + 0x0e8)
/* EFUSE_BLK3_DIN4 : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
@ -866,6 +954,12 @@
#define EFUSE_BLK3_DIN4_M ((EFUSE_BLK3_DIN4_V)<<(EFUSE_BLK3_DIN4_S))
#define EFUSE_BLK3_DIN4_V 0xFFFFFFFF
#define EFUSE_BLK3_DIN4_S 0
/* EFUSE_CAL_RESERVED: R/W ; bitpos:[0:15] ; default : 16'h0 ; */
/*description: Reserved for future calibration use. Indicated by EFUSE_BLK3_PART_RESERVE */
#define EFUSE_CAL_RESERVED 0x0000FFFF
#define EFUSE_CAL_RESERVED_M ((EFUSE_CAL_RESERVED_V)<<(EFUSE_CAL_RESERVED_S))
#define EFUSE_CAL_RESERVED_V 0xFFFF
#define EFUSE_CAL_RESERVED_S 0
#define EFUSE_BLK3_WDATA5_REG (DR_REG_EFUSE_BASE + 0x0ec)
/* EFUSE_BLK3_DIN5 : R/W ;bitpos:[31:0] ;default: 32'h0 ; */

View file

@ -117,10 +117,15 @@ rtc_vddsdio_config_t rtc_vddsdio_get_config()
result.force = 0;
result.enable = (efuse_reg & EFUSE_RD_XPD_SDIO_REG_M) >> EFUSE_RD_XPD_SDIO_REG_S;
result.tieh = (efuse_reg & EFUSE_RD_SDIO_TIEH_M) >> EFUSE_RD_SDIO_TIEH_S;
// in this case, DREFH/M/L are also set from EFUSE
result.drefh = (efuse_reg & EFUSE_RD_SDIO_DREFH_M) >> EFUSE_RD_SDIO_DREFH_S;
result.drefm = (efuse_reg & EFUSE_RD_SDIO_DREFM_M) >> EFUSE_RD_SDIO_DREFM_S;
result.drefl = (efuse_reg & EFUSE_RD_SDIO_DREFL_M) >> EFUSE_RD_SDIO_DREFL_S;
//DREFH/M/L eFuse are used for EFUSE_ADC_VREF instead. Therefore tuning
//will only be available on older chips that don't have EFUSE_ADC_VREF
if(REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG ,EFUSE_RD_BLK3_PART_RESERVE) == 0){
//BLK3_PART_RESERVE indicates the presence of EFUSE_ADC_VREF
// in this case, DREFH/M/L are also set from EFUSE
result.drefh = (efuse_reg & EFUSE_RD_SDIO_DREFH_M) >> EFUSE_RD_SDIO_DREFH_S;
result.drefm = (efuse_reg & EFUSE_RD_SDIO_DREFM_M) >> EFUSE_RD_SDIO_DREFM_S;
result.drefl = (efuse_reg & EFUSE_RD_SDIO_DREFL_M) >> EFUSE_RD_SDIO_DREFL_S;
}
return result;
}

BIN
docs/_static/adc-noise-graph.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
docs/_static/adc-vref-graph.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View file

@ -85,55 +85,58 @@ The value read in both these examples is 12 bits wide (range 0-4095).
.. _adc-api-adc-calibration:
Minimizing Noise
----------------
The ESP32 ADC can be sensitive to noise leading to large discrepancies in ADC readings. To minimize noise, users may connect a 0.1uF capacitor to the ADC input pad in use. Multisampling may also be used to further mitigate the effects of noise.
.. figure:: ../../_static/adc-noise-graph.jpg
:align: center
:alt: ADC noise mitigation
Graph illustrating noise mitigation using capacitor and multisampling of 64 samples.
ADC Calibration
---------------
The :component_file:`esp_adc_cal/include/esp_adc_cal.h` API provides functions to correct for differences in measured voltages caused by non-ideal ADC reference voltages in ESP32s. The ideal ADC reference voltage is 1100 mV however the reference voltage of different ESP32s can range from 1000 mV to 1200 mV.
The :component_file:`esp_adc_cal/include/esp_adc_cal.h` API provides functions to correct for differences in measured voltages caused by non-ideal ADC reference voltages and non-linear characteristics (only applicable at 11dB attenuation). The ideal ADC reference voltage is 1100mV, however true reference voltages can range from 1000mV to 1200 mV amongst ESP32s.
Correcting the measured voltage using this API involves referencing a lookup table of voltages. The voltage obtained from the lookup table is then scaled and shifted by a gain and offset factor that is based on the ADC's reference voltage. This is done with function :cpp:func:`esp_adc_cal_get_characteristics`.
The reference voltage of the ADCs can be routed to certain GPIOs and measured manually using the ADC drivers :cpp:func:`adc2_vref_to_gpio` function.
Example of Reading Calibrated Values
------------------------------------
Reading the ADC and obtaining a result in mV::
#include <driver/adc.h>
#include <esp_adc_cal.h>
.. figure:: ../../_static/adc-vref-graph.jpg
:align: center
:alt: ADC reference voltage comparison
...
#define V_REF 1100 // ADC reference voltage
// Configure ADC
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_11db);
// Calculate ADC characteristics i.e. gain and offset factors
esp_adc_cal_characteristics_t characteristics;
esp_adc_cal_get_characteristics(V_REF, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, &characteristics);
// Read ADC and obtain result in mV
uint32_t voltage = adc1_to_voltage(ADC1_CHANNEL_6, &characteristics);
printf("%d mV\n",voltage);
Routing ADC reference voltage to GPIO, so it can be manually measured and entered in function :cpp:func:`esp_adc_cal_get_characteristics`::
Graph illustrating effect of differing reference voltages on the ADC voltage curve.
#include <driver/adc.h>
#include <driver/gpio.h>
#include <esp_err.h>
Correcting ADC readings using this API involves characterizing one of the ADCs at a given attenuation to obtain a characteristics curve (ADC-Voltage curve). The characteristics curve is used to convert ADC readings to voltages in mV. Representation of characteristics curve will differ under **Linear Mode** and **Lookup Table Mode**. Calculation of the characteristics curve is based on calibration values which can be stored in eFuse or provided by the user.
...
.. _linear-mode:
esp_err_t status = adc2_vref_to_gpio(GPIO_NUM_25);
if (status == ESP_OK){
printf("v_ref routed to GPIO\n");
}else{
printf("failed to route v_ref\n");
}
Linear Mode
^^^^^^^^^^^
An example of using the ADC driver and obtaining calibrated measurements is available in esp-idf: :example:`peripherals/adc`
Linear Mode characterization will generate a linear characteristics curve in the form of ``y = coeff_a * x + coeff_b``. The linear curve will map ADC readings to a voltage in mV. The calibration values which the calculation of ``coeff_a`` and ``coeff_b`` can be based on will be prioritized in the following order
1. Two Point values
2. eFuse Vref
3. Default Vref
.. _lut-mode:
Lookup Table Mode
^^^^^^^^^^^^^^^^^
Lookup Table (LUT) Mode characterization utilizes a LUT to represent an ADCs characteristics curve. Each LUT consists of a High and Low reference curve which are representative of the characteristic curve of ESP32s with a Vref of 1200mV and 1000mV respectively. Converting an ADC reading to a voltage using a LUT involves interpolating between the High and Low curves based on an ESP32s true Vref. The true Vref can be read from eFuse (eFuse Vref) or provided by the user (Default Vref) if eFuse Vref is unavailable.
Calibration Values
^^^^^^^^^^^^^^^^^^
Calibration values are used during the characterization processes, and there are currently three possible types of calibration values. Note the availability of these calibration values will depend on the type of version of the ESP32 chip/module.
The **Two Point** calibration values represent each of the ADCs readings at 150mV and 850mV. The values are burned into eFuse during factory calibration and are used in Linear Mode to generate a linear characteristics curve. Note that the Two Point values are only available on some versions of ESP32 chips/modules
The **eFuse Vref** value represents the true reference voltage of the ADCs and can be used in both Linear and LUT modes. This value is measured and burned into eFuse during factory calibration. Note that eFuse Vref is not available on older variations of ESP32 chips/modules
**Default Vref** is an estimate of the ADC reference voltage provided by the user as a parameter during characterization. If Two Point or eFuse Vref values are unavailable, Default Vref will be used. To obtain an estimate of an ESP32 modules Vref, users can call the function ``adc2_vref_to_gpio()`` to route the ADC refernce voltage to a GPIO and measure it manually.
GPIO Lookup Macros
------------------

View file

@ -10,42 +10,71 @@
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_system.h"
#include "esp_adc_cal.h"
/*Note: Different ESP32 modules may have different reference voltages varying from
* 1000mV to 1200mV. Use #define GET_VREF to route v_ref to a GPIO
*/
#define V_REF 1100
#define ADC1_TEST_CHANNEL (ADC1_CHANNEL_6) //GPIO 34
//#define V_REF_TO_GPIO //Remove comment on define to route v_ref to GPIO
#define PRINT_VAL_SUPPORT(support, type) ({ \
if(support == ESP_OK){ \
printf("%s: supported\n", (type)); \
} else { \
printf("%s: not supported\n", (type)); \
} \
})
#define PRINT_VAL_TYPE(type, mode) ({ \
if(type == ESP_ADC_CAL_VAL_EFUSE_TP){ \
printf("%s mode: Two Point Value\n", (mode)); \
} else if (type == ESP_ADC_CAL_VAL_EFUSE_VREF){ \
printf("%s mode: eFuse Vref\n", (mode)); \
} else { \
printf("%s mode: Default Vref\n", (mode)); \
} \
})
#define DEFAULT_VREF 1100 //Use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES 64
static esp_adc_cal_characteristics_t *adc_linear_chars;
static esp_adc_cal_characteristics_t *adc_lut_chars;
static adc1_channel_t channel = ADC1_CHANNEL_6;
void app_main(void)
{
#ifndef V_REF_TO_GPIO
//Init ADC and Characteristics
esp_adc_cal_characteristics_t characteristics;
//Check if Two Point or Vref are burned into eFuse
esp_err_t efuse_vref_support = esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF);
esp_err_t efuse_tp_support = esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP);
PRINT_VAL_SUPPORT(efuse_vref_support, "eFuse Vref");
PRINT_VAL_SUPPORT(efuse_tp_support, "eFuse Two Point");
//Configure ADC1
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_TEST_CHANNEL, ADC_ATTEN_DB_0);
esp_adc_cal_get_characteristics(V_REF, ADC_ATTEN_DB_0, ADC_WIDTH_BIT_12, &characteristics);
uint32_t voltage;
adc1_config_channel_atten(channel, ADC_ATTEN_DB_0);
//Characterize ADC1 in both linear and lut mode
adc_linear_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
adc_lut_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t lin_val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_0, ESP_ADC_CAL_MODE_LIN, DEFAULT_VREF, adc_linear_chars);
esp_adc_cal_value_t lut_val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_0, ESP_ADC_CAL_MODE_LUT, DEFAULT_VREF, adc_lut_chars);
PRINT_VAL_TYPE(lin_val_type, "Linear");
PRINT_VAL_TYPE(lut_val_type, "LUT");
//Continuously sample ADC1
while(1){
voltage = adc1_to_voltage(ADC1_TEST_CHANNEL, &characteristics);
printf("%d mV\n",voltage);
uint32_t adc1_raw = 0;
//Multisample
for(int i = 0; i < NO_OF_SAMPLES; i++){
adc1_raw += adc1_get_raw(channel);
}
adc1_raw /= NO_OF_SAMPLES;
uint32_t corrected_linear = esp_adc_cal_raw_to_voltage(adc1_raw, ADC_WIDTH_BIT_12, adc_linear_chars);
uint32_t corrected_lut = esp_adc_cal_raw_to_voltage(adc1_raw, ADC_WIDTH_BIT_12, adc_lut_chars);
printf("Raw: %d\tLinear: %dmV\tLUT: %dmV\n", adc1_raw, corrected_linear, corrected_lut);
vTaskDelay(pdMS_TO_TICKS(1000));
}
#else
//Get v_ref
esp_err_t status;
status = adc2_vref_to_gpio(GPIO_NUM_25);
if (status == ESP_OK){
printf("v_ref routed to GPIO\n");
}else{
printf("failed to route v_ref\n");
}
fflush(stdout);
#endif
}