1
use core::marker::PhantomData;
2

            
3
cfg_select! {
4
    any(esp32c6, esp32c61) => {
5
        use Interrupt::APB_SARADC as InterruptSource;
6
    }
7
    _ => {
8
        use Interrupt::APB_ADC as InterruptSource;
9
    }
10
}
11

            
12
use core::{
13
    pin::Pin,
14
    task::{Context, Poll},
15
};
16

            
17
use procmacros::handler;
18

            
19
pub use self::calibration::*;
20
use super::{AdcConfig, Attenuation};
21
use crate::{
22
    Async,
23
    Blocking,
24
    asynch::AtomicWaker,
25
    efuse::AdcCalibUnit,
26
    interrupt::{InterruptConfigurable, InterruptHandler},
27
    peripherals::{APB_SARADC, Interrupt},
28
    rtc_cntl::WakeLock,
29
    soc::regi2c,
30
    system::{GenericPeripheralGuard, Peripheral},
31
};
32

            
33
mod calibration;
34

            
35
// Constants taken from:
36
// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32c2/include/soc/regi2c_saradc.h
37
// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32c3/include/soc/regi2c_saradc.h
38
// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32c6/include/soc/regi2c_saradc.h
39
// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32h2/include/soc/regi2c_saradc.h
40
const ADC_VAL_MASK: u16 = 0xfff;
41

            
42
pub(super) const NUM_ATTENS: usize = property!("adc.channel_count");
43

            
44
impl<ADCX> AdcConfig<ADCX>
45
where
46
    ADCX: RegisterAccess,
