embassy_stm32/adc/
mod.rs

1//! Analog to Digital Converter (ADC)
2
3#![macro_use]
4#![allow(missing_docs)] // TODO
5#![cfg_attr(adc_f3_v2, allow(unused))]
6
7#[cfg(not(any(adc_f3_v2)))]
8#[cfg_attr(adc_f1, path = "f1.rs")]
9#[cfg_attr(adc_f3, path = "f3.rs")]
10#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
11#[cfg_attr(adc_v1, path = "v1.rs")]
12#[cfg_attr(adc_l0, path = "v1.rs")]
13#[cfg_attr(adc_v2, path = "v2.rs")]
14#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")]
15#[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")]
16#[cfg_attr(adc_g4, path = "g4.rs")]
17mod _version;
18
19use core::marker::PhantomData;
20
21#[allow(unused)]
22#[cfg(not(any(adc_f3_v2)))]
23pub use _version::*;
24#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
25use embassy_sync::waitqueue::AtomicWaker;
26
27#[cfg(adc_u5)]
28#[path = "u5_adc4.rs"]
29pub mod adc4;
30
31pub use crate::pac::adc::vals;
32#[cfg(not(any(adc_f1, adc_f3_v2)))]
33pub use crate::pac::adc::vals::Res as Resolution;
34pub use crate::pac::adc::vals::SampleTime;
35use crate::peripherals;
36
37dma_trait!(RxDma, Instance);
38#[cfg(adc_u5)]
39dma_trait!(RxDma4, adc4::Instance);
40
41/// Analog to Digital driver.
42pub struct Adc<'d, T: Instance> {
43    #[allow(unused)]
44    adc: crate::PeripheralRef<'d, T>,
45    #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))]
46    sample_time: SampleTime,
47}
48
49#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
50pub struct State {
51    pub waker: AtomicWaker,
52}
53
54#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
55impl State {
56    pub const fn new() -> Self {
57        Self {
58            waker: AtomicWaker::new(),
59        }
60    }
61}
62
63trait SealedInstance {
64    #[allow(unused)]
65    fn regs() -> crate::pac::adc::Adc;
66    #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
67    #[allow(unused)]
68    fn common_regs() -> crate::pac::adccommon::AdcCommon;
69    #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
70    fn state() -> &'static State;
71}
72
73pub(crate) trait SealedAdcChannel<T> {
74    #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
75    fn setup(&mut self) {}
76
77    #[allow(unused)]
78    fn channel(&self) -> u8;
79}
80
81/// Performs a busy-wait delay for a specified number of microseconds.
82#[allow(unused)]
83pub(crate) fn blocking_delay_us(us: u32) {
84    #[cfg(feature = "time")]
85    embassy_time::block_for(embassy_time::Duration::from_micros(us as u64));
86    #[cfg(not(feature = "time"))]
87    {
88        let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
89        let us = us as u64;
90        let cycles = freq * us / 1_000_000;
91        cortex_m::asm::delay(cycles as u32);
92    }
93}
94
95/// ADC instance.
96#[cfg(not(any(
97    adc_f1,
98    adc_v1,
99    adc_l0,
100    adc_v2,
101    adc_v3,
102    adc_v4,
103    adc_g4,
104    adc_f3,
105    adc_f3_v1_1,
106    adc_g0,
107    adc_u0,
108    adc_h5,
109    adc_u5
110)))]
111#[allow(private_bounds)]
112pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
113    type Interrupt: crate::interrupt::typelevel::Interrupt;
114}
115/// ADC instance.
116#[cfg(any(
117    adc_f1,
118    adc_v1,
119    adc_l0,
120    adc_v2,
121    adc_v3,
122    adc_v4,
123    adc_g4,
124    adc_f3,
125    adc_f3_v1_1,
126    adc_g0,
127    adc_u0,
128    adc_h5,
129    adc_u5
130))]
131#[allow(private_bounds)]
132pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {
133    type Interrupt: crate::interrupt::typelevel::Interrupt;
134}
135
136/// ADC channel.
137#[allow(private_bounds)]
138pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
139    #[allow(unused_mut)]
140    fn degrade_adc(mut self) -> AnyAdcChannel<T> {
141        #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
142        self.setup();
143
144        AnyAdcChannel {
145            channel: self.channel(),
146            _phantom: PhantomData,
147        }
148    }
149}
150
151/// A type-erased channel for a given ADC instance.
152///
153/// This is useful in scenarios where you need the ADC channels to have the same type, such as
154/// storing them in an array.
155pub struct AnyAdcChannel<T> {
156    channel: u8,
157    _phantom: PhantomData<T>,
158}
159
160impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {}
161impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
162    fn channel(&self) -> u8 {
163        self.channel
164    }
165}
166
167#[cfg(adc_u5)]
168foreach_adc!(
169    (ADC4, $common_inst:ident, $clock:ident) => {
170        impl crate::adc::adc4::SealedInstance for peripherals::ADC4 {
171            fn regs() -> crate::pac::adc::Adc4 {
172                crate::pac::ADC4
173            }
174        }
175
176        impl crate::adc::adc4::Instance for peripherals::ADC4 {
177            type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL;
178        }
179    };
180
181    ($inst:ident, $common_inst:ident, $clock:ident) => {
182        impl crate::adc::SealedInstance for peripherals::$inst {
183            fn regs() -> crate::pac::adc::Adc {
184                crate::pac::$inst
185            }
186
187            fn common_regs() -> crate::pac::adccommon::AdcCommon {
188                return crate::pac::$common_inst
189            }
190        }
191
192        impl crate::adc::Instance for peripherals::$inst {
193            type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
194        }
195    };
196);
197
198#[cfg(not(adc_u5))]
199foreach_adc!(
200    ($inst:ident, $common_inst:ident, $clock:ident) => {
201        impl crate::adc::SealedInstance for peripherals::$inst {
202            fn regs() -> crate::pac::adc::Adc {
203                crate::pac::$inst
204            }
205
206            #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
207            fn common_regs() -> crate::pac::adccommon::AdcCommon {
208                return crate::pac::$common_inst
209            }
210
211            #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
212            fn state() -> &'static State {
213                static STATE: State = State::new();
214                &STATE
215            }
216        }
217
218        impl crate::adc::Instance for peripherals::$inst {
219            type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
220        }
221    };
222);
223
224macro_rules! impl_adc_pin {
225    ($inst:ident, $pin:ident, $ch:expr) => {
226        impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {}
227        impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin {
228            #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
229            fn setup(&mut self) {
230                <Self as crate::gpio::SealedPin>::set_as_analog(self);
231            }
232
233            fn channel(&self) -> u8 {
234                $ch
235            }
236        }
237    };
238}
239
240/// Get the maximum reading value for this resolution.
241///
242/// This is `2**n - 1`.
243#[cfg(not(any(adc_f1, adc_f3_v2)))]
244pub const fn resolution_to_max_count(res: Resolution) -> u32 {
245    match res {
246        #[cfg(adc_v4)]
247        Resolution::BITS16 => (1 << 16) - 1,
248        #[cfg(any(adc_v4, adc_u5))]
249        Resolution::BITS14 => (1 << 14) - 1,
250        #[cfg(adc_v4)]
251        Resolution::BITS14V => (1 << 14) - 1,
252        #[cfg(adc_v4)]
253        Resolution::BITS12V => (1 << 12) - 1,
254        Resolution::BITS12 => (1 << 12) - 1,
255        Resolution::BITS10 => (1 << 10) - 1,
256        Resolution::BITS8 => (1 << 8) - 1,
257        #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))]
258        Resolution::BITS6 => (1 << 6) - 1,
259        #[allow(unreachable_patterns)]
260        _ => core::unreachable!(),
261    }
262}