1#![macro_use]
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, Ordering};
8use core::task::Poll;
9
10use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{impl_peripheral, Peri};
12use embassy_sync::waitqueue::AtomicWaker;
13pub(crate) use vals::Psel as InputChannel;
14
15use crate::interrupt::InterruptExt;
16use crate::pac::saadc::vals;
17use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
18use crate::timer::{Frequency, Instance as TimerInstance, Timer};
19use crate::{interrupt, pac, peripherals};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24#[non_exhaustive]
25pub enum Error {}
26
27pub struct InterruptHandler {
29    _private: (),
30}
31
32impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler {
33    unsafe fn on_interrupt() {
34        let r = pac::SAADC;
35
36        if r.events_calibratedone().read() != 0 {
37            r.intenclr().write(|w| w.set_calibratedone(true));
38            WAKER.wake();
39        }
40
41        if r.events_end().read() != 0 {
42            r.intenclr().write(|w| w.set_end(true));
43            WAKER.wake();
44        }
45
46        if r.events_started().read() != 0 {
47            r.intenclr().write(|w| w.set_started(true));
48            WAKER.wake();
49        }
50    }
51}
52
53static WAKER: AtomicWaker = AtomicWaker::new();
54
55#[non_exhaustive]
59pub struct Config {
60    pub resolution: Resolution,
62    pub oversample: Oversample,
64}
65
66impl Default for Config {
67    fn default() -> Self {
69        Self {
70            resolution: Resolution::_12BIT,
71            oversample: Oversample::BYPASS,
72        }
73    }
74}
75
76#[non_exhaustive]
81pub struct ChannelConfig<'d> {
82    pub reference: Reference,
84    pub gain: Gain,
86    pub resistor: Resistor,
88    pub time: Time,
90    p_channel: AnyInput<'d>,
92    n_channel: Option<AnyInput<'d>>,
94}
95
96impl<'d> ChannelConfig<'d> {
97    pub fn single_ended(input: impl Input + 'd) -> Self {
99        Self {
100            reference: Reference::INTERNAL,
101            gain: Gain::GAIN1_6,
102            resistor: Resistor::BYPASS,
103            time: Time::_10US,
104            p_channel: input.degrade_saadc(),
105            n_channel: None,
106        }
107    }
108    pub fn differential(p_input: impl Input + 'd, n_input: impl Input + 'd) -> Self {
110        Self {
111            reference: Reference::INTERNAL,
112            gain: Gain::GAIN1_6,
113            resistor: Resistor::BYPASS,
114            time: Time::_10US,
115            p_channel: p_input.degrade_saadc(),
116            n_channel: Some(n_input.degrade_saadc()),
117        }
118    }
119}
120
121#[derive(PartialEq)]
123pub enum CallbackResult {
124    Continue,
126    Stop,
128}
129
130pub struct Saadc<'d, const N: usize> {
132    _p: Peri<'d, peripherals::SAADC>,
133}
134
135impl<'d, const N: usize> Saadc<'d, N> {
136    pub fn new(
138        saadc: Peri<'d, peripherals::SAADC>,
139        _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SAADC, InterruptHandler> + 'd,
140        config: Config,
141        channel_configs: [ChannelConfig; N],
142    ) -> Self {
143        let r = pac::SAADC;
144
145        let Config { resolution, oversample } = config;
146
147        r.enable().write(|w| w.set_enable(true));
149        r.resolution().write(|w| w.set_val(resolution.into()));
150        r.oversample().write(|w| w.set_oversample(oversample.into()));
151
152        for (i, cc) in channel_configs.iter().enumerate() {
153            r.ch(i).pselp().write(|w| w.set_pselp(cc.p_channel.channel()));
154            if let Some(n_channel) = &cc.n_channel {
155                r.ch(i).pseln().write(|w| w.set_pseln(n_channel.channel()));
156            }
157            r.ch(i).config().write(|w| {
158                w.set_refsel(cc.reference.into());
159                w.set_gain(cc.gain.into());
160                w.set_tacq(cc.time.into());
161                w.set_mode(match cc.n_channel {
162                    None => vals::ConfigMode::SE,
163                    Some(_) => vals::ConfigMode::DIFF,
164                });
165                w.set_resp(cc.resistor.into());
166                w.set_resn(vals::Resn::BYPASS);
167                w.set_burst(!matches!(oversample, Oversample::BYPASS));
168            });
169        }
170
171        r.intenclr().write(|w| w.0 = 0x003F_FFFF);
173
174        interrupt::SAADC.unpend();
175        unsafe { interrupt::SAADC.enable() };
176
177        Self { _p: saadc }
178    }
179
180    fn regs() -> pac::saadc::Saadc {
181        pac::SAADC
182    }
183
184    pub async fn calibrate(&self) {
186        let r = Self::regs();
187
188        r.events_calibratedone().write_value(0);
190        r.intenset().write(|w| w.set_calibratedone(true));
191
192        compiler_fence(Ordering::SeqCst);
194
195        r.tasks_calibrateoffset().write_value(1);
196
197        poll_fn(|cx| {
199            let r = Self::regs();
200
201            WAKER.register(cx.waker());
202
203            if r.events_calibratedone().read() != 0 {
204                r.events_calibratedone().write_value(0);
205                return Poll::Ready(());
206            }
207
208            Poll::Pending
209        })
210        .await;
211    }
212
213    pub async fn sample(&mut self, buf: &mut [i16; N]) {
218        let on_drop = OnDrop::new(Self::stop_sampling_immediately);
220
221        let r = Self::regs();
222
223        r.result().ptr().write_value(buf.as_mut_ptr() as u32);
225        r.result().maxcnt().write(|w| w.set_maxcnt(N as _));
226
227        r.events_end().write_value(0);
229        r.intenset().write(|w| w.set_end(true));
230
231        compiler_fence(Ordering::SeqCst);
234
235        r.tasks_start().write_value(1);
236        r.tasks_sample().write_value(1);
237
238        poll_fn(|cx| {
240            let r = Self::regs();
241
242            WAKER.register(cx.waker());
243
244            if r.events_end().read() != 0 {
245                r.events_end().write_value(0);
246                return Poll::Ready(());
247            }
248
249            Poll::Pending
250        })
251        .await;
252
253        drop(on_drop);
254    }
255
256    pub async fn run_task_sampler<F, T: TimerInstance, const N0: usize>(
280        &mut self,
281        timer: Peri<'_, T>,
282        ppi_ch1: Peri<'_, impl ConfigurableChannel>,
283        ppi_ch2: Peri<'_, impl ConfigurableChannel>,
284        frequency: Frequency,
285        sample_counter: u32,
286        bufs: &mut [[[i16; N]; N0]; 2],
287        callback: F,
288    ) where
289        F: FnMut(&[[i16; N]]) -> CallbackResult,
290    {
291        let r = Self::regs();
292
293        let mut start_ppi = Ppi::new_one_to_one(
297            ppi_ch1,
298            Event::from_reg(r.events_end()),
299            Task::from_reg(r.tasks_start()),
300        );
301        start_ppi.enable();
302
303        let timer = Timer::new(timer);
304        timer.set_frequency(frequency);
305        timer.cc(0).write(sample_counter);
306        timer.cc(0).short_compare_clear();
307
308        let timer_cc = timer.cc(0);
309
310        let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(r.tasks_sample()));
311
312        timer.start();
313
314        self.run_sampler(
315            bufs,
316            None,
317            || {
318                sample_ppi.enable();
319            },
320            callback,
321        )
322        .await;
323    }
324
325    async fn run_sampler<I, F, const N0: usize>(
326        &mut self,
327        bufs: &mut [[[i16; N]; N0]; 2],
328        sample_rate_divisor: Option<u16>,
329        mut init: I,
330        mut callback: F,
331    ) where
332        I: FnMut(),
333        F: FnMut(&[[i16; N]]) -> CallbackResult,
334    {
335        let on_drop = OnDrop::new(Self::stop_sampling_immediately);
337
338        let r = Self::regs();
339
340        match sample_rate_divisor {
342            Some(sr) => {
343                r.samplerate().write(|w| {
344                    w.set_cc(sr);
345                    w.set_mode(vals::SamplerateMode::TIMERS);
346                });
347                r.tasks_sample().write_value(1); }
349            None => r.samplerate().write(|w| {
350                w.set_cc(0);
351                w.set_mode(vals::SamplerateMode::TASK);
352            }),
353        }
354
355        r.result().ptr().write_value(bufs[0].as_mut_ptr() as u32);
357        r.result().maxcnt().write(|w| w.set_maxcnt((N0 * N) as _));
358
359        r.events_end().write_value(0);
361        r.events_started().write_value(0);
362        r.intenset().write(|w| {
363            w.set_end(true);
364            w.set_started(true);
365        });
366
367        compiler_fence(Ordering::SeqCst);
370
371        r.tasks_start().write_value(1);
372
373        let mut inited = false;
374        let mut current_buffer = 0;
375
376        let r = poll_fn(|cx| {
378            let r = Self::regs();
379
380            WAKER.register(cx.waker());
381
382            if r.events_end().read() != 0 {
383                compiler_fence(Ordering::SeqCst);
384
385                r.events_end().write_value(0);
386                r.intenset().write(|w| w.set_end(true));
387
388                match callback(&bufs[current_buffer]) {
389                    CallbackResult::Continue => {
390                        let next_buffer = 1 - current_buffer;
391                        current_buffer = next_buffer;
392                    }
393                    CallbackResult::Stop => {
394                        return Poll::Ready(());
395                    }
396                }
397            }
398
399            if r.events_started().read() != 0 {
400                r.events_started().write_value(0);
401                r.intenset().write(|w| w.set_started(true));
402
403                if !inited {
404                    init();
405                    inited = true;
406                }
407
408                let next_buffer = 1 - current_buffer;
409                r.result().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32);
410            }
411
412            Poll::Pending
413        })
414        .await;
415
416        drop(on_drop);
417
418        r
419    }
420
421    fn stop_sampling_immediately() {
423        let r = Self::regs();
424
425        compiler_fence(Ordering::SeqCst);
426
427        r.events_stopped().write_value(0);
428        r.tasks_stop().write_value(1);
429
430        while r.events_stopped().read() == 0 {}
431        r.events_stopped().write_value(0);
432    }
433}
434
435impl<'d> Saadc<'d, 1> {
436    pub async fn run_timer_sampler<I, S, const N0: usize>(
447        &mut self,
448        bufs: &mut [[[i16; 1]; N0]; 2],
449        sample_rate_divisor: u16,
450        sampler: S,
451    ) where
452        S: FnMut(&[[i16; 1]]) -> CallbackResult,
453    {
454        self.run_sampler(bufs, Some(sample_rate_divisor), || {}, sampler).await;
455    }
456}
457
458impl<'d, const N: usize> Drop for Saadc<'d, N> {
459    fn drop(&mut self) {
460        #[cfg(feature = "_nrf52")]
468        {
469            unsafe { core::ptr::write_volatile(0x40007FFC as *mut u32, 0) }
470            unsafe { core::ptr::read_volatile(0x40007FFC as *const ()) }
471            unsafe { core::ptr::write_volatile(0x40007FFC as *mut u32, 1) }
472        }
473        let r = Self::regs();
474        r.enable().write(|w| w.set_enable(false));
475        for i in 0..N {
476            r.ch(i).pselp().write(|w| w.set_pselp(InputChannel::NC));
477            r.ch(i).pseln().write(|w| w.set_pseln(InputChannel::NC));
478        }
479    }
480}
481
482impl From<Gain> for vals::Gain {
483    fn from(gain: Gain) -> Self {
484        match gain {
485            Gain::GAIN1_6 => vals::Gain::GAIN1_6,
486            Gain::GAIN1_5 => vals::Gain::GAIN1_5,
487            Gain::GAIN1_4 => vals::Gain::GAIN1_4,
488            Gain::GAIN1_3 => vals::Gain::GAIN1_3,
489            Gain::GAIN1_2 => vals::Gain::GAIN1_2,
490            Gain::GAIN1 => vals::Gain::GAIN1,
491            Gain::GAIN2 => vals::Gain::GAIN2,
492            Gain::GAIN4 => vals::Gain::GAIN4,
493        }
494    }
495}
496
497#[non_exhaustive]
499#[derive(Clone, Copy)]
500pub enum Gain {
501    GAIN1_6 = 0,
503    GAIN1_5 = 1,
505    GAIN1_4 = 2,
507    GAIN1_3 = 3,
509    GAIN1_2 = 4,
511    GAIN1 = 5,
513    GAIN2 = 6,
515    GAIN4 = 7,
517}
518
519impl From<Reference> for vals::Refsel {
520    fn from(reference: Reference) -> Self {
521        match reference {
522            Reference::INTERNAL => vals::Refsel::INTERNAL,
523            Reference::VDD1_4 => vals::Refsel::VDD1_4,
524        }
525    }
526}
527
528#[non_exhaustive]
530#[derive(Clone, Copy)]
531pub enum Reference {
532    INTERNAL = 0,
534    VDD1_4 = 1,
536}
537
538impl From<Resistor> for vals::Resp {
539    fn from(resistor: Resistor) -> Self {
540        match resistor {
541            Resistor::BYPASS => vals::Resp::BYPASS,
542            Resistor::PULLDOWN => vals::Resp::PULLDOWN,
543            Resistor::PULLUP => vals::Resp::PULLUP,
544            Resistor::VDD1_2 => vals::Resp::VDD1_2,
545        }
546    }
547}
548
549#[non_exhaustive]
551#[derive(Clone, Copy)]
552pub enum Resistor {
553    BYPASS = 0,
555    PULLDOWN = 1,
557    PULLUP = 2,
559    VDD1_2 = 3,
561}
562
563impl From<Time> for vals::Tacq {
564    fn from(time: Time) -> Self {
565        match time {
566            Time::_3US => vals::Tacq::_3US,
567            Time::_5US => vals::Tacq::_5US,
568            Time::_10US => vals::Tacq::_10US,
569            Time::_15US => vals::Tacq::_15US,
570            Time::_20US => vals::Tacq::_20US,
571            Time::_40US => vals::Tacq::_40US,
572        }
573    }
574}
575
576#[non_exhaustive]
578#[derive(Clone, Copy)]
579pub enum Time {
580    _3US = 0,
582    _5US = 1,
584    _10US = 2,
586    _15US = 3,
588    _20US = 4,
590    _40US = 5,
592}
593
594impl From<Oversample> for vals::Oversample {
595    fn from(oversample: Oversample) -> Self {
596        match oversample {
597            Oversample::BYPASS => vals::Oversample::BYPASS,
598            Oversample::OVER2X => vals::Oversample::OVER2X,
599            Oversample::OVER4X => vals::Oversample::OVER4X,
600            Oversample::OVER8X => vals::Oversample::OVER8X,
601            Oversample::OVER16X => vals::Oversample::OVER16X,
602            Oversample::OVER32X => vals::Oversample::OVER32X,
603            Oversample::OVER64X => vals::Oversample::OVER64X,
604            Oversample::OVER128X => vals::Oversample::OVER128X,
605            Oversample::OVER256X => vals::Oversample::OVER256X,
606        }
607    }
608}
609
610#[non_exhaustive]
612#[derive(Clone, Copy)]
613pub enum Oversample {
614    BYPASS = 0,
616    OVER2X = 1,
618    OVER4X = 2,
620    OVER8X = 3,
622    OVER16X = 4,
624    OVER32X = 5,
626    OVER64X = 6,
628    OVER128X = 7,
630    OVER256X = 8,
632}
633
634impl From<Resolution> for vals::Val {
635    fn from(resolution: Resolution) -> Self {
636        match resolution {
637            Resolution::_8BIT => vals::Val::_8BIT,
638            Resolution::_10BIT => vals::Val::_10BIT,
639            Resolution::_12BIT => vals::Val::_12BIT,
640            Resolution::_14BIT => vals::Val::_14BIT,
641        }
642    }
643}
644
645#[non_exhaustive]
647#[derive(Clone, Copy)]
648pub enum Resolution {
649    _8BIT = 0,
651    _10BIT = 1,
653    _12BIT = 2,
655    _14BIT = 3,
657}
658
659pub(crate) trait SealedInput {
660    fn channel(&self) -> InputChannel;
661}
662
663#[allow(private_bounds)]
665pub trait Input: SealedInput + Sized {
666    fn degrade_saadc<'a>(self) -> AnyInput<'a>
671    where
672        Self: 'a,
673    {
674        AnyInput {
675            channel: self.channel(),
676            _phantom: core::marker::PhantomData,
677        }
678    }
679}
680
681pub struct AnyInput<'a> {
686    channel: InputChannel,
687    _phantom: PhantomData<&'a ()>,
688}
689
690impl<'a> AnyInput<'a> {
691    pub fn reborrow(&mut self) -> AnyInput<'_> {
695        Self {
698            channel: self.channel,
699            _phantom: PhantomData,
700        }
701    }
702}
703
704impl SealedInput for AnyInput<'_> {
705    fn channel(&self) -> InputChannel {
706        self.channel
707    }
708}
709
710impl Input for AnyInput<'_> {}
711
712macro_rules! impl_saadc_input {
713    ($pin:ident, $ch:ident) => {
714        impl_saadc_input!(@local, crate::Peri<'_, crate::peripherals::$pin>, $ch);
715    };
716    (@local, $pin:ty, $ch:ident) => {
717        impl crate::saadc::SealedInput for $pin {
718            fn channel(&self) -> crate::saadc::InputChannel {
719                crate::saadc::InputChannel::$ch
720            }
721        }
722        impl crate::saadc::Input for $pin {}
723    };
724}
725
726pub struct VddInput;
729
730impl_peripheral!(VddInput);
731#[cfg(not(feature = "_nrf91"))]
732impl_saadc_input!(@local, VddInput, VDD);
733#[cfg(feature = "_nrf91")]
734impl_saadc_input!(@local, VddInput, VDD_GPIO);
735
736#[cfg(any(feature = "_nrf5340-app", feature = "nrf52833", feature = "nrf52840"))]
739pub struct VddhDiv5Input;
740
741#[cfg(any(feature = "_nrf5340-app", feature = "nrf52833", feature = "nrf52840"))]
742impl_peripheral!(VddhDiv5Input);
743
744#[cfg(any(feature = "_nrf5340-app", feature = "nrf52833", feature = "nrf52840"))]
745impl_saadc_input!(@local, VddhDiv5Input, VDDHDIV5);