esp_hal/analog/adc/
esp32.rs

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