[ADC] Support measuring VCC on Raspberry Pico (W) (#5335)

* [ADC] Support measuring VCC on Raspberry Pico (W)

Added support for measuring VCC on Raspberry Pico (W) with ADC.
GPIO pin is provided as `VCC`, same as with ESP8266. VSYS is the voltage
being actually processed, and might have an offset from actual power
supply voltage (e.g. USB on VBUS) due to voltage drop on
Schottky diode between VSYS and VBUS on Rasberry Pico. The offset has
experimentally been found to be ~0.25V on Pico W and ~0.1 on Pico,
presumably due to different power consumption.

Example usage:

	sensor:
	  - platform: adc
	    pin: VCC
	    name: "VSYS"

* + Added tests for VCC measuring on `rpipicow` board
This commit is contained in:
Ilia Sotnikov 2023-09-09 12:00:45 +03:00 committed by GitHub
parent ccc30116ba
commit 7bb67ae94b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 4 deletions

View file

@ -5,6 +5,10 @@ from esphome.const import CONF_ANALOG, CONF_INPUT
from esphome.core import CORE from esphome.core import CORE
from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32 import get_esp32_variant
from esphome.const import (
PLATFORM_ESP8266,
PLATFORM_RP2040,
)
from esphome.components.esp32.const import ( from esphome.components.esp32.const import (
VARIANT_ESP32, VARIANT_ESP32,
VARIANT_ESP32C2, VARIANT_ESP32C2,
@ -143,7 +147,7 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
def validate_adc_pin(value): def validate_adc_pin(value):
if str(value).upper() == "VCC": if str(value).upper() == "VCC":
return cv.only_on_esp8266("VCC") return cv.only_on([PLATFORM_ESP8266, PLATFORM_RP2040])("VCC")
if str(value).upper() == "TEMPERATURE": if str(value).upper() == "TEMPERATURE":
return cv.only_on_rp2040("TEMPERATURE") return cv.only_on_rp2040("TEMPERATURE")

View file

@ -12,6 +12,9 @@ ADC_MODE(ADC_VCC)
#endif #endif
#ifdef USE_RP2040 #ifdef USE_RP2040
#ifdef CYW43_USES_VSYS_PIN
#include "pico/cyw43_arch.h"
#endif
#include <hardware/adc.h> #include <hardware/adc.h>
#endif #endif
@ -123,13 +126,19 @@ void ADCSensor::dump_config() {
} }
} }
#endif // USE_ESP32 #endif // USE_ESP32
#ifdef USE_RP2040 #ifdef USE_RP2040
if (this->is_temperature_) { if (this->is_temperature_) {
ESP_LOGCONFIG(TAG, " Pin: Temperature"); ESP_LOGCONFIG(TAG, " Pin: Temperature");
} else { } else {
#ifdef USE_ADC_SENSOR_VCC
ESP_LOGCONFIG(TAG, " Pin: VCC");
#else
LOG_PIN(" Pin: ", pin_); LOG_PIN(" Pin: ", pin_);
#endif // USE_ADC_SENSOR_VCC
} }
#endif #endif // USE_RP2040
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }
@ -238,7 +247,20 @@ float ADCSensor::sample() {
delay(1); delay(1);
adc_select_input(4); adc_select_input(4);
} else { } else {
uint8_t pin = this->pin_->get_pin(); uint8_t pin;
#ifdef USE_ADC_SENSOR_VCC
#ifdef CYW43_USES_VSYS_PIN
// Measuring VSYS on Raspberry Pico W needs to be wrapped with
// `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
// https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
// VSYS ADC both share GPIO29
cyw43_thread_enter();
#endif // CYW43_USES_VSYS_PIN
pin = PICO_VSYS_PIN;
#else
pin = this->pin_->get_pin();
#endif // USE_ADC_SENSOR_VCC
adc_gpio_init(pin); adc_gpio_init(pin);
adc_select_input(pin - 26); adc_select_input(pin - 26);
} }
@ -246,11 +268,23 @@ float ADCSensor::sample() {
int32_t raw = adc_read(); int32_t raw = adc_read();
if (this->is_temperature_) { if (this->is_temperature_) {
adc_set_temp_sensor_enabled(false); adc_set_temp_sensor_enabled(false);
} else {
#ifdef USE_ADC_SENSOR_VCC
#ifdef CYW43_USES_VSYS_PIN
cyw43_thread_exit();
#endif // CYW43_USES_VSYS_PIN
#endif // USE_ADC_SENSOR_VCC
} }
if (output_raw_) { if (output_raw_) {
return raw; return raw;
} }
return raw * 3.3f / 4096.0f; float coeff = 1.0;
#ifdef USE_ADC_SENSOR_VCC
// As per Raspberry Pico (W) datasheet (section 2.1) the VSYS/3 is measured
coeff = 3.0;
#endif // USE_ADC_SENSOR_VCC
return raw * 3.3f / 4096.0f * coeff;
} }
#endif #endif

View file

@ -62,3 +62,6 @@ switch:
sensor: sensor:
- platform: internal_temperature - platform: internal_temperature
name: Internal Temperature name: Internal Temperature
- platform: adc
pin: VCC
name: VSYS