47
{
48
    /// Measures the initial code that cancels the unit's zero-voltage offset at `atten`.
49
    pub fn adc_calibrate(atten: Attenuation) -> u16
50
    where
51
        ADCX: super::CalibrationAccess,
52
    {
53
        // This can be called without an `Adc`, so it cannot rely on `Adc::new` having clocked
54
        // and powered the unit.
55
        let _guard = GenericPeripheralGuard::<{ Peripheral::ApbSarAdc as u8 }>::new();
56
        let _clock = FunctionClockGuard::new();
57
        let sar_power = SarPowerGuard::new();
58
9
        init_hardware();
59
        sar_power.force_on();
60

            
61
9
        ADCX::enable_vdef(true);
62

            
63
        // Start sampling
64
9
        ADCX::setup_calibration(atten);
65

            
66
        // Connect calibration source
67
9
        ADCX::connect_gnd(true);
68

            
69
9
        ADCX::calibration_init();
70
        let cal_val = super::search_init_code::<ADCX>(read_cal_channel::<ADCX>);
71
9
        ADCX::reset();
72

            
73
        // Disconnect calibration source
74
9
        ADCX::connect_gnd(false);
75

            
76
        cal_val
77
    }
78
}
79

            
80
// Converts the connected calibration source once.
81
//
82
// See `read_cal_channel` in
83
// <https://github.com/espressif/esp-idf/blob/v6.1/components/esp_hal_ana_conv/adc_hal_common.c>
84
fn read_cal_channel<ADCX: RegisterAccess>() -> u16 {
85
    // Only the done flag - `reset` would disarm the unit `setup_calibration` armed.
86
1080
    ADCX::clear_done();
87

            
88
1080
    ADCX::set_onetime_start(false);
89
    crate::rom::ets_delay_us(5);
90
1080
    ADCX::set_onetime_start(true);
91

            
92
1080
    while !ADCX::is_done() {}
93
    settle_after_done();
94

            
95
1080
    ADCX::read_data() & ADC_VAL_MASK
96
}
97

            
98
// Configures clocks and powers up the SAR ADC.
99
//
100
// See `adc_oneshot_hal_setup` in
101
// <https://github.com/espressif/esp-idf/blob/v6.1/components/esp_hal_ana_conv/adc_oneshot_hal.c>
102
27
fn init_hardware() {
103
    // controller_clk = source / (DIV_NUM + DIV_A / DIV_B + 1)
104
    // The ESP32-H2 divides its faster source further, landing at the same 5 MHz as the other chips.
105
    #[cfg(esp32h2)]
106
    const DIV: (u8, u8, u8) = (18, 5, 1);
107
    #[cfg(not(esp32h2))]
108
    const DIV: (u8, u8, u8) = (15, 1, 0);
109

            
110
    let (div_num, div_b, div_a) = DIV;
111

            
112
    // The ESP32-C2 and ESP32-C3 keep the divider in the ADC itself, and only support APB as the
113
    // source. The other chips take the PLL output via the PCR - 80 MHz, or 96 MHz on the
114
    // ESP32-H2.
115
    #[cfg(not(adc_pcr_clock))]
116
    APB_SARADC::regs().clkm_conf().modify(|_, w| unsafe {
117
        w.clk_sel().bits(2);
118
        w.clkm_div_num().bits(div_num);
119
        w.clkm_div_b().bits(div_b);
120
        w.clkm_div_a().bits(div_a)
121
    });
122

            
123
    #[cfg(adc_pcr_clock)]
124
    {
125
        // The PLL is source 1 on the ESP32-C6 and ESP32-H2, but source 2 on the ESP32-C5 and
126
        // ESP32-C61 - there, 1 selects the imprecise RC_FAST oscillator instead.
127
        let pll: u8 = property!("adc.pll_clock_sel");
128

            
129
        // The peripheral guard only enables the bus clock (`saradc_reg_clk_en`); the
130
        // controller runs off a separate function clock that has to be enabled here.
131
        // See `adc_ll_enable_func_clock`.
132
        crate::peripherals::PCR::regs()
133
            .saradc_clkm_conf()
134
            .modify(|_, w| unsafe {
135
                w.saradc_clkm_en().set_bit();
136
                w.saradc_clkm_sel().bits(pll);
137
                w.saradc_clkm_div_num().bits(div_num);
138
                w.saradc_clkm_div_b().bits(div_b);
139
                w.saradc_clkm_div_a().bits(div_a)
140
            });
141
    }
142

            
143
    APB_SARADC::regs().ctrl().modify(|_, w| unsafe {
144
        // Conversions are triggered through `onetime_start`, so the software start of the
145
        // digital controller has to stay off - a concurrently running controller disturbs the
146
        // sampling and biases the results low.
147
        w.start_force().clear_bit();
148
        w.start().clear_bit();
149
        w.sar_clk_gated().set_bit();
150
        #[cfg(not(adc_pcr_sar_clk_div))]
151
        w.sar_clk_div().bits(1);
152
        w.xpd_sar_force().bits(0b11)
153
    });
154

            
155
    // The ESP32-C5, ESP32-C61, and ESP32-H2 configure the divider in PCR.
156
    // See `adc_ll_digi_set_clk_div`.
157
    #[cfg(adc_pcr_sar_clk_div)]
158
    crate::peripherals::PCR::regs()
159
        .sar_clk_div()
160
        .modify(|_, w| unsafe { w.sar1_clk_div_num().bits(1) });
161
27
}
162

            
163
/// Keeps the PLL output that `init_hardware` selects as the controller clock running.
164
///
165
/// Nothing else necessarily requests that clock, and the bootloader may leave it gated.
166
struct FunctionClockGuard;
167

            
168
impl FunctionClockGuard {
169
    fn new() -> Self {
170
        #[cfg(any(esp32c5, esp32c6, esp32c61))]
171
        crate::clock::ll::ClockTree::with(crate::clock::ll::request_pll_f80m);
172
        #[cfg(esp32h2)]
173
        crate::clock::ll::ClockTree::with(crate::clock::ll::request_pll_f96m_clk);
174
        Self
175
    }
176
}
177

            
178
impl Drop for FunctionClockGuard {
179
    fn drop(&mut self) {
180
        #[cfg(any(esp32c5, esp32c6, esp32c61))]
181
        crate::clock::ll::ClockTree::with(crate::clock::ll::release_pll_f80m);
182
        #[cfg(esp32h2)]
183
        crate::clock::ll::ClockTree::with(crate::clock::ll::release_pll_f96m_clk);
184
    }
185
}
186

            
187
/// Keeps the SAR powered while a radio is running.
188
///
189
/// Radio initialization hands SAR power to the PHY's power detector (PWDET), which powers the SAR
190
/// down between its own measurements - conversions then saturate. Like ESP-IDF, the driver
191
/// overrides that through `PWDET_CONF` while the ADC is in use, and hands control back to the
192
/// power detector when the last guard drops. On the ESP32-C2 and ESP32-C3 the power detector does
193
/// not control the SAR, so this does nothing there.
194
///
195
/// See `s_sar_power_acquire` in
196
/// <https://github.com/espressif/esp-idf/blob/v6.1/components/esp_hw_support/port/esp32c6/sar_periph_ctrl.c>
197
struct SarPowerGuard;
198

            
199
cfg_select! {
200
    adc_sar_power_override => {
201
        static SAR_POWER_REFS: esp_sync::NonReentrantMutex<u8> =
202
            esp_sync::NonReentrantMutex::new(0);
203

            
204
        impl SarPowerGuard {
205
            fn new() -> Self {
206
                SAR_POWER_REFS.with(|refs| *refs += 1);
207
                Self
208
            }
209

            
210
            /// Forces the SAR on.
211
            ///
212
            /// Radio initialization rewrites `PWDET_CONF`, so this has to run before every
213
            /// conversion rather than once when the guard is created.
214
            fn force_on(&self) {
215
                SAR_POWER_REFS.with(|_| force_sar_power(true));
216
            }
217
        }
218

            
219
        impl Drop for SarPowerGuard {
220
            fn drop(&mut self) {
221
                SAR_POWER_REFS.with(|refs| {
222
                    *refs -= 1;
223
                    if *refs == 0 {
224
                        force_sar_power(false);
225
                    }
226
                });
227
            }
228
        }
229

            
230
        /// Sets or releases the power detector's override of SAR power.
231
        ///
232
        /// `PWDET_CONF` is clocked by the modem front-end APB clock, which the radio gates while
233
        /// its PHY is off, and writes are dropped while it is gated. The clock is enabled only
234
        /// around the write, so the radio finds it the way it left it. Callers hold
235
        /// `SAR_POWER_REFS`, a critical section, which keeps the radio from reconfiguring the
236
        /// clock in between.
237
        ///
238
        /// See `sar_ctrl_ll_set_power_mode_from_pwdet` in
239
        /// <https://github.com/espressif/esp-idf/blob/v6.1/components/hal/esp32c6/include/hal/sar_ctrl_ll.h>
240
        fn force_sar_power(force: bool) {
241
            // The PACs do not describe the power detector.
242
            const PWDET_CONF: *mut u32 = cfg_select! {
243
                esp32c61 => 0x600A_0808 as *mut u32,
244
                _ => 0x600A_0810 as *mut u32,
245
            };
246
            const SAR_POWER_FORCE: u32 = 1 << 24;
247
            const SAR_POWER_CNTL: u32 = 1 << 23;
248

            
249
            let clk_conf1 = crate::peripherals::MODEM_SYSCON::regs().clk_conf1();
250
            let fe_apb_clock_enabled = clk_conf1.read().clk_fe_apb_en().bit();
251
            clk_conf1.modify(|_, w| w.clk_fe_apb_en().set_bit());
252

            
253
            unsafe {
254
                let conf = PWDET_CONF.read_volatile();
255
                let conf = if force {
256
                    conf | SAR_POWER_FORCE | SAR_POWER_CNTL
257
                } else {
258
                    conf & !SAR_POWER_FORCE
259
                };
260
                PWDET_CONF.write_volatile(conf);
261
            }
262

            
263
            clk_conf1.modify(|_, w| w.clk_fe_apb_en().bit(fe_apb_clock_enabled));
264
        }
265
    }
266
    _ => {
267
        impl SarPowerGuard {
268
            fn new() -> Self {
269
                Self
270
            }
271

            
272
            fn force_on(&self) {}
273
        }
274
    }
275
}
276

            
277
// Triggers a single conversion.
278
//
279
// See `adc_hal_onetime_start` in
280
// <https://github.com/espressif/esp-idf/blob/v6.1/components/esp_hal_ana_conv/adc_oneshot_hal.c>
281
fn start_onetime_sample<ADCX: RegisterAccess>(sar_power: &SarPowerGuard) {
282
    sar_power.force_on();
283
32
    ADCX::set_onetime_start(true);
284
}
285

            
286
/// Waits for the conversion result to become readable after the done flag has come up.
287
///
288
/// The ESP32-H2 needs five SAR clock cycles here or it reports zero. `init_hardware` leaves the SAR
289
/// at the 5 MHz digital controller clock, which makes that one microsecond per cycle.
290
///
291
/// See `ADC_LL_DELAY_CYCLE_AFTER_DONE_SIGNAL`, which is zero on every other chip here.
292
#[inline]
293
fn settle_after_done() {
294
    #[cfg(esp32h2)]
295
    crate::rom::ets_delay_us(5);
296
}
297

            
298
#[doc(hidden)]
299
pub trait RegisterAccess {
300
    /// Configures one-time sampling parameters.
301
    fn config_onetime_sample(channel: u8, attenuation: u8);
302

            
303
    /// Drives the `onetime_start` trigger level.
304
    ///
305
    /// Callers go through [`start_onetime_sample`], which raises it once per conversion; `reset`
306
    /// lowers it again after the read.
307
    fn set_onetime_start(enable: bool);
308

            
309
    /// Returns whether sampling is done.
310
    fn is_done() -> bool;
311

            
312
    /// Reads sample data.
313
    fn read_data() -> u16;
314

            
315
    /// Clears the conversion-done flag.
316
    fn clear_done();
317

            
318
    /// Clears the done flag and ends the one-shot session.
319
    fn reset();
320

            
321
    /// Sets up ADC hardware for calibration.
322
    fn calibration_init();
323

            
324
    /// Sets calibration parameter to ADC hardware.
325
    fn set_init_code(data: u16);
326
}
327

            
328
impl RegisterAccess for crate::peripherals::ADC1<'_> {
329
288
    fn config_onetime_sample(channel: u8, attenuation: u8) {
330
        #[cfg(esp32c6)]
331
        let was_armed = APB_SARADC::regs()
332
            .onetime_sample()
333
            .read()
334
            .saradc1_onetime_sample()
335
            .bit();
336

            
337
        APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
338
            // Disarm ADC2 before configuring ADC1.
339
            // See `adc_oneshot_ll_disable_all_unit`.
340
            w.saradc2_onetime_sample().clear_bit();
341
            w.saradc1_onetime_sample().set_bit();
342
            w.onetime_channel().bits(channel);
343
            w.onetime_atten().bits(attenuation)
344
        });
