atsamd_hal/peripherals/adc/
mod.rs1use core::ops::Deref;
26
27use atsamd_hal_macros::{hal_cfg, hal_module};
28use pac::Peripherals;
29
30use crate::{gpio::AnyPin, pac, typelevel::Sealed};
31
32#[hal_module(
33 any("adc-d11", "adc-d21") => "d11/mod.rs",
34 "adc-d5x" => "d5x/mod.rs",
35)]
36mod impls {}
37
38pub use impls::*;
39
40#[cfg(feature = "async")]
41mod async_api;
42#[cfg(feature = "async")]
43pub use async_api::*;
44
45mod builder;
46pub use builder::*;
47
48#[hal_cfg(any("adc-d11", "adc-d21"))]
49use crate::pac::adc as adc0;
50#[hal_cfg("adc-d5x")]
51use crate::pac::adc0;
52
53pub use adc0::refctrl::Refselselect as Reference;
54
55const ADC_SETTINGS_INTERNAL_READ: AdcSettings = AdcSettings {
58 clk_divider: Prescaler::Div64,
59 sample_clock_cycles: 32,
60 accumulation: Accumulation::average(SampleCount::_4),
61 vref: Reference::Intvcc1,
62};
63
64#[hal_cfg(any("adc-d21", "adc-d11"))]
66const ADC_SETTINGS_INTERNAL_READ_D21_TEMP: AdcSettings = AdcSettings {
67 clk_divider: Prescaler::Div64,
68 sample_clock_cycles: 32,
69 accumulation: Accumulation::average(SampleCount::_4),
70 vref: Reference::Int1v,
71};
72
73#[derive(Debug, Copy, Clone)]
75#[cfg_attr(feature = "defmt", derive(defmt::Format))]
76pub enum Error {
77 ClockTooFast,
89 BufferOverrun,
91}
92
93#[hal_cfg("adc-d5x")]
95#[derive(Copy, Clone, PartialEq, Eq)]
96#[repr(u8)]
97pub enum CpuVoltageSource {
98 Core = 0x18,
100 Vbat = 0x19,
102 Io = 0x1A,
104}
105
106#[hal_cfg(any("adc-d21", "adc-d11"))]
108#[derive(Copy, Clone, PartialEq, Eq)]
109#[repr(u8)]
110pub enum CpuVoltageSource {
111 Bandgap = 0x19,
113 Core = 0x1A,
115 Io = 0x1B,
117}
118
119bitflags::bitflags! {
120 #[derive(Clone, Copy)]
122 pub struct Flags: u8 {
123 const WINMON = 0x04;
125 const OVERRUN = 0x02;
127 const RESRDY = 0x01;
129 }
130}
131
132pub trait PrimaryAdc {}
134
135pub trait AdcInstance {
137 #[cfg(feature = "async")]
138 type Interrupt: crate::async_hal::interrupts::InterruptSource;
139
140 type Instance: Deref<Target = adc0::RegisterBlock>;
142
143 #[hal_cfg("adc-d5x")]
144 type ClockId: crate::clock::v2::apb::ApbId + crate::clock::v2::pclk::PclkId;
145
146 fn peripheral_reg_block(p: &mut Peripherals) -> &adc0::RegisterBlock;
147
148 #[hal_cfg(any("adc-d11", "adc-d21"))]
149 fn enable_pm(pm: &mut pac::Pm);
150
151 fn calibrate(instance: &Self::Instance);
152
153 #[cfg(feature = "async")]
154 fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker;
155}
156
157pub trait AdcPin<I>: AnyPin<Mode = crate::gpio::AlternateB> + Sealed
159where
160 I: AdcInstance,
161{
162 const CHANNEL: u8;
163}
164
165#[hal_cfg(any("adc-d11", "adc-d21"))]
167pub struct Adc<I: AdcInstance> {
168 adc: I::Instance,
169 cfg: AdcSettings,
170 discard: bool,
171}
172
173#[hal_cfg("adc-d5x")]
175pub struct Adc<I: AdcInstance> {
176 adc: I::Instance,
177 _apbclk: crate::clock::v2::apb::ApbClk<I::ClockId>,
178 cfg: AdcSettings,
179 discard: bool,
180}
181
182#[cfg(feature = "async")]
183pub struct FutureAdc<I: AdcInstance, F> {
184 inner: Adc<I>,
185 irqs: F,
186}
187
188impl<I: AdcInstance> Adc<I> {
189 #[hal_cfg("adc-d5x")]
205 #[inline]
206 pub(crate) fn new<PS: crate::clock::v2::pclk::PclkSourceId>(
207 adc: I::Instance,
208 settings: AdcSettings,
209 clk: crate::clock::v2::apb::ApbClk<I::ClockId>,
210 pclk: &crate::clock::v2::pclk::Pclk<I::ClockId, PS>,
211 ) -> Result<Self, Error> {
212 if pclk.freq() > fugit::HertzU32::from_raw(100_000_000) {
222 return Err(Error::ClockTooFast);
224 }
225
226 let mut new_adc = Self {
227 adc,
228 _apbclk: clk,
229 cfg: settings,
230 discard: true,
231 };
232 new_adc.configure(settings);
233 Ok(new_adc)
234 }
235
236 #[hal_cfg(any("adc-d11", "adc-d21"))]
244 #[inline]
245 pub(crate) fn new(
246 adc: I::Instance,
247 settings: AdcSettings,
248 pm: &mut pac::Pm,
249 clock: &crate::clock::AdcClock,
250 ) -> Result<Self, Error> {
251 if (clock.freq() as crate::time::Hertz).to_Hz() > 48_000_000 {
252 return Err(Error::ClockTooFast);
254 }
255
256 I::enable_pm(pm);
257 let mut new_adc = Self {
258 adc,
259 cfg: settings,
260 discard: true,
261 };
262 new_adc.configure(settings);
263 Ok(new_adc)
264 }
265
266 #[cfg(feature = "async")]
276 #[atsamd_hal_macros::hal_macro_helper]
277 #[inline]
278 pub fn into_future<F>(self, irqs: F) -> FutureAdc<I, F>
279 where
280 F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
281 {
282 use crate::async_hal::interrupts::InterruptSource;
283 unsafe {
284 I::Interrupt::unpend();
285 I::Interrupt::enable();
286 }
287 FutureAdc { inner: self, irqs }
288 }
289}
290
291impl<I: AdcInstance> Adc<I> {
292 fn reading_to_f32(&self, raw: u16) -> f32 {
295 let max = match self.cfg.accumulation.output_resolution() {
296 Resolution::_16bit => 65535,
297 Resolution::_12bit => 4095,
298 Resolution::_10bit => 1023,
299 Resolution::_8bit => 255,
300 };
301 raw as f32 / max as f32
302 }
303
304 pub(crate) fn with_specific_settings<F: FnOnce(&mut Adc<I>) -> T, T>(
310 &mut self,
311 settings: AdcSettings,
312 f: F,
313 ) -> T {
314 let old_cfg = self.cfg;
315 self.configure(settings);
316 let ret = f(self);
317 self.configure(old_cfg);
318 ret
319 }
320
321 #[inline]
322 fn set_reference(&mut self, reference: Reference) {
323 self.adc
324 .refctrl()
325 .modify(|_, w| w.refsel().variant(reference));
326 self.sync();
327 }
328
329 #[inline]
331 pub fn read<P: AdcPin<I>>(&mut self, _pin: &mut P) -> u16 {
332 self.read_channel(P::CHANNEL)
333 }
334
335 #[inline]
337 fn read_channel(&mut self, ch: u8) -> u16 {
338 self.clear_all_flags();
340 self.disable_interrupts(Flags::all());
341 self.disable_freerunning();
342 self.sync();
343 self.mux(ch);
344 self.check_read_discard();
345 self.start_conversion();
346 while !self.read_flags().contains(Flags::RESRDY) {
347 core::hint::spin_loop();
348 }
349 self.conversion_result()
350 }
351
352 #[inline]
355 pub fn check_read_discard(&mut self) {
356 if self.discard {
357 self.start_conversion();
358 while !self.read_flags().contains(Flags::RESRDY) {
359 core::hint::spin_loop();
360 }
361 self.discard = false;
362 }
363 }
364
365 #[inline]
367 pub fn read_buffer<P: AdcPin<I>>(
368 &mut self,
369 _pin: &mut P,
370 dst: &mut [u16],
371 ) -> Result<(), Error> {
372 self.read_buffer_channel(P::CHANNEL, dst)
373 }
374
375 #[inline]
377 fn read_buffer_channel(&mut self, ch: u8, dst: &mut [u16]) -> Result<(), Error> {
378 self.clear_all_flags();
380 self.disable_interrupts(Flags::all());
381 self.mux(ch);
382 self.enable_freerunning();
383 self.start_conversion();
384 if self.discard {
385 while !self.read_flags().contains(Flags::RESRDY) {
387 core::hint::spin_loop();
388 }
389 self.clear_all_flags();
390 self.discard = false;
391 }
392
393 for result in dst.iter_mut() {
394 while !self.read_flags().contains(Flags::RESRDY) {
395 core::hint::spin_loop();
396 }
397
398 let flags = self.read_flags();
399 self.clear_all_flags();
400 if let Err(e) = self.check_overrun(&flags) {
401 self.disable_freerunning();
403
404 return Err(e);
405 }
406
407 *result = self.conversion_result();
408 }
409 self.disable_freerunning();
411
412 Ok(())
413 }
414
415 #[hal_cfg(any("adc-d11", "adc-d21"))]
417 #[inline]
418 pub fn free(mut self) -> I::Instance {
419 self.software_reset();
420 self.adc
421 }
422
423 #[hal_cfg("adc-d5x")]
425 #[inline]
426 pub fn free(mut self) -> (I::Instance, crate::clock::v2::apb::ApbClk<I::ClockId>) {
427 self.software_reset();
428 (self.adc, self._apbclk)
429 }
430
431 #[inline]
435 fn software_reset(&mut self) {
436 self.adc.ctrla().modify(|_, w| w.swrst().set_bit());
437 self.sync();
438 }
439}
440
441#[cfg(feature = "async")]
442impl<I: AdcInstance, F> FutureAdc<I, F>
444where
445 F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
446{
447 pub fn into_blocking(self) -> (Adc<I>, F) {
450 (self.inner, self.irqs)
451 }
452
453 #[inline]
455 pub async fn read<P: AdcPin<I>>(&mut self, _pin: &mut P) -> u16 {
456 self.read_channel(P::CHANNEL).await
457 }
458
459 #[inline]
461 async fn read_channel(&mut self, ch: u8) -> u16 {
462 self.inner.clear_all_flags();
464 self.inner.disable_freerunning();
465 self.inner.mux(ch);
466 if self.inner.discard {
467 self.inner.start_conversion();
469 let _ = self.wait_flags(Flags::RESRDY).await;
470 self.inner.discard = false;
471 let _ = self.inner.conversion_result();
472 }
473 self.inner.start_conversion();
474 let _ = self.wait_flags(Flags::RESRDY).await;
477 let res = self.inner.conversion_result();
478 self.inner.sync();
480 res
481 }
482
483 #[inline]
485 pub async fn read_buffer<P: AdcPin<I>>(
486 &mut self,
487 _pin: &mut P,
488 dst: &mut [u16],
489 ) -> Result<(), Error> {
490 self.read_buffer_channel(P::CHANNEL, dst).await
491 }
492
493 #[inline]
495 async fn read_buffer_channel(&mut self, ch: u8, dst: &mut [u16]) -> Result<(), Error> {
496 self.inner.clear_all_flags();
498 self.inner.mux(ch);
499 self.inner.enable_freerunning();
500
501 if self.inner.discard {
502 let _ = self.wait_flags(Flags::RESRDY).await;
504 let _ = self.inner.conversion_result();
505 self.inner.discard = false;
506 self.inner.clear_all_flags();
507 }
508
509 for result in dst.iter_mut() {
511 if let Err(e) = self.wait_flags(Flags::RESRDY).await {
512 self.inner.disable_freerunning();
514
515 return Err(e);
516 }
517 *result = self.inner.conversion_result();
518 }
519
520 self.inner.disable_freerunning();
522
523 Ok(())
524 }
525}