atsamd_hal/peripherals/adc/
d11.rs

1//! Analogue-to-Digital Conversion
2use atsamd_hal_macros::hal_cfg;
3
4use crate::clock::GenericClockController;
5use crate::ehal_02::adc::{Channel, OneShot};
6use crate::gpio::*;
7use crate::pac::{self, adc, Pm};
8
9/// Samples per reading
10pub use adc::avgctrl::Samplenumselect as SampleRate;
11/// Clock frequency relative to the system clock
12pub use adc::ctrlb::Prescalerselect as Prescaler;
13/// Reading resolution in bits
14///
15/// For the resolution of Arduino boards,
16/// see the [analogueRead](https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/) docs.
17pub use adc::ctrlb::Resselselect as Resolution;
18/// The gain level
19pub use adc::inputctrl::Gainselect as Gain;
20/// Reference voltage (or its source)
21pub use adc::refctrl::Refselselect as Reference;
22
23/// `Adc` encapsulates the device ADC
24pub struct Adc<ADC> {
25    adc: ADC,
26}
27
28impl Adc<pac::Adc> {
29    /// Create a new `Adc` instance. The default configuration is:
30    /// * 1/32 prescaler
31    /// * 12 bit resolution
32    /// * 1 sample
33    /// * 1/2 gain
34    /// * 1/2 VDDANA reference voltage
35    #[allow(clippy::self_named_constructors)]
36    pub fn adc(adc: pac::Adc, pm: &mut Pm, clocks: &mut GenericClockController) -> Self {
37        pm.apbcmask().modify(|_, w| w.adc_().set_bit());
38
39        // set to 1 / (1 / (48000000 / 32) * 6) = 250000 SPS
40        let gclk0 = clocks.gclk0();
41        clocks.adc(&gclk0).expect("adc clock setup failed");
42        while adc.status().read().syncbusy().bit_is_set() {}
43
44        adc.ctrla().modify(|_, w| w.swrst().set_bit());
45        while adc.status().read().syncbusy().bit_is_set() {}
46
47        adc.ctrlb().modify(|_, w| {
48            w.prescaler().div32();
49            w.ressel()._12bit()
50        });
51        while adc.status().read().syncbusy().bit_is_set() {}
52
53        adc.sampctrl().modify(|_, w| unsafe { w.samplen().bits(5) }); //sample length
54        while adc.status().read().syncbusy().bit_is_set() {}
55
56        adc.inputctrl().modify(|_, w| w.muxneg().gnd()); // No negative input (internal gnd)
57        while adc.status().read().syncbusy().bit_is_set() {}
58
59        let mut newadc = Self { adc };
60        newadc.samples(adc::avgctrl::Samplenumselect::_1);
61        newadc.gain(adc::inputctrl::Gainselect::Div2);
62        newadc.reference(adc::refctrl::Refselselect::Intvcc1);
63
64        newadc
65    }
66
67    /// Set the sample rate
68    pub fn samples(&mut self, samples: SampleRate) {
69        use adc::avgctrl::Samplenumselect;
70        self.adc.avgctrl().modify(|_, w| {
71            w.samplenum().variant(samples);
72            unsafe {
73                // Table 32-3 (32.6.7) specifies the adjres
74                // values necessary for each SAMPLENUM value.
75                w.adjres().bits(match samples {
76                    Samplenumselect::_1 => 0,
77                    Samplenumselect::_2 => 1,
78                    Samplenumselect::_4 => 2,
79                    Samplenumselect::_8 => 3,
80                    _ => 4,
81                })
82            }
83        });
84        while self.adc.status().read().syncbusy().bit_is_set() {}
85    }
86
87    /// Set the gain factor
88    pub fn gain(&mut self, gain: Gain) {
89        self.adc.inputctrl().modify(|_, w| w.gain().variant(gain));
90        while self.adc.status().read().syncbusy().bit_is_set() {}
91    }
92
93    /// Set the voltage reference
94    pub fn reference(&mut self, reference: Reference) {
95        self.adc
96            .refctrl()
97            .modify(|_, w| w.refsel().variant(reference));
98        while self.adc.status().read().syncbusy().bit_is_set() {}
99    }
100
101    /// Set the prescaler for adjusting the clock relative to the system clock
102    pub fn prescaler(&mut self, prescaler: Prescaler) {
103        self.adc
104            .ctrlb()
105            .modify(|_, w| w.prescaler().variant(prescaler));
106        while self.adc.status().read().syncbusy().bit_is_set() {}
107    }
108
109    /// Set the input resolution.
110    pub fn resolution(&mut self, resolution: Resolution) {
111        self.adc
112            .ctrlb()
113            .modify(|_, w| w.ressel().variant(resolution));
114        while self.adc.status().read().syncbusy().bit_is_set() {}
115    }
116
117    fn power_up(&mut self) {
118        while self.adc.status().read().syncbusy().bit_is_set() {}
119        self.adc.ctrla().modify(|_, w| w.enable().set_bit());
120        while self.adc.status().read().syncbusy().bit_is_set() {}
121    }
122
123    fn power_down(&mut self) {
124        while self.adc.status().read().syncbusy().bit_is_set() {}
125        self.adc.ctrla().modify(|_, w| w.enable().clear_bit());
126        while self.adc.status().read().syncbusy().bit_is_set() {}
127    }
128
129    fn convert(&mut self) -> u16 {
130        self.adc.swtrig().modify(|_, w| w.start().set_bit());
131        while self.adc.intflag().read().resrdy().bit_is_clear() {}
132        while self.adc.status().read().syncbusy().bit_is_set() {}
133
134        // Clear the interrupt flag
135        self.adc.intflag().modify(|_, w| w.resrdy().set_bit());
136
137        // Start conversion again, since The first conversion after the reference is
138        // changed must not be used.
139        self.adc.swtrig().modify(|_, w| w.start().set_bit());
140        while self.adc.intflag().read().resrdy().bit_is_clear() {}
141        while self.adc.status().read().syncbusy().bit_is_set() {}
142
143        self.adc.result().read().result().bits()
144    }
145}
146
147impl<WORD, PIN> OneShot<pac::Adc, WORD, PIN> for Adc<pac::Adc>
148where
149    WORD: From<u16>,
150    PIN: Channel<pac::Adc, ID = u8>,
151{
152    type Error = ();
153
154    fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
155        let chan = PIN::channel();
156        while self.adc.status().read().syncbusy().bit_is_set() {}
157
158        self.adc
159            .inputctrl()
160            .modify(|_, w| unsafe { w.muxpos().bits(chan) });
161        self.power_up();
162        let result = self.convert();
163        self.power_down();
164
165        Ok(result.into())
166    }
167}
168
169macro_rules! adc_pins {
170    (
171        $(
172            $( #[$cfg:meta] )?
173            $PinId:ident: $CHAN:literal
174        ),+
175        $(,)?
176    ) => {
177        $(
178            $( #[$cfg] )?
179            impl Channel<$crate::pac::Adc> for Pin<$PinId, AlternateB> {
180               type ID = u8;
181               fn channel() -> u8 { $CHAN }
182            }
183        )+
184    }
185}
186
187#[hal_cfg("adc-d11")]
188adc_pins! {
189    #[hal_cfg("pa02")]
190    PA02: 0,
191    #[hal_cfg("pa03")]
192    PA03: 1,
193    #[hal_cfg("pa04")]
194    PA04: 2,
195    #[hal_cfg("pa05")]
196    PA05: 3,
197    #[hal_cfg("pa06")]
198    PA06: 4,
199    #[hal_cfg("pa07")]
200    PA07: 5,
201    #[hal_cfg("pa14")]
202    PA14: 6,
203    #[hal_cfg("pa15")]
204    PA15: 7,
205    #[hal_cfg("pa10")]
206    PA10: 8,
207    #[hal_cfg("pa11")]
208    PA11: 9,
209}
210
211#[hal_cfg("adc-d21")]
212adc_pins! {
213    #[hal_cfg("pa02")]
214    PA02: 0,
215    #[hal_cfg("pa03")]
216    PA03: 1,
217    #[hal_cfg("pb08")]
218    PB08: 2,
219    #[hal_cfg("pb09")]
220    PB09: 3,
221    #[hal_cfg("pa04")]
222    PA04: 4,
223    #[hal_cfg("pa05")]
224    PA05: 5,
225    #[hal_cfg("pa06")]
226    PA06: 6,
227    #[hal_cfg("pa07")]
228    PA07: 7,
229    #[hal_cfg("pb00")]
230    PB00: 8,
231    #[hal_cfg("pb01")]
232    PB01: 9,
233    #[hal_cfg("pb02")]
234    PB02: 10,
235    #[hal_cfg("pb03")]
236    PB03: 11,
237    #[hal_cfg("pb04")]
238    PB04: 12,
239    #[hal_cfg("pb05")]
240    PB05: 13,
241    #[hal_cfg("pb06")]
242    PB06: 14,
243    #[hal_cfg("pb07")]
244    PB07: 15,
245    #[hal_cfg("pa08")]
246    PA08: 16,
247    #[hal_cfg("pa09")]
248    PA09: 17,
249    #[hal_cfg("pa10")]
250    PA10: 18,
251    #[hal_cfg("pa11")]
252    PA11: 19,
253}