[ESP-IDF 5.1] Fix ADC calibration & crashes on ESP32-C3

This commit is contained in:
TD-er
2023-10-11 10:44:03 +02:00
parent c768b94f6e
commit e662f5b1fa
10 changed files with 653 additions and 124 deletions
+4
View File
@@ -25,6 +25,10 @@ extra_scripts = ${esp32_base_idf5.extra_scripts}
build_unflags = ${esp32_base_idf5.build_unflags}
-fexceptions
board_build.filesystem = littlefs
lib_ignore =
${core_esp32_IDF5_1__2_0_13.lib_ignore}
Adafruit NeoPixel
Adafruit NeoMatrix
[env:custom_ESP32c3_4M316k_CDC]
+23
View File
@@ -3212,6 +3212,29 @@ To create/register a plugin, you have to :
#endif
// RMT driver used in Adafruit_NeoPixel does NOT work on IDF5.1 for RiscV chips
#ifdef ESP32C3
#ifdef USES_P038
#undef USES_P038
#endif
#ifdef USES_P041
#undef USES_P041 // NeoClock
#endif
#ifdef USES_P042
#undef USES_P042 // Candle
#endif
#ifdef USES_P070
#undef USES_P070
#endif
#ifdef USES_P131
#undef USES_P131
#endif
#endif
// Internal temp sensor causes crashes on ESP32-C3
#ifdef FEATURE_INTERNAL_TEMPERATURE
# undef FEATURE_INTERNAL_TEMPERATURE
+42 -45
View File
@@ -99,6 +99,8 @@
#endif
#include "../Helpers/Hardware_ADC_cali.h"
#endif // ifdef ESP32
@@ -545,63 +547,58 @@ int espeasy_analogRead(int pin) {
#ifdef ESP32
// ESP32 ADC calibration datatypes.
#if ESP_IDF_VERSION_MAJOR >= 5
#include <esp_adc/adc_cali.h>
#include <esp_adc/adc_cali_scheme.h>
//esp_adc_cal_value_t adc1_calibration_type = ESP_ADC_CAL_VAL_NOT_SUPPORTED;
adc_cali_handle_t adc_chars[ADC_ATTENDB_MAX] = {};
// FIXME TD-er: For now keep a local array of the adc calibration
#if ESP_IDF_VERSION_MAJOR < 5
Hardware_ADC_cali_t ESP32_ADC_cali[ADC_ATTEN_MAX];
#else
esp_adc_cal_value_t adc1_calibration_type = ESP_ADC_CAL_VAL_NOT_SUPPORTED;
esp_adc_cal_characteristics_t adc_chars[ADC_ATTEN_MAX];
Hardware_ADC_cali_t ESP32_ADC_cali[ADC_ATTENDB_MAX];
#endif
void initADC() {
#if ESP_IDF_VERSION_MAJOR < 5
# ifndef DEFAULT_VREF
# define DEFAULT_VREF 1100
# endif // ifndef DEFAULT_VREF
const adc_bits_width_t adc_bit_width = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
for (size_t atten = 0; atten < ADC_ATTEN_MAX; ++atten) {
adc1_calibration_type =
esp_adc_cal_characterize(ADC_UNIT_1, static_cast<adc_atten_t>(atten), adc_bit_width, DEFAULT_VREF, &adc_chars[atten]);
}
#else
for (uint32_t i = 0; i < ADC_ATTENDB_MAX; ++i) {
if (adc_chars[i] == nullptr) {
adc_cali_line_fitting_config_t cali_config = {
.unit_id = ADC_UNIT_1,
.atten = static_cast<adc_atten_t>(i),
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
adc_cali_create_scheme_line_fitting(&cali_config, &adc_chars[i]);
for (size_t atten = 0; atten < NR_ELEMENTS(ESP32_ADC_cali); ++atten) {
if (!ESP32_ADC_cali[atten].initialized()) {
// FIXME TD-er: For now fake some pin which is connected to ADC1
#ifdef ESP32_CLASSIC
const int pin = 36;
#else
const int pin = 1;
#endif
ESP32_ADC_cali[atten].init(pin, static_cast<adc_atten_t>(atten));
}
}
#endif
}
float applyADCFactoryCalibration(float raw_value, adc_atten_t attenuation)
{
if (attenuation < NR_ELEMENTS(ESP32_ADC_cali))
return ESP32_ADC_cali[attenuation].applyFactoryCalibration(raw_value);
return raw_value;
}
bool hasADC_factory_calibration() {
#if ESP_IDF_VERSION_MAJOR < 5
return esp_adc_cal_check_efuse(adc1_calibration_type) == ESP_OK;
#else
return false;
#endif
return ESP32_ADC_cali[0].useFactoryCalibration();
}
const __FlashStringHelper* getADC_factory_calibration_type() {
#if ESP_IDF_VERSION_MAJOR < 5
switch (adc1_calibration_type) {
case ESP_ADC_CAL_VAL_EFUSE_VREF: return F("V_ref in eFuse");
case ESP_ADC_CAL_VAL_EFUSE_TP: return F("Two Point values in eFuse");
case ESP_ADC_CAL_VAL_DEFAULT_VREF: return F("Default reference voltage");
case ESP_ADC_CAL_VAL_EFUSE_TP_FIT: return F("Two Point values and fitting curve in eFuse");
case ESP_ADC_CAL_VAL_NOT_SUPPORTED:
break;
}
#endif
return F("Unknown");
const __FlashStringHelper* getADC_factory_calibration_type()
{
return ESP32_ADC_cali[0].getADC_factory_calibration_type();
}
float getADC_factory_calibrated_min(adc_atten_t attenuation)
{
if (attenuation < NR_ELEMENTS(ESP32_ADC_cali))
return ESP32_ADC_cali[attenuation].getMinOut();
return 0.0f;
}
float getADC_factory_calibrated_max(adc_atten_t attenuation)
{
if (attenuation < NR_ELEMENTS(ESP32_ADC_cali))
return ESP32_ADC_cali[attenuation].getMaxOut();
return MAX_ADC_VALUE;
}
int getADC_num_for_gpio(int pin) {
+6 -6
View File
@@ -63,22 +63,22 @@ int espeasy_analogRead(int pin);
#ifdef ESP32
void initADC();
float applyADCFactoryCalibration(
float raw_value,
adc_atten_t attenuation);
bool hasADC_factory_calibration();
const __FlashStringHelper* getADC_factory_calibration_type();
float getADC_factory_calibrated_min(adc_atten_t attenuation);
float getADC_factory_calibrated_max(adc_atten_t attenuation);
int getADC_num_for_gpio(int pin);
int getADC_num_for_gpio(int pin, int& channel);
int espeasy_analogRead(int pin,
bool readAsTouch = false);
#if ESP_IDF_VERSION_MAJOR >= 5
// ADC Factory calibration definition
extern adc_cali_handle_t adc_chars[ADC_ATTENDB_MAX];
#else
extern esp_adc_cal_characteristics_t adc_chars[ADC_ATTEN_MAX];
#endif
#endif // ifdef ESP32
#if FEATURE_INTERNAL_TEMPERATURE
+143
View File
@@ -0,0 +1,143 @@
#include "../Helpers/Hardware_ADC.h"
#ifdef ESP32
# include "../Helpers/Hardware.h"
#endif // ifdef ESP32
#ifdef ESP8266
bool Hardware_ADC_t::init() {}
int Hardware_ADC_t::read() {
if (!WiFiEventData.wifiConnectInProgress) {
# if FEATURE_ADC_VCC
_lastADCvalue = ESP.getVcc();
# else // if FEATURE_ADC_VCC
_lastADCvalue = analogRead(A0);
# endif // if FEATURE_ADC_VCC
}
return _lastADCvalue;
}
#endif // ifdef ESP8266
#ifdef ESP32
Hardware_ADC_t::~Hardware_ADC_t()
{
# if ESP_IDF_VERSION_MAJOR >= 5
adc_oneshot_del_unit(_adc_handle);
# else
// FIXME TD-er: Should we reset the GPIO config for this pin?
# endif // if ESP_IDF_VERSION_MAJOR >= 5
}
bool Hardware_ADC_t::init(int pin, adc_atten_t attenuation)
{
int ch{};
int t = -1;
if (!getADC_gpio_info(pin, _adc, ch, t)) {
return false;
}
_pin = pin;
# if HAS_TOUCH_GPIO
_isTouchPin = t >= 0;
# endif // if HAS_TOUCH_GPIO
_attenuation = attenuation;
# if ESP_IDF_VERSION_MAJOR >= 5
_channel = static_cast<adc_channel_t>(ch);
# if HAS_ADC2
const adc_unit_t unit = (_adc == 1) ? ADC_UNIT_1 : ADC_UNIT_2;
# else // if HAS_ADC2
if (_adc != 1) {
return false;
}
const adc_unit_t unit = ADC_UNIT_1;
# endif // if HAS_ADC2
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = unit
};
if (ESP_OK != adc_oneshot_new_unit(&init_config, &_adc_handle)) {
return false;
}
adc_oneshot_chan_cfg_t config = {
.atten = attenuation,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
return ESP_OK == adc_oneshot_config_channel(_adc_handle, _channel, &config);
# else // if ESP_IDF_VERSION_MAJOR >= 5
if ((_adc == 1) || (_adc == 2)) {
analogSetPinAttenuation(_pin, static_cast<adc_attenuation_t>(_attenuation));
}
return true;
# endif // if ESP_IDF_VERSION_MAJOR >= 5
}
bool Hardware_ADC_t::adc_calibration_init()
{
_useFactoryCalibration = _adc_cali_handle.init(_pin, _attenuation);
return _useFactoryCalibration;
}
int Hardware_ADC_t::read(bool readAsTouch) {
# if HAS_HALL_EFFECT_SENSOR
if (_adc == 0) {
return hallRead();
}
# endif // if HAS_HALL_EFFECT_SENSOR
// See:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html#configuration-and-reading-adc
// ADC2 is shared with WiFi, so don't read ADC2 when WiFi is on.
const bool canread = _adc == 1 || WiFi.getMode() == WIFI_OFF;
if (canread) {
# if HAS_TOUCH_GPIO
if (readAsTouch && _isTouchPin) {
return touchRead(_pin);
}
# endif // if HAS_TOUCH_GPIO
# if ESP_IDF_VERSION_MAJOR >= 5
int adc_raw{};
if (ESP_OK == adc_oneshot_read(_adc_handle, _channel, &adc_raw)) {
_lastADCvalue = adc_raw;
}
# else // if ESP_IDF_VERSION_MAJOR >= 5
_lastADCvalue = analogRead(_pin);
# endif // if ESP_IDF_VERSION_MAJOR >= 5
}
return _lastADCvalue;
}
float Hardware_ADC_t::applyFactoryCalibration(float rawValue) {
return _adc_cali_handle.applyFactoryCalibration(rawValue);
}
/*
bool Hardware_ADC_t::hasADC_factory_calibration() {
# if ESP_IDF_VERSION_MAJOR < 5
return esp_adc_cal_check_efuse(_adc_calibration_type) == ESP_OK;
# else // if ESP_IDF_VERSION_MAJOR < 5
return false;
# endif // if ESP_IDF_VERSION_MAJOR < 5
}
*/
#endif // ifdef ESP32
+85
View File
@@ -0,0 +1,85 @@
#ifndef HELPERS_HARDWARE_ADC_H
#define HELPERS_HARDWARE_ADC_H
#include "../../ESPEasy_common.h"
#ifdef ESP8266
# define HAS_ADC2 0
#endif // ifdef ESP8266
#ifdef ESP32
# include "../Helpers/Hardware_ADC_cali.h"
#endif // ifdef ESP32
class Hardware_ADC_t {
public:
Hardware_ADC_t() = default;
#ifdef ESP8266
bool init();
int read();
#endif // ifdef ESP8266
#ifdef ESP32
~Hardware_ADC_t();
bool init(int pin,
adc_atten_t attenuation = ADC_ATTEN_DB_11);
// Return whether factory calibration is actually enabled.
// Cannot enable factory calibration when no calibration is present.
bool adc_calibration_init();
int read(bool readAsTouch = false);
float applyFactoryCalibration(float rawValue);
// bool hasADC_factory_calibration();
# if ESP_IDF_VERSION_MAJOR >= 5
static bool adc_calibration_init(
int pin,
adc_atten_t atten,
adc_cali_handle_t *out_handle);
# endif // if ESP_IDF_VERSION_MAJOR >= 5
static float mapADCtoFloat(float float_value,
float adc1,
float adc2,
float out1,
float out2);
private:
int _pin = -1;
int _adc = -1;
# if HAS_TOUCH_GPIO
bool _isTouchPin = false;
# endif // if HAS_TOUCH_GPIO
bool _useFactoryCalibration = false;
adc_atten_t _attenuation = ADC_ATTEN_DB_11;
// ADC Factory calibration definition
Hardware_ADC_cali_t _adc_cali_handle;
# if ESP_IDF_VERSION_MAJOR >= 5
adc_channel_t _channel;
adc_oneshot_unit_handle_t _adc_handle;
# endif // if ESP_IDF_VERSION_MAJOR >= 5
#endif // ifdef ESP32
int _lastADCvalue{};
};
#endif // ifndef HELPERS_HARDWARE_ADC_H
+223
View File
@@ -0,0 +1,223 @@
#include "../Helpers/Hardware_ADC_cali.h"
#ifdef ESP32
# include "../Helpers/ESPEasy_math.h"
# include "../Helpers/Hardware.h"
Hardware_ADC_cali_t::~Hardware_ADC_cali_t()
{
# if ESP_IDF_VERSION_MAJOR >= 5
if (_useFactoryCalibration) {
# if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_delete_scheme_curve_fitting(_adc_cali_handle);
# elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
adc_cali_delete_scheme_line_fitting(_adc_cali_handle);
# endif // if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
}
# endif // if ESP_IDF_VERSION_MAJOR >= 5
}
bool Hardware_ADC_cali_t::init(int pin,
adc_atten_t attenuation)
{
# if ESP_IDF_VERSION_MAJOR >= 5 && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
_useHighResInterpolation = false;
# else // if ESP_IDF_VERSION_MAJOR >= 5 && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
_useHighResInterpolation = attenuation != adc_atten_t::ADC_ATTEN_DB_11;
# endif // if ESP_IDF_VERSION_MAJOR >= 5 && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
# if ESP_IDF_VERSION_MAJOR >= 5
if (_adc_cali_handle != nullptr) {
# if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_delete_scheme_curve_fitting(_adc_cali_handle);
# elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
adc_cali_delete_scheme_line_fitting(_adc_cali_handle);
# endif // if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
}
_useFactoryCalibration = Hardware_ADC_cali_t::adc_calibration_init(
pin,
attenuation,
&_adc_cali_handle);
if (_useFactoryCalibration) {
int tmp{};
adc_cali_raw_to_voltage(_adc_cali_handle, 0, &tmp);
_min_out = tmp;
adc_cali_raw_to_voltage(_adc_cali_handle, MAX_ADC_VALUE, &tmp);
_max_out = tmp;
}
# else // if ESP_IDF_VERSION_MAJOR >= 5
# ifndef DEFAULT_VREF
# define DEFAULT_VREF 1100
# endif // ifndef DEFAULT_VREF
constexpr adc_bits_width_t adc_bit_width = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
_adc_calibration_type =
esp_adc_cal_characterize((getADC_num_for_gpio(pin) == 1) ? ADC_UNIT_1 : ADC_UNIT_2,
static_cast<adc_atten_t>(attenuation),
adc_bit_width,
DEFAULT_VREF,
&_adc_chars);
_useFactoryCalibration = esp_adc_cal_check_efuse(_adc_calibration_type) == ESP_OK;
if (_useFactoryCalibration) {
_min_out = esp_adc_cal_raw_to_voltage(0, &_adc_chars);
_max_out = esp_adc_cal_raw_to_voltage(MAX_ADC_VALUE, &_adc_chars);
}
# endif // if ESP_IDF_VERSION_MAJOR >= 5
_initialized = true;
return _useFactoryCalibration;
}
float Hardware_ADC_cali_t::applyFactoryCalibration(float rawValue) const {
if (!_useFactoryCalibration) {
return rawValue;
}
if (!_useHighResInterpolation) {
const int raw = rawValue;
# if ESP_IDF_VERSION_MAJOR >= 5
int res{};
adc_cali_raw_to_voltage(_adc_cali_handle, raw, &res);
return res;
# else // if ESP_IDF_VERSION_MAJOR >= 5
return esp_adc_cal_raw_to_voltage(raw, &_adc_chars);
# endif // if ESP_IDF_VERSION_MAJOR >= 5
}
// All other attenuations do appear to have a straight calibration curve.
// But applying the factory calibration then reduces resolution.
// So we interpolate using the calibrated extremes
return mapADCtoFloat(
rawValue,
0,
MAX_ADC_VALUE,
_min_out,
_max_out);
}
const __FlashStringHelper * Hardware_ADC_cali_t::getADC_factory_calibration_type() const {
# if ESP_IDF_VERSION_MAJOR >= 5
if (_useFactoryCalibration) {
# if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
return F("Calibration Curve Fitting");
# endif // if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
# if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
return F("Calibration Line Fitting");
# endif // if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
}
# else // if ESP_IDF_VERSION_MAJOR >= 5
switch (_adc_calibration_type) {
case ESP_ADC_CAL_VAL_EFUSE_VREF: return F("V_ref in eFuse");
case ESP_ADC_CAL_VAL_EFUSE_TP: return F("Two Point values in eFuse");
case ESP_ADC_CAL_VAL_DEFAULT_VREF: return F("Default reference voltage");
case ESP_ADC_CAL_VAL_EFUSE_TP_FIT: return F("Two Point values and fitting curve in eFuse");
case ESP_ADC_CAL_VAL_NOT_SUPPORTED:
break;
}
# endif // if ESP_IDF_VERSION_MAJOR >= 5
return F("Unknown");
}
# if ESP_IDF_VERSION_MAJOR >= 5
bool Hardware_ADC_cali_t::adc_calibration_init(
int pin,
adc_atten_t atten,
adc_cali_handle_t *out_handle)
{
int ch{};
const int adc = getADC_num_for_gpio(pin, ch);
const adc_channel_t channel = static_cast<adc_channel_t>(ch);
# if HAS_ADC2
const adc_unit_t unit = (adc == 1) ? ADC_UNIT_1 : ADC_UNIT_2;
# else // if HAS_ADC2
const adc_unit_t unit = ADC_UNIT_1;
# endif // if HAS_ADC2
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
# if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (!calibrated) {
// calibration scheme version: Curve Fitting
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.chan = channel,
.atten = atten,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
# endif // if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
# if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (!calibrated) {
// calibration scheme version: Line Fitting
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
# endif // if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
*out_handle = handle;
/*
if (ret == ESP_OK) {
// Calibration Success
} else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
// eFuse not burnt, skip software calibration
} else {
// Invalid arg or no memory
}
*/
return calibrated;
}
# endif // if ESP_IDF_VERSION_MAJOR >= 5
float Hardware_ADC_cali_t::mapADCtoFloat(float float_value,
float adc1,
float adc2,
float out1,
float out2)
{
if (!approximatelyEqual(adc1, adc2))
{
const float normalized = (float_value - adc1) / (adc2 - adc1);
float_value = normalized * (out2 - out1) + out1;
}
return float_value;
}
#endif // ifdef ESP32
+101
View File
@@ -0,0 +1,101 @@
#ifndef HELPERS_HARDWARE_ADC_CALI_H
#define HELPERS_HARDWARE_ADC_CALI_H
#include "../../ESPEasy_common.h"
#ifdef ESP32
# include "../Helpers/Hardware_defines.h"
// Needed to get ADC Vref
# if ESP_IDF_VERSION_MAJOR >= 5
# include <soc/soc_caps.h>
# include <esp_adc/adc_oneshot.h>
# include <esp_adc/adc_cali.h>
# include <esp_adc/adc_cali_scheme.h>
# else // if ESP_IDF_VERSION_MAJOR >= 5
# include <esp_adc_cal.h>
# include <driver/adc.h>
# endif // if ESP_IDF_VERSION_MAJOR >= 5
# if (SOC_ADC_PERIPH_NUM >= 2) && !CONFIG_IDF_TARGET_ESP32C3
/**
* On ESP32C3, ADC2 is no longer supported, due to its HW limitation.
* Search for errata on espressif website for more details.
*/
# define HAS_ADC2 1
# else // if (SOC_ADC_PERIPH_NUM >= 2) && !CONFIG_IDF_TARGET_ESP32C3
# define HAS_ADC2 0
# endif // if (SOC_ADC_PERIPH_NUM >= 2) && !CONFIG_IDF_TARGET_ESP32C3
class Hardware_ADC_cali_t {
public:
Hardware_ADC_cali_t() = default;
~Hardware_ADC_cali_t();
// Return whether factory calibration is actually enabled.
// Cannot enable factory calibration when no calibration is present.
bool init(int pin,
adc_atten_t attenuation = ADC_ATTEN_DB_11);
bool initialized() const { return _initialized; }
// Convert the rawValue to milli Volt when factory calibration is present and initialized.
float applyFactoryCalibration(float rawValue) const;
float getMinOut() const {
return _min_out;
}
float getMaxOut() const {
return _max_out;
}
bool useFactoryCalibration() const {
return _useFactoryCalibration;
}
const __FlashStringHelper* getADC_factory_calibration_type() const;
private:
# if ESP_IDF_VERSION_MAJOR >= 5
static bool adc_calibration_init(
int pin,
adc_atten_t atten,
adc_cali_handle_t *out_handle);
# endif // if ESP_IDF_VERSION_MAJOR >= 5
public:
static float mapADCtoFloat(float float_value,
float adc1,
float adc2,
float out1,
float out2);
private:
// ADC Factory calibration definition
# if ESP_IDF_VERSION_MAJOR >= 5
adc_cali_handle_t _adc_cali_handle = nullptr;
# else // if ESP_IDF_VERSION_MAJOR >= 5
esp_adc_cal_value_t _adc_calibration_type = ESP_ADC_CAL_VAL_NOT_SUPPORTED;
esp_adc_cal_characteristics_t _adc_chars;
# endif // if ESP_IDF_VERSION_MAJOR >= 5
bool _useFactoryCalibration = false;
bool _useHighResInterpolation = false;
bool _initialized = false;
float _min_out{};
float _max_out = MAX_ADC_VALUE;
};
#endif // ifdef ESP32
#endif // ifndef HELPERS_HARDWARE_ADC_CALI_H
+25 -69
View File
@@ -4,11 +4,20 @@
# include "../Globals/RulesCalculate.h"
#include "../Helpers/Hardware_ADC_cali.h"
# ifndef DEFAULT_VREF
# define DEFAULT_VREF 1100
# endif // ifndef DEFAULT_VREF
#ifndef P002_ADC_ATTEN_MAX
#if ESP_IDF_VERSION_MAJOR < 5
#define P002_ADC_ATTEN_MAX ADC_ATTEN_MAX
#else
#define P002_ADC_ATTEN_MAX ADC_ATTENDB_MAX
#endif
#endif
void P002_data_struct::init(struct EventStruct *event)
{
@@ -172,19 +181,14 @@ void P002_data_struct::webformLoad(struct EventStruct *event)
# endif // if FEATURE_CHART_JS
formatADC_statistics(F("Current ADC to mV"), raw_value);
for (size_t att = 0; att < NR_ELEMENTS(adc_chars); ++att) {
#if ESP_IDF_VERSION_MAJOR >= 5
int low, high = 0;
adc_cali_raw_to_voltage(adc_chars[att], 0, &low);
adc_cali_raw_to_voltage(adc_chars[att], MAX_ADC_VALUE, &high);
#else
const int low = esp_adc_cal_raw_to_voltage(0, &adc_chars[att]);
const int high = esp_adc_cal_raw_to_voltage(MAX_ADC_VALUE, &adc_chars[att]);
#endif
for (size_t att = 0; att < P002_ADC_ATTEN_MAX; ++att) {
const adc_atten_t attenuation = static_cast<adc_atten_t>(att);
const int low = getADC_factory_calibrated_min(attenuation);
const int high = getADC_factory_calibrated_max(attenuation);
const float step = static_cast<float>(high - low) / MAX_ADC_VALUE;
String rowlabel = F("Attenuation @");
rowlabel += AttenuationToString(static_cast<adc_atten_t>(att));
rowlabel += AttenuationToString(attenuation);
addRowLabel(rowlabel);
addHtml(F("Range / Step: "));
addHtmlInt(low);
@@ -375,14 +379,14 @@ void P002_data_struct::webformLoad_calibrationCurve(struct EventStruct *event)
size_t current_attenuation = getAttenuation(event);
if (current_attenuation >= NR_ELEMENTS(adc_chars)) { current_attenuation = ADC_ATTEN_DB_11; }
if (current_attenuation >= P002_ADC_ATTEN_MAX) { current_attenuation = ADC_ATTEN_DB_11; }
for (size_t att = 0; att < NR_ELEMENTS(adc_chars); ++att)
for (size_t att = 0; att < P002_ADC_ATTEN_MAX; ++att)
{
float values[valueCount];
for (int i = 0; i < valueCount; ++i) {
values[i] = applyFactoryCalibration(xAxisValues[i], static_cast<adc_atten_t>(att));
values[i] = applyADCFactoryCalibration(xAxisValues[i], static_cast<adc_atten_t>(att));
}
add_ChartJS_dataset(
@@ -421,15 +425,10 @@ void P002_data_struct::getInputRange(struct EventStruct *event, int& minInputVal
if (useFactoryCalibration(event) && !ignoreCalibration) {
// reading in mVolt, not ADC
const size_t attenuation = getAttenuation(event);
const adc_atten_t attenuation = getAttenuation(event);
#if ESP_IDF_VERSION_MAJOR >= 5
adc_cali_raw_to_voltage(adc_chars[attenuation], 0, &minInputValue);
adc_cali_raw_to_voltage(adc_chars[attenuation], MAX_ADC_VALUE, &maxInputValue);
#else
minInputValue = esp_adc_cal_raw_to_voltage(0, &adc_chars[attenuation]);
maxInputValue = esp_adc_cal_raw_to_voltage(MAX_ADC_VALUE, &adc_chars[attenuation]);
#endif
minInputValue = getADC_factory_calibrated_min(attenuation);
maxInputValue = getADC_factory_calibrated_max(attenuation);
}
# endif // ifdef ESP32
}
@@ -507,7 +506,7 @@ void P002_data_struct::formatADC_statistics(const __FlashStringHelper *label, in
# ifdef ESP32
if (_useFactoryCalibration) {
float_value = applyFactoryCalibration(raw, _attenuation);
float_value = applyADCFactoryCalibration(raw, _attenuation);
html_add_estimate_symbol();
addHtmlFloat(float_value, _nrDecimals);
@@ -824,7 +823,7 @@ bool P002_data_struct::getValue(float& float_value,
# ifdef ESP32
if (_useFactoryCalibration) {
float_value = applyFactoryCalibration(raw_value, _attenuation);
float_value = applyADCFactoryCalibration(raw_value, _attenuation);
}
# endif // ifdef ESP32
@@ -894,7 +893,7 @@ bool P002_data_struct::getOversamplingValue(float& float_value, int& raw_value)
# ifdef ESP32
if (_useFactoryCalibration) {
float_value = applyFactoryCalibration(float_value, _attenuation);
float_value = applyADCFactoryCalibration(float_value, _attenuation);
}
# endif // ifdef ESP32
@@ -945,7 +944,7 @@ int P002_data_struct::computeADC_to_bin(const int& currentValue) const
# ifdef ESP32
if (_useFactoryCalibration) {
calibrated_value = applyFactoryCalibration(calibrated_value, _attenuation);
calibrated_value = applyADCFactoryCalibration(calibrated_value, _attenuation);
}
# endif // ifdef ESP32
@@ -1040,7 +1039,7 @@ float P002_data_struct::getCurrentValue(struct EventStruct *event, int& raw_valu
# ifdef ESP32
if (useFactoryCalibration(event)) {
return applyFactoryCalibration(raw_value, getAttenuation(event));
return applyADCFactoryCalibration(raw_value, getAttenuation(event));
}
# endif // ifdef ESP32
@@ -1070,49 +1069,6 @@ bool P002_data_struct::useFactoryCalibration(struct EventStruct *event) {
return false;
}
float P002_data_struct::applyFactoryCalibration(float raw_value, adc_atten_t attenuation)
{
if (attenuation == adc_atten_t::ADC_ATTEN_DB_11) {
#if ESP_IDF_VERSION_MAJOR >= 5
int res{};
adc_cali_raw_to_voltage(adc_chars[attenuation], raw_value, &res);
return res;
#else
return esp_adc_cal_raw_to_voltage(raw_value, &adc_chars[attenuation]);
#endif
}
// All other attenuations do appear to have a straight calibration curve.
// But applying the factory calibration then reduces resolution.
// So we interpolate using the calibrated extremes
// Cache the computing of the values.
static adc_atten_t last_Attn = static_cast<adc_atten_t>(NR_ELEMENTS(adc_chars));
static float last_out1 = 0.0;
static float last_out2 = MAX_ADC_VALUE;
if (last_Attn != attenuation) {
last_Attn = attenuation;
#if ESP_IDF_VERSION_MAJOR >= 5
int tmp{};
adc_cali_raw_to_voltage(adc_chars[attenuation], 0, &tmp);
last_out1 = tmp;
adc_cali_raw_to_voltage(adc_chars[attenuation], MAX_ADC_VALUE, &tmp);
last_out2 = tmp;
#else
last_out1 = esp_adc_cal_raw_to_voltage(0, &adc_chars[attenuation]);
last_out2 = esp_adc_cal_raw_to_voltage(MAX_ADC_VALUE, &adc_chars[attenuation]);
#endif
}
return mapADCtoFloat(
raw_value,
0,
MAX_ADC_VALUE,
last_out1,
last_out2);
}
# endif // ifdef ESP32
# ifndef LIMIT_BUILD_SIZE
+1 -4
View File
@@ -213,10 +213,6 @@ public:
# ifdef ESP32
static bool useFactoryCalibration(struct EventStruct *event);
static float applyFactoryCalibration(float raw_value,
adc_atten_t attenuation);
# endif // ifdef ESP32
private:
@@ -276,6 +272,7 @@ private:
bool _useFactoryCalibration = false;
adc_atten_t _attenuation = ADC_ATTEN_DB_11;
# endif // ifdef ESP32
};