Skip to main content

esp_hal/analog/adc/
esp32.rs

1use core::{
2    marker::PhantomData,
3    sync::atomic::{AtomicBool, Ordering},
4};
5
6use super::{AdcCalScheme, AdcConfig, Attenuation, Error};
7use crate::{
8    peripherals::{ADC1, ADC2, SENS},
9    private,
10};
11
12pub(super) const NUM_ATTENS: usize = 10;
13
14mod calibration;
15pub use self::calibration::*;
16
17// ADC2 cannot be used with `radio` functionality on `esp32`, this global helps us to track it's
18// state to prevent unexpected behaviour
19static ADC2_IN_USE: AtomicBool = AtomicBool::new(false);
20
21#[doc(hidden)]
22/// Tries to "claim" `ADC2` peripheral and sets its status.
23pub fn try_claim_adc2(_: private::Internal) -> Result<(), Error> {
24    if ADC2_IN_USE.fetch_or(true, Ordering::Relaxed) {
25        Err(Error::Adc2InUse)
26    } else {
27        Ok(())
28    }
29}
30
31#[doc(hidden)]
32/// Resets `ADC2` usage status to `Unused`.
33pub fn release_adc2(_: private::Internal) {
34    ADC2_IN_USE.store(false, Ordering::Relaxed);
35}
36
37/// The sampling/readout resolution of the ADC.
38#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40#[allow(clippy::enum_variant_names, reason = "unit of measurement")]
41pub enum Resolution {
42    /// 9-bit resolution
43    _9Bit,
44    /// 10-bit resolution
45    _10Bit,
46    /// 11-bit resolution
47    _11Bit,
48    /// 12-bit resolution
49    #[default]
50    _12Bit,
51}
52
53#[doc(hidden)]
54pub trait RegisterAccess {
55    fn set_resolution(resolution: u8);
56
57    fn set_attenuation(channel: usize, attenuation: u8);
58
59    fn clear_dig_force();
60
61    fn set_start_force();
62
63    fn set_en_pad_force();
64
65    fn set_en_pad(channel: u8);
66
67    fn clear_start_sar();
68
69    fn set_start_sar();
70
71    fn read_done_sar() -> bool;
72
73    fn read_data_sar() -> u16;
74
75    fn instance_number() -> u8;
76}
77
78impl RegisterAccess for ADC1<'_> {
79    fn set_resolution(resolution: u8) {
80        SENS::regs()
81            .sar_start_force()
82            .modify(|_, w| unsafe { w.sar1_bit_width().bits(resolution) });
83        SENS::regs()
84            .sar_read_ctrl()
85            .modify(|_, w| unsafe { w.sar1_sample_bit().bits(resolution) });
86    }
87
88    fn set_attenuation(channel: usize, attenuation: u8) {
89        SENS::regs().sar_atten1().modify(|r, w| {
90            let new_value = (r.bits() & !(0b11 << (channel * 2)))
91                | (((attenuation & 0b11) as u32) << (channel * 2));
92
93            unsafe { w.sar1_atten().bits(new_value) }
94        });
95    }
96
97    fn clear_dig_force() {
98        SENS::regs()
99            .sar_read_ctrl()
100            .modify(|_, w| w.sar1_dig_force().clear_bit());
101    }
102
103    fn set_start_force() {
104        SENS::regs()
105            .sar_meas_start1()
106            .modify(|_, w| w.meas1_start_force().set_bit());
107    }
108
109    fn set_en_pad_force() {
110        SENS::regs()
111            .sar_meas_start1()
112            .modify(|_, w| w.sar1_en_pad_force().set_bit());
113    }
114
115    fn set_en_pad(channel: u8) {
116        SENS::regs()
117            .sar_meas_start1()
118            .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
119    }
120
121    fn clear_start_sar() {
122        SENS::regs()
123            .sar_meas_start1()
124            .modify(|_, w| w.meas1_start_sar().clear_bit());
125    }
126
127    fn set_start_sar() {
128        SENS::regs()
129            .sar_meas_start1()
130            .modify(|_, w| w.meas1_start_sar().set_bit());
131    }
132
133    fn read_done_sar() -> bool {
134        SENS::regs()
135            .sar_meas_start1()
136            .read()
137            .meas1_done_sar()
138            .bit_is_set()
139    }
140
141    fn read_data_sar() -> u16 {
142        SENS::regs()
143            .sar_meas_start1()
144            .read()
145            .meas1_data_sar()
146            .bits()
147    }
148
149    fn instance_number() -> u8 {
150        1
151    }
152}
153
154impl RegisterAccess for ADC2<'_> {
155    fn set_resolution(resolution: u8) {
156        SENS::regs()
157            .sar_start_force()
158            .modify(|_, w| unsafe { w.sar2_bit_width().bits(resolution) });
159        SENS::regs()
160            .sar_read_ctrl2()
161            .modify(|_, w| unsafe { w.sar2_sample_bit().bits(resolution) });
162    }
163
164    fn set_attenuation(channel: usize, attenuation: u8) {
165        SENS::regs().sar_atten2().modify(|r, w| {
166            let new_value = (r.bits() & !(0b11 << (channel * 2)))
167                | (((attenuation & 0b11) as u32) << (channel * 2));
168
169            unsafe { w.sar2_atten().bits(new_value) }
170        });
171    }
172
173    fn clear_dig_force() {
174        SENS::regs()
175            .sar_read_ctrl2()
176            .modify(|_, w| w.sar2_dig_force().clear_bit());
177    }
178
179    fn set_start_force() {
180        SENS::regs()
181            .sar_meas_start2()
182            .modify(|_, w| w.meas2_start_force().set_bit());
183    }
184
185    fn set_en_pad_force() {
186        SENS::regs()
187            .sar_meas_start2()
188            .modify(|_, w| w.sar2_en_pad_force().set_bit());
189    }
190
191    fn set_en_pad(channel: u8) {
192        SENS::regs()
193            .sar_meas_start2()
194            .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << channel) });
195    }
196
197    fn clear_start_sar() {
198        SENS::regs()
199            .sar_meas_start2()
200            .modify(|_, w| w.meas2_start_sar().clear_bit());
201    }
202
203    fn set_start_sar() {
204        SENS::regs()
205            .sar_meas_start2()
206            .modify(|_, w| w.meas2_start_sar().set_bit());
207    }
208
209    fn read_done_sar() -> bool {
210        SENS::regs()
211            .sar_meas_start2()
212            .read()
213            .meas2_done_sar()
214            .bit_is_set()
215    }
216
217    fn read_data_sar() -> u16 {
218        SENS::regs()
219            .sar_meas_start2()
220            .read()
221            .meas2_data_sar()
222            .bits()
223    }
224
225    fn instance_number() -> u8 {
226        2
227    }
228}
229
230/// Analog-to-Digital Converter peripheral driver.
231pub struct Adc<'d, ADC, Dm: crate::DriverMode> {
232    _adc: ADC,
233    attenuations: [Option<Attenuation>; NUM_ATTENS],
234    active_channel: Option<u8>,
235    resolution_bits: u8,
236    // Set when this driver claimed ADC2, which it then releases on drop.
237    adc2_claimed: bool,
238    _phantom: PhantomData<(Dm, &'d mut ())>,
239}
240
241impl<'d, ADCX> Adc<'d, ADCX, crate::Blocking>
242where
243    ADCX: RegisterAccess + 'd,
244{
245    /// Configures a given ADC instance using the provided configuration, and
246    /// initializes the ADC for use.
247    ///
248    /// # Errors
249    ///
250    /// Returns [`Error::Adc2InUse`] if `ADC2` is already in use by the radio.
251    /// `ADC2` cannot be used simultaneously with `radio` functionalities.
252    /// The handle is consumed even on failure; pass a reborrowed handle to retry later.
253    pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Result<Self, Error> {
254        // Claim ADC2 for exclusive use; the driver releases it on drop.
255        let adc2_claimed = if ADCX::instance_number() == 2 {
256            if try_claim_adc2(private::Internal).is_err() {
257                return Err(Error::Adc2InUse);
258            }
259            true
260        } else {
261            false
262        };
263
264        let sensors = SENS::regs();
265
266        // Set reading and sampling resolution
267        ADCX::set_resolution(config.resolution as u8);
268
269        // Set attenuation for pins
270        let attenuations = config.attenuations;
271
272        for (channel, attenuation) in attenuations.iter().enumerate() {
273            if let Some(attenuation) = attenuation {
274                ADCX::set_attenuation(channel, *attenuation as u8);
275            }
276        }
277
278        // Set controller to RTC
279        ADCX::clear_dig_force();
280        ADCX::set_start_force();
281        ADCX::set_en_pad_force();
282        sensors.sar_touch_ctrl1().modify(|_, w| {
283            w.xpd_hall_force().set_bit();
284            w.hall_phase_force().set_bit()
285        });
286
287        sensors.sar_meas_wait2().modify(|_, w| unsafe {
288            // Set power to SW power on
289            w.force_xpd_sar().bits(0b11);
290            // disable AMP
291            w.force_xpd_amp().bits(0b10)
292        });
293        sensors.sar_meas_ctrl().modify(|_, w| unsafe {
294            w.amp_rst_fb_fsm().bits(0);
295            w.amp_short_ref_fsm().bits(0);
296            w.amp_short_ref_gnd_fsm().bits(0)
297        });
298        sensors.sar_meas_wait1().modify(|_, w| unsafe {
299            w.sar_amp_wait1().bits(1);
300            w.sar_amp_wait2().bits(1)
301        });
302        sensors
303            .sar_meas_wait2()
304            .modify(|_, w| unsafe { w.sar_amp_wait3().bits(1) });
305
306        // Do *not* invert the output
307        // NOTE: This seems backwards, but was verified experimentally.
308        sensors
309            .sar_read_ctrl()
310            .modify(|_, w| w.sar1_data_inv().set_bit());
311        sensors
312            .sar_read_ctrl2()
313            .modify(|_, w| w.sar2_data_inv().set_bit());
314
315        Ok(Adc {
316            _adc: adc_instance,
317            attenuations: config.attenuations,
318            active_channel: None,
319            resolution_bits: match config.resolution {
320                Resolution::_9Bit => 9,
321                Resolution::_10Bit => 10,
322                Resolution::_11Bit => 11,
323                Resolution::_12Bit => 12,
324            },
325            adc2_claimed,
326            _phantom: PhantomData,
327        })
328    }
329
330    /// Requests that the ADC begin a conversion on the specified pin.
331    ///
332    /// Takes an [`AdcPin`](super::AdcPin) reference, as it is
333    /// expected that the ADC will be able to sample whatever channel
334    /// underlies the pin.
335    ///
336    /// # Errors
337    ///
338    /// Returns [`Error::ChannelNotConfigured`] if the channel was not configured in
339    /// [`AdcConfig`].
340    pub fn read_oneshot<PIN, CS>(
341        &mut self,
342        pin: &mut super::AdcPin<PIN, ADCX, CS>,
343    ) -> nb::Result<u16, Error>
344    where
345        PIN: super::AdcChannel,
346        CS: AdcCalScheme<ADCX>,
347    {
348        let channel = pin.pin.adc_channel();
349        if self.attenuations[channel as usize].is_none() {
350            return Err(nb::Error::Other(Error::ChannelNotConfigured(channel)));
351        }
352
353        if let Some(active_channel) = self.active_channel {
354            // There is conversion in progress:
355            // - if it's for a different channel try again later
356            // - if it's for the given channel, go ahead and check progress
357            if active_channel != pin.pin.adc_channel() {
358                return Err(nb::Error::WouldBlock);
359            }
360        } else {
361            // If no conversions are in progress, start a new one for given channel
362            self.active_channel = Some(pin.pin.adc_channel());
363
364            ADCX::set_en_pad(pin.pin.adc_channel());
365
366            ADCX::clear_start_sar();
367            ADCX::set_start_sar();
368        }
369
370        // Wait for ADC to finish conversion
371        let conversion_finished = ADCX::read_done_sar();
372        if !conversion_finished {
373            return Err(nb::Error::WouldBlock);
374        }
375
376        // Get converted value and scale to 12 bits
377        let mut converted_value = ADCX::read_data_sar() as u32;
378        converted_value <<= 12 - self.resolution_bits;
379        if converted_value > 4095 {
380            converted_value = 4095;
381        }
382
383        // Mark that no conversions are currently in progress
384        self.active_channel = None;
385
386        Ok(pin.cal_scheme.adc_val(converted_value as u16))
387    }
388}
389
390impl<ADC, Dm: crate::DriverMode> Drop for Adc<'_, ADC, Dm> {
391    fn drop(&mut self) {
392        if self.adc2_claimed {
393            release_adc2(private::Internal);
394        }
395    }
396}