ESPHome 2026.9.0-dev
Loading...
Searching...
No Matches
adc_sensor_rp2.cpp
Go to the documentation of this file.
1#ifdef USE_RP2
2
3#include "adc_sensor.h"
4#include "esphome/core/log.h"
5
6#ifdef CYW43_USES_VSYS_PIN
7#include "pico/cyw43_arch.h"
8#endif // CYW43_USES_VSYS_PIN
9#include <hardware/adc.h>
10
11// PICO_VSYS_PIN is defined in pico-sdk board headers (e.g. boards/pico2.h),
12// but the Arduino framework's config_autogen.h includes a generic board header
13// that doesn't define it. Provide the standard value (pin 29) as a fallback.
14#ifndef PICO_VSYS_PIN
15#define PICO_VSYS_PIN 29 // NOLINT(cppcoreguidelines-macro-usage)
16#endif
17
18namespace esphome::adc {
19
20static const char *const TAG = "adc";
21
22// The on-die temperature sensor sits on the last ADC channel: input 4 on RP2040
23// and RP2350A, but input 8 on RP2350B, which has eight external channels rather
24// than four.
25//
26// This deliberately does not use the SDK's ADC_TEMPERATURE_CHANNEL_NUM. That
27// derives from NUM_ADC_CHANNELS, which <pico.h> settles from a board header, and
28// arduino-pico supplies a fixed B-die one for every RP2350 build. The real die
29// is only declared later, by the variant's pins_arduino.h, so the SDK constant
30// reads 8 on A-die boards. PICO_RP2350A itself is correct by the time this file
31// is compiled, on both arduino-pico and pico-sdk builds.
32#if defined(PICO_RP2350) && !defined(PICO_RP2350A)
33#error "PICO_RP2350A is not defined, so the RP2350 die is unknown and the temperature ADC channel cannot be chosen"
34#endif
35#if defined(PICO_RP2350) && !PICO_RP2350A
36static constexpr uint8_t TEMPERATURE_ADC_INPUT = 8;
37#else
38static constexpr uint8_t TEMPERATURE_ADC_INPUT = 4;
39#endif
40
41void ADCSensor::setup() {
42 static bool initialized = false;
43 if (!initialized) {
44 adc_init();
45 initialized = true;
46 }
47}
48
50 LOG_SENSOR("", "ADC Sensor", this);
51 if (this->is_temperature_) {
52 ESP_LOGCONFIG(TAG, " Pin: Temperature");
53 } else {
54#ifdef USE_ADC_SENSOR_VCC
55 ESP_LOGCONFIG(TAG, " Pin: VCC");
56#else
57 LOG_PIN(" Pin: ", this->pin_);
58#endif // USE_ADC_SENSOR_VCC
59 }
60 ESP_LOGCONFIG(TAG,
61 " Samples: %i\n"
62 " Sampling mode: %s",
63 this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
64 LOG_UPDATE_INTERVAL(this);
65}
66
67float ADCSensor::sample() {
68 uint32_t raw = 0;
69 auto aggr = Aggregator<uint32_t>(this->sampling_mode_);
70
71 if (this->is_temperature_) {
72 adc_set_temp_sensor_enabled(true);
73 delay(1);
74 adc_select_input(TEMPERATURE_ADC_INPUT);
75
76 for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
77 raw = adc_read();
78 aggr.add_sample(raw);
79 }
80 adc_set_temp_sensor_enabled(false);
81 if (this->output_raw_) {
82 return aggr.aggregate();
83 }
84 return aggr.aggregate() * 3.3f / 4096.0f;
85 }
86
87 uint8_t pin = this->pin_->get_pin();
88#if defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
89 if (pin == PICO_VSYS_PIN) {
90 // Measuring VSYS on Raspberry Pico W needs to be wrapped with
91 // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
92 // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
93 // VSYS ADC both share GPIO29.
94 // The USE_WIFI guard is required because CYW43_USES_VSYS_PIN can be defined
95 // transitively (e.g. via lwip_wrap.h) even on non-WiFi boards where the CYW43
96 // driver is never initialized; calling cyw43_thread_enter() there hard-faults.
97 cyw43_thread_enter();
98 }
99#endif // defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
100
101 adc_gpio_init(pin);
102 adc_select_input(pin - 26);
103
104 for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
105 raw = adc_read();
106 aggr.add_sample(raw);
107 }
108
109#if defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
110 if (pin == PICO_VSYS_PIN) {
111 cyw43_thread_exit();
112 }
113#endif // defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
114
115 if (this->output_raw_) {
116 return aggr.aggregate();
117 }
118 float coeff = pin == PICO_VSYS_PIN ? 3.0f : 1.0f;
119 return aggr.aggregate() * 3.3f / 4096.0f * coeff;
120}
121
122} // namespace esphome::adc
123
124#endif // USE_RP2
uint8_t raw[35]
Definition bl0939.h:0
virtual uint8_t get_pin() const =0
float sample() override
Perform a single ADC sampling operation and return the measured value.
void setup() override
Set up the ADC sensor by initializing hardware and calibration parameters.
InternalGPIOPin * pin_
Definition adc_sensor.h:133
void dump_config() override
Output the configuration details of the ADC sensor for debugging purposes.
SamplingMode sampling_mode_
Definition adc_sensor.h:134
const LogString * sampling_mode_to_str(SamplingMode mode)
void HOT delay(uint32_t ms)
Definition hal.cpp:85
static void uint32_t