345

            
346
        // The ESP32-C6 channel selection needs 50 µs to settle after arming ADC1, which is why
347
        // `reset` leaves it armed there. See `adc_oneshot_ll_enable`.
348
        #[cfg(esp32c6)]
349
        if !was_armed {
350
            crate::rom::ets_delay_us(50);
351
        }
352
288
    }
353

            
354
2448
    fn set_onetime_start(enable: bool) {
355
        APB_SARADC::regs()
356
            .onetime_sample()
357
            .modify(|_, w| w.onetime_start().bit(enable));
358
2448
    }
359

            
360
1368
    fn is_done() -> bool {
361
        APB_SARADC::regs().int_raw().read().adc1_done().bit()
362
1368
    }
363

            
364
1368
    fn read_data() -> u16 {
365
        APB_SARADC::regs()
366
            .sar1data_status()
367
            .read()
368
            .saradc1_data()
369
            .bits() as u16
370
            & 0xfff
371
1368
    }
372

            
373
1112
    fn clear_done() {
374
        APB_SARADC::regs()
375
            .int_clr()
376
            .write(|w| w.adc1_done().clear_bit_by_one());
377
1112
    }
378

            
379
317
    fn reset() {
380
        Self::clear_done();
381

            
382
        // Disarm both units along with the trigger - except on the ESP32-C6, which keeps
383
        // ADC1 armed for the whole one-shot session.
384
        // See `adc_oneshot_ll_disable_all_unit`.
385
        APB_SARADC::regs().onetime_sample().modify(|_, w| {
386
            #[cfg(not(esp32c6))]
387
            {
388
                w.saradc2_onetime_sample().clear_bit();
389
                w.saradc1_onetime_sample().clear_bit();
390
            }
391
            w.onetime_start().clear_bit()
392
        });
393
317
    }
