diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 2d6b87c51a..18464940f2 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -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; } diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index 0e58a6e423..7498d72902 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -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}; diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index df47731d69..1008706a8c 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -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 = ; - zephyr,input-positive = ; /* P0.03 */ - zephyr,resolution = <12>; - }; - - channel@1 { - reg = <1>; - zephyr,gain = "ADC_GAIN_1_6"; - zephyr,reference = "ADC_REF_INTERNAL"; - zephyr,acquisition-time = ; - zephyr,input-positive = ; + zephyr,input-positive = ; 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 = ; - zephyr,input-positive = ; /* P0.30 */ - zephyr,input-negative = ; /* P0.31 */ - zephyr,resolution = <12>; - }; -}; + }}; +}}; """ ) else: diff --git a/esphome/components/nrf52/gpio.py b/esphome/components/nrf52/gpio.py index 0271972f92..5b31d63b57 100644 --- a/esphome/components/nrf52/gpio.py +++ b/esphome/components/nrf52/gpio.py @@ -46,7 +46,7 @@ ADC_INPUTS = [ "AIN6", "AIN7", "VDD", - "VDDH", + "VDDHDIV5", ] diff --git a/esphome/components/zephyr_ble_nus/ble_nus.h b/esphome/components/zephyr_ble_nus/ble_nus.h index b08c3d102e..b980c36d1b 100644 --- a/esphome/components/zephyr_ble_nus/ble_nus.h +++ b/esphome/components/zephyr_ble_nus/ble_nus.h @@ -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; diff --git a/tests/components/adc/test.nrf52-adafruit.yaml b/tests/components/adc/test.nrf52-adafruit.yaml new file mode 100644 index 0000000000..4a83d173d5 --- /dev/null +++ b/tests/components/adc/test.nrf52-adafruit.yaml @@ -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 diff --git a/tests/components/adc/test.nrf52.yaml b/tests/components/adc/test.nrf52.yaml new file mode 100644 index 0000000000..4a83d173d5 --- /dev/null +++ b/tests/components/adc/test.nrf52.yaml @@ -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 diff --git a/tests/components/uptime/test.nrf52-adafruit.yaml b/tests/components/uptime/test.nrf52-adafruit.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/uptime/test.nrf52-adafruit.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/uptime/test.nrf52.yaml b/tests/components/uptime/test.nrf52.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/uptime/test.nrf52.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/test12.2.yaml b/tests/test12.2.yaml index f2bb074fdc..cb4dbe3b0e 100644 --- a/tests/test12.2.yaml +++ b/tests/test12.2.yaml @@ -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" diff --git a/tests/test12.3.yaml b/tests/test12.3.yaml index fb26628820..9cc5b6997b 100644 --- a/tests/test12.3.yaml +++ b/tests/test12.3.yaml @@ -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