mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-19 23:45:28 +02:00
esp_adc_cal: Added ADC calibration component
Added component containg API that is able to correct raw ADC readings into a voltage in mV. Also provided a helper function that combines the process of getting the raw ADC1 reading then converting it to a voltage in mV. In doing so, the adc1_get_voltage() function of the ADC driver has been deprecated. Instead there is now adc1_get_raw to obtain the raw ADC1 reading, and adc1_to_voltage() that gets the raw reading and converts all in one function. Functions using the deprecated adc1_get_voltage() have also been updated to use adc1_get_raw(). Conversion is based on ADC characteristics. The characteristics are based on the ADC's v_ref, herefore the appropriate structure and functions have been provided to obtain the ADC characteristics. The existing ADC driver has also been modified by adding a function to route the internal ADC reference voltage to a GPIO allowing users to measure it manually. Relevant documentation has also been updated
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
// 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 <stdint.h>
|
||||
#include "driver/adc.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};
|
||||
|
||||
uint32_t get_adc_vref_from_efuse()
|
||||
{
|
||||
//TODO: Replaced with read to eFuse once ATE confirms location of 5 bits
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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_12Bit - 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user