diff options
| author | Sam Mason <[email protected]> | 2023-12-04 14:03:31 +1100 |
|---|---|---|
| committer | Sam Mason <[email protected]> | 2023-12-04 14:03:31 +1100 |
| commit | 35f16c6003b4be69ee18d24440560ce8a700169c (patch) | |
| tree | 05791f59e137d22334d9f0f7256493785a7058b9 | |
| parent | e5fdd35bd680b30b03372d44f8b29129a8f49f3e (diff) | |
stm32: add ADC f3_v1_1
| -rw-r--r-- | embassy-stm32/src/adc/f3_v1_1.rs | 408 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/resolution.rs | 26 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/sample_time.rs | 25 |
4 files changed, 466 insertions, 14 deletions
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs new file mode 100644 index 000000000..0bbfd3137 --- /dev/null +++ b/embassy-stm32/src/adc/f3_v1_1.rs | |||
| @@ -0,0 +1,408 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::task::Poll; | ||
| 4 | |||
| 5 | use embassy_futures::yield_now; | ||
| 6 | use embassy_hal_internal::into_ref; | ||
| 7 | use embassy_time::Instant; | ||
| 8 | |||
| 9 | use super::Resolution; | ||
| 10 | use crate::adc::{Adc, AdcPin, Instance, SampleTime}; | ||
| 11 | use crate::interrupt::typelevel::Interrupt; | ||
| 12 | use crate::time::Hertz; | ||
| 13 | use crate::{interrupt, Peripheral}; | ||
| 14 | |||
| 15 | const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; | ||
| 16 | |||
| 17 | pub const VDDA_CALIB_MV: u32 = 3300; | ||
| 18 | pub const ADC_MAX: u32 = (1 << 12) - 1; | ||
| 19 | pub const VREF_INT: u32 = 1230; | ||
| 20 | |||
| 21 | pub enum AdcPowerMode { | ||
| 22 | AlwaysOn, | ||
| 23 | DelayOff, | ||
| 24 | IdleOff, | ||
| 25 | DelayIdleOff, | ||
| 26 | } | ||
| 27 | |||
| 28 | pub enum Prescaler { | ||
| 29 | Div1, | ||
| 30 | Div2, | ||
| 31 | Div3, | ||
| 32 | Div4, | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Interrupt handler. | ||
| 36 | pub struct InterruptHandler<T: Instance> { | ||
| 37 | _phantom: PhantomData<T>, | ||
| 38 | } | ||
| 39 | |||
| 40 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 41 | unsafe fn on_interrupt() { | ||
| 42 | if T::regs().sr().read().eoc() { | ||
| 43 | T::regs().cr1().modify(|w| w.set_eocie(false)); | ||
| 44 | } else { | ||
| 45 | return; | ||
| 46 | } | ||
| 47 | |||
| 48 | T::state().waker.wake(); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | fn update_vref<T: Instance>(op: i8) { | ||
| 53 | static VREF_STATUS: core::sync::atomic::AtomicU8 = core::sync::atomic::AtomicU8::new(0); | ||
| 54 | |||
| 55 | if op > 0 { | ||
| 56 | if VREF_STATUS.fetch_add(1, core::sync::atomic::Ordering::SeqCst) == 0 { | ||
| 57 | T::regs().ccr().modify(|w| w.set_tsvrefe(true)); | ||
| 58 | } | ||
| 59 | } else { | ||
| 60 | if VREF_STATUS.fetch_sub(1, core::sync::atomic::Ordering::SeqCst) == 1 { | ||
| 61 | T::regs().ccr().modify(|w| w.set_tsvrefe(false)); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | pub struct Vref<T: Instance>(core::marker::PhantomData<T>); | ||
| 67 | impl<T: Instance> AdcPin<T> for Vref<T> {} | ||
| 68 | impl<T: Instance> super::sealed::AdcPin<T> for Vref<T> { | ||
| 69 | fn channel(&self) -> u8 { | ||
| 70 | 17 | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | impl<T: Instance> Vref<T> { | ||
| 75 | /// The value that vref would be if vdda was at 3000mv | ||
| 76 | pub fn calibrated_value(&self) -> u16 { | ||
| 77 | crate::pac::VREFINTCAL.data().read().value() | ||
| 78 | } | ||
| 79 | |||
| 80 | pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { | ||
| 81 | let vref_val = adc.read(self).await; | ||
| 82 | Calibration { | ||
| 83 | vref_cal: self.calibrated_value(), | ||
| 84 | vref_val, | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | pub struct Calibration { | ||
| 90 | vref_cal: u16, | ||
| 91 | vref_val: u16, | ||
| 92 | } | ||
| 93 | |||
| 94 | impl Calibration { | ||
| 95 | /// The millivolts that the calibration value was measured at | ||
| 96 | pub const CALIBRATION_UV: u32 = 3_000_000; | ||
| 97 | |||
| 98 | /// Returns the measured VddA in microvolts (uV) | ||
| 99 | pub fn vdda_uv(&self) -> u32 { | ||
| 100 | (Self::CALIBRATION_UV * self.vref_cal as u32) / self.vref_val as u32 | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Returns the measured VddA as an f32 | ||
| 104 | pub fn vdda_f32(&self) -> f32 { | ||
| 105 | (Self::CALIBRATION_UV as f32 / 1_000.0) * (self.vref_cal as f32 / self.vref_val as f32) | ||
| 106 | } | ||
| 107 | |||
| 108 | /// Returns a calibrated voltage value as in microvolts (uV) | ||
| 109 | pub fn cal_uv(&self, raw: u16, resolution: super::Resolution) -> u32 { | ||
| 110 | (self.vdda_uv() / resolution.to_max_count()) * raw as u32 | ||
| 111 | } | ||
| 112 | |||
| 113 | /// Returns a calibrated voltage value as an f32 | ||
| 114 | pub fn cal_f32(&self, raw: u16, resolution: super::Resolution) -> f32 { | ||
| 115 | raw as f32 * self.vdda_f32() / resolution.to_max_count() as f32 | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | impl<T: Instance> Drop for Vref<T> { | ||
| 120 | fn drop(&mut self) { | ||
| 121 | update_vref::<T>(-1) | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | pub struct Temperature<T: Instance>(core::marker::PhantomData<T>); | ||
| 126 | impl<T: Instance> AdcPin<T> for Temperature<T> {} | ||
| 127 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature<T> { | ||
| 128 | fn channel(&self) -> u8 { | ||
| 129 | 16 | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | impl<T: Instance> Drop for Temperature<T> { | ||
| 134 | fn drop(&mut self) { | ||
| 135 | update_vref::<T>(-1) | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | impl<'d, T: Instance> Adc<'d, T> { | ||
| 140 | pub fn new( | ||
| 141 | adc: impl Peripheral<P = T> + 'd, | ||
| 142 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 143 | ) -> Self { | ||
| 144 | into_ref!(adc); | ||
| 145 | |||
| 146 | T::enable_and_reset(); | ||
| 147 | |||
| 148 | //let r = T::regs(); | ||
| 149 | //r.cr2().write(|w| w.set_align(true)); | ||
| 150 | |||
| 151 | T::Interrupt::unpend(); | ||
| 152 | unsafe { | ||
| 153 | T::Interrupt::enable(); | ||
| 154 | } | ||
| 155 | |||
| 156 | Self { adc } | ||
| 157 | } | ||
| 158 | |||
| 159 | fn freq() -> Hertz { | ||
| 160 | let div = T::regs().ccr().read().adcpre() + 1; | ||
| 161 | ADC_FREQ / div as u32 | ||
| 162 | } | ||
| 163 | |||
| 164 | pub async fn set_resolution(&mut self, res: Resolution) { | ||
| 165 | let was_on = Self::is_on(); | ||
| 166 | if was_on { | ||
| 167 | self.stop_adc().await; | ||
| 168 | } | ||
| 169 | |||
| 170 | T::regs().cr1().modify(|w| w.set_res(res.into())); | ||
| 171 | |||
| 172 | if was_on { | ||
| 173 | self.start_adc().await; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | pub fn resolution(&self) -> Resolution { | ||
| 178 | T::regs().cr1().read().res().into() | ||
| 179 | } | ||
| 180 | |||
| 181 | pub fn enable_vref(&self) -> Vref<T> { | ||
| 182 | update_vref::<T>(1); | ||
| 183 | |||
| 184 | Vref(core::marker::PhantomData) | ||
| 185 | } | ||
| 186 | |||
| 187 | pub fn enable_temperature(&self) -> Temperature<T> { | ||
| 188 | T::regs().ccr().modify(|w| w.set_tsvrefe(true)); | ||
| 189 | |||
| 190 | Temperature::<T>(core::marker::PhantomData) | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Perform a single conversion. | ||
| 194 | async fn convert(&mut self) -> u16 { | ||
| 195 | let was_on = Self::is_on(); | ||
| 196 | |||
| 197 | if !was_on { | ||
| 198 | self.start_adc().await; | ||
| 199 | } | ||
| 200 | |||
| 201 | self.wait_sample_ready().await; | ||
| 202 | |||
| 203 | T::regs().sr().write(|_| {}); | ||
| 204 | T::regs().cr1().modify(|w| { | ||
| 205 | w.set_eocie(true); | ||
| 206 | w.set_scan(false); | ||
| 207 | }); | ||
| 208 | T::regs().cr2().modify(|w| { | ||
| 209 | w.set_swstart(true); | ||
| 210 | w.set_cont(false); | ||
| 211 | }); // swstart cleared by HW | ||
| 212 | |||
| 213 | let res = poll_fn(|cx| { | ||
| 214 | T::state().waker.register(cx.waker()); | ||
| 215 | |||
| 216 | if T::regs().sr().read().eoc() { | ||
| 217 | let res = T::regs().dr().read().rdata(); | ||
| 218 | Poll::Ready(res) | ||
| 219 | } else { | ||
| 220 | Poll::Pending | ||
| 221 | } | ||
| 222 | }) | ||
| 223 | .await; | ||
| 224 | |||
| 225 | if !was_on { | ||
| 226 | self.stop_adc().await; | ||
| 227 | } | ||
| 228 | |||
| 229 | res | ||
| 230 | } | ||
| 231 | |||
| 232 | #[inline(always)] | ||
| 233 | fn is_on() -> bool { | ||
| 234 | T::regs().sr().read().adons() || T::regs().cr2().read().adon() | ||
| 235 | } | ||
| 236 | |||
| 237 | pub async fn start_adc(&self) { | ||
| 238 | //defmt::trace!("Turn ADC on"); | ||
| 239 | T::regs().cr2().modify(|w| w.set_adon(true)); | ||
| 240 | //defmt::trace!("Waiting for ADC to turn on"); | ||
| 241 | |||
| 242 | let mut t = Instant::now(); | ||
| 243 | |||
| 244 | while !T::regs().sr().read().adons() { | ||
| 245 | yield_now().await; | ||
| 246 | if t.elapsed() > embassy_time::Duration::from_millis(1000) { | ||
| 247 | t = Instant::now(); | ||
| 248 | //defmt::trace!("ADC still not on"); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | //defmt::trace!("ADC on"); | ||
| 253 | } | ||
| 254 | |||
| 255 | pub async fn stop_adc(&self) { | ||
| 256 | if T::regs().cr2().read().adon() { | ||
| 257 | //defmt::trace!("ADC should be on, wait for it to start"); | ||
| 258 | while !T::regs().csr().read().adons1() { | ||
| 259 | yield_now().await; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | //defmt::trace!("Turn ADC off"); | ||
| 264 | |||
| 265 | T::regs().cr2().modify(|w| w.set_adon(false)); | ||
| 266 | |||
| 267 | //defmt::trace!("Waiting for ADC to turn off"); | ||
| 268 | |||
| 269 | while T::regs().csr().read().adons1() { | ||
| 270 | yield_now().await; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | ||
| 275 | self.set_sample_sequence(&[pin.channel()]).await; | ||
| 276 | self.convert().await | ||
| 277 | } | ||
| 278 | |||
| 279 | async fn wait_sample_ready(&self) { | ||
| 280 | //trace!("Waiting for sample channel to be ready"); | ||
| 281 | while T::regs().sr().read().rcnr() { | ||
| 282 | yield_now().await; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | pub async fn set_sample_time(&mut self, pin: &mut impl AdcPin<T>, sample_time: SampleTime) { | ||
| 287 | if Self::get_channel_sample_time(pin.channel()) != sample_time { | ||
| 288 | self.stop_adc().await; | ||
| 289 | unsafe { | ||
| 290 | Self::set_channel_sample_time(pin.channel(), sample_time); | ||
| 291 | } | ||
| 292 | self.start_adc().await; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | pub fn get_sample_time(&self, pin: &impl AdcPin<T>) -> SampleTime { | ||
| 297 | Self::get_channel_sample_time(pin.channel()) | ||
| 298 | } | ||
| 299 | |||
| 300 | /// Sets the channel sample time | ||
| 301 | /// | ||
| 302 | /// ## SAFETY: | ||
| 303 | /// - ADON == 0 i.e ADC must not be enabled when this is called. | ||
| 304 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||
| 305 | let sample_time = sample_time.into(); | ||
| 306 | |||
| 307 | match ch { | ||
| 308 | 0..=9 => T::regs().smpr3().modify(|reg| reg.set_smp(ch as _, sample_time)), | ||
| 309 | 10..=19 => T::regs() | ||
| 310 | .smpr2() | ||
| 311 | .modify(|reg| reg.set_smp(ch as usize - 10, sample_time)), | ||
| 312 | 20..=29 => T::regs() | ||
| 313 | .smpr1() | ||
| 314 | .modify(|reg| reg.set_smp(ch as usize - 20, sample_time)), | ||
| 315 | 30..=31 => T::regs() | ||
| 316 | .smpr0() | ||
| 317 | .modify(|reg| reg.set_smp(ch as usize - 30, sample_time)), | ||
| 318 | _ => panic!("Invalid channel to sample"), | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | fn get_channel_sample_time(ch: u8) -> SampleTime { | ||
| 323 | match ch { | ||
| 324 | 0..=9 => T::regs().smpr3().read().smp(ch as _), | ||
| 325 | 10..=19 => T::regs().smpr2().read().smp(ch as usize - 10), | ||
| 326 | 20..=29 => T::regs().smpr1().read().smp(ch as usize - 20), | ||
| 327 | 30..=31 => T::regs().smpr0().read().smp(ch as usize - 30), | ||
| 328 | _ => panic!("Invalid channel to sample"), | ||
| 329 | } | ||
| 330 | .into() | ||
| 331 | } | ||
| 332 | |||
| 333 | /// Sets the sequence to sample the ADC. Must be less than 28 elements. | ||
| 334 | async fn set_sample_sequence(&self, sequence: &[u8]) { | ||
| 335 | assert!(sequence.len() <= 28); | ||
| 336 | let mut iter = sequence.iter(); | ||
| 337 | T::regs().sqr1().modify(|w| w.set_l((sequence.len() - 1) as _)); | ||
| 338 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 339 | T::regs().sqr5().modify(|w| w.set_sq(idx, *ch)); | ||
| 340 | } | ||
| 341 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 342 | T::regs().sqr4().modify(|w| w.set_sq(idx, *ch)); | ||
| 343 | } | ||
| 344 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 345 | T::regs().sqr3().modify(|w| w.set_sq(idx, *ch)); | ||
| 346 | } | ||
| 347 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 348 | T::regs().sqr2().modify(|w| w.set_sq(idx, *ch)); | ||
| 349 | } | ||
| 350 | for (idx, ch) in iter.by_ref().take(4).enumerate() { | ||
| 351 | T::regs().sqr1().modify(|w| w.set_sq(idx, *ch)); | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | fn get_res_clks(res: Resolution) -> u32 { | ||
| 356 | match res { | ||
| 357 | Resolution::TwelveBit => 12, | ||
| 358 | Resolution::TenBit => 11, | ||
| 359 | Resolution::EightBit => 9, | ||
| 360 | Resolution::SixBit => 7, | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | fn get_sample_time_clks(sample_time: SampleTime) -> u32 { | ||
| 365 | match sample_time { | ||
| 366 | SampleTime::Cycles4 => 4, | ||
| 367 | SampleTime::Cycles9 => 9, | ||
| 368 | SampleTime::Cycles16 => 16, | ||
| 369 | SampleTime::Cycles24 => 24, | ||
| 370 | SampleTime::Cycles48 => 48, | ||
| 371 | SampleTime::Cycles96 => 96, | ||
| 372 | SampleTime::Cycles192 => 192, | ||
| 373 | SampleTime::Cycles384 => 384, | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { | ||
| 378 | let res_clks = Self::get_res_clks(self.resolution()); | ||
| 379 | let us_clks = us * Self::freq().0 / 1_000_000; | ||
| 380 | let clks = us_clks.saturating_sub(res_clks); | ||
| 381 | match clks { | ||
| 382 | 0..=4 => SampleTime::Cycles4, | ||
| 383 | 5..=9 => SampleTime::Cycles9, | ||
| 384 | 10..=16 => SampleTime::Cycles16, | ||
| 385 | 17..=24 => SampleTime::Cycles24, | ||
| 386 | 25..=48 => SampleTime::Cycles48, | ||
| 387 | 49..=96 => SampleTime::Cycles96, | ||
| 388 | 97..=192 => SampleTime::Cycles192, | ||
| 389 | 193.. => SampleTime::Cycles384, | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | pub fn us_for_cfg(&self, res: Resolution, sample_time: SampleTime) -> u32 { | ||
| 394 | let res_clks = Self::get_res_clks(res); | ||
| 395 | let sample_clks = Self::get_sample_time_clks(sample_time); | ||
| 396 | (res_clks + sample_clks) * 1_000_000 / Self::freq().0 | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | impl<'d, T: Instance> Drop for Adc<'d, T> { | ||
| 401 | fn drop(&mut self) { | ||
| 402 | while !T::regs().sr().read().adons() {} | ||
| 403 | |||
| 404 | T::regs().cr2().modify(|w| w.set_adon(false)); | ||
| 405 | |||
| 406 | T::disable(); | ||
| 407 | } | ||
| 408 | } | ||
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 3e2980bf4..dbe53c807 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #[cfg(not(adc_f3_v2))] | 3 | #[cfg(not(adc_f3_v2))] |
| 4 | #[cfg_attr(adc_f1, path = "f1.rs")] | 4 | #[cfg_attr(adc_f1, path = "f1.rs")] |
| 5 | #[cfg_attr(adc_f3, path = "f3.rs")] | 5 | #[cfg_attr(adc_f3, path = "f3.rs")] |
| 6 | #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] | ||
| 6 | #[cfg_attr(adc_v1, path = "v1.rs")] | 7 | #[cfg_attr(adc_v1, path = "v1.rs")] |
| 7 | #[cfg_attr(adc_v2, path = "v2.rs")] | 8 | #[cfg_attr(adc_v2, path = "v2.rs")] |
| 8 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] | 9 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] |
| @@ -26,20 +27,20 @@ use crate::peripherals; | |||
| 26 | pub struct Adc<'d, T: Instance> { | 27 | pub struct Adc<'d, T: Instance> { |
| 27 | #[allow(unused)] | 28 | #[allow(unused)] |
| 28 | adc: crate::PeripheralRef<'d, T>, | 29 | adc: crate::PeripheralRef<'d, T>, |
| 29 | #[cfg(not(adc_f3_v2))] | 30 | #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] |
| 30 | sample_time: SampleTime, | 31 | sample_time: SampleTime, |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | pub(crate) mod sealed { | 34 | pub(crate) mod sealed { |
| 34 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | 35 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] |
| 35 | use embassy_sync::waitqueue::AtomicWaker; | 36 | use embassy_sync::waitqueue::AtomicWaker; |
| 36 | 37 | ||
| 37 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | 38 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] |
| 38 | pub struct State { | 39 | pub struct State { |
| 39 | pub waker: AtomicWaker, | 40 | pub waker: AtomicWaker, |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | 43 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] |
| 43 | impl State { | 44 | impl State { |
| 44 | pub const fn new() -> Self { | 45 | pub const fn new() -> Self { |
| 45 | Self { | 46 | Self { |
| @@ -54,11 +55,11 @@ pub(crate) mod sealed { | |||
| 54 | 55 | ||
| 55 | pub trait Instance: InterruptableInstance { | 56 | pub trait Instance: InterruptableInstance { |
| 56 | fn regs() -> crate::pac::adc::Adc; | 57 | fn regs() -> crate::pac::adc::Adc; |
| 57 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] | 58 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] |
| 58 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 59 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 59 | #[cfg(adc_f3)] | 60 | #[cfg(adc_f3)] |
| 60 | fn frequency() -> crate::time::Hertz; | 61 | fn frequency() -> crate::time::Hertz; |
| 61 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | 62 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] |
| 62 | fn state() -> &'static State; | 63 | fn state() -> &'static State; |
| 63 | } | 64 | } |
| 64 | 65 | ||
| @@ -74,9 +75,9 @@ pub(crate) mod sealed { | |||
| 74 | } | 75 | } |
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0)))] | 78 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] |
| 78 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 79 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} |
| 79 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0))] | 80 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] |
| 80 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 81 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} |
| 81 | 82 | ||
| 82 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} | 83 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} |
| @@ -89,7 +90,7 @@ foreach_adc!( | |||
| 89 | crate::pac::$inst | 90 | crate::pac::$inst |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] | 93 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] |
| 93 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 94 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 94 | return crate::pac::$common_inst | 95 | return crate::pac::$common_inst |
| 95 | } | 96 | } |
| @@ -99,7 +100,7 @@ foreach_adc!( | |||
| 99 | unsafe { crate::rcc::get_freqs() }.$clock.unwrap() | 100 | unsafe { crate::rcc::get_freqs() }.$clock.unwrap() |
| 100 | } | 101 | } |
| 101 | 102 | ||
| 102 | #[cfg(any(adc_f1, adc_f3, adc_v1))] | 103 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] |
| 103 | fn state() -> &'static sealed::State { | 104 | fn state() -> &'static sealed::State { |
| 104 | static STATE: sealed::State = sealed::State::new(); | 105 | static STATE: sealed::State = sealed::State::new(); |
| 105 | &STATE | 106 | &STATE |
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 5668137b5..b1597a821 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] | 1 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] |
| 2 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 2 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| 3 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 3 | pub enum Resolution { | 4 | pub enum Resolution { |
| 4 | TwelveBit, | 5 | TwelveBit, |
| 5 | TenBit, | 6 | TenBit, |
| @@ -9,6 +10,7 @@ pub enum Resolution { | |||
| 9 | 10 | ||
| 10 | #[cfg(adc_v4)] | 11 | #[cfg(adc_v4)] |
| 11 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 12 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| 13 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 12 | pub enum Resolution { | 14 | pub enum Resolution { |
| 13 | SixteenBit, | 15 | SixteenBit, |
| 14 | FourteenBit, | 16 | FourteenBit, |
| @@ -19,7 +21,7 @@ pub enum Resolution { | |||
| 19 | 21 | ||
| 20 | impl Default for Resolution { | 22 | impl Default for Resolution { |
| 21 | fn default() -> Self { | 23 | fn default() -> Self { |
| 22 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] | 24 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] |
| 23 | { | 25 | { |
| 24 | Self::TwelveBit | 26 | Self::TwelveBit |
| 25 | } | 27 | } |
| @@ -40,12 +42,28 @@ impl From<Resolution> for crate::pac::adc::vals::Res { | |||
| 40 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, | 42 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, |
| 41 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, | 43 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, |
| 42 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, | 44 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, |
| 43 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] | 45 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] |
| 44 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, | 46 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, |
| 45 | } | 47 | } |
| 46 | } | 48 | } |
| 47 | } | 49 | } |
| 48 | 50 | ||
| 51 | impl From<crate::pac::adc::vals::Res> for Resolution { | ||
| 52 | fn from(res: crate::pac::adc::vals::Res) -> Resolution { | ||
| 53 | match res { | ||
| 54 | #[cfg(adc_v4)] | ||
| 55 | crate::pac::adc::vals::Res::SIXTEENBIT => Resolution::SixteenBit, | ||
| 56 | #[cfg(adc_v4)] | ||
| 57 | crate::pac::adc::vals::Res::FOURTEENBITV => Resolution::FourteenBit, | ||
| 58 | crate::pac::adc::vals::Res::TWELVEBIT => Resolution::TwelveBit, | ||
| 59 | crate::pac::adc::vals::Res::TENBIT => Resolution::TenBit, | ||
| 60 | crate::pac::adc::vals::Res::EIGHTBIT => Resolution::EightBit, | ||
| 61 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1, adc_f3_v3))] | ||
| 62 | crate::pac::adc::vals::Res::SIXBIT => Resolution::SixBit, | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 49 | impl Resolution { | 67 | impl Resolution { |
| 50 | pub fn to_max_count(&self) -> u32 { | 68 | pub fn to_max_count(&self) -> u32 { |
| 51 | match self { | 69 | match self { |
| @@ -56,7 +74,7 @@ impl Resolution { | |||
| 56 | Resolution::TwelveBit => (1 << 12) - 1, | 74 | Resolution::TwelveBit => (1 << 12) - 1, |
| 57 | Resolution::TenBit => (1 << 10) - 1, | 75 | Resolution::TenBit => (1 << 10) - 1, |
| 58 | Resolution::EightBit => (1 << 8) - 1, | 76 | Resolution::EightBit => (1 << 8) - 1, |
| 59 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] | 77 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] |
| 60 | Resolution::SixBit => (1 << 6) - 1, | 78 | Resolution::SixBit => (1 << 6) - 1, |
| 61 | } | 79 | } |
| 62 | } | 80 | } |
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index 6a6619299..5a06f1a5a 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs | |||
| @@ -3,6 +3,7 @@ macro_rules! impl_sample_time { | |||
| 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { | 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { |
| 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] | 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] |
| 5 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] | 5 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] |
| 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 6 | pub enum SampleTime { | 7 | pub enum SampleTime { |
| 7 | $( | 8 | $( |
| 8 | #[doc = concat!($doc, " ADC clock cycles.")] | 9 | #[doc = concat!($doc, " ADC clock cycles.")] |
| @@ -18,6 +19,14 @@ macro_rules! impl_sample_time { | |||
| 18 | } | 19 | } |
| 19 | } | 20 | } |
| 20 | 21 | ||
| 22 | impl From<crate::pac::adc::vals::SampleTime> for SampleTime { | ||
| 23 | fn from(sample_time: crate::pac::adc::vals::SampleTime) -> SampleTime { | ||
| 24 | match sample_time { | ||
| 25 | $(crate::pac::adc::vals::SampleTime::$pac_variant => SampleTime::$variant),* | ||
| 26 | } | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 21 | impl Default for SampleTime { | 30 | impl Default for SampleTime { |
| 22 | fn default() -> Self { | 31 | fn default() -> Self { |
| 23 | Self::$default | 32 | Self::$default |
| @@ -121,3 +130,19 @@ impl_sample_time!( | |||
| 121 | ("601.5", Cycles601_5, CYCLES601_5) | 130 | ("601.5", Cycles601_5, CYCLES601_5) |
| 122 | ) | 131 | ) |
| 123 | ); | 132 | ); |
| 133 | |||
| 134 | #[cfg(any(adc_f3_v1_1))] | ||
| 135 | impl_sample_time!( | ||
| 136 | "4", | ||
| 137 | Cycles4, | ||
| 138 | ( | ||
| 139 | ("4", Cycles4, CYCLES4), | ||
| 140 | ("9", Cycles9, CYCLES9), | ||
| 141 | ("16", Cycles16, CYCLES16), | ||
| 142 | ("24", Cycles24, CYCLES24), | ||
| 143 | ("48", Cycles48, CYCLES48), | ||
| 144 | ("96", Cycles96, CYCLES96), | ||
| 145 | ("192", Cycles192, CYCLES192), | ||
| 146 | ("384", Cycles384, CYCLES384) | ||
| 147 | ) | ||
| 148 | ); | ||
