1use core::{marker::PhantomData, task::Poll};
12
13use cortex_m::asm;
14use embassy_hal_internal::{Peri, PeripheralType};
15
16use crate::{
17 adc::channel::AdcChannel,
18 interrupt::typelevel::{Binding, Interrupt as InterruptType},
19 module_stop::ModuleStop,
20 pac,
21};
22
23#[cfg(adc12)]
24use pac::adc12::{self as adc_pac, Adc12 as AdcPac};
25#[cfg(adc14)]
26use pac::adc14::{self as adc_pac, Adc14 as AdcPac};
27#[cfg(adc16)]
28use pac::adc16::{self as adc_pac, Adc16 as AdcPac};
29
30use adc_pac::{
31 regs::Adans,
32 vals::{AdcCountSelect, Adcs},
33};
34
35#[cfg(adc12)]
36use crate::peripherals::ADC12_0;
37
38#[cfg(adc14)]
39use crate::{pac::adc14::vals::Adprc, peripherals::ADC14_0};
40
41#[cfg(adc16)]
42use crate::peripherals::ADC16_0;
43
44pub use channel::{AdcInputPin, AdcPin, AdcSequence, Temperature, Vref};
45
46#[cfg(dmac)]
47use crate::dmac::{Channel as DmacChannel, DmacInterruptHandler};
48
49pub(crate) mod channel;
50
51#[allow(private_bounds)]
53pub struct Adc<'d, I: Instance> {
54 _phantom: PhantomData<&'d I>,
55 average_mode: AverageMode,
56 sample_time: u8,
57}
58
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65#[derive(Copy, Clone, Default, PartialEq)]
66pub enum AverageMode {
67 #[default]
69 Off,
70
71 Average2,
73
74 Average4,
76
77 #[cfg(any(adc12, adc14))]
79 Add2,
80
81 #[cfg(any(adc12, adc14))]
83 Add3,
84
85 #[cfg(any(adc12, adc14))]
87 Add4,
88
89 #[cfg(any(adc12, adc14))]
91 Add16,
92}
93
94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
96#[derive(Copy, Clone, Default)]
97pub enum Resolution {
98 #[cfg(any(adc12, adc14))]
100 #[default]
101 _12bit,
102
103 #[cfg(adc14)]
105 _14bit,
106
107 #[cfg(adc16)]
109 #[default]
110 _16bit,
111}
112
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115#[derive(Copy, Clone, Default)]
116pub enum Alignment {
117 FlushLeft,
119
120 #[default]
122 FlushRight,
123}
124
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
127#[derive(Copy, Clone)]
128pub struct AdcConfig {
129 #[allow(missing_docs)]
130 pub resolution: Resolution,
131
132 pub clear_on_read: bool,
134
135 #[allow(missing_docs)]
136 #[cfg(not(adc16))]
137 pub alignment: Alignment,
138
139 #[allow(missing_docs)]
140 pub average_mode: AverageMode,
141
142 pub sample_time: u8,
148}
149
150#[derive(Copy, Clone)]
151struct AdcChannelConfig {
152 pub average_mode: AverageMode,
153 pub sample_time: u8,
154}
155
156#[allow(private_bounds)]
158pub trait Instance: SealedInstance + ModuleStop + PeripheralType + 'static + Send {
159 const RX_EVENT: crate::event_link::InterruptEvent;
161}
162
163impl Default for AdcConfig {
164 fn default() -> Self {
165 Self {
166 resolution: Default::default(),
167 clear_on_read: Default::default(),
168 #[cfg(not(adc16))]
169 alignment: Default::default(),
170 average_mode: Default::default(),
171 sample_time: 13,
172 }
173 }
174}
175
176trait SealedInstance: PeripheralType {
177 fn regs() -> AdcPac;
178}
179
180#[cfg(adc12)]
181impl SealedInstance for ADC12_0 {
182 fn regs() -> AdcPac {
183 pac::ADC12_0
184 }
185}
186
187#[cfg(adc14)]
188impl SealedInstance for ADC14_0 {
189 fn regs() -> AdcPac {
190 pac::ADC14_0
191 }
192}
193
194#[cfg(adc16)]
195impl SealedInstance for ADC16_0 {
196 fn regs() -> AdcPac {
197 pac::ADC16_0
198 }
199}
200
201#[cfg(adc12)]
202impl Instance for ADC12_0 {
203 const RX_EVENT: crate::event_link::InterruptEvent =
204 crate::event_link::InterruptEvent::Adc0ScanEnd;
205}
206
207#[cfg(adc14)]
208impl Instance for ADC14_0 {
209 const RX_EVENT: crate::event_link::InterruptEvent =
210 crate::event_link::InterruptEvent::Adc0ScanEnd;
211}
212
213#[cfg(adc16)]
214impl Instance for ADC16_0 {
215 const RX_EVENT: crate::event_link::InterruptEvent =
216 crate::event_link::InterruptEvent::Adc0ScanEnd;
217}
218
219impl<'d, I: Instance> Adc<'d, I> {
220 pub fn new(_adc: Peri<'d, I>, config: AdcConfig) -> Self {
222 #[cfg(feature = "strict-assert")]
223 assert!(config.sample_time >= 5);
224
225 I::start_module();
226
227 #[cfg(adc14)]
228 let resolution = match config.resolution {
229 Resolution::_12bit => Adprc::_12bit,
230 Resolution::_14bit => Adprc::_14bit,
231 };
232
233 let clear_on_read = config.clear_on_read;
234
235 #[cfg(not(adc16))]
236 let alignment = match config.alignment {
237 Alignment::FlushLeft => true,
238 Alignment::FlushRight => false,
239 };
240
241 let adc = I::regs();
242
243 adc.adansa(0).write_value(Adans(0));
245 adc.adansa(1).write_value(Adans(0));
246
247 adc.adexicr().modify(|w| {
248 w.set_ocsa(false);
249 w.set_tssa(false);
250 });
251
252 adc.adcer().write(|w| {
253 #[cfg(adc14)]
254 {
255 w.set_adprc(resolution);
256 }
257
258 #[cfg(any(adc12, adc14))]
259 {
260 w.set_adrfmt(alignment);
261 }
262
263 w.set_ace(clear_on_read);
264 });
265
266 adc.adadc().write(|w| match config.average_mode {
267 AverageMode::Off => {}
268 AverageMode::Average2 => {
269 #[cfg(any(adc12, adc14))]
270 w.set_avee(true);
271 w.set_adc(AdcCountSelect::Convert2);
272 }
273 AverageMode::Average4 => {
274 #[cfg(any(adc12, adc14))]
275 w.set_avee(true);
276 w.set_adc(AdcCountSelect::Convert4);
277 }
278 #[cfg(any(adc12, adc14))]
279 AverageMode::Add2 => {
280 w.set_avee(false);
281 w.set_adc(AdcCountSelect::Convert2);
282 }
283 #[cfg(any(adc12, adc14))]
284 AverageMode::Add3 => {
285 w.set_avee(false);
286 w.set_adc(AdcCountSelect::Convert3);
287 }
288 #[cfg(any(adc12, adc14))]
289 AverageMode::Add4 => {
290 w.set_avee(false);
291 w.set_adc(AdcCountSelect::Convert4);
292 }
293 #[cfg(any(adc12, adc14))]
294 AverageMode::Add16 => {
295 w.set_avee(false);
296 w.set_adc(AdcCountSelect::Convert16);
297 }
298 });
299
300 Self {
301 _phantom: PhantomData,
302 average_mode: config.average_mode,
303 sample_time: config.sample_time,
304 }
305 }
306
307 pub fn resolution(&self) -> Resolution {
309 #[cfg(adc12)]
310 {
311 Resolution::_12bit
312 }
313
314 #[cfg(adc14)]
315 {
316 let adc = I::regs();
317
318 match adc.adcer().read().adprc() {
319 Adprc::_12bit => Resolution::_12bit,
320 Adprc::_RESERVED_1 => unimplemented!(),
321 Adprc::_RESERVED_2 => unimplemented!(),
322 Adprc::_14bit => Resolution::_14bit,
323 }
324 }
325
326 #[cfg(adc16)]
327 {
328 Resolution::_16bit
329 }
330 }
331
332 #[cfg(adc14)]
334 pub fn alignment(&self) -> Alignment {
335 let adc = I::regs();
336
337 match adc.adcer().read().adrfmt() {
338 true => Alignment::FlushLeft,
339 false => Alignment::FlushRight,
340 }
341 }
342
343 pub fn temperature_channel(&self) -> Temperature {
345 Temperature {}
346 }
347
348 pub fn vref_channel(&self) -> Vref {
350 Vref {}
351 }
352
353 pub fn blocking_read<R, C: AdcChannel<R>>(&self, channel: &C) -> R {
356 let adc = I::regs();
357
358 channel.enable::<I>(AdcChannelConfig {
359 average_mode: self.average_mode,
360 sample_time: self.sample_time,
361 });
362
363 adc.adcsr().modify(|w| w.set_adcs(Adcs::Single));
366
367 adc.adcsr().modify(|w| w.set_adst(true));
368
369 while adc.adcsr().read().adst() {
371 asm::nop()
372 }
373
374 channel.disable::<I>();
375
376 channel.read_one::<I>()
377 }
378
379 #[cfg(dmac)]
385 pub async fn read<
386 'a,
387 R: crate::dmac::Word,
388 RxDmaInstance: crate::dmac::Instance,
389 C: AdcChannel<R>,
390 DmaInt: InterruptType,
391 >(
392 &'a self,
393 rx_dma: Peri<'a, RxDmaInstance>,
394 channel: &C,
395 reading: &mut R,
396 irqs: impl Binding<DmaInt, DmacInterruptHandler<RxDmaInstance>>,
397 ) {
398 let adc = I::regs();
399
400 let mut rx_dma = DmacChannel::new(rx_dma, irqs);
401
402 channel.enable::<I>(AdcChannelConfig {
403 average_mode: self.average_mode,
404 sample_time: self.sample_time,
405 });
406
407 adc.adcsr().modify(|w| w.set_adcs(Adcs::Single));
408
409 let rx = rx_dma.read::<R>(
410 channel.address::<I>(),
411 core::slice::from_mut(reading),
412 I::RX_EVENT,
413 );
414
415 adc.adcsr().modify(|w| w.set_adst(true));
416 rx.await;
417
418 channel.disable::<I>();
419 }
420
421 #[cfg(dmac)]
427 pub fn configured_sequence<
428 'a,
429 R: crate::dmac::Word,
430 RxDmaInstance: crate::dmac::Instance,
431 C: AdcChannel<R>,
432 DmaInt: InterruptType,
433 >(
434 &'a self,
435 rx_dma: Peri<'a, RxDmaInstance>,
436 channel: &C,
437 irqs: impl Binding<DmaInt, DmacInterruptHandler<RxDmaInstance>> + 'a,
438 ) -> ConfiguredSequence<'a, I, R> {
439 let adc = I::regs();
440
441 channel.enable::<I>(AdcChannelConfig {
442 average_mode: self.average_mode,
443 sample_time: self.sample_time,
444 });
445
446 adc.adcsr().modify(|w| w.set_adcs(Adcs::Single));
447
448 ConfiguredSequence {
449 dma: DmacChannel::new(rx_dma, irqs),
450 source: channel.address::<I>(),
451 _phantom: PhantomData,
452 }
453 }
454
455 #[cfg(dmac)]
468 pub fn into_ring_buffered<
469 'a,
470 R: crate::dmac::Word,
471 RxDmaInstance: crate::dmac::Instance,
472 C: AdcChannel<u16>,
473 DmaInt: InterruptType,
474 >(
475 self,
476 rx_dma: Peri<'a, RxDmaInstance>,
477 channel: &C,
478 dma_buf: &'a mut [R],
479 irqs: impl Binding<DmaInt, DmacInterruptHandler<RxDmaInstance>> + 'a,
480 ) -> RingBufferedAdc<'a, I, R>
481 where
482 'd: 'a,
483 {
484 assert!(
485 dma_buf.len() >= 2 && dma_buf.len() % 2 == 0,
486 "DMA buffer must have an even length >= 2"
487 );
488
489 let source = channel.address::<I>();
490
491 channel.enable::<I>(AdcChannelConfig {
492 average_mode: self.average_mode,
493 sample_time: self.sample_time,
494 });
495
496 I::regs().adcsr().modify(|w| w.set_adcs(Adcs::Continuous));
497
498 let mut dma = DmacChannel::new(rx_dma, irqs);
499 dma.configure_peripheral_read::<R>(source as _, I::RX_EVENT);
500
501 core::mem::forget(self);
503
504 RingBufferedAdc {
505 dma,
506 source: source as _,
507 buf: dma_buf.as_mut_ptr(),
508 half_len: dma_buf.len() / 2,
509 fill_half: false,
510 started: false,
511 _phantom: PhantomData,
512 }
513 }
514}
515
516#[cfg(dmac)]
526#[allow(private_bounds)]
527pub struct RingBufferedAdc<'d, I: Instance, R: crate::dmac::Word> {
528 dma: DmacChannel<'d>,
529 #[allow(dead_code)]
530 source: *const R,
531 buf: *mut R,
532 half_len: usize,
533 fill_half: bool,
536 started: bool,
537 _phantom: PhantomData<(&'d I, *mut R)>,
538}
539
540#[cfg(dmac)]
541impl<'d, I: Instance, R: crate::dmac::Word> RingBufferedAdc<'d, I, R> {
542 #[inline]
544 fn arm(&mut self) {
545 let dest = unsafe {
546 if self.fill_half {
547 self.buf.add(self.half_len)
548 } else {
549 self.buf
550 }
551 };
552 self.dma.rearm::<R>(dest, self.half_len);
553 }
554
555 pub fn start(&mut self) {
557 if self.started {
558 return;
559 }
560 self.started = true;
561 self.fill_half = false;
562 self.arm();
563 I::regs().adcsr().modify(|w| w.set_adst(true));
564 }
565
566 pub fn stop(&mut self) {
568 I::regs().adcsr().modify(|w| w.set_adst(false));
569 self.dma.disable_dte();
570 self.started = false;
571 }
572
573 pub async fn read(&mut self, buf: &mut [R]) {
581 #[cfg(feature = "strict-assert")]
582 assert_eq!(
583 buf.len(),
584 self.half_len,
585 "Buffer must be half the DMA buffer length"
586 );
587
588 if !self.started {
589 self.start();
590 }
591
592 let fill_half = self.fill_half;
593
594 core::future::poll_fn(|cx| {
595 self.dma.register_waker(cx.waker());
596
597 if self.dma.take_dtif() {
598 self.fill_half = !fill_half;
600 self.arm();
601 Poll::Ready(())
602 } else {
603 Poll::Pending
604 }
605 })
606 .await;
607
608 let src_offset = if fill_half { self.half_len } else { 0 };
610 let src = unsafe { core::slice::from_raw_parts(self.buf.add(src_offset), self.half_len) };
611 buf.copy_from_slice(src);
612 }
613}
614
615#[cfg(dmac)]
616impl<I: Instance, R: crate::dmac::Word> Drop for RingBufferedAdc<'_, I, R> {
617 fn drop(&mut self) {
618 if self.started {
619 self.stop();
620 }
621 let adc = I::regs();
622 adc.adansa(0).write_value(Adans(0));
623 adc.adansa(1).write_value(Adans(0));
624 adc.adexicr().modify(|w| {
625 w.set_ocsa(false);
626 w.set_tssa(false);
627 });
628 I::stop_module();
629 }
630}
631
632#[cfg(dmac)]
640#[allow(private_bounds)]
641pub struct ConfiguredSequence<'d, I: Instance, R: crate::dmac::Word> {
642 dma: DmacChannel<'d>,
643 source: *const R,
644 _phantom: PhantomData<(&'d I, R)>,
645}
646
647#[cfg(dmac)]
648impl<'d, I: Instance, R: crate::dmac::Word> ConfiguredSequence<'d, I, R> {
649 pub async fn read(&mut self, reading: &mut R) {
651 let adc = I::regs();
652 let rx = self
653 .dma
654 .read::<R>(self.source, core::slice::from_mut(reading), I::RX_EVENT);
655 adc.adcsr().modify(|w| w.set_adst(true));
656 rx.await;
657 }
658}
659
660#[cfg(dmac)]
661impl<I: Instance, R: crate::dmac::Word> Drop for ConfiguredSequence<'_, I, R> {
662 fn drop(&mut self) {
663 let adc = I::regs();
664 adc.adansa(0).write_value(Adans(0));
665 adc.adansa(1).write_value(Adans(0));
666 adc.adexicr().modify(|w| {
667 w.set_ocsa(false);
668 w.set_tssa(false);
669 });
670 }
671}
672
673impl<'d, I: Instance> Drop for Adc<'d, I> {
674 fn drop(&mut self) {
675 I::stop_module();
676 }
677}