394

            
395
297
    fn calibration_init() {
396
        // e.g.
397
        // https://github.com/espressif/esp-idf/blob/800f141f94c0f880c162de476512e183df671307/components/hal/esp32c3/include/hal/adc_ll.h#L702
398
297
        regi2c::ADC_SAR1_DREF.write_field(1);
399
    }
400

            
401
1368
    fn set_init_code(data: u16) {
402
        let [msb, lsb] = data.to_be_bytes();
403

            
404
1368
        regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
405
1368
        regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
406
    }
407
}
408

            
409
impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
410
    const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
411
    const SUPPORTS_SELF_CALIBRATION: bool = !cfg!(esp32c5);
412

            
413
9
    fn enable_vdef(enable: bool) {
414
9
        regi2c::ADC_SAR1_DREF.write_field(enable as _);
415
    }
416

            
417
18
    fn connect_gnd(enable: bool) {
418
18
        regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as _);
419
    }
420

            
421
9
    fn setup_calibration(atten: Attenuation) {
422
        // `adc_oneshot_ll_disable_channel` deselects every pad by writing
423
        // `(unit << 3) | 0xf` to the channel field. The attenuation is shared by all
424
        // channels on these chips, so programming it is enough.
425
        Self::config_onetime_sample(0xf, atten as u8);
426
9
    }
