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.clear_all_flags();
362 self.discard = false;
363 }
364 }
365
366 #[inline]
368 pub fn read_buffer<P: AdcPin<I>>(
369 &mut self,
370 _pin: &mut P,
371 dst: &mut [u16],
372 ) -> Result<(), Error> {
373 self.read_buffer_channel(P::CHANNEL, dst)
374 }
375
376 #[inline]
378 fn read_buffer_channel(&mut self, ch: u8, dst: &mut [u16]) -> Result<(), Error> {
379 self.clear_all_flags();
381 self.disable_interrupts(Flags::all());
382 self.mux(ch);
383 self.enable_freerunning();
384 self.start_conversion();
385 self.check_read_discard();
386 for result in dst.iter_mut() {
387 while !self.read_flags().contains(Flags::RESRDY) {
388 core::hint::spin_loop();
389 }
390
391 let flags = self.read_flags();
392 self.clear_all_flags();
393 if let Err(e) = self.check_overrun(&flags) {
394 self.disable_freerunning();
396
397 return Err(e);
398 }
399
400 *result = self.conversion_result();
401 }
402 self.disable_freerunning();
404
405 Ok(())
406 }
407
408 #[hal_cfg(any("adc-d11", "adc-d21"))]
410 #[inline]
411 pub fn free(mut self) -> I::Instance {
412 self.software_reset();
413 self.adc
414 }
415
416 #[hal_cfg("adc-d5x")]
418 #[inline]
419 pub fn free(mut self) -> (I::Instance, crate::clock::v2::apb::ApbClk<I::ClockId>) {
420 self.software_reset();
421 (self.adc, self._apbclk)
422 }
423
424 #[inline]
428 fn software_reset(&mut self) {
429 self.adc.ctrla().modify(|_, w| w.swrst().set_bit());
430 self.sync();
431 }
432}
433
434#[cfg(feature = "async")]
435impl<I: AdcInstance, F> FutureAdc<I, F>
437where
438 F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
439{
440 pub fn into_blocking(self) -> (Adc<I>, F) {
443 (self.inner, self.irqs)
444 }
445
446 #[inline]
448 pub async fn read<P: AdcPin<I>>(&mut self, _pin: &mut P) -> u16 {
449 self.read_channel(P::CHANNEL).await
450 }
451
452 #[inline]
454 async fn read_channel(&mut self, ch: u8) -> u16 {
455 self.inner.clear_all_flags();
457 self.inner.disable_freerunning();
458 self.inner.mux(ch);
459 if self.inner.discard {
460 self.inner.start_conversion();
462 let _ = self.wait_flags(Flags::RESRDY).await;
463 self.inner.discard = false;
464 self.inner.clear_all_flags();
465 }
466 self.inner.start_conversion();
467 let _ = self.wait_flags(Flags::RESRDY).await;
470 let res = self.inner.conversion_result();
471 self.inner.sync();
473 res
474 }
475
476 #[inline]
478 pub async fn read_buffer<P: AdcPin<I>>(
479 &mut self,
480 _pin: &mut P,
481 dst: &mut [u16],
482 ) -> Result<(), Error> {
483 self.read_buffer_channel(P::CHANNEL, dst).await
484 }
485
486 #[inline]
488 async fn read_buffer_channel(&mut self, ch: u8, dst: &mut [u16]) -> Result<(), Error> {
489 self.inner.clear_all_flags();
491 self.inner.mux(ch);
492 self.inner.enable_freerunning();
493
494 if self.inner.discard {
495 let _ = self.wait_flags(Flags::RESRDY).await;
497 let _ = self.inner.conversion_result();
498 self.inner.discard = false;
499 self.inner.clear_all_flags();
500 }
501
502 for result in dst.iter_mut() {
504 if let Err(e) = self.wait_flags(Flags::RESRDY).await {
505 self.inner.disable_freerunning();
507
508 return Err(e);
509 }
510 *result = self.inner.conversion_result();
511 }
512
513 self.inner.disable_freerunning();
515
516 Ok(())
517 }
518}