diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-12-08 19:30:50 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-12-08 19:30:50 +0000 |
| commit | a9ec623622de294478506630c02bb003a9e15734 (patch) | |
| tree | 100cf3c9b11b0d181d6866074cc36e42568bca11 | |
| parent | c94a9b8d75ef938aaeb3df18c1eaeb996d655ba0 (diff) | |
| parent | fe218ed978a76014b45410e188f974e20adba1a0 (diff) | |
Merge pull request #2246 from CaptainMaso/adc_f3_v1_1
stm32: add ADC f3_v1_1
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/f1.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/f3_v1_1.rs | 413 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/resolution.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/sample_time.rs | 25 | ||||
| -rw-r--r-- | embassy-stm32/src/can/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/g4.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 4 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 17 | ||||
| -rw-r--r-- | tests/stm32/src/bin/dac.rs | 5 | ||||
| -rw-r--r-- | tests/stm32/src/bin/dac_l1.rs | 86 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 9 |
14 files changed, 572 insertions, 32 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index a8790ce63..979d15c0c 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -58,7 +58,7 @@ rand_core = "0.6.3" | |||
| 58 | sdio-host = "0.5.0" | 58 | sdio-host = "0.5.0" |
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 60 | critical-section = "1.1" |
| 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-019a5da1c47c092c199bc39a7f84fb444f2adcdf" } |
| 62 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 76 | [build-dependencies] | 76 | [build-dependencies] |
| 77 | proc-macro2 = "1.0.36" | 77 | proc-macro2 = "1.0.36" |
| 78 | quote = "1.0.15" | 78 | quote = "1.0.15" |
| 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd", default-features = false, features = ["metadata"]} | 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-019a5da1c47c092c199bc39a7f84fb444f2adcdf", default-features = false, features = ["metadata"]} |
| 80 | 80 | ||
| 81 | 81 | ||
| 82 | [features] | 82 | [features] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 7bfd290d2..0eef43ac4 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -930,6 +930,10 @@ fn main() { | |||
| 930 | } else if pin.signal.starts_with("INN") { | 930 | } else if pin.signal.starts_with("INN") { |
| 931 | // TODO handle in the future when embassy supports differential measurements | 931 | // TODO handle in the future when embassy supports differential measurements |
| 932 | None | 932 | None |
| 933 | } else if pin.signal.starts_with("IN") && pin.signal.ends_with("b") { | ||
| 934 | // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63 | ||
| 935 | let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix("b").unwrap(); | ||
| 936 | Some(32u8 + signal.parse::<u8>().unwrap()) | ||
| 933 | } else if pin.signal.starts_with("IN") { | 937 | } else if pin.signal.starts_with("IN") { |
| 934 | Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap()) | 938 | Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap()) |
| 935 | } else { | 939 | } else { |
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index ad0f13826..fb27bb87b 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs | |||
| @@ -148,7 +148,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 148 | reg.set_cont(false); | 148 | reg.set_cont(false); |
| 149 | reg.set_exttrig(true); | 149 | reg.set_exttrig(true); |
| 150 | reg.set_swstart(false); | 150 | reg.set_swstart(false); |
| 151 | reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART); | 151 | reg.set_extsel(7); // SWSTART |
| 152 | }); | 152 | }); |
| 153 | 153 | ||
| 154 | // Configure the channel to sample | 154 | // Configure the channel to sample |
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..6915a8f1c --- /dev/null +++ b/embassy-stm32/src/adc/f3_v1_1.rs | |||
| @@ -0,0 +1,413 @@ | |||
| 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 | match T::regs().cr1().read().res() { | ||
| 179 | crate::pac::adc::vals::Res::TWELVEBIT => Resolution::TwelveBit, | ||
| 180 | crate::pac::adc::vals::Res::TENBIT => Resolution::TenBit, | ||
| 181 | crate::pac::adc::vals::Res::EIGHTBIT => Resolution::EightBit, | ||
| 182 | crate::pac::adc::vals::Res::SIXBIT => Resolution::SixBit, | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | pub fn enable_vref(&self) -> Vref<T> { | ||
| 187 | update_vref::<T>(1); | ||
| 188 | |||
| 189 | Vref(core::marker::PhantomData) | ||
| 190 | } | ||
| 191 | |||
| 192 | pub fn enable_temperature(&self) -> Temperature<T> { | ||
| 193 | T::regs().ccr().modify(|w| w.set_tsvrefe(true)); | ||
| 194 | |||
| 195 | Temperature::<T>(core::marker::PhantomData) | ||
| 196 | } | ||
| 197 | |||
| 198 | /// Perform a single conversion. | ||
| 199 | async fn convert(&mut self) -> u16 { | ||
| 200 | let was_on = Self::is_on(); | ||
| 201 | |||
| 202 | if !was_on { | ||
| 203 | self.start_adc().await; | ||
| 204 | } | ||
| 205 | |||
| 206 | self.wait_sample_ready().await; | ||
| 207 | |||
| 208 | T::regs().sr().write(|_| {}); | ||
| 209 | T::regs().cr1().modify(|w| { | ||
| 210 | w.set_eocie(true); | ||
| 211 | w.set_scan(false); | ||
| 212 | }); | ||
| 213 | T::regs().cr2().modify(|w| { | ||
| 214 | w.set_swstart(true); | ||
| 215 | w.set_cont(false); | ||
| 216 | }); // swstart cleared by HW | ||
| 217 | |||
| 218 | let res = poll_fn(|cx| { | ||
| 219 | T::state().waker.register(cx.waker()); | ||
| 220 | |||
| 221 | if T::regs().sr().read().eoc() { | ||
| 222 | let res = T::regs().dr().read().rdata(); | ||
| 223 | Poll::Ready(res) | ||
| 224 | } else { | ||
| 225 | Poll::Pending | ||
| 226 | } | ||
| 227 | }) | ||
| 228 | .await; | ||
| 229 | |||
| 230 | if !was_on { | ||
| 231 | self.stop_adc().await; | ||
| 232 | } | ||
| 233 | |||
| 234 | res | ||
| 235 | } | ||
| 236 | |||
| 237 | #[inline(always)] | ||
| 238 | fn is_on() -> bool { | ||
| 239 | T::regs().sr().read().adons() || T::regs().cr2().read().adon() | ||
| 240 | } | ||
| 241 | |||
| 242 | pub async fn start_adc(&self) { | ||
| 243 | //defmt::trace!("Turn ADC on"); | ||
| 244 | T::regs().cr2().modify(|w| w.set_adon(true)); | ||
| 245 | //defmt::trace!("Waiting for ADC to turn on"); | ||
| 246 | |||
| 247 | let mut t = Instant::now(); | ||
| 248 | |||
| 249 | while !T::regs().sr().read().adons() { | ||
| 250 | yield_now().await; | ||
| 251 | if t.elapsed() > embassy_time::Duration::from_millis(1000) { | ||
| 252 | t = Instant::now(); | ||
| 253 | //defmt::trace!("ADC still not on"); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | //defmt::trace!("ADC on"); | ||
| 258 | } | ||
| 259 | |||
| 260 | pub async fn stop_adc(&self) { | ||
| 261 | if T::regs().cr2().read().adon() { | ||
| 262 | //defmt::trace!("ADC should be on, wait for it to start"); | ||
| 263 | while !T::regs().csr().read().adons1() { | ||
| 264 | yield_now().await; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | //defmt::trace!("Turn ADC off"); | ||
| 269 | |||
| 270 | T::regs().cr2().modify(|w| w.set_adon(false)); | ||
| 271 | |||
| 272 | //defmt::trace!("Waiting for ADC to turn off"); | ||
| 273 | |||
| 274 | while T::regs().csr().read().adons1() { | ||
| 275 | yield_now().await; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | ||
| 280 | self.set_sample_sequence(&[pin.channel()]).await; | ||
| 281 | self.convert().await | ||
| 282 | } | ||
| 283 | |||
| 284 | async fn wait_sample_ready(&self) { | ||
| 285 | //trace!("Waiting for sample channel to be ready"); | ||
| 286 | while T::regs().sr().read().rcnr() { | ||
| 287 | yield_now().await; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | pub async fn set_sample_time(&mut self, pin: &mut impl AdcPin<T>, sample_time: SampleTime) { | ||
| 292 | if Self::get_channel_sample_time(pin.channel()) != sample_time { | ||
| 293 | self.stop_adc().await; | ||
| 294 | unsafe { | ||
| 295 | Self::set_channel_sample_time(pin.channel(), sample_time); | ||
| 296 | } | ||
| 297 | self.start_adc().await; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | pub fn get_sample_time(&self, pin: &impl AdcPin<T>) -> SampleTime { | ||
| 302 | Self::get_channel_sample_time(pin.channel()) | ||
| 303 | } | ||
| 304 | |||
| 305 | /// Sets the channel sample time | ||
| 306 | /// | ||
| 307 | /// ## SAFETY: | ||
| 308 | /// - ADON == 0 i.e ADC must not be enabled when this is called. | ||
| 309 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||
| 310 | let sample_time = sample_time.into(); | ||
| 311 | |||
| 312 | match ch { | ||
| 313 | 0..=9 => T::regs().smpr3().modify(|reg| reg.set_smp(ch as _, sample_time)), | ||
| 314 | 10..=19 => T::regs() | ||
| 315 | .smpr2() | ||
| 316 | .modify(|reg| reg.set_smp(ch as usize - 10, sample_time)), | ||
| 317 | 20..=29 => T::regs() | ||
| 318 | .smpr1() | ||
| 319 | .modify(|reg| reg.set_smp(ch as usize - 20, sample_time)), | ||
| 320 | 30..=31 => T::regs() | ||
| 321 | .smpr0() | ||
| 322 | .modify(|reg| reg.set_smp(ch as usize - 30, sample_time)), | ||
| 323 | _ => panic!("Invalid channel to sample"), | ||
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | fn get_channel_sample_time(ch: u8) -> SampleTime { | ||
| 328 | match ch { | ||
| 329 | 0..=9 => T::regs().smpr3().read().smp(ch as _), | ||
| 330 | 10..=19 => T::regs().smpr2().read().smp(ch as usize - 10), | ||
| 331 | 20..=29 => T::regs().smpr1().read().smp(ch as usize - 20), | ||
| 332 | 30..=31 => T::regs().smpr0().read().smp(ch as usize - 30), | ||
| 333 | _ => panic!("Invalid channel to sample"), | ||
| 334 | } | ||
| 335 | .into() | ||
| 336 | } | ||
| 337 | |||
| 338 | /// Sets the sequence to sample the ADC. Must be less than 28 elements. | ||
| 339 | async fn set_sample_sequence(&self, sequence: &[u8]) { | ||
| 340 | assert!(sequence.len() <= 28); | ||
| 341 | let mut iter = sequence.iter(); | ||
| 342 | T::regs().sqr1().modify(|w| w.set_l((sequence.len() - 1) as _)); | ||
| 343 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 344 | T::regs().sqr5().modify(|w| w.set_sq(idx, *ch)); | ||
| 345 | } | ||
| 346 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 347 | T::regs().sqr4().modify(|w| w.set_sq(idx, *ch)); | ||
| 348 | } | ||
| 349 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 350 | T::regs().sqr3().modify(|w| w.set_sq(idx, *ch)); | ||
| 351 | } | ||
| 352 | for (idx, ch) in iter.by_ref().take(6).enumerate() { | ||
| 353 | T::regs().sqr2().modify(|w| w.set_sq(idx, *ch)); | ||
| 354 | } | ||
| 355 | for (idx, ch) in iter.by_ref().take(4).enumerate() { | ||
| 356 | T::regs().sqr1().modify(|w| w.set_sq(idx, *ch)); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | fn get_res_clks(res: Resolution) -> u32 { | ||
| 361 | match res { | ||
| 362 | Resolution::TwelveBit => 12, | ||
| 363 | Resolution::TenBit => 11, | ||
| 364 | Resolution::EightBit => 9, | ||
| 365 | Resolution::SixBit => 7, | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | fn get_sample_time_clks(sample_time: SampleTime) -> u32 { | ||
| 370 | match sample_time { | ||
| 371 | SampleTime::Cycles4 => 4, | ||
| 372 | SampleTime::Cycles9 => 9, | ||
| 373 | SampleTime::Cycles16 => 16, | ||
| 374 | SampleTime::Cycles24 => 24, | ||
| 375 | SampleTime::Cycles48 => 48, | ||
| 376 | SampleTime::Cycles96 => 96, | ||
| 377 | SampleTime::Cycles192 => 192, | ||
| 378 | SampleTime::Cycles384 => 384, | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { | ||
| 383 | let res_clks = Self::get_res_clks(self.resolution()); | ||
| 384 | let us_clks = us * Self::freq().0 / 1_000_000; | ||
| 385 | let clks = us_clks.saturating_sub(res_clks); | ||
| 386 | match clks { | ||
| 387 | 0..=4 => SampleTime::Cycles4, | ||
| 388 | 5..=9 => SampleTime::Cycles9, | ||
| 389 | 10..=16 => SampleTime::Cycles16, | ||
| 390 | 17..=24 => SampleTime::Cycles24, | ||
| 391 | 25..=48 => SampleTime::Cycles48, | ||
| 392 | 49..=96 => SampleTime::Cycles96, | ||
| 393 | 97..=192 => SampleTime::Cycles192, | ||
| 394 | 193.. => SampleTime::Cycles384, | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | pub fn us_for_cfg(&self, res: Resolution, sample_time: SampleTime) -> u32 { | ||
| 399 | let res_clks = Self::get_res_clks(res); | ||
| 400 | let sample_clks = Self::get_sample_time_clks(sample_time); | ||
| 401 | (res_clks + sample_clks) * 1_000_000 / Self::freq().0 | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | impl<'d, T: Instance> Drop for Adc<'d, T> { | ||
| 406 | fn drop(&mut self) { | ||
| 407 | while !T::regs().sr().read().adons() {} | ||
| 408 | |||
| 409 | T::regs().cr2().modify(|w| w.set_adon(false)); | ||
| 410 | |||
| 411 | T::disable(); | ||
| 412 | } | ||
| 413 | } | ||
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..383980b5a 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,7 +42,7 @@ 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 | } |
| @@ -56,7 +58,7 @@ impl Resolution { | |||
| 56 | Resolution::TwelveBit => (1 << 12) - 1, | 58 | Resolution::TwelveBit => (1 << 12) - 1, |
| 57 | Resolution::TenBit => (1 << 10) - 1, | 59 | Resolution::TenBit => (1 << 10) - 1, |
| 58 | Resolution::EightBit => (1 << 8) - 1, | 60 | Resolution::EightBit => (1 << 8) - 1, |
| 59 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] | 61 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] |
| 60 | Resolution::SixBit => (1 << 6) - 1, | 62 | Resolution::SixBit => (1 << 6) - 1, |
| 61 | } | 63 | } |
| 62 | } | 64 | } |
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 | ); | ||
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs index 4ff5aa0de..425f9ac2e 100644 --- a/embassy-stm32/src/can/mod.rs +++ b/embassy-stm32/src/can/mod.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg_attr(can_bxcan, path = "bxcan.rs")] | 3 | #[cfg_attr(can_bxcan, path = "bxcan.rs")] |
| 4 | #[cfg_attr(can_fdcan, path = "fdcan.rs")] | 4 | #[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")] |
| 5 | mod _version; | 5 | mod _version; |
| 6 | pub use _version::*; | 6 | pub use _version::*; |
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 48b27255d..7af05b485 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs | |||
| @@ -315,6 +315,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 315 | adc: adc12_ck, | 315 | adc: adc12_ck, |
| 316 | adc34: adc345_ck, | 316 | adc34: adc345_ck, |
| 317 | pll1_p: None, | 317 | pll1_p: None, |
| 318 | pll1_q: None, // TODO | ||
| 319 | hse: None, // TODO | ||
| 318 | rtc, | 320 | rtc, |
| 319 | }); | 321 | }); |
| 320 | } | 322 | } |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 2e144dc77..40a5a619d 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -119,7 +119,7 @@ pub struct Clocks { | |||
| 119 | 119 | ||
| 120 | #[cfg(any(stm32g4, rcc_l4))] | 120 | #[cfg(any(stm32g4, rcc_l4))] |
| 121 | pub pll1_p: Option<Hertz>, | 121 | pub pll1_p: Option<Hertz>, |
| 122 | #[cfg(any(stm32h5, stm32h7, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_l4))] | 122 | #[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g4))] |
| 123 | pub pll1_q: Option<Hertz>, | 123 | pub pll1_q: Option<Hertz>, |
| 124 | #[cfg(any(stm32h5, stm32h7))] | 124 | #[cfg(any(stm32h5, stm32h7))] |
| 125 | pub pll2_p: Option<Hertz>, | 125 | pub pll2_p: Option<Hertz>, |
| @@ -167,7 +167,7 @@ pub struct Clocks { | |||
| 167 | 167 | ||
| 168 | #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))] | 168 | #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))] |
| 169 | pub lse: Option<Hertz>, | 169 | pub lse: Option<Hertz>, |
| 170 | #[cfg(any(stm32h5, stm32h7))] | 170 | #[cfg(any(stm32h5, stm32h7, stm32g4))] |
| 171 | pub hse: Option<Hertz>, | 171 | pub hse: Option<Hertz>, |
| 172 | 172 | ||
| 173 | #[cfg(stm32h5)] | 173 | #[cfg(stm32h5)] |
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index c37d89a40..4f53e84f0 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -10,14 +10,14 @@ stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] | |||
| 10 | stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] | 10 | stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] |
| 11 | stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"] | 11 | stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"] |
| 12 | stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] | 12 | stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] |
| 13 | stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin", "rng"] | 13 | stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] |
| 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac-adc-pin", "sdmmc"] | 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] |
| 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] |
| 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac-adc-pin"] | 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] |
| 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"] | 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"] |
| 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] | 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] |
| 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] | 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] |
| 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin", "rng"] | 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"] |
| 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"] | 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"] |
| 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] | 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] |
| 23 | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] | 23 | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] |
| @@ -41,7 +41,7 @@ ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] | |||
| 41 | mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] | 41 | mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] |
| 42 | embassy-stm32-wpan = [] | 42 | embassy-stm32-wpan = [] |
| 43 | not-gpdma = [] | 43 | not-gpdma = [] |
| 44 | dac-adc-pin = [] | 44 | dac = [] |
| 45 | 45 | ||
| 46 | cm0 = ["portable-atomic/unsafe-assume-single-core"] | 46 | cm0 = ["portable-atomic/unsafe-assume-single-core"] |
| 47 | 47 | ||
| @@ -84,7 +84,12 @@ required-features = [ "can",] | |||
| 84 | [[bin]] | 84 | [[bin]] |
| 85 | name = "dac" | 85 | name = "dac" |
| 86 | path = "src/bin/dac.rs" | 86 | path = "src/bin/dac.rs" |
| 87 | required-features = [ "dac-adc-pin",] | 87 | required-features = [ "dac",] |
| 88 | |||
| 89 | [[bin]] | ||
| 90 | name = "dac_l1" | ||
| 91 | path = "src/bin/dac_l1.rs" | ||
| 92 | required-features = [ "stm32l152re",] | ||
| 88 | 93 | ||
| 89 | [[bin]] | 94 | [[bin]] |
| 90 | name = "eth" | 95 | name = "eth" |
diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs index cf43106b3..9d64742df 100644 --- a/tests/stm32/src/bin/dac.rs +++ b/tests/stm32/src/bin/dac.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | // required-features: dac-adc-pin | 4 | // required-features: dac |
| 5 | 5 | ||
| 6 | #[path = "../common.rs"] | 6 | #[path = "../common.rs"] |
| 7 | mod common; | 7 | mod common; |
| @@ -22,12 +22,13 @@ async fn main(_spawner: Spawner) { | |||
| 22 | // Initialize the board and obtain a Peripherals instance | 22 | // Initialize the board and obtain a Peripherals instance |
| 23 | let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); | 23 | let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); |
| 24 | 24 | ||
| 25 | let adc = peri!(p, ADC); | ||
| 25 | let dac = peri!(p, DAC); | 26 | let dac = peri!(p, DAC); |
| 26 | let dac_pin = peri!(p, DAC_PIN); | 27 | let dac_pin = peri!(p, DAC_PIN); |
| 27 | let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; | 28 | let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; |
| 28 | 29 | ||
| 29 | let mut dac = DacCh1::new(dac, NoDma, dac_pin); | 30 | let mut dac = DacCh1::new(dac, NoDma, dac_pin); |
| 30 | let mut adc = Adc::new(p.ADC1, &mut Delay); | 31 | let mut adc = Adc::new(adc, &mut Delay); |
| 31 | 32 | ||
| 32 | #[cfg(feature = "stm32h755zi")] | 33 | #[cfg(feature = "stm32h755zi")] |
| 33 | let normalization_factor = 256; | 34 | let normalization_factor = 256; |
diff --git a/tests/stm32/src/bin/dac_l1.rs b/tests/stm32/src/bin/dac_l1.rs new file mode 100644 index 000000000..f8b00aaef --- /dev/null +++ b/tests/stm32/src/bin/dac_l1.rs | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | // required-features: stm32l152re | ||
| 5 | |||
| 6 | #[path = "../common.rs"] | ||
| 7 | mod common; | ||
| 8 | use core::f32::consts::PI; | ||
| 9 | |||
| 10 | use common::*; | ||
| 11 | use defmt::assert; | ||
| 12 | use embassy_executor::Spawner; | ||
| 13 | use embassy_stm32::adc::Adc; | ||
| 14 | use embassy_stm32::dac::{DacCh1, Value}; | ||
| 15 | use embassy_stm32::dma::NoDma; | ||
| 16 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 17 | use embassy_time::Timer; | ||
| 18 | use micromath::F32Ext; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | bind_interrupts!(struct Irqs { | ||
| 22 | ADC1 => embassy_stm32::adc::InterruptHandler<peripherals::ADC>; | ||
| 23 | }); | ||
| 24 | |||
| 25 | #[embassy_executor::main] | ||
| 26 | async fn main(_spawner: Spawner) { | ||
| 27 | // Initialize the board and obtain a Peripherals instance | ||
| 28 | let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); | ||
| 29 | |||
| 30 | let adc = peri!(p, ADC); | ||
| 31 | let dac = peri!(p, DAC); | ||
| 32 | let dac_pin = peri!(p, DAC_PIN); | ||
| 33 | let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; | ||
| 34 | |||
| 35 | let mut dac = DacCh1::new(dac, NoDma, dac_pin); | ||
| 36 | let mut adc = Adc::new(adc, Irqs); | ||
| 37 | |||
| 38 | #[cfg(feature = "stm32h755zi")] | ||
| 39 | let normalization_factor = 256; | ||
| 40 | #[cfg(any( | ||
| 41 | feature = "stm32f429zi", | ||
| 42 | feature = "stm32f446re", | ||
| 43 | feature = "stm32g071rb", | ||
| 44 | feature = "stm32l152re", | ||
| 45 | ))] | ||
| 46 | let normalization_factor: i32 = 16; | ||
| 47 | |||
| 48 | dac.set(Value::Bit8(0)); | ||
| 49 | // Now wait a little to obtain a stable value | ||
| 50 | Timer::after_millis(30).await; | ||
| 51 | let offset = adc.read(&mut adc_pin).await; | ||
| 52 | |||
| 53 | for v in 0..=255 { | ||
| 54 | // First set the DAC output value | ||
| 55 | let dac_output_val = to_sine_wave(v); | ||
| 56 | dac.set(Value::Bit8(dac_output_val)); | ||
| 57 | |||
| 58 | // Now wait a little to obtain a stable value | ||
| 59 | Timer::after_millis(30).await; | ||
| 60 | |||
| 61 | // Need to steal the peripherals here because PA4 is obviously in use already | ||
| 62 | let measured = adc.read(&mut unsafe { embassy_stm32::Peripherals::steal() }.PA4).await; | ||
| 63 | // Calibrate and normalize the measurement to get close to the dac_output_val | ||
| 64 | let measured_normalized = ((measured as i32 - offset as i32) / normalization_factor) as i16; | ||
| 65 | |||
| 66 | info!("value / measured: {} / {}", dac_output_val, measured_normalized); | ||
| 67 | |||
| 68 | // The deviations are quite enormous but that does not matter since this is only a quick test | ||
| 69 | assert!((dac_output_val as i16 - measured_normalized).abs() < 15); | ||
| 70 | } | ||
| 71 | |||
| 72 | info!("Test OK"); | ||
| 73 | cortex_m::asm::bkpt(); | ||
| 74 | } | ||
| 75 | |||
| 76 | fn to_sine_wave(v: u8) -> u8 { | ||
| 77 | if v >= 128 { | ||
| 78 | // top half | ||
| 79 | let r = PI * ((v - 128) as f32 / 128.0); | ||
| 80 | (r.sin() * 128.0 + 127.0) as u8 | ||
| 81 | } else { | ||
| 82 | // bottom half | ||
| 83 | let r = PI + PI * (v as f32 / 128.0); | ||
| 84 | (r.sin() * 128.0 + 127.0) as u8 | ||
| 85 | } | ||
| 86 | } | ||
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 155e1d9df..313380b35 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -101,14 +101,14 @@ define_peris!( | |||
| 101 | define_peris!( | 101 | define_peris!( |
| 102 | UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, | 102 | UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, |
| 103 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, | 103 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, |
| 104 | DAC = DAC1, DAC_PIN = PA4, | 104 | ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, |
| 105 | @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, | 105 | @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, |
| 106 | ); | 106 | ); |
| 107 | #[cfg(feature = "stm32f429zi")] | 107 | #[cfg(feature = "stm32f429zi")] |
| 108 | define_peris!( | 108 | define_peris!( |
| 109 | UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1, | 109 | UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1, |
| 110 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2, | 110 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2, |
| 111 | DAC = DAC, DAC_PIN = PA4, | 111 | ADC = ADC1, DAC = DAC, DAC_PIN = PA4, |
| 112 | CAN = CAN1, CAN_RX = PD0, CAN_TX = PD1, | 112 | CAN = CAN1, CAN_RX = PD0, CAN_TX = PD1, |
| 113 | @irq UART = {USART6 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART6>;}, | 113 | @irq UART = {USART6 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART6>;}, |
| 114 | ); | 114 | ); |
| @@ -116,7 +116,7 @@ define_peris!( | |||
| 116 | define_peris!( | 116 | define_peris!( |
| 117 | UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA2_CH7, UART_RX_DMA = DMA2_CH5, | 117 | UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA2_CH7, UART_RX_DMA = DMA2_CH5, |
| 118 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2, | 118 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2, |
| 119 | DAC = DAC, DAC_PIN = PA4, | 119 | ADC = ADC1, DAC = DAC, DAC_PIN = PA4, |
| 120 | CAN = CAN1, CAN_RX = PA11, CAN_TX = PA12, | 120 | CAN = CAN1, CAN_RX = PA11, CAN_TX = PA12, |
| 121 | @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, | 121 | @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, |
| 122 | ); | 122 | ); |
| @@ -130,7 +130,7 @@ define_peris!( | |||
| 130 | define_peris!( | 130 | define_peris!( |
| 131 | UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, | 131 | UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, |
| 132 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, | 132 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, |
| 133 | DAC = DAC1, DAC_PIN = PA4, | 133 | ADC = ADC1, DAC = DAC1, DAC_PIN = PA4, |
| 134 | @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, | 134 | @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, |
| 135 | ); | 135 | ); |
| 136 | #[cfg(feature = "stm32h7a3zi")] | 136 | #[cfg(feature = "stm32h7a3zi")] |
| @@ -191,6 +191,7 @@ define_peris!( | |||
| 191 | define_peris!( | 191 | define_peris!( |
| 192 | UART = USART3, UART_TX = PB10, UART_RX = PB11, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, | 192 | UART = USART3, UART_TX = PB10, UART_RX = PB11, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, |
| 193 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, | 193 | SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, |
| 194 | ADC = ADC, DAC = DAC, DAC_PIN = PA4, | ||
| 194 | @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;}, | 195 | @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;}, |
| 195 | ); | 196 | ); |
| 196 | #[cfg(feature = "stm32l552ze")] | 197 | #[cfg(feature = "stm32l552ze")] |
