atsamd_hal/peripherals/adc/
d5x.rs

1//! Analogue-to-Digital Conversion
2use atsamd_hal_macros::hal_cfg;
3
4use crate::clock::GenericClockController;
5#[rustfmt::skip]
6use crate::gpio::*;
7use crate::ehal_02::adc::{Channel, OneShot};
8use crate::pac::gclk::genctrl::Srcselect::Dfll;
9use crate::pac::gclk::pchctrl::Genselect;
10use crate::pac::{adc0, Adc0, Adc1, Mclk};
11
12use crate::calibration;
13
14/// Samples per reading
15pub use adc0::avgctrl::Samplenumselect as SampleRate;
16/// Clock frequency relative to the system clock
17pub use adc0::ctrla::Prescalerselect as Prescaler;
18/// Reading resolution in bits
19pub use adc0::ctrlb::Resselselect as Resolution;
20/// Reference voltage (or its source)
21pub use adc0::refctrl::Refselselect as Reference;
22
23/// An ADC where results are accessible via interrupt servicing.
24pub struct InterruptAdc<ADC, C>
25where
26    C: ConversionMode<ADC>,
27{
28    adc: Adc<ADC>,
29    m: core::marker::PhantomData<C>,
30}
31
32/// `Adc` encapsulates the device ADC
33pub struct Adc<ADC> {
34    adc: ADC,
35}
36
37/// Describes how an interrupt-driven ADC should finalize the peripheral
38/// upon the completion of a conversion.
39pub trait ConversionMode<ADC> {
40    fn on_start(adc: &mut Adc<ADC>);
41    fn on_complete(adc: &mut Adc<ADC>);
42    fn on_stop(adc: &mut Adc<ADC>);
43}
44
45pub struct SingleConversion;
46pub struct FreeRunning;
47
48macro_rules! adc_hal {
49    ($($ADC:ident: ($init:ident, $mclk:ident, $apmask:ident, $compcal:ident, $refcal:ident, $r2rcal:ident),)+) => {
50        $(
51impl Adc<$ADC> {
52    pub fn $init(adc: $ADC, mclk: &mut Mclk, clocks: &mut GenericClockController, gclk:Genselect) -> Self {
53        mclk.$mclk().modify(|_, w| w.$apmask().set_bit());
54        // set to 1/(1/(48000000/32) * 6) = 250000 SPS
55        let adc_clock = clocks.configure_gclk_divider_and_source(gclk, 1, Dfll, false)
56            .expect("adc clock setup failed");
57        clocks.$init(&adc_clock).expect("adc clock setup failed");
58        adc.ctrla().modify(|_, w| w.prescaler().div32());
59        adc.ctrlb().modify(|_, w| w.ressel()._12bit());
60        while adc.syncbusy().read().ctrlb().bit_is_set() {}
61        adc.sampctrl().modify(|_, w| unsafe {w.samplen().bits(5)}); // sample length
62        while adc.syncbusy().read().sampctrl().bit_is_set() {}
63        adc.inputctrl().modify(|_, w| w.muxneg().gnd()); // No negative input (internal gnd)
64        while adc.syncbusy().read().inputctrl().bit_is_set() {}
65
66        adc.calib().write(|w| unsafe {
67            w.biascomp().bits(calibration::$compcal());
68            w.biasrefbuf().bits(calibration::$refcal());
69            w.biasr2r().bits(calibration::$r2rcal())
70        });
71
72        let mut newadc = Self { adc };
73        newadc.samples(adc0::avgctrl::Samplenumselect::_1);
74        newadc.reference(adc0::refctrl::Refselselect::Intvcc1);
75
76        newadc
77    }
78
79    /// Set the sample rate
80    pub fn samples(&mut self, samples: SampleRate) {
81        use adc0::avgctrl::Samplenumselect;
82        self.adc.avgctrl().modify(|_, w| {
83            w.samplenum().variant(samples);
84            unsafe {
85                // Table 45-3 (45.6.2.10) specifies the adjres
86                // values necessary for each SAMPLENUM value.
87                w.adjres().bits(match samples {
88                    Samplenumselect::_1 => 0,
89                    Samplenumselect::_2 => 1,
90                    Samplenumselect::_4 => 2,
91                    Samplenumselect::_8 => 3,
92                    _ => 4,
93                })
94            }
95        });
96        while self.adc.syncbusy().read().avgctrl().bit_is_set() {}
97    }
98
99    /// Set the voltage reference
100    pub fn reference(&mut self, reference: Reference) {
101        self.adc
102            .refctrl()
103            .modify(|_, w| w.refsel().variant(reference));
104        while self.adc.syncbusy().read().refctrl().bit_is_set() {}
105    }
106
107    /// Set the prescaler for adjusting the clock relative to the system clock
108    pub fn prescaler(&mut self, prescaler: Prescaler) {
109        self.adc
110            .ctrla()
111            .modify(|_, w| w.prescaler().variant(prescaler));
112        // Note there is no syncbusy for ctrla
113    }
114
115    /// Set the input resolution
116    pub fn resolution(&mut self, resolution: Resolution) {
117        self.adc
118            .ctrlb()
119            .modify(|_, w| w.ressel().variant(resolution));
120        while self.adc.syncbusy().read().ctrlb().bit_is_set() {}
121    }
122
123    fn power_up(&mut self) {
124        while self.adc.syncbusy().read().enable().bit_is_set() {}
125        self.adc.ctrla().modify(|_, w| w.enable().set_bit());
126        while self.adc.syncbusy().read().enable().bit_is_set() {}
127    }
128
129    fn power_down(&mut self) {
130        while self.adc.syncbusy().read().enable().bit_is_set() {}
131        self.adc.ctrla().modify(|_, w| w.enable().clear_bit());
132        while self.adc.syncbusy().read().enable().bit_is_set() {}
133    }
134
135    #[inline(always)]
136    fn start_conversion(&mut self) {
137        // start conversion
138        self.adc.swtrig().modify(|_, w| w.start().set_bit());
139        // do it again because the datasheet tells us to
140        self.adc.swtrig().modify(|_, w| w.start().set_bit());
141    }
142
143    fn enable_freerunning(&mut self) {
144        self.adc.ctrlb().modify(|_, w| w.freerun().set_bit());
145        while self.adc.syncbusy().read().ctrlb().bit_is_set() {}
146    }
147
148    fn disable_freerunning(&mut self) {
149        self.adc.ctrlb().modify(|_, w| w.freerun().set_bit());
150        while self.adc.syncbusy().read().ctrlb().bit_is_set() {}
151    }
152
153    fn synchronous_convert(&mut self) -> u16 {
154        self.start_conversion();
155        while self.adc.intflag().read().resrdy().bit_is_clear() {}
156
157        self.adc.result().read().result().bits()
158    }
159
160    /// Enables an interrupt when conversion is ready.
161    fn enable_interrupts(&mut self) {
162        self.adc.intflag().write(|w| w.resrdy().set_bit());
163        self.adc.intenset().write(|w| w.resrdy().set_bit());
164    }
165
166    /// Disables the interrupt for when conversion is ready.
167    fn disable_interrupts(&mut self) {
168        self.adc.intenclr().write(|w| w.resrdy().set_bit());
169    }
170
171    fn service_interrupt_ready(&mut self) -> Option<u16> {
172        if self.adc.intflag().read().resrdy().bit_is_set() {
173            self.adc.intflag().write(|w| w.resrdy().set_bit());
174
175            Some(self.adc.result().read().result().bits())
176        } else {
177            None
178        }
179    }
180
181    /// Sets the mux to a particular pin. The pin mux is enabled-protected,
182    /// so must be called while the peripheral is disabled.
183    fn mux<PIN: Channel<$ADC, ID=u8>>(&mut self, _pin: &mut PIN) {
184        let chan = PIN::channel();
185        while self.adc.syncbusy().read().inputctrl().bit_is_set() {}
186        self.adc.inputctrl().modify(|_, w| unsafe{ w.muxpos().bits(chan) });
187    }
188}
189
190impl ConversionMode<$ADC> for SingleConversion  {
191    fn on_start(_adc: &mut Adc<$ADC>) {
192    }
193    fn on_complete(adc: &mut Adc<$ADC>) {
194        adc.disable_interrupts();
195        adc.power_down();
196    }
197    fn on_stop(_adc: &mut Adc<$ADC>) {
198    }
199}
200
201impl ConversionMode<$ADC> for FreeRunning {
202    fn on_start(adc: &mut Adc<$ADC>) {
203        adc.enable_freerunning();
204    }
205    fn on_complete(_adc: &mut Adc<$ADC>) {
206    }
207    fn on_stop(adc: &mut Adc<$ADC>) {
208        adc.disable_interrupts();
209        adc.power_down();
210        adc.disable_freerunning();
211    }
212}
213
214impl<C> InterruptAdc<$ADC, C>
215    where C: ConversionMode<$ADC>
216{
217    pub fn service_interrupt_ready(&mut self) -> Option<u16> {
218        if let Some(res) = self.adc.service_interrupt_ready() {
219            C::on_complete(&mut self.adc);
220            Some(res)
221        } else {
222            None
223        }
224    }
225
226    /// Starts a conversion sampling the specified pin.
227    pub fn start_conversion<PIN: Channel<$ADC, ID=u8>>(&mut self, pin: &mut PIN) {
228        self.adc.mux(pin);
229        self.adc.power_up();
230        C::on_start(&mut self.adc);
231        self.adc.enable_interrupts();
232        self.adc.start_conversion();
233    }
234
235    pub fn stop_conversion(&mut self) {
236        C::on_stop(&mut self.adc);
237    }
238}
239
240impl<C> From<Adc<$ADC>> for InterruptAdc<$ADC, C>
241    where C: ConversionMode<$ADC>
242{
243    fn from(adc: Adc<$ADC>) -> Self {
244        Self {
245            adc,
246            m: core::marker::PhantomData{},
247        }
248    }
249}
250
251impl<WORD, PIN> OneShot<$ADC, WORD, PIN> for Adc<$ADC>
252where
253   WORD: From<u16>,
254   PIN: Channel<$ADC, ID=u8>,
255{
256   type Error = ();
257
258   fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
259        self.mux(pin);
260        self.power_up();
261        let result = self.synchronous_convert();
262        self.power_down();
263        Ok(result.into())
264   }
265}
266        )+
267    }
268}
269
270adc_hal! {
271    Adc0: (adc0, apbdmask, adc0_, adc0_biascomp_scale_cal, adc0_biasref_scale_cal, adc0_biasr2r_scale_cal),
272    Adc1: (adc1, apbdmask, adc1_, adc1_biascomp_scale_cal, adc1_biasref_scale_cal, adc1_biasr2r_scale_cal),
273}
274
275macro_rules! adc_pins {
276    (
277        $(
278            $( #[$cfg:meta] )?
279            $PinId:ident: ($ADC:ident, $CHAN:literal)
280        ),+
281        $(,)?
282    ) => {
283        $(
284            $( #[$cfg] )?
285            impl Channel<$ADC> for Pin<$PinId, AlternateB> {
286               type ID = u8;
287               fn channel() -> u8 { $CHAN }
288            }
289        )+
290    }
291}
292
293adc_pins! {
294    #[hal_cfg("pa02")]
295    PA02: (Adc0, 0),
296    #[hal_cfg("pa03")]
297    PA03: (Adc0, 1),
298    #[hal_cfg("pb08")]
299    PB08: (Adc0, 2),
300    #[hal_cfg("pb09")]
301    PB09: (Adc0, 3),
302    #[hal_cfg("pa04")]
303    PA04: (Adc0, 4),
304    #[hal_cfg("pa05")]
305    PA05: (Adc0, 5),
306    #[hal_cfg("pa06")]
307    PA06: (Adc0, 6),
308    #[hal_cfg("pa07")]
309    PA07: (Adc0, 7),
310    #[hal_cfg("pa08")]
311    PA08: (Adc0, 8),
312    #[hal_cfg("pa09")]
313    PA09: (Adc0, 9),
314    #[hal_cfg("pa10")]
315    PA10: (Adc0, 10),
316    #[hal_cfg("pa11")]
317    PA11: (Adc0, 11),
318    #[hal_cfg("pb00")]
319    PB00: (Adc0, 12),
320    #[hal_cfg("pb01")]
321    PB01: (Adc0, 13),
322    #[hal_cfg("pb02")]
323    PB02: (Adc0, 14),
324    #[hal_cfg("pb03")]
325    PB03: (Adc0, 15),
326
327    #[hal_cfg("pb08")]
328    PB08: (Adc1, 0),
329    #[hal_cfg("pb09")]
330    PB09: (Adc1, 1),
331    #[hal_cfg("pa08")]
332    PA08: (Adc1, 2),
333    #[hal_cfg("pa09")]
334    PA09: (Adc1, 3),
335    #[hal_cfg("pc02")]
336    PC02: (Adc1, 4),
337    #[hal_cfg("pc03")]
338    PC03: (Adc1, 5),
339    #[hal_cfg("pb04")]
340    PB04: (Adc1, 6),
341    #[hal_cfg("pb05")]
342    PB05: (Adc1, 7),
343    #[hal_cfg("pb06")]
344    PB06: (Adc1, 8),
345    #[hal_cfg("pb07")]
346    PB07: (Adc1, 9),
347    #[hal_cfg("pc00")]
348    PC00: (Adc1, 10),
349    #[hal_cfg("pc01")]
350    PC01: (Adc1, 11),
351    #[hal_cfg("pc30")]
352    PC30: (Adc1, 12),
353    #[hal_cfg("pc31")]
354    PC31: (Adc1, 13),
355    #[hal_cfg("pd00")]
356    PD00: (Adc1, 14),
357    #[hal_cfg("pd01")]
358    PD01: (Adc1, 15),
359}