From 9944ca414e45c52f560349c420212a7cbb875bdb Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 17 Nov 2022 13:51:08 +1300 Subject: [PATCH] Support ADC on RP2040 (#4040) --- esphome/components/adc/adc_sensor.cpp | 51 +++++++++++++++++++++++++-- esphome/components/adc/adc_sensor.h | 8 +++++ esphome/components/adc/sensor.py | 11 ++++++ esphome/config_validation.py | 1 + 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 5a29d86404..1e8d740062 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -11,6 +11,10 @@ ADC_MODE(ADC_VCC) #endif #endif +#ifdef USE_RP2040 +#include +#endif + namespace esphome { namespace adc { @@ -32,9 +36,13 @@ static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 b static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) #endif -void ADCSensor::setup() { +#ifdef USE_RP2040 +extern "C" +#endif + void + ADCSensor::setup() { ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); -#ifndef USE_ADC_SENSOR_VCC +#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040) pin_->setup(); #endif @@ -63,6 +71,16 @@ void ADCSensor::setup() { } #endif // USE_ESP32 + +#ifdef USE_RP2040 + static bool initialized = false; + if (!initialized) { + adc_init(); + initialized = true; + } +#endif + + ESP_LOGCONFIG(TAG, "ADC '%s' setup finished!", this->get_name().c_str()); } void ADCSensor::dump_config() { @@ -98,6 +116,12 @@ void ADCSensor::dump_config() { } } #endif // USE_ESP32 +#ifdef USE_RP2040 + if (this->is_temperature_) + ESP_LOGCONFIG(TAG, " Pin: Temperature"); + else + LOG_PIN(" Pin: ", pin_); +#endif LOG_UPDATE_INTERVAL(this); } @@ -175,6 +199,29 @@ float ADCSensor::sample() { } #endif // USE_ESP32 +#ifdef USE_RP2040 +float ADCSensor::sample() { + if (this->is_temperature_) { + adc_set_temp_sensor_enabled(true); + delay(1); + adc_select_input(4); + } else { + uint8_t pin = this->pin_->get_pin(); + adc_gpio_init(pin); + adc_select_input(pin - 26); + } + + int raw = adc_read(); + if (this->is_temperature_) { + adc_set_temp_sensor_enabled(false); + } + if (output_raw_) { + return raw; + } + return raw * 3.3f / 4096.0f; +} +#endif + #ifdef USE_ESP8266 std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; } #endif diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index 12272a1577..22cddde6f8 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -38,10 +38,18 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage std::string unique_id() override; #endif +#ifdef USE_RP2040 + void set_is_temperature() { is_temperature_ = true; } +#endif + protected: InternalGPIOPin *pin_; bool output_raw_{false}; +#ifdef USE_RP2040 + bool is_temperature_{false}; +#endif + #ifdef USE_ESP32 adc_atten_t attenuation_{ADC_ATTEN_DB_0}; adc1_channel_t channel_{}; diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index 5443b9875a..1a519d7506 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -94,6 +94,9 @@ def validate_adc_pin(value): if str(value).upper() == "VCC": return cv.only_on_esp8266("VCC") + if str(value).upper() == "TEMPERATURE": + return cv.only_on_rp2040("TEMPERATURE") + if CORE.is_esp32: value = pins.internal_gpio_input_pin_number(value) variant = get_esp32_variant() @@ -117,6 +120,12 @@ def validate_adc_pin(value): {CONF_ANALOG: True, CONF_INPUT: True}, internal=True )(value) + if CORE.is_rp2040: + value = pins.internal_gpio_input_pin_number(value) + if value not in (26, 27, 28, 29): + raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.") + return pins.internal_gpio_input_pin_schema(value) + raise NotImplementedError @@ -160,6 +169,8 @@ async def to_code(config): if config[CONF_PIN] == "VCC": cg.add_define("USE_ADC_SENSOR_VCC") + elif config[CONF_PIN] == "TEMPERATURE": + cg.add(var.set_is_temperature()) else: pin = await cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index afc800f3f2..90018b4d56 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -548,6 +548,7 @@ def only_with_framework(frameworks): only_on_esp32 = only_on("esp32") only_on_esp8266 = only_on("esp8266") +only_on_rp2040 = only_on("rp2040") only_with_arduino = only_with_framework("arduino") only_with_esp_idf = only_with_framework("esp-idf")