Skip to content

esp32_adc

ADC1: eight channels of analog input on GPIO 32–39.

ADC2 shares its SAR with the Wi-Fi radio and is unusable whenever the radio is up. An API that hands out ADC2 channels invites a bug that appears the day someone turns on networking and not before, which is the worst kind. This crate does not expose ADC2 at all. If it ever does, it must refuse while the radio is running.

Every reading here is a raw SAR count. The ESP32’s ADC is not linear and its gain and offset vary per chip; Espressif burns per-chip calibration into eFuse for exactly that reason. Converting counts to millivolts without it is off by enough to matter — tens of millivolts, more at the ends of the range.

So this returns counts, and says so in the type. to_millivolts is deliberately absent rather than approximate: a function that returns a number in volts is trusted as volts.

The input range is not 0–3.3 V by default. At 0 dB the ADC saturates around 1.1 V; the wider ranges trade accuracy for headroom. Picking the wrong one gives a reading pinned at full scale, which reads like a shorted input rather than a configuration mistake.

Attenuation Usable input, roughly
0 dB 0–1.1 V
2.5 dB 0–1.5 V
6 dB 0–2.2 V
11 dB 0–3.9 V, clipped by the 3.3 V supply

From esp-idf soc/sens_reg.h, DR_REG_SENS_BASE = 0x3FF48800:

Register Offset Fields
SAR_READ_CTRL 0x00 SAR1_SAMPLE_BIT [17:16], SAR1_DIG_FORCE 27, SAR1_DATA_INV 28
SAR_ATTEN1 0x34 two bits per channel
SAR_MEAS_START1 0x54 EN_PAD_FORCE 31, EN_PAD [30:19], START_FORCE 18, START_SAR 17, DONE_SAR 16 (RO), DATA_SAR [15:0] (RO)
struct Adc1 { /* private fields */ }

ADC1, taken as a whole.

One instance: the channels share a SAR, a sample width and one set of control registers, so two owners would interleave conversions and read each other’s results.

struct PadDebug {
pub pad: u32,
pub enable: u32,
pub out: u32,
pub input: u32,
pub bit: u32,
}

What [Adc1::pad_debug] found. bit is this pad’s position in the three RTC GPIO registers, so a caller can pick its pin out of them.

Implements: Clone, Copy, Debug

enum AdcError {
Timeout,
NoPullOnThisPad,
}

Why a reading or a pad change failed.

Implements: Clone, Copy, Debug, Eq, From, PartialEq, StructuralPartialEq

enum Channel {
Gpio36,
Gpio37,
Gpio38,
Gpio39,
Gpio32,
Gpio33,
Gpio34,
Gpio35,
}

An ADC1 channel, named by the GPIO it reads.

Implements: Clone, Copy, Debug, Eq, PartialEq, StructuralPartialEq

enum Pull {
None,
Up,
Down,
}

What the pad’s own resistor does.

Implements: Clone, Copy, Debug, Eq, PartialEq, StructuralPartialEq