Skip to main content

esp_hal/analog/adc/
p4.rs

1use core::{
2    marker::PhantomData,
3    pin::Pin,
4    task::{Context, Poll},
5};
6
7// One-shot ADC is handled by the LP_ADC peripheral.
8use Interrupt::LP_ADC as InterruptSource;
9// Both units share one interrupt, so the enabled instances have to be counted.
10use portable_atomic::{AtomicU32, Ordering};
11use procmacros::handler;
12
13pub use self::calibration::*;
14use super::{AdcCalScheme, AdcChannel, AdcConfig, AdcPin, Attenuation, Error};
15use crate::{
16    Async,
17    Blocking,
18    asynch::AtomicWaker,
19    efuse::AdcCalibUnit,
20    interrupt::{InterruptConfigurable, InterruptHandler},
21    peripherals::{Interrupt, LP_ADC, LP_PERI},
22    rtc_cntl::WakeLock,
23    soc::regi2c,
24    system::{GenericPeripheralGuard, Peripheral},
25};
26
27mod calibration;
28
29/// ADC1 covers channels 0..=7, ADC2 covers channels 0..=5. The attenuation
30/// table is indexed by channel, so it has to hold the larger of the two.
31pub(super) const NUM_ATTENS: usize = 8;
32
33const ADC_VAL_MASK: u16 = 0xfff;
34
35/// Powers the SAR up by software, instead of leaving it to the FSM.
36const FORCE_XPD_SAR_PU: u8 = 3;
37
38impl<ADCX> AdcConfig<ADCX>
39where
40    ADCX: RegisterAccess,
41{
42    /// Measures the initial code that cancels the unit's zero-voltage offset at `atten`.
43    pub fn adc_calibrate(atten: Attenuation) -> u16
44    where
45        ADCX: super::CalibrationAccess,
46    {
47        // This can be called without an `Adc`, so it cannot rely on `Adc::new` having clocked
48        // and powered the unit.
49        let _guard = GenericPeripheralGuard::<{ Peripheral::ApbSarAdc as u8 }>::new();
50        init_hardware::<ADCX>();
51
52        ADCX::enable_vdef(true);
53
54        // Start sampling
55        ADCX::setup_calibration(atten);
56
57        // Connect calibration source
58        ADCX::connect_gnd(true);
59
60        ADCX::calibration_init();
61        let cal_val = super::search_init_code::<ADCX>(|| {
62            // Clearing the done flag up front, rather than after the read, keeps a conversion left
63            // over from the previous code from being mistaken for this one's result.
64            ADCX::reset();
65            ADCX::start_sample();
66            while !ADCX::is_done() {}
67
68            ADCX::read_data() & ADCX::ADC_VAL_MASK
69        });
70        ADCX::reset();
71
72        // Disconnect calibration source
73        ADCX::connect_gnd(false);
74
75        cal_val
76    }
77}
78
79/// Clocks the RTC controller and powers the unit up.
80///
81/// Writes nothing that depends on previous state, so it is safe to run more than once.
82fn init_hardware<ADCX: RegisterAccess>() {
83    // The RTC controller lives in the LP domain and has its own clock gate.
84    LP_PERI::regs()
85        .clk_en()
86        .modify(|_, w| w.ck_en_lp_adc().set_bit());
87
88    ADCX::set_rtc_controller();
89    ADCX::set_sar_clk_div();
90    ADCX::power_up();
91}
92
93#[doc(hidden)]
94pub trait RegisterAccess {
95    fn set_attenuation(channel: usize, attenuation: u8);
96
97    /// Routes the unit to the RTC controller, driven by software.
98    fn set_rtc_controller();
99
100    fn set_en_pad(channel: u8);
101
102    fn clear_start_sample();
103
104    fn start_sample();
105
106    /// Returns whether sampling is done.
107    fn is_done() -> bool;
108
109    /// Reads sample data.
110    fn read_data() -> u16;
111
112    /// Powers the SAR up.
113    fn power_up();
114
115    /// Configures the SAR clock divider.
116    ///
117    /// See `adc_ll_set_sar_clk_div` and `ADC_LL_SAR_CLK_DIV_DEFAULT`.
118    fn set_sar_clk_div();
119
120    /// Sets up ADC hardware for calibration.
121    fn calibration_init();
122
123    /// Sets calibration parameter to ADC hardware.
124    fn set_init_code(data: u16);
125
126    /// Resets flags.
127    fn reset();
128}
129
130#[cfg(adc_adc1)]
131impl RegisterAccess for crate::peripherals::ADC1<'_> {
132    fn set_attenuation(channel: usize, attenuation: u8) {
133        LP_ADC::regs().atten1().modify(|r, w| {
134            let new_value = (r.bits() & !(0b11 << (channel * 2)))
135                | (((attenuation & 0b11) as u32) << (channel * 2));
136
137            unsafe { w.sar1_atten().bits(new_value) }
138        });
139    }
140
141    fn set_rtc_controller() {
142        LP_ADC::regs()
143            .meas1_mux()
144            .modify(|_, w| w.sar1_dig_force().clear_bit());
145        LP_ADC::regs().meas1_ctrl2().modify(|_, w| {
146            w.meas1_start_force().set_bit();
147            w.sar1_en_pad_force().set_bit()
148        });
149    }
150
151    fn set_en_pad(channel: u8) {
152        LP_ADC::regs()
153            .meas1_ctrl2()
154            .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
155    }
156
157    fn clear_start_sample() {
158        LP_ADC::regs()
159            .meas1_ctrl2()
160            .modify(|_, w| w.meas1_start_sar().clear_bit());
161    }
162
163    fn start_sample() {
164        LP_ADC::regs()
165            .meas1_ctrl2()
166            .modify(|_, w| w.meas1_start_sar().set_bit());
167    }
168
169    fn is_done() -> bool {
170        LP_ADC::regs()
171            .meas1_ctrl2()
172            .read()
173            .meas1_done_sar()
174            .bit_is_set()
175    }
176
177    fn read_data() -> u16 {
178        LP_ADC::regs().meas1_ctrl2().read().meas1_data_sar().bits()
179    }
180
181    fn power_up() {
182        LP_ADC::regs()
183            .force_wpd_sar()
184            .modify(|_, w| unsafe { w.force_xpd_sar1().bits(FORCE_XPD_SAR_PU) });
185    }
186
187    fn set_sar_clk_div() {
188        LP_ADC::regs()
189            .reader1_ctrl()
190            .modify(|_, w| unsafe { w.sar1_clk_div().bits(1) });
191    }
192
193    fn calibration_init() {
194        // https://github.com/espressif/esp-idf/blob/08e0d30a74a/components/esp_hal_ana_conv/esp32p4/include/hal/adc_ll.h#L727
195        regi2c::ADC_SAR1_DREF.write_field(4);
196    }
197
198    fn set_init_code(data: u16) {
199        let [msb, lsb] = data.to_be_bytes();
200
201        regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
202        regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
203    }
204
205    fn reset() {
206        // The conversion-done interrupt latches even when it is masked, so clear it
207        // here to keep a later `into_async` from seeing a stale completion.
208        LP_ADC::regs()
209            .int_clr()
210            .write(|w| w.cocpu_saradc1_int_clr().set_bit());
211
212        LP_ADC::regs()
213            .meas1_ctrl2()
214            .modify(|_, w| w.meas1_start_sar().clear_bit());
215    }
216}
217
218#[cfg(adc_adc1)]
219impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
220    const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
221
222    fn enable_vdef(enable: bool) {
223        regi2c::ADC_SAR1_DREF.write_field(enable as u8);
224    }
225
226    fn connect_gnd(enable: bool) {
227        regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as u8);
228    }
229
230    fn setup_calibration(atten: Attenuation) {
231        // With no pad selected the hardware falls back to channel 0's attenuation, so
232        // that is where `cal_setup` programs it. Selecting the pseudo-channel the
233        // digital controller uses would shift past the register instead.
234        LP_ADC::regs()
235            .meas1_ctrl2()
236            .modify(|_, w| unsafe { w.sar1_en_pad().bits(0) });
237        Self::set_attenuation(0, atten as u8);
238    }
239}
240
241/// ADC2 channels are wired to SAR pads 2..=7, so the pad index is the channel
242/// number plus two.
243///
244/// See `ADC_LL_UNIT2_CHANNEL_SUBSTRATION` in
245/// `components/esp_hal_ana_conv/esp32p4/include/hal/adc_ll.h`.
246#[cfg(adc_adc2)]
247const ADC2_PAD_OFFSET: u8 = 2;
248
249#[cfg(adc_adc2)]
250impl RegisterAccess for crate::peripherals::ADC2<'_> {
251    fn set_attenuation(channel: usize, attenuation: u8) {
252        let pad = channel + ADC2_PAD_OFFSET as usize;
253        LP_ADC::regs().atten2().modify(|r, w| {
254            let new_value =
255                (r.bits() & !(0b11 << (pad * 2))) | (((attenuation & 0b11) as u32) << (pad * 2));
256
257            unsafe { w.sar2_atten().bits(new_value) }
258        });
259    }
260
261    fn set_rtc_controller() {
262        LP_ADC::regs()
263            .meas2_mux()
264            .modify(|_, w| w.sar2_rtc_force().set_bit());
265        LP_ADC::regs().meas2_ctrl2().modify(|_, w| {
266            w.meas2_start_force().set_bit();
267            w.sar2_en_pad_force().set_bit()
268        });
269    }
270
271    fn set_en_pad(channel: u8) {
272        LP_ADC::regs()
273            .meas2_ctrl2()
274            .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << (channel + ADC2_PAD_OFFSET)) });
275    }
276
277    fn clear_start_sample() {
278        LP_ADC::regs()
279            .meas2_ctrl2()
280            .modify(|_, w| w.meas2_start_sar().clear_bit());
281    }
282
283    fn start_sample() {
284        LP_ADC::regs()
285            .meas2_ctrl2()
286            .modify(|_, w| w.meas2_start_sar().set_bit());
287    }
288
289    fn is_done() -> bool {
290        LP_ADC::regs()
291            .meas2_ctrl2()
292            .read()
293            .meas2_done_sar()
294            .bit_is_set()
295    }
296
297    fn read_data() -> u16 {
298        LP_ADC::regs().meas2_ctrl2().read().meas2_data_sar().bits()
299    }
300
301    fn power_up() {
302        LP_ADC::regs()
303            .force_wpd_sar()
304            .modify(|_, w| unsafe { w.force_xpd_sar2().bits(FORCE_XPD_SAR_PU) });
305    }
306
307    fn set_sar_clk_div() {
308        LP_ADC::regs()
309            .reader2_ctrl()
310            .modify(|_, w| unsafe { w.sar2_clk_div().bits(1) });
311    }
312
313    fn calibration_init() {
314        regi2c::ADC_SAR2_DREF.write_field(4);
315    }
316
317    fn set_init_code(data: u16) {
318        let [msb, lsb] = data.to_be_bytes();
319
320        regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb);
321        regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb);
322    }
323
324    fn reset() {
325        // The conversion-done interrupt latches even when it is masked, so clear it
326        // here to keep a later `into_async` from seeing a stale completion.
327        LP_ADC::regs()
328            .int_clr()
329            .write(|w| w.cocpu_saradc2_int_clr().set_bit());
330
331        LP_ADC::regs()
332            .meas2_ctrl2()
333            .modify(|_, w| w.meas2_start_sar().clear_bit());
334    }
335}
336
337#[cfg(adc_adc2)]
338impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
339    const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
340
341    fn enable_vdef(enable: bool) {
342        regi2c::ADC_SAR2_DREF.write_field(enable as u8);
343    }
344
345    fn connect_gnd(enable: bool) {
346        regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as u8);
347    }
348
349    fn setup_calibration(atten: Attenuation) {
350        LP_ADC::regs()
351            .meas2_ctrl2()
352            .modify(|_, w| unsafe { w.sar2_en_pad().bits(0) });
353        Self::set_attenuation(0, atten as u8);
354    }
355}
356
357#[cfg(adc_adc1)]
358impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
359    fn init_code(atten: Attenuation) -> Option<u16> {
360        crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
361    }
362
363    fn cal_mv(atten: Attenuation) -> Option<u16> {
364        crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
365    }
366
367    fn cal_code(atten: Attenuation) -> Option<u16> {
368        crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
369    }
370
371    fn cal_chan_compens(atten: Attenuation, channel: u8) -> Option<i32> {
372        crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC1, channel.into(), atten)
373    }
374}
375
376#[cfg(adc_adc2)]
377impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
378    fn init_code(atten: Attenuation) -> Option<u16> {
379        crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC2, atten)
380    }
381
382    fn cal_mv(atten: Attenuation) -> Option<u16> {
383        crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC2, atten)
384    }
385
386    fn cal_code(atten: Attenuation) -> Option<u16> {
387        crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC2, atten)
388    }
389
390    fn cal_chan_compens(atten: Attenuation, channel: u8) -> Option<i32> {
391        crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC2, channel.into(), atten)
392    }
393}
394
395/// Analog-to-Digital Converter peripheral driver.
396pub struct Adc<'d, ADC, Dm: crate::DriverMode> {
397    _adc: ADC,
398    attenuations: [Option<Attenuation>; NUM_ATTENS],
399    /// Hardware calibration code per attenuation, indexed by [`Attenuation`].
400    init_codes: [u16; super::ATTENUATION_COUNT],
401    active_channel: Option<u8>,
402    _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
403    _phantom: PhantomData<(Dm, &'d mut ())>,
404}
405
406impl<ADCX, Dm> Adc<'_, ADCX, Dm>
407where
408    ADCX: RegisterAccess,
409    Dm: crate::DriverMode,
410{
411    fn start_sample<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>) -> Result<(), Error>
412    where
413        PIN: AdcChannel,
414        CS: AdcCalScheme<ADCX>,
415    {
416        let channel = pin.pin.adc_channel();
417        let attenuation = super::channel_attenuation(&self.attenuations, channel)?;
418
419        // Reprogrammed for every conversion: the regi2c block is shared with the PHY,
420        // so the code cannot be assumed to survive between reads.
421        ADCX::calibration_init();
422        ADCX::set_init_code(self.init_codes[attenuation as usize]);
423
424        ADCX::set_en_pad(channel);
425
426        ADCX::clear_start_sample();
427        ADCX::start_sample();
428
429        Ok(())
430    }
431}
432
433impl<'d, ADCX> Adc<'d, ADCX, Blocking>
434where
435    ADCX: RegisterAccess + 'd,
436{
437    /// Creates a new ADC instance with the given configuration.
438    pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Result<Self, Error>
439    where
440        ADCX: super::AdcCalEfuse + super::CalibrationAccess,
441    {
442        let guard = GenericPeripheralGuard::new();
443
444        let attenuations = config.attenuations;
445
446        init_hardware::<ADCX>();
447
448        let init_codes = super::hw_init_codes::<ADCX>(&attenuations);
449
450        for (channel, attenuation) in attenuations.iter().enumerate() {
451            if let Some(attenuation) = attenuation {
452                ADCX::set_attenuation(channel, *attenuation as u8);
453            }
454        }
455
456        // The bootloader runs conversions of its own to seed the RNG, so the done flag can
457        // already be set here and would make the first read return a stale result.
458        ADCX::reset();
459
460        Ok(Adc {
461            _adc: adc_instance,
462            attenuations,
463            init_codes,
464            active_channel: None,
465            _guard: guard,
466            _phantom: PhantomData,
467        })
468    }
469
470    /// Starts and waits for a conversion on the specified pin and returns the
471    /// result.
472    ///
473    /// # Errors
474    ///
475    /// Returns [`Error::ChannelNotConfigured`] if the channel was not configured in
476    /// [`AdcConfig`].
477    pub fn read_blocking<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>) -> Result<u16, Error>
478    where
479        PIN: AdcChannel,
480        CS: AdcCalScheme<ADCX>,
481    {
482        self.start_sample(pin)?;
483
484        // Wait for ADC to finish conversion
485        while !ADCX::is_done() {}
486
487        // Get converted value
488        let converted_value = ADCX::read_data();
489        ADCX::reset();
490
491        // Postprocess converted value according to calibration scheme used for pin
492        Ok(pin.cal_scheme.adc_val(converted_value))
493    }
494
495    /// Requests that the ADC begin a conversion on the specified pin.
496    ///
497    /// Takes an [`AdcPin`](super::AdcPin) reference, as it is
498    /// expected that the ADC will be able to sample whatever channel
499    /// underlies the pin.
500    ///
501    /// # Errors
502    ///
503    /// Returns [`Error::ChannelNotConfigured`] if the channel was not configured in
504    /// [`AdcConfig`].
505    pub fn read_oneshot<PIN, CS>(
506        &mut self,
507        pin: &mut super::AdcPin<PIN, ADCX, CS>,
508    ) -> nb::Result<u16, Error>
509    where
510        PIN: super::AdcChannel,
511        CS: super::AdcCalScheme<ADCX>,
512    {
513        if let Some(active_channel) = self.active_channel {
514            // There is conversion in progress:
515            // - if it's for a different channel try again later
516            // - if it's for the given channel, go ahead and check progress
517            if active_channel != pin.pin.adc_channel() {
518                return Err(nb::Error::WouldBlock);
519            }
520        } else {
521            // If no conversions are in progress, start a new one for given channel
522            self.start_sample(pin).map_err(nb::Error::Other)?;
523            self.active_channel = Some(pin.pin.adc_channel());
524        }
525
526        // Wait for ADC to finish conversion
527        let conversion_finished = ADCX::is_done();
528        if !conversion_finished {
529            return Err(nb::Error::WouldBlock);
530        }
531
532        // Get converted value
533        let converted_value = ADCX::read_data();
534        ADCX::reset();
535
536        // Postprocess converted value according to calibration scheme used for pin
537        let converted_value = pin.cal_scheme.adc_val(converted_value);
538
539        // Mark that no conversions are currently in progress
540        self.active_channel = None;
541
542        Ok(converted_value)
543    }
544
545    /// Reconfigures the ADC driver to operate in asynchronous mode.
546    pub fn into_async(mut self) -> Adc<'d, ADCX, Async> {
547        acquire_async_adc();
548        self.set_interrupt_handler(adc_interrupt_handler);
549
550        // Clear a stale done flag so that the first future does not complete early.
551        ADCX::reset();
552
553        Adc {
554            _adc: self._adc,
555            attenuations: self.attenuations,
556            init_codes: self.init_codes,
557            active_channel: self.active_channel,
558            _guard: self._guard,
559            _phantom: PhantomData,
560        }
561    }
562}
563
564impl<ADCX> crate::private::Sealed for Adc<'_, ADCX, Blocking> {}
565
566impl<ADCX> InterruptConfigurable for Adc<'_, ADCX, Blocking> {
567    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
568        for core in crate::system::Cpu::other() {
569            crate::interrupt::disable(core, InterruptSource);
570        }
571        crate::interrupt::bind_handler(InterruptSource, handler);
572    }
573}
574
575impl<'d, ADCX> Adc<'d, ADCX, Async>
576where
577    ADCX: RegisterAccess + 'd,
578{
579    /// Reconfigures the ADC driver to operate in [`Blocking`] mode.
580    pub fn into_blocking(self) -> Adc<'d, ADCX, Blocking> {
581        if release_async_adc() {
582            // Disable the ADC interrupt on all cores once the last async instance goes away.
583            for cpu in crate::system::Cpu::all() {
584                crate::interrupt::disable(cpu, InterruptSource);
585            }
586        }
587        Adc {
588            _adc: self._adc,
589            attenuations: self.attenuations,
590            init_codes: self.init_codes,
591            active_channel: self.active_channel,
592            _guard: self._guard,
593            _phantom: PhantomData,
594        }
595    }
596
597    /// Starts a conversion on the specified pin and waits for the result.
598    ///
599    /// Takes an [`AdcPin`](super::AdcPin) reference, as it is
600    /// expected that the ADC will be able to sample whatever channel
601    /// underlies the pin.
602    ///
603    /// # Errors
604    ///
605    /// Returns [`Error::ChannelNotConfigured`] if the channel was not configured in
606    /// [`AdcConfig`].
607    pub async fn read_oneshot<PIN, CS>(
608        &mut self,
609        pin: &mut super::AdcPin<PIN, ADCX, CS>,
610    ) -> Result<u16, Error>
611    where
612        ADCX: Instance,
613        PIN: super::AdcChannel,
614        CS: super::AdcCalScheme<ADCX>,
615    {
616        self.start_sample(pin)?;
617
618        AdcFuture::<ADCX>::new(self).await;
619
620        let converted_value = ADCX::read_data();
621        ADCX::reset();
622
623        // Postprocess converted value according to calibration scheme used for pin
624        Ok(pin.cal_scheme.adc_val(converted_value))
625    }
626}
627
628static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
629
630fn acquire_async_adc() {
631    ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
632}
633
634fn release_async_adc() -> bool {
635    ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
636}
637
638#[handler]
639pub(crate) fn adc_interrupt_handler() {
640    let interrupt_status = LP_ADC::regs().int_st().read();
641
642    #[cfg(adc_adc1)]
643    if interrupt_status.cocpu_saradc1_int_st().bit_is_set() {
644        unsafe { handle_async(crate::peripherals::ADC1::steal()) }
645    }
646
647    #[cfg(adc_adc2)]
648    if interrupt_status.cocpu_saradc2_int_st().bit_is_set() {
649        unsafe { handle_async(crate::peripherals::ADC2::steal()) }
650    }
651}
652
653fn handle_async<ADCX: Instance>(_instance: ADCX) {
654    ADCX::waker().wake();
655    ADCX::unlisten();
656}
657
658/// Enables asynchronous access.
659pub trait Instance: crate::private::Sealed {
660    /// Enables the ADC interrupt.
661    fn listen();
662
663    /// Disables the ADC interrupt.
664    fn unlisten();
665
666    /// Clears the ADC interrupt.
667    fn clear_interrupt();
668
669    /// Obtains the waker for the ADC interrupt.
670    fn waker() -> &'static AtomicWaker;
671}
672
673#[cfg(adc_adc1)]
674impl Instance for crate::peripherals::ADC1<'_> {
675    fn listen() {
676        LP_ADC::regs()
677            .int_ena_w1ts()
678            .write(|w| w.cocpu_saradc1_int_ena_w1ts().set_bit());
679    }
680
681    fn unlisten() {
682        LP_ADC::regs()
683            .int_ena_w1tc()
684            .write(|w| w.cocpu_saradc1_int_ena_w1tc().set_bit());
685    }
686
687    fn clear_interrupt() {
688        LP_ADC::regs()
689            .int_clr()
690            .write(|w| w.cocpu_saradc1_int_clr().set_bit());
691    }
692
693    fn waker() -> &'static AtomicWaker {
694        static WAKER: AtomicWaker = AtomicWaker::new();
695
696        &WAKER
697    }
698}
699
700#[cfg(adc_adc2)]
701impl Instance for crate::peripherals::ADC2<'_> {
702    fn listen() {
703        LP_ADC::regs()
704            .int_ena_w1ts()
705            .write(|w| w.cocpu_saradc2_int_ena_w1ts().set_bit());
706    }
707
708    fn unlisten() {
709        LP_ADC::regs()
710            .int_ena_w1tc()
711            .write(|w| w.cocpu_saradc2_int_ena_w1tc().set_bit());
712    }
713
714    fn clear_interrupt() {
715        LP_ADC::regs()
716            .int_clr()
717            .write(|w| w.cocpu_saradc2_int_clr().set_bit());
718    }
719
720    fn waker() -> &'static AtomicWaker {
721        static WAKER: AtomicWaker = AtomicWaker::new();
722
723        &WAKER
724    }
725}
726
727#[must_use = "futures do nothing unless you `.await` or poll them"]
728pub(crate) struct AdcFuture<ADCX: Instance> {
729    phantom: PhantomData<ADCX>,
730    _wake_lock: WakeLock,
731}
732
733impl<ADCX: Instance> AdcFuture<ADCX> {
734    pub fn new(_self: &super::Adc<'_, ADCX, Async>) -> Self {
735        ADCX::listen();
736        Self {
737            phantom: PhantomData,
738            _wake_lock: WakeLock::new(),
739        }
740    }
741}
742
743impl<ADCX: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCX> {
744    type Output = ();
745
746    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
747        ADCX::waker().register(cx.waker());
748        if ADCX::is_done() {
749            ADCX::clear_interrupt();
750            Poll::Ready(())
751        } else {
752            Poll::Pending
753        }
754    }
755}
756
757impl<ADCX: Instance> Drop for AdcFuture<ADCX> {
758    fn drop(&mut self) {
759        ADCX::unlisten();
760    }
761}