427
}
428

            
429
/// Analog-to-Digital Converter peripheral driver.
430
pub struct Adc<'d, ADCX, Dm: crate::DriverMode> {
431
    _adc: ADCX,
432
    attenuations: [Option<Attenuation>; NUM_ATTENS],
433
    /// Hardware calibration code per attenuation, indexed by [`Attenuation`].
434
    init_codes: [u16; super::ATTENUATION_COUNT],
435
    active_channel: Option<u8>,
436
    _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
437
    _clock: FunctionClockGuard,
438
    sar_power: SarPowerGuard,
439
    _phantom: PhantomData<(Dm, &'d mut ())>,
440
}
441

            
442
impl<'d, ADCX> Adc<'d, ADCX, Blocking>
443
where
444
    ADCX: RegisterAccess + 'd,
445
{
446
    /// Creates a new ADC instance with the given configuration.
447
18
    pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Self
448
    where
449
        ADCX: super::AdcCalEfuse + super::CalibrationAccess,
450
    {
451
        let guard = GenericPeripheralGuard::new();
452
        let clock = FunctionClockGuard::new();
453
        let sar_power = SarPowerGuard::new();
454

            
455
18
        init_hardware();
456

            
457
        let init_codes = super::hw_init_codes::<ADCX>(&config.attenuations);
458

            
459
        // The bootloader runs conversions of its own to seed the RNG, so the done flag can
460
        // already be set here and would make the first read return a stale result.
461
18
        ADCX::reset();
462

            
463
18
        Adc {
464
            _adc: adc_instance,
465
            attenuations: config.attenuations,
466
            init_codes,
467
            active_channel: None,
468
            _guard: guard,
469
            _clock: clock,
470
            sar_power,
471
            _phantom: PhantomData,
472
        }
473
18
    }
474

            
475
    /// Reconfigures the ADC driver to operate in asynchronous mode.
476
    pub fn into_async(mut self) -> Adc<'d, ADCX, Async> {
477
        self.set_interrupt_handler(adc_interrupt_handler);
478

            
479
        // Reset interrupt flags and disable oneshot reading to normalize state before
480
        // entering async mode, otherwise there can be '0' readings, happening initially
481
        // using ADC2
482
2
        ADCX::reset();
483

            
484
2
        Adc {
485
            _adc: self._adc,
486
2
            attenuations: self.attenuations,
487
2
            init_codes: self.init_codes,
488
2
            active_channel: self.active_channel,
489
            _guard: self._guard,
490
            _clock: self._clock,
491
            sar_power: self.sar_power,
492
            _phantom: PhantomData,
493
        }
494
    }
495

            
496
    /// Requests that the ADC begin a conversion on the specified pin.
497
    ///
498
    /// Takes an [`AdcPin`](super::AdcPin) reference, as it is
499
    /// expected that the ADC will be able to sample whatever channel
500
    /// underlies the pin.
501
    ///
502
    /// # Panics
503
    ///
504
    /// Panics if the channel was not configured in [`AdcConfig`].
