add test for adc

This commit is contained in:
Tomasz Duda 2024-05-12 13:37:32 +02:00
parent df35ceea7b
commit de236e7ea1
11 changed files with 208 additions and 54 deletions

View File

@ -19,7 +19,7 @@ ADC_MODE(ADC_VCC)
#endif
#ifdef USE_ZEPHYR
static const struct adc_dt_spec adc_chan = ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 1);
#include "hal/nrf_saadc.h"
#endif
namespace esphome {
@ -95,15 +95,14 @@ extern "C"
#endif
#ifdef USE_ZEPHYR
adc_chan_ = &adc_chan;
if (!adc_is_ready_dt(adc_chan_)) {
ESP_LOGE(TAG, "ADC controller device %s not ready", adc_chan_->dev->name);
if (!adc_is_ready_dt(adc_channel_)) {
ESP_LOGE(TAG, "ADC controller device %s not ready", adc_channel_->dev->name);
return;
}
auto err = adc_channel_setup_dt(adc_chan_);
auto err = adc_channel_setup_dt(adc_channel_);
if (err < 0) {
ESP_LOGE(TAG, "Could not setup channel %s (%d)", adc_chan_->dev->name, err);
ESP_LOGE(TAG, "Could not setup channel %s (%d)", adc_channel_->dev->name, err);
return;
}
#endif
@ -158,8 +157,110 @@ void ADCSensor::dump_config() {
#endif // USE_RP2040
#ifdef USE_ZEPHYR
ESP_LOGCONFIG(TAG, " Name: %s, channel_id: %d, vref_mv: %d, resolution %d, oversampling %d", adc_chan_->dev->name,
adc_chan_->channel_id, adc_chan_->vref_mv, adc_chan_->resolution, adc_chan_->oversampling);
ESP_LOGCONFIG(TAG, " Name: %s, channel_id: %d, vref_mv: %d, resolution %d, oversampling %d", adc_channel_->dev->name,
adc_channel_->channel_id, adc_channel_->vref_mv, adc_channel_->resolution, adc_channel_->oversampling);
auto gain = [](enum adc_gain gain) {
switch (gain) {
case ADC_GAIN_1_6: /**< x 1/6. */
return "1/6";
case ADC_GAIN_1_5: /**< x 1/5. */
return "1/5";
case ADC_GAIN_1_4: /**< x 1/4. */
return "1/4";
case ADC_GAIN_1_3: /**< x 1/3. */
return "1/3";
case ADC_GAIN_2_5: /**< x 2/5. */
return "2/5";
case ADC_GAIN_1_2: /**< x 1/2. */
return "1/2";
case ADC_GAIN_2_3: /**< x 2/3. */
return "2/3";
case ADC_GAIN_4_5: /**< x 4/5. */
return "4/5";
case ADC_GAIN_1: /**< x 1. */
return "1";
case ADC_GAIN_2: /**< x 2. */
return "2";
case ADC_GAIN_3: /**< x 3. */
return "3";
case ADC_GAIN_4: /**< x 4. */
return "4";
case ADC_GAIN_6: /**< x 6. */
return "6";
case ADC_GAIN_8: /**< x 8. */
return "8";
case ADC_GAIN_12: /**< x 12. */
return "12";
case ADC_GAIN_16: /**< x 16. */
return "16";
case ADC_GAIN_24: /**< x 24. */
return "24";
case ADC_GAIN_32: /**< x 32. */
return "32";
case ADC_GAIN_64: /**< x 64. */
return "64";
case ADC_GAIN_128: /**< x 128. */
return "128";
}
return "undefined";
};
auto reference = [](enum adc_reference reference) {
switch (reference) {
case ADC_REF_VDD_1:
return "VDD";
case ADC_REF_VDD_1_2:
return "VDD/2";
case ADC_REF_VDD_1_3:
return "VDD/2";
case ADC_REF_VDD_1_4:
return "VDD/4";
case ADC_REF_INTERNAL:
return "INTERNAL";
case ADC_REF_EXTERNAL0:
return "External, input 0";
case ADC_REF_EXTERNAL1:
return "External, input 1";
}
return "undefined";
};
auto input = [](uint8_t input) {
switch (input) {
case NRF_SAADC_INPUT_AIN0:
return "AIN0";
case NRF_SAADC_INPUT_AIN1:
return "AIN1";
case NRF_SAADC_INPUT_AIN2:
return "AIN2";
case NRF_SAADC_INPUT_AIN3:
return "AIN3";
case NRF_SAADC_INPUT_AIN4:
return "AIN4";
case NRF_SAADC_INPUT_AIN5:
return "AIN5";
case NRF_SAADC_INPUT_AIN6:
return "AIN6";
case NRF_SAADC_INPUT_AIN7:
return "AIN7";
case NRF_SAADC_INPUT_VDD:
return "VDD";
case NRF_SAADC_INPUT_VDDHDIV5:
return "VDDHDIV5";
}
return "undefined";
};
ESP_LOGCONFIG(TAG, " Gain: %s, reference: %s, acquisition_time: %d, differential %s",
gain(adc_channel_->channel_cfg.gain), reference(adc_channel_->channel_cfg.reference),
adc_channel_->channel_cfg.acquisition_time, YESNO(adc_channel_->channel_cfg.differential));
if (adc_channel_->channel_cfg.differential) {
ESP_LOGCONFIG(TAG, " Input positive: %s, negative: %s", input(adc_channel_->channel_cfg.input_positive),
input(adc_channel_->channel_cfg.input_negative));
} else {
ESP_LOGCONFIG(TAG, " Input positive: %s", input(adc_channel_->channel_cfg.input_positive));
}
#endif
LOG_UPDATE_INTERVAL(this);
@ -331,11 +432,11 @@ float ADCSensor::sample() {
};
int32_t val_mv;
adc_sequence_init_dt(adc_chan_, &sequence);
adc_sequence_init_dt(adc_channel_, &sequence);
auto err = adc_read(adc_chan_->dev, &sequence);
auto err = adc_read(adc_channel_->dev, &sequence);
if (err < 0) {
ESP_LOGE(TAG, "Could not read %s (%d)", adc_chan_->dev->name, err);
ESP_LOGE(TAG, "Could not read %s (%d)", adc_channel_->dev->name, err);
return 0.0;
}
@ -344,7 +445,7 @@ float ADCSensor::sample() {
* in the ADC sample buffer should be a signed 2's
* complement value.
*/
if (adc_chan_->channel_cfg.differential) {
if (adc_channel_->channel_cfg.differential) {
val_mv = (int32_t) ((int16_t) buf);
} else {
val_mv = (int32_t) buf;
@ -354,10 +455,10 @@ float ADCSensor::sample() {
return val_mv;
}
err = adc_raw_to_millivolts_dt(adc_chan_, &val_mv);
err = adc_raw_to_millivolts_dt(adc_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)", adc_chan_->dev->name, err);
ESP_LOGE(TAG, "Value in mV not available %s (%d)", adc_channel_->dev->name, err);
return 0.0;
}

View File

@ -42,6 +42,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
float get_setup_priority() const override;
#ifndef USE_ZEPHYR
void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
#else
void set_adc_channel(const adc_dt_spec *adc_channel) { this->adc_channel_ = adc_channel; }
#endif
void set_output_raw(bool output_raw) { output_raw_ = output_raw; }
float sample() override;
@ -58,7 +60,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
#ifndef USE_ZEPHYR
InternalGPIOPin *pin_;
#else
const struct adc_dt_spec *adc_chan_;
const struct adc_dt_spec *adc_channel_ = nullptr;
#endif
bool output_raw_{false};

View File

@ -1,3 +1,4 @@
from esphome.cpp_generator import MockObj
import esphome.codegen as cg
import esphome.config_validation as cv
import esphome.final_validate as fv
@ -56,6 +57,10 @@ ADCSensor = adc_ns.class_(
"ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
)
CONF_NRF_SAADC = "nrf_saadc"
adc_dt_spec = cg.global_ns.class_("adc_dt_spec").operator("const")
CONFIG_SCHEMA = cv.All(
sensor.sensor_schema(
ADCSensor,
@ -71,6 +76,9 @@ CONFIG_SCHEMA = cv.All(
cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
cv.only_on_esp32, cv.enum(ATTENUATION_MODES, lower=True)
),
cv.GenerateID(CONF_NRF_SAADC): cv.All(
cv.only_on_nrf52, cv.declare_id(adc_dt_spec)
),
}
)
.extend(cv.polling_component_schema("60s")),
@ -91,48 +99,36 @@ async def to_code(config):
cg.add(var.set_is_temperature())
elif CORE.using_zephyr:
zephyr_add_prj_conf("ADC", True)
nrf_saadc = config[CONF_NRF_SAADC]
channel_id = int(str(nrf_saadc)[str(nrf_saadc).find("_id") + 4 :] or "1") - 1
rhs = MockObj(f"ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), {channel_id})")
adc = cg.new_Pvariable(nrf_saadc, rhs)
cg.add(var.set_adc_channel(adc))
gain = "ADC_GAIN_1_6"
zephyr_add_overlay(
"""
/ {
zephyr,user {
io-channels = <&adc 0>, <&adc 1>, <&adc 7>;
io-channels = <&adc 0>, <&adc 1>, <&adc 2>;
};
};
&adc {
};"""
)
zephyr_add_overlay(
f"""
&adc {{
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
zephyr,gain = "ADC_GAIN_1_6";
channel@{channel_id} {{
reg = <{channel_id}>;
zephyr,gain = "{gain}";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,input-positive = <NRF_SAADC_AIN1>; /* P0.03 */
zephyr,resolution = <12>;
};
channel@1 {
reg = <1>;
zephyr,gain = "ADC_GAIN_1_6";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,input-positive = <NRF_SAADC_VDD>;
zephyr,input-positive = <NRF_SAADC_{config[CONF_PIN][CONF_NUMBER]}>;
zephyr,resolution = <14>;
zephyr,oversampling = <8>;
};
channel@7 {
reg = <7>;
zephyr,gain = "ADC_GAIN_1_5";
zephyr,reference = "ADC_REF_VDD_1_4";
zephyr,vref-mv = <750>;
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,input-positive = <NRF_SAADC_AIN6>; /* P0.30 */
zephyr,input-negative = <NRF_SAADC_AIN7>; /* P0.31 */
zephyr,resolution = <12>;
};
};
}};
}};
"""
)
else:

View File

@ -46,7 +46,7 @@ ADC_INPUTS = [
"AIN6",
"AIN7",
"VDD",
"VDDH",
"VDDHDIV5",
]

View File

@ -16,7 +16,7 @@ class BLENUS : public Component {
};
public:
BLENUS(size_t buffer_size = 1024);
BLENUS(size_t buffer_size = 2048);
void setup() override;
void dump_config() override;
void loop() override;

View File

@ -0,0 +1,18 @@
sensor:
- platform: uptime
name: Uptime Sensor
update_interval: 5sec
- platform: adc
pin: VDDHDIV5
name: "VDDH Voltage"
update_interval: 5sec
filters:
- multiply: 5
- platform: adc
pin: VDD
name: "VDD Voltage"
update_interval: 5sec
- platform: adc
pin: AIN0
name: "AIN0 Voltage"
update_interval: 5sec

View File

@ -0,0 +1,18 @@
sensor:
- platform: uptime
name: Uptime Sensor
update_interval: 5sec
- platform: adc
pin: VDDHDIV5
name: "VDDH Voltage"
update_interval: 5sec
filters:
- multiply: 5
- platform: adc
pin: VDD
name: "VDD Voltage"
update_interval: 5sec
- platform: adc
pin: AIN0
name: "AIN0 Voltage"
update_interval: 5sec

View File

@ -0,0 +1 @@
<<: !include common.yaml

View File

@ -0,0 +1 @@
<<: !include common.yaml

View File

@ -80,10 +80,15 @@ zephyr_debug:
debug:
sensor:
- platform: uptime
name: Uptime Sensor
update_interval: 5sec
- platform: adc
pin: VDDH
pin: VDDHDIV5
name: "VDDH Voltage"
update_interval: 5sec
filters:
- multiply: 5
- platform: adc
pin: VDD
name: "VDD Voltage"

View File

@ -45,9 +45,21 @@ zephyr_debug:
debug:
text_sensor:
- platform: debug
device:
name: "Device Info"
reset_reason:
name: "Reset Reason"
sensor:
- platform: uptime
name: Uptime Sensor
update_interval: 5sec
- platform: adc
pin: VDDHDIV5
name: "VDDH Voltage"
update_interval: 5sec
filters:
- multiply: 5
- platform: adc
pin: VDD
name: "VDD Voltage"
update_interval: 5sec
- platform: adc
pin: AIN0
name: "AIN0 Voltage"
update_interval: 5sec