py32_hal/adc/
mod.rs

1//! Analog to Digital Converter (ADC)
2
3#![macro_use]
4#![allow(missing_docs)] // TODO
5
6// The following code is modified from embassy-stm32
7// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32
8// Special thanks to the Embassy Project and its contributors for their work!
9
10#[cfg_attr(adc_v1, path = "v1.rs")]
11#[cfg_attr(adc_v1b, path = "v1.rs")]
12#[cfg_attr(adc_v2, path = "v2.rs")]
13mod _version;
14
15#[allow(unused)]
16pub use _version::*;
17
18use core::marker::PhantomData;
19use embassy_sync::waitqueue::AtomicWaker;
20
21pub use crate::pac::adc::vals;
22pub use crate::pac::adc::vals::Res as Resolution;
23pub use crate::pac::adc::vals::SampleTime;
24use crate::peripherals;
25
26#[cfg(dma)]
27dma_trait!(RxDma, Instance);
28
29/// Analog to Digital driver.
30pub struct Adc<'d, T: Instance> {
31    #[allow(unused)]
32    adc: crate::PeripheralRef<'d, T>,
33    sample_time: SampleTime,
34}
35
36pub struct State {
37    pub waker: AtomicWaker,
38}
39
40impl State {
41    pub const fn new() -> Self {
42        Self {
43            waker: AtomicWaker::new(),
44        }
45    }
46}
47
48trait SealedInstance {
49    #[allow(unused)]
50    fn regs() -> crate::pac::adc::Adc;
51    #[allow(unused)]
52    fn state() -> &'static State;
53}
54
55pub(crate) trait SealedAdcChannel<T> {
56    fn setup(&mut self) {}
57
58    #[allow(unused)]
59    fn channel(&self) -> u8;
60}
61
62/// Performs a busy-wait delay for a specified number of microseconds.
63#[allow(unused)]
64pub(crate) fn blocking_delay_us(us: u32) {
65    #[cfg(feature = "time")]
66    embassy_time::block_for(embassy_time::Duration::from_micros(us as u64));
67    #[cfg(not(feature = "time"))]
68    {
69        let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
70        let us = us as u64;
71        let cycles = freq * us / 1_000_000;
72        cortex_m::asm::delay(cycles as u32);
73    }
74}
75
76/// ADC instance.
77#[allow(private_bounds)]
78pub trait Instance:
79    SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral
80{
81    type Interrupt: crate::interrupt::typelevel::Interrupt;
82}
83
84/// ADC channel.
85#[allow(private_bounds)]
86pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
87    #[allow(unused_mut)]
88    fn degrade_adc(mut self) -> AnyAdcChannel<T> {
89        self.setup();
90
91        AnyAdcChannel {
92            channel: self.channel(),
93            _phantom: PhantomData,
94        }
95    }
96}
97
98/// A type-erased channel for a given ADC instance.
99///
100/// This is useful in scenarios where you need the ADC channels to have the same type, such as
101/// storing them in an array.
102pub struct AnyAdcChannel<T> {
103    channel: u8,
104    _phantom: PhantomData<T>,
105}
106
107impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {}
108impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
109    fn channel(&self) -> u8 {
110        self.channel
111    }
112}
113
114foreach_adc!(
115    ($inst:ident, $common_inst:ident, $clock:ident) => {
116        impl crate::adc::SealedInstance for peripherals::$inst {
117            fn regs() -> crate::pac::adc::Adc {
118                crate::pac::$inst
119            }
120
121            fn state() -> &'static State {
122                static STATE: State = State::new();
123                &STATE
124            }
125        }
126
127        impl crate::adc::Instance for peripherals::$inst {
128            type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
129        }
130    };
131);
132
133#[allow(unused_macros)]
134macro_rules! impl_adc_pin {
135    ($inst:ident, $pin:ident, $ch:expr) => {
136        impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {}
137        impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin {
138            fn setup(&mut self) {
139                <Self as crate::gpio::SealedPin>::set_as_analog(self);
140            }
141
142            fn channel(&self) -> u8 {
143                $ch
144            }
145        }
146    };
147}
148
149/// Get the maximum reading value for this resolution.
150///
151/// This is `2**n - 1`.
152pub const fn resolution_to_max_count(res: Resolution) -> u32 {
153    match res {
154        Resolution::BITS12 => (1 << 12) - 1,
155        Resolution::BITS10 => (1 << 10) - 1,
156        Resolution::BITS8 => (1 << 8) - 1,
157        Resolution::BITS6 => (1 << 6) - 1,
158        #[allow(unreachable_patterns)]
159        _ => core::unreachable!(),
160    }
161}