505
    pub fn read_oneshot<PIN, CS>(
506
        &mut self,
507
        pin: &mut super::AdcPin<PIN, ADCX, CS>,
508
    ) -> nb::Result<u16, ()>
509
    where
510
        PIN: super::AdcChannel,
511
        CS: super::AdcCalScheme<ADCX>,
512
    {
513
        let channel = pin.pin.adc_channel();
514
32
        let attenuation = super::channel_attenuation(&self.attenuations, channel);
515

            
516
32
        if let Some(active_channel) = self.active_channel {
517
            // There is conversion in progress:
518
            // - if it's for a different channel try again later
519
            // - if it's for the given channel, go ahead and check progress
520
2
            if active_channel != channel {
521
                return Err(nb::Error::WouldBlock);
522
            }
523
        } else {
524
            // If no conversions are in progress, start a new one for given channel
525
32
            self.active_channel = Some(channel);
526

            
527
32
            ADCX::calibration_init();
528
32
            ADCX::set_init_code(self.init_codes[attenuation as usize]);
529

            
530
32
            ADCX::config_onetime_sample(channel, attenuation as u8);
531
            start_onetime_sample::<ADCX>(&self.sar_power);
532
        }
533

            
534
        // Wait for ADC to finish conversion
535
32
        let conversion_finished = ADCX::is_done();
536
        if !conversion_finished {
537
            return Err(nb::Error::WouldBlock);
538
        }
539
        settle_after_done();
540

            
541
        // Get converted value
542
32
        let converted_value = ADCX::read_data();
543
32
        ADCX::reset();
544

            
545
        // Postprocess converted value according to calibration scheme used for pin
546
        let converted_value = pin.cal_scheme.adc_val(converted_value);
547

            
548
        // Mark that no conversions are currently in progress
549
32
        self.active_channel = None;
550

            
551
        Ok(converted_value)
552
    }
553
}
554

            
555
impl<ADCX> crate::private::Sealed for Adc<'_, ADCX, Blocking> {}
556

            
557
impl<ADCX> InterruptConfigurable for Adc<'_, ADCX, Blocking> {
558
    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
559
        for core in crate::system::Cpu::other() {
560
            crate::interrupt::disable(core, InterruptSource);
561
        }
562
2
        crate::interrupt::bind_handler(InterruptSource, handler);
563
    }
564
}
565

            
566
impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
567
9
    fn init_code(atten: Attenuation) -> Option<u16> {
568
9
        crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
569
    }
570

            
571
    fn cal_mv(atten: Attenuation) -> u16 {
572
        crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
573
    }
574

            
575
4
    fn cal_code(atten: Attenuation) -> Option<u16> {
576
4
        crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
577
    }
578

            
579
    #[cfg(adc_channel_compensation)]
580
    fn cal_chan_compens(atten: Attenuation, channel: u8) -> Option<i32> {
581
        crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC1, channel, atten)
582
    }
583
}
584

            
585
impl<'d, ADCX> Adc<'d, ADCX, Async>
586
where
587
    ADCX: RegisterAccess + 'd,
588
{
589
    /// Reconfigures the ADC driver to operate in [`Blocking`] mode.
590
    pub fn into_blocking(self) -> Adc<'d, ADCX, Blocking> {
591
        // Every chip handled by this driver has a single ADC unit, so no other driver can be
592
        // sharing the interrupt and it is always safe to disable it here.
593
        for cpu in crate::system::Cpu::all() {
594
            crate::interrupt::disable(cpu, InterruptSource);
595
        }
596
        Adc {
597
            _adc: self._adc,
598
            attenuations: self.attenuations,
599
            init_codes: self.init_codes,
600
            active_channel: self.active_channel,
601
            _guard: self._guard,
602
            _clock: self._clock,
603
            sar_power: self.sar_power,
604
            _phantom: PhantomData,
605
        }
606
    }
607

            
608
    /// Requests that the ADC begin a conversion on the specified pin.
609
    ///
610
    /// Takes an [`AdcPin`](super::AdcPin) reference, as it is
611
    /// expected that the ADC will be able to sample whatever channel
612
    /// underlies the pin.
613
    ///
614
    /// # Panics
615
    ///
