mirror of
https://github.com/esphome/esphome.git
synced 2024-11-14 02:58:11 +01:00
[ESP32] ADC auto-range setting (#2541)
This commit is contained in:
parent
bcc77c73e1
commit
e79f7ce290
3 changed files with 110 additions and 60 deletions
|
@ -1,5 +1,6 @@
|
||||||
#include "adc_sensor.h"
|
#include "adc_sensor.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
#ifdef USE_ADC_SENSOR_VCC
|
#ifdef USE_ADC_SENSOR_VCC
|
||||||
|
@ -16,8 +17,6 @@ namespace adc {
|
||||||
static const char *const TAG = "adc";
|
static const char *const TAG = "adc";
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
void ADCSensor::set_attenuation(adc_atten_t attenuation) { this->attenuation_ = attenuation; }
|
|
||||||
|
|
||||||
inline adc1_channel_t gpio_to_adc1(uint8_t pin) {
|
inline adc1_channel_t gpio_to_adc1(uint8_t pin) {
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
switch (pin) {
|
switch (pin) {
|
||||||
|
@ -57,6 +56,8 @@ inline adc1_channel_t gpio_to_adc1(uint8_t pin) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
void ADCSensor::set_attenuation(adc_atten_t attenuation) { this->attenuation_ = attenuation; }
|
||||||
|
void ADCSensor::set_autorange(bool autorange) { this->autorange_ = autorange; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ADCSensor::setup() {
|
void ADCSensor::setup() {
|
||||||
|
@ -66,6 +67,8 @@ void ADCSensor::setup() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
|
if (this->autorange_)
|
||||||
|
this->attenuation_ = ADC_ATTEN_DB_11;
|
||||||
adc1_config_channel_atten(gpio_to_adc1(pin_->get_pin()), attenuation_);
|
adc1_config_channel_atten(gpio_to_adc1(pin_->get_pin()), attenuation_);
|
||||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||||
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
|
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
|
||||||
|
@ -84,6 +87,9 @@ void ADCSensor::dump_config() {
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
LOG_PIN(" Pin: ", pin_);
|
LOG_PIN(" Pin: ", pin_);
|
||||||
|
if (autorange_)
|
||||||
|
ESP_LOGCONFIG(TAG, " Attenuation: auto");
|
||||||
|
else
|
||||||
switch (this->attenuation_) {
|
switch (this->attenuation_) {
|
||||||
case ADC_ATTEN_DB_0:
|
case ADC_ATTEN_DB_0:
|
||||||
ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)");
|
ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)");
|
||||||
|
@ -109,56 +115,92 @@ void ADCSensor::update() {
|
||||||
ESP_LOGD(TAG, "'%s': Got voltage=%.2fV", this->get_name().c_str(), value_v);
|
ESP_LOGD(TAG, "'%s': Got voltage=%.2fV", this->get_name().c_str(), value_v);
|
||||||
this->publish_state(value_v);
|
this->publish_state(value_v);
|
||||||
}
|
}
|
||||||
float ADCSensor::sample() {
|
uint16_t ADCSensor::read_raw_() {
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
int raw = adc1_get_raw(gpio_to_adc1(pin_->get_pin()));
|
return adc1_get_raw(gpio_to_adc1(pin_->get_pin()));
|
||||||
float value_v = raw / 4095.0f;
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
switch (this->attenuation_) {
|
|
||||||
case ADC_ATTEN_DB_0:
|
|
||||||
value_v *= 1.1;
|
|
||||||
break;
|
|
||||||
case ADC_ATTEN_DB_2_5:
|
|
||||||
value_v *= 1.5;
|
|
||||||
break;
|
|
||||||
case ADC_ATTEN_DB_6:
|
|
||||||
value_v *= 2.2;
|
|
||||||
break;
|
|
||||||
case ADC_ATTEN_DB_11:
|
|
||||||
value_v *= 3.9;
|
|
||||||
break;
|
|
||||||
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
|
|
||||||
switch (this->attenuation_) {
|
|
||||||
case ADC_ATTEN_DB_0:
|
|
||||||
value_v *= 0.84;
|
|
||||||
break;
|
|
||||||
case ADC_ATTEN_DB_2_5:
|
|
||||||
value_v *= 1.13;
|
|
||||||
break;
|
|
||||||
case ADC_ATTEN_DB_6:
|
|
||||||
value_v *= 1.56;
|
|
||||||
break;
|
|
||||||
case ADC_ATTEN_DB_11:
|
|
||||||
value_v *= 3.0;
|
|
||||||
break;
|
|
||||||
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return value_v;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
#ifdef USE_ADC_SENSOR_VCC
|
#ifdef USE_ADC_SENSOR_VCC
|
||||||
return ESP.getVcc() / 1024.0f; // NOLINT(readability-static-accessed-through-instance)
|
return ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance)
|
||||||
#else
|
#else
|
||||||
return analogRead(this->pin_->get_pin()) / 1024.0f; // NOLINT
|
return analogRead(this->pin_->get_pin()); // NOLINT
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
uint32_t ADCSensor::raw_to_microvolts_(uint16_t raw) {
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
switch (this->attenuation_) {
|
||||||
|
case ADC_ATTEN_DB_0:
|
||||||
|
return raw * 269; // 1e6 * 1.1 / 4095
|
||||||
|
case ADC_ATTEN_DB_2_5:
|
||||||
|
return raw * 366; // 1e6 * 1.5 / 4095
|
||||||
|
case ADC_ATTEN_DB_6:
|
||||||
|
return raw * 537; // 1e6 * 2.2 / 4095
|
||||||
|
case ADC_ATTEN_DB_11:
|
||||||
|
return raw * 952; // 1e6 * 3.9 / 4095
|
||||||
|
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
||||||
|
return raw * 244; // 1e6 * 1.0 / 4095
|
||||||
|
}
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
|
||||||
|
switch (this->attenuation_) {
|
||||||
|
case ADC_ATTEN_DB_0:
|
||||||
|
return raw * 205; // 1e6 * 0.84 / 4095
|
||||||
|
case ADC_ATTEN_DB_2_5:
|
||||||
|
return raw * 276; // 1e6 * 1.13 / 4095
|
||||||
|
case ADC_ATTEN_DB_6:
|
||||||
|
return raw * 381; // 1e6 * 1.56 / 4095
|
||||||
|
case ADC_ATTEN_DB_11:
|
||||||
|
return raw * 733; // 1e6 * 3.0 / 4095
|
||||||
|
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
||||||
|
return raw * 244; // 1e6 * 1.0 / 4095
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ESP8266
|
||||||
|
return raw * 977; // 1e6 / 1024
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
float ADCSensor::sample() {
|
||||||
|
int raw = this->read_raw_();
|
||||||
|
uint32_t v = this->raw_to_microvolts_(raw);
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
if (autorange_) {
|
||||||
|
int raw11 = raw, raw6 = 4095, raw2 = 4095, raw0 = 4095;
|
||||||
|
uint32_t v11 = v, v6 = 0, v2 = 0, v0 = 0;
|
||||||
|
if (raw11 < 4095) { // Progressively read all attenuation ranges
|
||||||
|
adc1_config_channel_atten(gpio_to_adc1(pin_->get_pin()), ADC_ATTEN_DB_6);
|
||||||
|
raw6 = this->read_raw_();
|
||||||
|
v6 = this->raw_to_microvolts_(raw6);
|
||||||
|
if (raw6 < 4095) {
|
||||||
|
adc1_config_channel_atten(gpio_to_adc1(pin_->get_pin()), ADC_ATTEN_DB_2_5);
|
||||||
|
raw2 = this->read_raw_();
|
||||||
|
v2 = this->raw_to_microvolts_(raw2);
|
||||||
|
if (raw2 < 4095) {
|
||||||
|
adc1_config_channel_atten(gpio_to_adc1(pin_->get_pin()), ADC_ATTEN_DB_0);
|
||||||
|
raw0 = this->read_raw_();
|
||||||
|
v0 = this->raw_to_microvolts_(raw0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adc1_config_channel_atten(gpio_to_adc1(pin_->get_pin()), ADC_ATTEN_DB_11);
|
||||||
|
} // Contribution coefficients (normalized to 2048)
|
||||||
|
uint16_t c11 = clamp(raw11, 0, 2048); // high 1, middle 1, low 0
|
||||||
|
uint16_t c6 = (2048 - abs(raw6 - 2048)); // high 0, middle 1, low 0
|
||||||
|
uint16_t c2 = (2048 - abs(raw2 - 2048)); // high 0, middle 1, low 0
|
||||||
|
uint16_t c0 = clamp(4095 - raw0, 0, 2048); // high 0, middle 1, low 1
|
||||||
|
uint32_t csum = c11 + c6 + c2 + c0; // sum to normalize the final result
|
||||||
|
if (csum > 0)
|
||||||
|
v = (v11 * c11) + (v6 * c6) + (v2 * c2) + (v0 * c0);
|
||||||
|
else // in case of error, this keeps the 11db output (v)
|
||||||
|
csum = 1;
|
||||||
|
csum *= 1e6; // include the 1e6 microvolts->volts conversion factor
|
||||||
|
return (float) v / (float) csum; // normalize, convert & return
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return v / (float) 1e6; // convert from microvolts to volts
|
||||||
|
}
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,6 +18,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
/// Set the attenuation for this pin. Only available on the ESP32.
|
/// Set the attenuation for this pin. Only available on the ESP32.
|
||||||
void set_attenuation(adc_atten_t attenuation);
|
void set_attenuation(adc_atten_t attenuation);
|
||||||
|
void set_autorange(bool autorange);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Update adc values.
|
/// Update adc values.
|
||||||
|
@ -36,9 +37,12 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InternalGPIOPin *pin_;
|
InternalGPIOPin *pin_;
|
||||||
|
uint16_t read_raw_();
|
||||||
|
uint32_t raw_to_microvolts_(uint16_t raw);
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
||||||
|
bool autorange_{false};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ ATTENUATION_MODES = {
|
||||||
"2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
|
"2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
|
||||||
"6db": cg.global_ns.ADC_ATTEN_DB_6,
|
"6db": cg.global_ns.ADC_ATTEN_DB_6,
|
||||||
"11db": cg.global_ns.ADC_ATTEN_DB_11,
|
"11db": cg.global_ns.ADC_ATTEN_DB_11,
|
||||||
|
"auto": "auto",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,4 +93,7 @@ async def to_code(config):
|
||||||
cg.add(var.set_pin(pin))
|
cg.add(var.set_pin(pin))
|
||||||
|
|
||||||
if CONF_ATTENUATION in config:
|
if CONF_ATTENUATION in config:
|
||||||
|
if config[CONF_ATTENUATION] == "auto":
|
||||||
|
cg.add(var.set_autorange(cg.global_ns.true))
|
||||||
|
else:
|
||||||
cg.add(var.set_attenuation(config[CONF_ATTENUATION]))
|
cg.add(var.set_attenuation(config[CONF_ATTENUATION]))
|
||||||
|
|
Loading…
Reference in a new issue