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
111 lines
4.9 KiB
C
111 lines
4.9 KiB
C
// 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);
|
|
}
|
|
|