mirror of
https://github.com/esphome/esphome.git
synced 2025-09-02 03:12:20 +01:00
208 lines
5.7 KiB
C++
208 lines
5.7 KiB
C++
|
|
#include "adc_sensor.h"
|
|
#ifdef USE_ZEPHYR
|
|
#include "esphome/core/log.h"
|
|
|
|
#include "hal/nrf_saadc.h"
|
|
|
|
namespace esphome {
|
|
namespace adc {
|
|
|
|
static const char *const TAG = "adc.zephyr";
|
|
|
|
void ADCSensor::setup() {
|
|
if (!adc_is_ready_dt(this->channel_)) {
|
|
ESP_LOGE(TAG, "ADC controller device %s not ready", this->channel_->dev->name);
|
|
return;
|
|
}
|
|
|
|
auto err = adc_channel_setup_dt(this->channel_);
|
|
if (err < 0) {
|
|
ESP_LOGE(TAG, "Could not setup channel %s (%d)", this->channel_->dev->name, err);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
|
static const LogString *gain_to_str(enum adc_gain gain) {
|
|
switch (gain) {
|
|
case ADC_GAIN_1_6:
|
|
return LOG_STR("1/6");
|
|
case ADC_GAIN_1_5:
|
|
return LOG_STR("1/5");
|
|
case ADC_GAIN_1_4:
|
|
return LOG_STR("1/4");
|
|
case ADC_GAIN_1_3:
|
|
return LOG_STR("1/3");
|
|
case ADC_GAIN_2_5:
|
|
return LOG_STR("2/5");
|
|
case ADC_GAIN_1_2:
|
|
return LOG_STR("1/2");
|
|
case ADC_GAIN_2_3:
|
|
return LOG_STR("2/3");
|
|
case ADC_GAIN_4_5:
|
|
return LOG_STR("4/5");
|
|
case ADC_GAIN_1:
|
|
return LOG_STR("1");
|
|
case ADC_GAIN_2:
|
|
return LOG_STR("2");
|
|
case ADC_GAIN_3:
|
|
return LOG_STR("3");
|
|
case ADC_GAIN_4:
|
|
return LOG_STR("4");
|
|
case ADC_GAIN_6:
|
|
return LOG_STR("6");
|
|
case ADC_GAIN_8:
|
|
return LOG_STR("8");
|
|
case ADC_GAIN_12:
|
|
return LOG_STR("12");
|
|
case ADC_GAIN_16:
|
|
return LOG_STR("16");
|
|
case ADC_GAIN_24:
|
|
return LOG_STR("24");
|
|
case ADC_GAIN_32:
|
|
return LOG_STR("32");
|
|
case ADC_GAIN_64:
|
|
return LOG_STR("64");
|
|
case ADC_GAIN_128:
|
|
return LOG_STR("128");
|
|
}
|
|
return LOG_STR("undefined gain");
|
|
}
|
|
|
|
static const LogString *reference_to_str(enum adc_reference reference) {
|
|
switch (reference) {
|
|
case ADC_REF_VDD_1:
|
|
return LOG_STR("VDD");
|
|
case ADC_REF_VDD_1_2:
|
|
return LOG_STR("VDD/2");
|
|
case ADC_REF_VDD_1_3:
|
|
return LOG_STR("VDD/3");
|
|
case ADC_REF_VDD_1_4:
|
|
return LOG_STR("VDD/4");
|
|
case ADC_REF_INTERNAL:
|
|
return LOG_STR("INTERNAL");
|
|
case ADC_REF_EXTERNAL0:
|
|
return LOG_STR("External, input 0");
|
|
case ADC_REF_EXTERNAL1:
|
|
return LOG_STR("External, input 1");
|
|
}
|
|
return LOG_STR("undefined reference");
|
|
}
|
|
|
|
static const LogString *input_to_str(uint8_t input) {
|
|
switch (input) {
|
|
case NRF_SAADC_INPUT_AIN0:
|
|
return LOG_STR("AIN0");
|
|
case NRF_SAADC_INPUT_AIN1:
|
|
return LOG_STR("AIN1");
|
|
case NRF_SAADC_INPUT_AIN2:
|
|
return LOG_STR("AIN2");
|
|
case NRF_SAADC_INPUT_AIN3:
|
|
return LOG_STR("AIN3");
|
|
case NRF_SAADC_INPUT_AIN4:
|
|
return LOG_STR("AIN4");
|
|
case NRF_SAADC_INPUT_AIN5:
|
|
return LOG_STR("AIN5");
|
|
case NRF_SAADC_INPUT_AIN6:
|
|
return LOG_STR("AIN6");
|
|
case NRF_SAADC_INPUT_AIN7:
|
|
return LOG_STR("AIN7");
|
|
case NRF_SAADC_INPUT_VDD:
|
|
return LOG_STR("VDD");
|
|
case NRF_SAADC_INPUT_VDDHDIV5:
|
|
return LOG_STR("VDDHDIV5");
|
|
}
|
|
return LOG_STR("undefined input");
|
|
}
|
|
#endif // ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
|
|
|
void ADCSensor::dump_config() {
|
|
LOG_SENSOR("", "ADC Sensor", this);
|
|
LOG_PIN(" Pin: ", this->pin_);
|
|
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
|
ESP_LOGV(TAG,
|
|
" Name: %s\n"
|
|
" Channel: %d\n"
|
|
" vref_mv: %d\n"
|
|
" Resolution %d\n"
|
|
" Oversampling %d",
|
|
this->channel_->dev->name, this->channel_->channel_id, this->channel_->vref_mv, this->channel_->resolution,
|
|
this->channel_->oversampling);
|
|
|
|
ESP_LOGV(TAG,
|
|
" Gain: %s\n"
|
|
" reference: %s\n"
|
|
" acquisition_time: %d\n"
|
|
" differential %s",
|
|
LOG_STR_ARG(gain_to_str(this->channel_->channel_cfg.gain)),
|
|
LOG_STR_ARG(reference_to_str(this->channel_->channel_cfg.reference)),
|
|
this->channel_->channel_cfg.acquisition_time, YESNO(this->channel_->channel_cfg.differential));
|
|
if (this->channel_->channel_cfg.differential) {
|
|
ESP_LOGV(TAG,
|
|
" Positive: %s\n"
|
|
" Negative: %s",
|
|
LOG_STR_ARG(input_to_str(this->channel_->channel_cfg.input_positive)),
|
|
LOG_STR_ARG(input_to_str(this->channel_->channel_cfg.input_negative)));
|
|
} else {
|
|
ESP_LOGV(TAG, " Positive: %s", LOG_STR_ARG(input_to_str(this->channel_->channel_cfg.input_positive)));
|
|
}
|
|
#endif
|
|
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
float ADCSensor::sample() {
|
|
auto aggr = Aggregator<int32_t>(this->sampling_mode_);
|
|
int err;
|
|
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
|
int16_t buf = 0;
|
|
struct adc_sequence sequence = {
|
|
.buffer = &buf,
|
|
/* buffer size in bytes, not number of samples */
|
|
.buffer_size = sizeof(buf),
|
|
};
|
|
int32_t val_raw;
|
|
|
|
err = adc_sequence_init_dt(this->channel_, &sequence);
|
|
if (err < 0) {
|
|
ESP_LOGE(TAG, "Could sequence init %s (%d)", this->channel_->dev->name, err);
|
|
return 0.0;
|
|
}
|
|
|
|
err = adc_read(this->channel_->dev, &sequence);
|
|
if (err < 0) {
|
|
ESP_LOGE(TAG, "Could not read %s (%d)", this->channel_->dev->name, err);
|
|
return 0.0;
|
|
}
|
|
|
|
val_raw = (int32_t) buf;
|
|
if (!this->channel_->channel_cfg.differential) {
|
|
// https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/0ed4d9ffc674ae407be7cacf5696a02f5e789861/cores/nRF5/wiring_analog_nRF52.c#L222
|
|
if (val_raw < 0) {
|
|
val_raw = 0;
|
|
}
|
|
}
|
|
aggr.add_sample(val_raw);
|
|
}
|
|
|
|
int32_t val_mv = aggr.aggregate();
|
|
|
|
if (this->output_raw_) {
|
|
return val_mv;
|
|
}
|
|
|
|
err = adc_raw_to_millivolts_dt(this->channel_, &val_mv);
|
|
/* conversion to mV may not be supported, skip if not */
|
|
if (err < 0) {
|
|
ESP_LOGE(TAG, "Value in mV not available %s (%d)", this->channel_->dev->name, err);
|
|
return 0.0;
|
|
}
|
|
|
|
return val_mv / 1000.0f;
|
|
}
|
|
|
|
} // namespace adc
|
|
} // namespace esphome
|
|
#endif
|