616
    /// Panics if the channel was not configured in [`AdcConfig`].
617
32
    pub async fn read_oneshot<PIN, CS>(&mut self, pin: &mut super::AdcPin<PIN, ADCX, CS>) -> u16
618
    where
619
        ADCX: Instance,
620
        PIN: super::AdcChannel,
621
        CS: super::AdcCalScheme<ADCX>,
622
    {
623
        let channel = pin.pin.adc_channel();
624
32
        let attenuation = super::channel_attenuation(&self.attenuations, channel);
625

            
626
32
        ADCX::calibration_init();
627
32
        ADCX::set_init_code(self.init_codes[attenuation as usize]);
628

            
629
32
        ADCX::config_onetime_sample(channel, attenuation as u8);
630
        start_onetime_sample::<ADCX>(&self.sar_power);
631

            
632
        // Wait for ADC to finish conversion and get value
633
        let adc_ready_future = AdcFuture::new(self);
634
32
        adc_ready_future.await;
635
        settle_after_done();
636

            
637
32
        let converted_value = ADCX::read_data();
638

            
639
32
        ADCX::reset();
640

            
641
        // Postprocess converted value according to calibration scheme used for pin
642
        pin.cal_scheme.adc_val(converted_value)
643
32
    }
644
}
645

            
646
#[handler]
647
pub(crate) fn adc_interrupt_handler() {
648
    let saradc = APB_SARADC::regs();
649
    let interrupt_status = saradc.int_st().read();
650

            
651
    if interrupt_status.adc1_done().bit_is_set() {
652
        unsafe { handle_async(crate::peripherals::ADC1::steal()) }
653
    }
654
}
655

            
656
fn handle_async<ADCX: Instance>(_instance: ADCX) {
657
    ADCX::waker().wake();
658
    ADCX::unlisten();
659
}
660

            
661
/// Enables asynchronous access.
662
pub trait Instance: crate::private::Sealed {
663
    /// Enables the ADC interrupt.
664
    fn listen();
665

            
666
    /// Disables the ADC interrupt.
667
    fn unlisten();
668

            
669
    /// Clears the ADC interrupt.
670
    fn clear_interrupt();
671

            
672
    /// Obtains the waker for the ADC interrupt.
673
    fn waker() -> &'static AtomicWaker;
674
}
675

            
676
impl Instance for crate::peripherals::ADC1<'_> {
677
    fn listen() {
678
        APB_SARADC::regs()
679
            .int_ena()
680
            .modify(|_, w| w.adc1_done().set_bit());
681
    }
682

            
683
32
    fn unlisten() {
684
        APB_SARADC::regs()
685
            .int_ena()
686
            .modify(|_, w| w.adc1_done().clear_bit());
687
32
    }
688

            
689
    fn clear_interrupt() {
690
        APB_SARADC::regs()
691
            .int_clr()
692
            .write(|w| w.adc1_done().clear_bit_by_one());
693
    }
694

            
695
    fn waker() -> &'static AtomicWaker {
696
        static WAKER: AtomicWaker = AtomicWaker::new();
697

            
698
        &WAKER
699
    }
700
}
701

            
702
#[must_use = "futures do nothing unless you `.await` or poll them"]
703
pub(crate) struct AdcFuture<ADCX: Instance> {
704
    phantom: PhantomData<ADCX>,
705
    _wake_lock: WakeLock,
706
}
707

            
708
impl<ADCX: Instance> AdcFuture<ADCX> {
709
    pub fn new(_self: &super::Adc<'_, ADCX, Async>) -> Self {
710
        Self {
711
            phantom: PhantomData,
712
32
            _wake_lock: WakeLock::new(),
713
        }
714
    }
715
}
716

            
717
impl<ADCX: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCX> {
718
    type Output = ();
719

            
720
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
721
32
        if ADCX::is_done() {
722
32
            ADCX::clear_interrupt();
723
            Poll::Ready(())
724
        } else {
725
            ADCX::waker().register(cx.waker());
726
            ADCX::listen();
727
            Poll::Pending
728
        }
729
    }
730
}
731

            
732
impl<ADCX: Instance> Drop for AdcFuture<ADCX> {
733
    fn drop(&mut self) {
734
32
        ADCX::unlisten();
735
    }
736
}