mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/adc_calibration' into 'master'
esp_adc_cal component See merge request !1084
This commit is contained in:
commit
a1b5813049
@ -21,6 +21,7 @@ extern "C" {
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
typedef enum {
|
||||
ADC_ATTEN_0db = 0, /*!<The input voltage of ADC will be reduced to about 1/1 */
|
||||
@ -66,7 +67,7 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit);
|
||||
*
|
||||
* @note This function also configures the input GPIO pin mux to
|
||||
* connect it to the ADC1 channel. It must be called before calling
|
||||
* adc1_get_voltage() for this channel.
|
||||
* adc1_get_raw() for this channel.
|
||||
*
|
||||
* The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage,
|
||||
* usually 3.3V) requires setting >0dB signal attenuation for that ADC channel.
|
||||
@ -107,13 +108,22 @@ esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten);
|
||||
* - -1: Parameter error
|
||||
* - Other: ADC1 channel reading.
|
||||
*/
|
||||
int adc1_get_voltage(adc1_channel_t channel);
|
||||
int adc1_get_raw(adc1_channel_t channel);
|
||||
|
||||
/** @cond */ //Doxygen command to hide deprecated function from API Reference
|
||||
/*
|
||||
* @deprecated This function returns an ADC1 reading but is deprecated due to
|
||||
* a misleading name and has been changed to directly call the new function.
|
||||
* Use the new function adc1_get_raw() instead
|
||||
*/
|
||||
int adc1_get_voltage(adc1_channel_t channel) __attribute__((deprecated));
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Configure ADC1 to be usable by the ULP
|
||||
*
|
||||
* This function reconfigures ADC1 to be controlled by the ULP.
|
||||
* Effect of this function can be reverted using adc1_get_voltage function.
|
||||
* Effect of this function can be reverted using adc1_get_raw function.
|
||||
*
|
||||
* Note that adc1_config_channel_atten, adc1_config_width functions need
|
||||
* to be called to configure ADC1 channels, before ADC1 is used by the ULP.
|
||||
@ -136,6 +146,22 @@ void adc1_ulp_enable();
|
||||
*/
|
||||
int hall_sensor_read();
|
||||
|
||||
/**
|
||||
* @brief Output ADC2 reference voltage to gpio 25 or 26 or 27
|
||||
*
|
||||
* This function utilizes the testing mux exclusive to ADC 2 to route the
|
||||
* reference voltage one of ADC2's channels. Supported gpios are gpios
|
||||
* 25, 26, and 27. This refernce voltage can be manually read from the pin
|
||||
* and used in the esp_adc_cal component.
|
||||
*
|
||||
* @param[in] gpio GPIO number (gpios 25,26,27 supported)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: v_ref successfully routed to selected gpio
|
||||
* - ESP_ERR_INVALID_ARG: Unsupported gpio
|
||||
*/
|
||||
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -945,7 +945,7 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int adc1_get_voltage(adc1_channel_t channel)
|
||||
int adc1_get_raw(adc1_channel_t channel)
|
||||
{
|
||||
uint16_t adc_value;
|
||||
|
||||
@ -975,6 +975,11 @@ int adc1_get_voltage(adc1_channel_t channel)
|
||||
return adc_value;
|
||||
}
|
||||
|
||||
int adc1_get_voltage(adc1_channel_t channel) //Deprecated. Use adc1_get_raw() instead
|
||||
{
|
||||
return adc1_get_raw(channel);
|
||||
}
|
||||
|
||||
void adc1_ulp_enable(void)
|
||||
{
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
@ -989,6 +994,43 @@ void adc1_ulp_enable(void)
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
}
|
||||
|
||||
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
|
||||
{
|
||||
int channel;
|
||||
if(gpio == GPIO_NUM_25){
|
||||
channel = 8; //Channel 8 bit
|
||||
}else if (gpio == GPIO_NUM_26){
|
||||
channel = 9; //Channel 9 bit
|
||||
}else if (gpio == GPIO_NUM_27){
|
||||
channel = 7; //Channel 7 bit
|
||||
}else{
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
//Configure RTC gpio
|
||||
rtc_gpio_init(gpio);
|
||||
rtc_gpio_output_disable(gpio);
|
||||
rtc_gpio_input_disable(gpio);
|
||||
rtc_gpio_pullup_dis(gpio);
|
||||
rtc_gpio_pulldown_dis(gpio);
|
||||
|
||||
SET_PERI_REG_BITS(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0, RTC_CNTL_DBG_ATTEN_S); //Check DBG effect outside sleep mode
|
||||
//set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2)
|
||||
SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 1, RTC_CNTL_DTEST_RTC_S); //Config test mux to route v_ref to ADC2 Channels
|
||||
//set ent
|
||||
SET_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC_M);
|
||||
//set sar2_en_test
|
||||
SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_SAR2_EN_TEST_M);
|
||||
//force fsm
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); //Select power source of ADC
|
||||
//set sar2 en force
|
||||
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M); //Pad bitmap controlled by SW
|
||||
//set en_pad for channels 7,8,9 (bits 0x380)
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, 1<<channel, SENS_SAR2_EN_PAD_S);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
DAC
|
||||
---------------------------------------------------------------*/
|
||||
@ -1141,11 +1183,11 @@ static int hall_sensor_get_value() //hall sensor without LNA
|
||||
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_XPD_HALL); // xpd hall
|
||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE_M); // phase force
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE); // hall phase
|
||||
Sens_Vp0 = adc1_get_voltage(ADC1_CHANNEL_0);
|
||||
Sens_Vn0 = adc1_get_voltage(ADC1_CHANNEL_3);
|
||||
Sens_Vp0 = adc1_get_raw(ADC1_CHANNEL_0);
|
||||
Sens_Vn0 = adc1_get_raw(ADC1_CHANNEL_3);
|
||||
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE);
|
||||
Sens_Vp1 = adc1_get_voltage(ADC1_CHANNEL_0);
|
||||
Sens_Vn1 = adc1_get_voltage(ADC1_CHANNEL_3);
|
||||
Sens_Vp1 = adc1_get_raw(ADC1_CHANNEL_0);
|
||||
Sens_Vn1 = adc1_get_raw(ADC1_CHANNEL_3);
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE);
|
||||
|
5
components/esp_adc_cal/component.mk
Normal file
5
components/esp_adc_cal/component.mk
Normal file
@ -0,0 +1,5 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
111
components/esp_adc_cal/esp_adc_cal.c
Normal file
111
components/esp_adc_cal/esp_adc_cal.c
Normal file
@ -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);
|
||||
}
|
||||
|
96
components/esp_adc_cal/esp_adc_cal_lookup_tables.c
Normal file
96
components/esp_adc_cal/esp_adc_cal_lookup_tables.c
Normal file
@ -0,0 +1,96 @@
|
||||
// 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
|
||||
}
|
||||
};
|
||||
|
141
components/esp_adc_cal/include/esp_adc_cal.h
Normal file
141
components/esp_adc_cal/include/esp_adc_cal.h
Normal file
@ -0,0 +1,141 @@
|
||||
// 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"
|
||||
|
||||
/** @cond */
|
||||
#define ADC_CAL_GAIN_SCALE 16
|
||||
#define ADC_CAL_OFFSET_SCALE 10
|
||||
|
||||
#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 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.
|
||||
*
|
||||
* @note A seperate LUT is provided for each attenuation and are defined in
|
||||
* esp_adc_cal_lookup_tables.c
|
||||
*/
|
||||
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 */
|
||||
} 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.
|
||||
*
|
||||
* @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_12Bit */
|
||||
const esp_adc_cal_lookup_table_t *table; /**<Pointer to LUT */
|
||||
} 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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @note reference voltage of the ADCs can be routed to GPIO using
|
||||
* adc2_vref_to_gpio() from the ADC driver
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Convert raw ADC reading to voltage in mV
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @return Calculated voltage in mV
|
||||
*
|
||||
* @note characteristics structure must be initialized using
|
||||
* esp_adc_cal_get_characteristics() before this function is used
|
||||
*/
|
||||
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc,
|
||||
const esp_adc_cal_characteristics_t *chars);
|
||||
|
||||
/**
|
||||
* @brief Reads ADC1 and returns 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().
|
||||
*
|
||||
* @param[in] channel Channel of ADC1 to measure
|
||||
* @param[in] chars Pointer to ADC characteristics struct
|
||||
*
|
||||
* @return voltage Calculated 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
|
||||
*/
|
||||
uint32_t adc1_to_voltage(adc1_channel_t channel, const esp_adc_cal_characteristics_t *chars);
|
||||
|
@ -74,6 +74,7 @@ INPUT = \
|
||||
../components/driver/include/driver/timer.h \
|
||||
../components/driver/include/driver/touch_pad.h \
|
||||
../components/driver/include/driver/uart.h \
|
||||
../components/esp_adc_cal/include/esp_adc_cal.h \
|
||||
##
|
||||
## Protocols - API Reference
|
||||
##
|
||||
|
@ -9,13 +9,15 @@ analog signals.
|
||||
|
||||
The ADC driver API currently only supports ADC1 (9 channels, attached to GPIOs 32-39).
|
||||
|
||||
Taking an ADC reading involves configuring the ADC with the desired precision and attentuation settings, and then calling adc1_get_voltage() to read the channel.
|
||||
Taking an ADC reading involves configuring the ADC with the desired precision and attentuation settings, and then calling adc1_get_raw() to read the channel.
|
||||
|
||||
It is also possible to read the internal hall effect sensor via ADC1.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
A full example using the ADC driver and the esp_adc_cal is available in esp-idf: :example:`peripherals/adc`
|
||||
|
||||
Reading voltage on ADC1 channel 0 (GPIO 36)::
|
||||
|
||||
#include <driver/adc.h>
|
||||
@ -24,7 +26,7 @@ Reading voltage on ADC1 channel 0 (GPIO 36)::
|
||||
|
||||
adc1_config_width(ADC_WIDTH_12Bit);
|
||||
adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_0db);
|
||||
int val = adc1_get_voltage(ADC1_CHANNEL_0);
|
||||
int val = adc1_get_raw(ADC1_CHANNEL_0);
|
||||
|
||||
Reading the internal hall effect sensor::
|
||||
|
||||
@ -43,3 +45,58 @@ API Reference
|
||||
.. include:: /_build/inc/adc.inc
|
||||
|
||||
|
||||
ADC Calibration
|
||||
===============
|
||||
|
||||
Overview
|
||||
--------
|
||||
The esp_adc_cal 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 1100mV however the reference voltage of different ESP32s can range from 1000mV to 1200mV.
|
||||
|
||||
Correcting the measured voltage using the esp_adc_cal API involves referencing a lookup table of voltages. The voltage obtained from the lookup table is the scaled and shifted by a gain and offset factor that is based on the ADC's reference voltage.
|
||||
|
||||
The reference voltage of the ADCs can be routed to certain GPIOs and measured manually using the ADC driver’s adc2_vref_to_gpio() function.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Reading the ADC and obtaining a result in mV::
|
||||
|
||||
#include <driver/adc.h>
|
||||
#include <esp_adc_cal.h>
|
||||
|
||||
...
|
||||
#define V_REF 1100 //ADC reference voltage
|
||||
|
||||
//Config ADC and characteristics
|
||||
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_11db, ADC_WIDTH_12Bit, &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::
|
||||
|
||||
#include <driver/adc.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
...
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_adc_cal.inc
|
51
examples/peripherals/adc/main/adc1_example_main.c
Normal file
51
examples/peripherals/adc/main/adc1_example_main.c
Normal file
@ -0,0 +1,51 @@
|
||||
/* ADC1 Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#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
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
#ifndef V_REF_TO_GPIO
|
||||
//Init ADC and Characteristics
|
||||
esp_adc_cal_characteristics_t characteristics;
|
||||
adc1_config_width(ADC_WIDTH_12Bit);
|
||||
adc1_config_channel_atten(ADC1_TEST_CHANNEL, ADC_ATTEN_0db);
|
||||
esp_adc_cal_get_characteristics(V_REF, ADC_ATTEN_0db, ADC_WIDTH_12Bit, &characteristics);
|
||||
uint32_t voltage;
|
||||
while(1){
|
||||
voltage = adc1_to_voltage(ADC1_TEST_CHANNEL, &characteristics);
|
||||
printf("%d mV\n",voltage);
|
||||
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
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/* ADC1 Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/adc.h"
|
||||
|
||||
#define ADC1_TEST_CHANNEL (ADC1_CHANNEL_6)
|
||||
|
||||
void adc1task(void* arg)
|
||||
{
|
||||
// initialize ADC
|
||||
adc1_config_width(ADC_WIDTH_12Bit);
|
||||
adc1_config_channel_atten(ADC1_TEST_CHANNEL, ADC_ATTEN_11db);
|
||||
while(1){
|
||||
printf("The adc1 value:%d\n",adc1_get_voltage(ADC1_TEST_CHANNEL));
|
||||
vTaskDelay(1000/portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
xTaskCreate(adc1task, "adc1task", 1024*3, NULL, 10, NULL);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ int sampling_period = 20;
|
||||
int i = 0;
|
||||
uint32_t sampling_start = esp_log_timestamp(); //this clock counts miliseconds
|
||||
do {
|
||||
ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc1_get_voltage(ADC1_TEST_CHANNEL));
|
||||
ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc1_get_raw(ADC1_TEST_CHANNEL));
|
||||
} while (esp_log_timestamp() - sampling_start < sampling_period);
|
||||
```
|
||||
|
||||
|
@ -87,7 +87,7 @@ int adc1_sample_and_show(int sampling_period)
|
||||
int i = 0;
|
||||
uint32_t sampling_start = esp_log_timestamp();
|
||||
do {
|
||||
ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc1_get_voltage(ADC1_TEST_CHANNEL));
|
||||
ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc1_get_raw(ADC1_TEST_CHANNEL));
|
||||
} while (esp_log_timestamp() - sampling_start < sampling_period);
|
||||
return i;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user