diff options
| author | xoviat <[email protected]> | 2025-11-12 20:06:00 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-11-12 20:06:00 -0600 |
| commit | f0506252e21c96ce3b03e0d1c061a831d7dfe3c3 (patch) | |
| tree | 839f8dac139321665abc293f907ad13d5721aede | |
| parent | 07c918023c1b233a2f9f16eb0b654169c0379f79 (diff) | |
stm32: extract adc4
extract adc4 into common adc system and add anyInstance trait to cover adc4 and not adc4
| -rw-r--r-- | embassy-stm32/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/adc4.rs | 312 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 206 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/injected.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 111 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/ringbuffered.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 66 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 302 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v4.rs | 220 | ||||
| -rw-r--r-- | examples/stm32u5/src/bin/adc.rs | 21 | ||||
| -rw-r--r-- | examples/stm32wba/src/bin/adc.rs | 17 | ||||
| -rw-r--r-- | examples/stm32wba6/src/bin/adc.rs | 17 |
13 files changed, 651 insertions, 644 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ec49924a2..2f4f2ce51 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -188,6 +188,7 @@ embedded-io = { version = "0.6.0" } | |||
| 188 | embedded-io-async = { version = "0.6.1" } | 188 | embedded-io-async = { version = "0.6.1" } |
| 189 | chrono = { version = "^0.4", default-features = false, optional = true } | 189 | chrono = { version = "^0.4", default-features = false, optional = true } |
| 190 | bit_field = "0.10.2" | 190 | bit_field = "0.10.2" |
| 191 | trait-set = "0.3.0" | ||
| 191 | document-features = "0.2.7" | 192 | document-features = "0.2.7" |
| 192 | 193 | ||
| 193 | static_assertions = { version = "1.1" } | 194 | static_assertions = { version = "1.1" } |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 48da475df..ad6743f96 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -1602,13 +1602,13 @@ fn main() { | |||
| 1602 | .into(); | 1602 | .into(); |
| 1603 | 1603 | ||
| 1604 | if chip_name.starts_with("stm32u5") { | 1604 | if chip_name.starts_with("stm32u5") { |
| 1605 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4)); | 1605 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); |
| 1606 | } else { | 1606 | } else { |
| 1607 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); | 1607 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); |
| 1608 | } | 1608 | } |
| 1609 | 1609 | ||
| 1610 | if chip_name.starts_with("stm32wba") { | 1610 | if chip_name.starts_with("stm32wba") { |
| 1611 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4)); | 1611 | signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); |
| 1612 | } | 1612 | } |
| 1613 | 1613 | ||
| 1614 | if chip_name.starts_with("stm32g4") { | 1614 | if chip_name.starts_with("stm32g4") { |
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 04d976513..52678d1b6 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs | |||
| @@ -4,8 +4,8 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR | |||
| 4 | #[cfg(stm32wba)] | 4 | #[cfg(stm32wba)] |
| 5 | use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; | 5 | use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; |
| 6 | 6 | ||
| 7 | use super::{AdcChannel, AnyAdcChannel, RxDma4, blocking_delay_us}; | 7 | use super::blocking_delay_us; |
| 8 | use crate::dma::Transfer; | 8 | use crate::adc::ConversionMode; |
| 9 | #[cfg(stm32u5)] | 9 | #[cfg(stm32u5)] |
| 10 | pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; | 10 | pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; |
| 11 | #[cfg(stm32wba)] | 11 | #[cfg(stm32wba)] |
| @@ -153,6 +153,121 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri | |||
| 153 | type Interrupt: crate::interrupt::typelevel::Interrupt; | 153 | type Interrupt: crate::interrupt::typelevel::Interrupt; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | foreach_adc!( | ||
| 157 | (ADC4, $common_inst:ident, $clock:ident) => { | ||
| 158 | use crate::peripherals::ADC4; | ||
| 159 | |||
| 160 | impl super::BasicAnyInstance for ADC4 { | ||
| 161 | type SampleTime = SampleTime; | ||
| 162 | } | ||
| 163 | |||
| 164 | impl super::SealedAnyInstance for ADC4 { | ||
| 165 | fn dr() -> *mut u16 { | ||
| 166 | ADC4::regs().dr().as_ptr() as *mut u16 | ||
| 167 | } | ||
| 168 | |||
| 169 | fn enable() { | ||
| 170 | ADC4::regs().isr().write(|w| w.set_adrdy(true)); | ||
| 171 | ADC4::regs().cr().modify(|w| w.set_aden(true)); | ||
| 172 | while !ADC4::regs().isr().read().adrdy() {} | ||
| 173 | ADC4::regs().isr().write(|w| w.set_adrdy(true)); | ||
| 174 | } | ||
| 175 | |||
| 176 | fn start() { | ||
| 177 | // Start conversion | ||
| 178 | ADC4::regs().cr().modify(|reg| { | ||
| 179 | reg.set_adstart(true); | ||
| 180 | }); | ||
| 181 | } | ||
| 182 | |||
| 183 | fn stop() { | ||
| 184 | if ADC4::regs().cr().read().adstart() && !ADC4::regs().cr().read().addis() { | ||
| 185 | ADC4::regs().cr().modify(|reg| { | ||
| 186 | reg.set_adstp(true); | ||
| 187 | }); | ||
| 188 | while ADC4::regs().cr().read().adstart() {} | ||
| 189 | } | ||
| 190 | |||
| 191 | // Reset configuration. | ||
| 192 | ADC4::regs().cfgr1().modify(|reg| { | ||
| 193 | reg.set_dmaen(false); | ||
| 194 | }); | ||
| 195 | } | ||
| 196 | |||
| 197 | fn configure_dma(conversion_mode: ConversionMode) { | ||
| 198 | match conversion_mode { | ||
| 199 | ConversionMode::Singular => { | ||
| 200 | ADC4::regs().isr().modify(|reg| { | ||
| 201 | reg.set_ovr(true); | ||
| 202 | reg.set_eos(true); | ||
| 203 | reg.set_eoc(true); | ||
| 204 | }); | ||
| 205 | |||
| 206 | ADC4::regs().cfgr1().modify(|reg| { | ||
| 207 | reg.set_dmaen(true); | ||
| 208 | reg.set_dmacfg(Dmacfg::ONE_SHOT); | ||
| 209 | #[cfg(stm32u5)] | ||
| 210 | reg.set_chselrmod(false); | ||
| 211 | #[cfg(stm32wba)] | ||
| 212 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) | ||
| 213 | }); | ||
| 214 | } | ||
| 215 | _ => unreachable!(), | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | ||
| 220 | let mut prev_channel: i16 = -1; | ||
| 221 | #[cfg(stm32wba)] | ||
| 222 | ADC4::regs().chselr().write_value(Chselr(0_u32)); | ||
| 223 | #[cfg(stm32u5)] | ||
| 224 | ADC4::regs().chselrmod0().write_value(Chselr(0_u32)); | ||
| 225 | for (_i, ((channel, _), sample_time)) in sequence.enumerate() { | ||
| 226 | ADC4::regs().smpr().modify(|w| { | ||
| 227 | w.set_smp(_i, sample_time); | ||
| 228 | }); | ||
| 229 | |||
| 230 | let channel_num = channel; | ||
| 231 | if channel_num as i16 <= prev_channel { | ||
| 232 | return; | ||
| 233 | }; | ||
| 234 | prev_channel = channel_num as i16; | ||
| 235 | |||
| 236 | #[cfg(stm32wba)] | ||
| 237 | ADC4::regs().chselr().modify(|w| { | ||
| 238 | w.set_chsel0(channel as usize, true); | ||
| 239 | }); | ||
| 240 | #[cfg(stm32u5)] | ||
| 241 | ADC4::regs().chselrmod0().modify(|w| { | ||
| 242 | w.set_chsel(channel as usize, true); | ||
| 243 | }); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | fn convert() -> u16 { | ||
| 248 | // Reset interrupts | ||
| 249 | ADC4::regs().isr().modify(|reg| { | ||
| 250 | reg.set_eos(true); | ||
| 251 | reg.set_eoc(true); | ||
| 252 | }); | ||
| 253 | |||
| 254 | // Start conversion | ||
| 255 | ADC4::regs().cr().modify(|reg| { | ||
| 256 | reg.set_adstart(true); | ||
| 257 | }); | ||
| 258 | |||
| 259 | while !ADC4::regs().isr().read().eos() { | ||
| 260 | // spin | ||
| 261 | } | ||
| 262 | |||
| 263 | ADC4::regs().dr().read().0 as u16 | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | impl super::AnyInstance for ADC4 {} | ||
| 268 | }; | ||
| 269 | ); | ||
| 270 | |||
| 156 | pub struct Adc4<'d, T: Instance> { | 271 | pub struct Adc4<'d, T: Instance> { |
| 157 | #[allow(unused)] | 272 | #[allow(unused)] |
| 158 | adc: crate::Peri<'d, T>, | 273 | adc: crate::Peri<'d, T>, |
| @@ -164,9 +279,9 @@ pub enum Adc4Error { | |||
| 164 | DMAError, | 279 | DMAError, |
| 165 | } | 280 | } |
| 166 | 281 | ||
| 167 | impl<'d, T: Instance> Adc4<'d, T> { | 282 | impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { |
| 168 | /// Create a new ADC driver. | 283 | /// Create a new ADC driver. |
| 169 | pub fn new(adc: Peri<'d, T>) -> Self { | 284 | pub fn new_adc4(adc: Peri<'d, T>) -> Self { |
| 170 | rcc::enable_and_reset::<T>(); | 285 | rcc::enable_and_reset::<T>(); |
| 171 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 286 | let prescaler = Prescaler::from_ker_ck(T::frequency()); |
| 172 | 287 | ||
| @@ -200,7 +315,7 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 200 | 315 | ||
| 201 | blocking_delay_us(1); | 316 | blocking_delay_us(1); |
| 202 | 317 | ||
| 203 | Self::enable(); | 318 | T::enable(); |
| 204 | 319 | ||
| 205 | // single conversion mode, software trigger | 320 | // single conversion mode, software trigger |
| 206 | T::regs().cfgr1().modify(|w| { | 321 | T::regs().cfgr1().modify(|w| { |
| @@ -231,15 +346,8 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 231 | Self { adc } | 346 | Self { adc } |
| 232 | } | 347 | } |
| 233 | 348 | ||
| 234 | fn enable() { | ||
| 235 | T::regs().isr().write(|w| w.set_adrdy(true)); | ||
| 236 | T::regs().cr().modify(|w| w.set_aden(true)); | ||
| 237 | while !T::regs().isr().read().adrdy() {} | ||
| 238 | T::regs().isr().write(|w| w.set_adrdy(true)); | ||
| 239 | } | ||
| 240 | |||
| 241 | /// Enable reading the voltage reference internal channel. | 349 | /// Enable reading the voltage reference internal channel. |
| 242 | pub fn enable_vrefint(&self) -> super::VrefInt { | 350 | pub fn enable_vrefint_adc4(&self) -> super::VrefInt { |
| 243 | T::regs().ccr().modify(|w| { | 351 | T::regs().ccr().modify(|w| { |
| 244 | w.set_vrefen(true); | 352 | w.set_vrefen(true); |
| 245 | }); | 353 | }); |
| @@ -248,7 +356,7 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 248 | } | 356 | } |
| 249 | 357 | ||
| 250 | /// Enable reading the temperature internal channel. | 358 | /// Enable reading the temperature internal channel. |
| 251 | pub fn enable_temperature(&self) -> super::Temperature { | 359 | pub fn enable_temperature_adc4(&self) -> super::Temperature { |
| 252 | T::regs().ccr().modify(|w| { | 360 | T::regs().ccr().modify(|w| { |
| 253 | w.set_vsensesel(true); | 361 | w.set_vsensesel(true); |
| 254 | }); | 362 | }); |
| @@ -258,7 +366,7 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 258 | 366 | ||
| 259 | /// Enable reading the vbat internal channel. | 367 | /// Enable reading the vbat internal channel. |
| 260 | #[cfg(stm32u5)] | 368 | #[cfg(stm32u5)] |
| 261 | pub fn enable_vbat(&self) -> super::Vbat { | 369 | pub fn enable_vbat_adc4(&self) -> super::Vbat { |
| 262 | T::regs().ccr().modify(|w| { | 370 | T::regs().ccr().modify(|w| { |
| 263 | w.set_vbaten(true); | 371 | w.set_vbaten(true); |
| 264 | }); | 372 | }); |
| @@ -267,13 +375,13 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 267 | } | 375 | } |
| 268 | 376 | ||
| 269 | /// Enable reading the vbat internal channel. | 377 | /// Enable reading the vbat internal channel. |
| 270 | pub fn enable_vcore(&self) -> super::Vcore { | 378 | pub fn enable_vcore_adc4(&self) -> super::Vcore { |
| 271 | super::Vcore {} | 379 | super::Vcore {} |
| 272 | } | 380 | } |
| 273 | 381 | ||
| 274 | /// Enable reading the vbat internal channel. | 382 | /// Enable reading the vbat internal channel. |
| 275 | #[cfg(stm32u5)] | 383 | #[cfg(stm32u5)] |
| 276 | pub fn enable_dac_channel(&self, dac: DacChannel) -> super::Dac { | 384 | pub fn enable_dac_channel_adc4(&self, dac: DacChannel) -> super::Dac { |
| 277 | let mux; | 385 | let mux; |
| 278 | match dac { | 386 | match dac { |
| 279 | DacChannel::OUT1 => mux = false, | 387 | DacChannel::OUT1 => mux = false, |
| @@ -284,13 +392,13 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 284 | } | 392 | } |
| 285 | 393 | ||
| 286 | /// Set the ADC resolution. | 394 | /// Set the ADC resolution. |
| 287 | pub fn set_resolution(&mut self, resolution: Resolution) { | 395 | pub fn set_resolution_adc4(&mut self, resolution: Resolution) { |
| 288 | T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); | 396 | T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); |
| 289 | } | 397 | } |
| 290 | 398 | ||
| 291 | /// Set hardware averaging. | 399 | /// Set hardware averaging. |
| 292 | #[cfg(stm32u5)] | 400 | #[cfg(stm32u5)] |
| 293 | pub fn set_averaging(&mut self, averaging: Averaging) { | 401 | pub fn set_averaging_adc4(&mut self, averaging: Averaging) { |
| 294 | let (enable, samples, right_shift) = match averaging { | 402 | let (enable, samples, right_shift) = match averaging { |
| 295 | Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), | 403 | Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), |
| 296 | Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), | 404 | Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), |
| @@ -310,7 +418,7 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 310 | }) | 418 | }) |
| 311 | } | 419 | } |
| 312 | #[cfg(stm32wba)] | 420 | #[cfg(stm32wba)] |
| 313 | pub fn set_averaging(&mut self, averaging: Averaging) { | 421 | pub fn set_averaging_adc4(&mut self, averaging: Averaging) { |
| 314 | let (enable, samples, right_shift) = match averaging { | 422 | let (enable, samples, right_shift) = match averaging { |
| 315 | Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), | 423 | Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), |
| 316 | Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), | 424 | Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), |
| @@ -329,168 +437,4 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 329 | w.set_ovse(enable) | 437 | w.set_ovse(enable) |
| 330 | }) | 438 | }) |
| 331 | } | 439 | } |
| 332 | |||
| 333 | /// Read an ADC channel. | ||
| 334 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { | ||
| 335 | T::regs().smpr().modify(|w| { | ||
| 336 | w.set_smp(0, sample_time); | ||
| 337 | }); | ||
| 338 | |||
| 339 | channel.setup(); | ||
| 340 | |||
| 341 | // Select channel | ||
| 342 | #[cfg(stm32wba)] | ||
| 343 | { | ||
| 344 | T::regs().chselr().write_value(Chselr(0_u32)); | ||
| 345 | T::regs().chselr().modify(|w| { | ||
| 346 | w.set_chsel0(channel.channel() as usize, true); | ||
| 347 | }); | ||
| 348 | } | ||
| 349 | #[cfg(stm32u5)] | ||
| 350 | { | ||
| 351 | T::regs().chselrmod0().write_value(Chselr(0_u32)); | ||
| 352 | T::regs().chselrmod0().modify(|w| { | ||
| 353 | w.set_chsel(channel.channel() as usize, true); | ||
| 354 | }); | ||
| 355 | } | ||
| 356 | |||
| 357 | // Reset interrupts | ||
| 358 | T::regs().isr().modify(|reg| { | ||
| 359 | reg.set_eos(true); | ||
| 360 | reg.set_eoc(true); | ||
| 361 | }); | ||
| 362 | |||
| 363 | // Start conversion | ||
| 364 | T::regs().cr().modify(|reg| { | ||
| 365 | reg.set_adstart(true); | ||
| 366 | }); | ||
| 367 | |||
| 368 | while !T::regs().isr().read().eos() { | ||
| 369 | // spin | ||
| 370 | } | ||
| 371 | |||
| 372 | T::regs().dr().read().0 as u16 | ||
| 373 | } | ||
| 374 | |||
| 375 | /// Read one or multiple ADC channels using DMA. | ||
| 376 | /// | ||
| 377 | /// `sequence` iterator and `readings` must have the same length. | ||
| 378 | /// The channels in `sequence` must be in ascending order. | ||
| 379 | /// | ||
| 380 | /// Example | ||
| 381 | /// ```rust,ignore | ||
| 382 | /// use embassy_stm32::adc::adc4; | ||
| 383 | /// use embassy_stm32::adc::AdcChannel; | ||
| 384 | /// | ||
| 385 | /// let mut adc4 = adc4::Adc4::new(p.ADC4); | ||
| 386 | /// let mut adc4_pin1 = p.PC1; | ||
| 387 | /// let mut adc4_pin2 = p.PC0; | ||
| 388 | /// let mut.into()d41 = adc4_pin1.into(); | ||
| 389 | /// let mut.into()d42 = adc4_pin2.into(); | ||
| 390 | /// let mut measurements = [0u16; 2]; | ||
| 391 | /// // not that the channels must be in ascending order | ||
| 392 | /// adc4.read( | ||
| 393 | /// &mut p.GPDMA1_CH1, | ||
| 394 | /// [ | ||
| 395 | /// &mut.into()d42, | ||
| 396 | /// &mut.into()d41, | ||
| 397 | /// ] | ||
| 398 | /// .into_iter(), | ||
| 399 | /// &mut measurements, | ||
| 400 | /// ).await.unwrap(); | ||
| 401 | /// ``` | ||
| 402 | pub async fn read( | ||
| 403 | &mut self, | ||
| 404 | rx_dma: Peri<'_, impl RxDma4<T>>, | ||
| 405 | sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>, | ||
| 406 | readings: &mut [u16], | ||
| 407 | ) -> Result<(), Adc4Error> { | ||
| 408 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | ||
| 409 | assert!( | ||
| 410 | sequence.len() == readings.len(), | ||
| 411 | "Sequence length must be equal to readings length" | ||
| 412 | ); | ||
| 413 | |||
| 414 | // Ensure no conversions are ongoing | ||
| 415 | Self::cancel_conversions(); | ||
| 416 | |||
| 417 | T::regs().isr().modify(|reg| { | ||
| 418 | reg.set_ovr(true); | ||
| 419 | reg.set_eos(true); | ||
| 420 | reg.set_eoc(true); | ||
| 421 | }); | ||
| 422 | |||
| 423 | T::regs().cfgr1().modify(|reg| { | ||
| 424 | reg.set_dmaen(true); | ||
| 425 | reg.set_dmacfg(Dmacfg::ONE_SHOT); | ||
| 426 | #[cfg(stm32u5)] | ||
| 427 | reg.set_chselrmod(false); | ||
| 428 | #[cfg(stm32wba)] | ||
| 429 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) | ||
| 430 | }); | ||
| 431 | |||
| 432 | // Verify and activate sequence | ||
| 433 | let mut prev_channel: i16 = -1; | ||
| 434 | #[cfg(stm32wba)] | ||
| 435 | T::regs().chselr().write_value(Chselr(0_u32)); | ||
| 436 | #[cfg(stm32u5)] | ||
| 437 | T::regs().chselrmod0().write_value(Chselr(0_u32)); | ||
| 438 | for channel in sequence { | ||
| 439 | let channel_num = channel.channel; | ||
| 440 | if channel_num as i16 <= prev_channel { | ||
| 441 | return Err(Adc4Error::InvalidSequence); | ||
| 442 | }; | ||
| 443 | prev_channel = channel_num as i16; | ||
| 444 | |||
| 445 | #[cfg(stm32wba)] | ||
| 446 | T::regs().chselr().modify(|w| { | ||
| 447 | w.set_chsel0(channel.channel as usize, true); | ||
| 448 | }); | ||
| 449 | #[cfg(stm32u5)] | ||
| 450 | T::regs().chselrmod0().modify(|w| { | ||
| 451 | w.set_chsel(channel.channel as usize, true); | ||
| 452 | }); | ||
| 453 | } | ||
| 454 | |||
| 455 | let request = rx_dma.request(); | ||
| 456 | let transfer = unsafe { | ||
| 457 | Transfer::new_read( | ||
| 458 | rx_dma, | ||
| 459 | request, | ||
| 460 | T::regs().dr().as_ptr() as *mut u16, | ||
| 461 | readings, | ||
| 462 | Default::default(), | ||
| 463 | ) | ||
| 464 | }; | ||
| 465 | |||
| 466 | // Start conversion | ||
| 467 | T::regs().cr().modify(|reg| { | ||
| 468 | reg.set_adstart(true); | ||
| 469 | }); | ||
| 470 | |||
| 471 | transfer.await; | ||
| 472 | |||
| 473 | // Ensure conversions are finished. | ||
| 474 | Self::cancel_conversions(); | ||
| 475 | |||
| 476 | // Reset configuration. | ||
| 477 | T::regs().cfgr1().modify(|reg| { | ||
| 478 | reg.set_dmaen(false); | ||
| 479 | }); | ||
| 480 | |||
| 481 | if T::regs().isr().read().ovr() { | ||
| 482 | Err(Adc4Error::DMAError) | ||
| 483 | } else { | ||
| 484 | Ok(()) | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | fn cancel_conversions() { | ||
| 489 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | ||
| 490 | T::regs().cr().modify(|reg| { | ||
| 491 | reg.set_adstp(true); | ||
| 492 | }); | ||
| 493 | while T::regs().cr().read().adstart() {} | ||
| 494 | } | ||
| 495 | } | ||
| 496 | } | 440 | } |
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 0a9f35a5b..71dc8acc0 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -12,7 +12,7 @@ use super::{ | |||
| 12 | Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, | 12 | Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, |
| 13 | blocking_delay_us, | 13 | blocking_delay_us, |
| 14 | }; | 14 | }; |
| 15 | use crate::adc::SealedAdcChannel; | 15 | use crate::adc::{AnyInstance, SealedAdcChannel}; |
| 16 | use crate::time::Hertz; | 16 | use crate::time::Hertz; |
| 17 | use crate::{Peri, pac, rcc}; | 17 | use crate::{Peri, pac, rcc}; |
| 18 | 18 | ||
| @@ -122,98 +122,12 @@ pub struct ConversionTrigger { | |||
| 122 | pub edge: Exten, | 122 | pub edge: Exten, |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | impl<'d, T: Instance> Adc<'d, T> { | 125 | impl<T: Instance> super::SealedAnyInstance for T { |
| 126 | /// Create a new ADC driver. | 126 | fn dr() -> *mut u16 { |
| 127 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 127 | T::regs().dr().as_ptr() as *mut u16 |
| 128 | rcc::enable_and_reset::<T>(); | ||
| 129 | |||
| 130 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | ||
| 131 | |||
| 132 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | ||
| 133 | |||
| 134 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | ||
| 135 | trace!("ADC frequency set to {}", frequency); | ||
| 136 | |||
| 137 | if frequency > MAX_ADC_CLK_FREQ { | ||
| 138 | panic!( | ||
| 139 | "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", | ||
| 140 | MAX_ADC_CLK_FREQ.0 / 1_000_000 | ||
| 141 | ); | ||
| 142 | } | ||
| 143 | |||
| 144 | T::regs().cr().modify(|reg| { | ||
| 145 | reg.set_deeppwd(false); | ||
| 146 | reg.set_advregen(true); | ||
| 147 | }); | ||
| 148 | |||
| 149 | blocking_delay_us(20); | ||
| 150 | |||
| 151 | T::regs().difsel().modify(|w| { | ||
| 152 | for n in 0..18 { | ||
| 153 | w.set_difsel(n, Difsel::SINGLE_ENDED); | ||
| 154 | } | ||
| 155 | }); | ||
| 156 | |||
| 157 | T::regs().cr().modify(|w| { | ||
| 158 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); | ||
| 159 | }); | ||
| 160 | |||
| 161 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 162 | |||
| 163 | while T::regs().cr().read().adcal() {} | ||
| 164 | |||
| 165 | blocking_delay_us(20); | ||
| 166 | |||
| 167 | T::regs().cr().modify(|w| { | ||
| 168 | w.set_adcaldif(Adcaldif::DIFFERENTIAL); | ||
| 169 | }); | ||
| 170 | |||
| 171 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 172 | |||
| 173 | while T::regs().cr().read().adcal() {} | ||
| 174 | |||
| 175 | blocking_delay_us(20); | ||
| 176 | |||
| 177 | Self::enable(); | ||
| 178 | |||
| 179 | // single conversion mode, software trigger | ||
| 180 | T::regs().cfgr().modify(|w| { | ||
| 181 | w.set_cont(false); | ||
| 182 | w.set_exten(Exten::DISABLED); | ||
| 183 | }); | ||
| 184 | |||
| 185 | if let Some(dual) = config.dual_mode { | ||
| 186 | T::common_regs().ccr().modify(|reg| { | ||
| 187 | reg.set_dual(dual); | ||
| 188 | }) | ||
| 189 | } | ||
| 190 | |||
| 191 | if let Some(resolution) = config.resolution { | ||
| 192 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 193 | } | ||
| 194 | |||
| 195 | #[cfg(stm32g4)] | ||
| 196 | if let Some(shift) = config.oversampling_shift { | ||
| 197 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 198 | } | ||
| 199 | |||
| 200 | #[cfg(stm32g4)] | ||
| 201 | if let Some(ratio) = config.oversampling_ratio { | ||
| 202 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 203 | } | ||
| 204 | |||
| 205 | #[cfg(stm32g4)] | ||
| 206 | if let Some((mode, trig_mode, enable)) = config.oversampling_mode { | ||
| 207 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 208 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 209 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 210 | } | ||
| 211 | |||
| 212 | Self { adc } | ||
| 213 | } | 128 | } |
| 214 | 129 | ||
| 215 | /// Enable the ADC | 130 | fn enable() { |
| 216 | pub(super) fn enable() { | ||
| 217 | // Make sure bits are off | 131 | // Make sure bits are off |
| 218 | while T::regs().cr().read().addis() { | 132 | while T::regs().cr().read().addis() { |
| 219 | // spin | 133 | // spin |
| @@ -234,15 +148,13 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 234 | } | 148 | } |
| 235 | } | 149 | } |
| 236 | 150 | ||
| 237 | /// Start regular adc conversion | 151 | fn start() { |
| 238 | pub(super) fn start() { | ||
| 239 | T::regs().cr().modify(|reg| { | 152 | T::regs().cr().modify(|reg| { |
| 240 | reg.set_adstart(true); | 153 | reg.set_adstart(true); |
| 241 | }); | 154 | }); |
| 242 | } | 155 | } |
| 243 | 156 | ||
| 244 | /// Stop regular conversions and disable DMA | 157 | fn stop() { |
| 245 | pub(super) fn stop() { | ||
| 246 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 158 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
| 247 | T::regs().cr().modify(|reg| { | 159 | T::regs().cr().modify(|reg| { |
| 248 | reg.set_adstp(Adstp::STOP); | 160 | reg.set_adstp(Adstp::STOP); |
| @@ -259,8 +171,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 259 | }); | 171 | }); |
| 260 | } | 172 | } |
| 261 | 173 | ||
| 262 | /// Perform a single conversion. | 174 | fn convert() -> u16 { |
| 263 | pub(super) fn convert() -> u16 { | ||
| 264 | T::regs().isr().modify(|reg| { | 175 | T::regs().isr().modify(|reg| { |
| 265 | reg.set_eos(true); | 176 | reg.set_eos(true); |
| 266 | reg.set_eoc(true); | 177 | reg.set_eoc(true); |
| @@ -278,7 +189,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 278 | T::regs().dr().read().0 as u16 | 189 | T::regs().dr().read().0 as u16 |
| 279 | } | 190 | } |
| 280 | 191 | ||
| 281 | pub(super) fn configure_dma(conversion_mode: ConversionMode) { | 192 | fn configure_dma(conversion_mode: ConversionMode) { |
| 282 | T::regs().isr().modify(|reg| { | 193 | T::regs().isr().modify(|reg| { |
| 283 | reg.set_ovr(true); | 194 | reg.set_ovr(true); |
| 284 | }); | 195 | }); |
| @@ -316,7 +227,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 316 | } | 227 | } |
| 317 | } | 228 | } |
| 318 | 229 | ||
| 319 | pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 230 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 320 | // Set sequence length | 231 | // Set sequence length |
| 321 | T::regs().sqr1().modify(|w| { | 232 | T::regs().sqr1().modify(|w| { |
| 322 | w.set_l(sequence.len() as u8 - 1); | 233 | w.set_l(sequence.len() as u8 - 1); |
| @@ -374,6 +285,97 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 374 | } | 285 | } |
| 375 | } | 286 | } |
| 376 | } | 287 | } |
| 288 | } | ||
| 289 | |||
| 290 | impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | ||
| 291 | /// Create a new ADC driver. | ||
| 292 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { | ||
| 293 | rcc::enable_and_reset::<T>(); | ||
| 294 | |||
| 295 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | ||
| 296 | |||
| 297 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | ||
| 298 | |||
| 299 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | ||
| 300 | trace!("ADC frequency set to {}", frequency); | ||
| 301 | |||
| 302 | if frequency > MAX_ADC_CLK_FREQ { | ||
| 303 | panic!( | ||
| 304 | "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", | ||
| 305 | MAX_ADC_CLK_FREQ.0 / 1_000_000 | ||
| 306 | ); | ||
| 307 | } | ||
| 308 | |||
| 309 | T::regs().cr().modify(|reg| { | ||
| 310 | reg.set_deeppwd(false); | ||
| 311 | reg.set_advregen(true); | ||
| 312 | }); | ||
| 313 | |||
| 314 | blocking_delay_us(20); | ||
| 315 | |||
| 316 | T::regs().difsel().modify(|w| { | ||
| 317 | for n in 0..18 { | ||
| 318 | w.set_difsel(n, Difsel::SINGLE_ENDED); | ||
| 319 | } | ||
| 320 | }); | ||
| 321 | |||
| 322 | T::regs().cr().modify(|w| { | ||
| 323 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); | ||
| 324 | }); | ||
| 325 | |||
| 326 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 327 | |||
| 328 | while T::regs().cr().read().adcal() {} | ||
| 329 | |||
| 330 | blocking_delay_us(20); | ||
| 331 | |||
| 332 | T::regs().cr().modify(|w| { | ||
| 333 | w.set_adcaldif(Adcaldif::DIFFERENTIAL); | ||
| 334 | }); | ||
| 335 | |||
| 336 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 337 | |||
| 338 | while T::regs().cr().read().adcal() {} | ||
| 339 | |||
| 340 | blocking_delay_us(20); | ||
| 341 | |||
| 342 | T::enable(); | ||
| 343 | |||
| 344 | // single conversion mode, software trigger | ||
| 345 | T::regs().cfgr().modify(|w| { | ||
| 346 | w.set_cont(false); | ||
| 347 | w.set_exten(Exten::DISABLED); | ||
| 348 | }); | ||
| 349 | |||
| 350 | if let Some(dual) = config.dual_mode { | ||
| 351 | T::common_regs().ccr().modify(|reg| { | ||
| 352 | reg.set_dual(dual); | ||
| 353 | }) | ||
| 354 | } | ||
| 355 | |||
| 356 | if let Some(resolution) = config.resolution { | ||
| 357 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 358 | } | ||
| 359 | |||
| 360 | #[cfg(stm32g4)] | ||
| 361 | if let Some(shift) = config.oversampling_shift { | ||
| 362 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 363 | } | ||
| 364 | |||
| 365 | #[cfg(stm32g4)] | ||
| 366 | if let Some(ratio) = config.oversampling_ratio { | ||
| 367 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 368 | } | ||
| 369 | |||
| 370 | #[cfg(stm32g4)] | ||
| 371 | if let Some((mode, trig_mode, enable)) = config.oversampling_mode { | ||
| 372 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 373 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 374 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 375 | } | ||
| 376 | |||
| 377 | Self { adc } | ||
| 378 | } | ||
| 377 | 379 | ||
| 378 | /// Enable reading the voltage reference internal channel. | 380 | /// Enable reading the voltage reference internal channel. |
| 379 | pub fn enable_vrefint(&self) -> super::VrefInt | 381 | pub fn enable_vrefint(&self) -> super::VrefInt |
| @@ -464,8 +466,8 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 464 | NR_INJECTED_RANKS | 466 | NR_INJECTED_RANKS |
| 465 | ); | 467 | ); |
| 466 | 468 | ||
| 467 | Self::stop(); | 469 | T::stop(); |
| 468 | Self::enable(); | 470 | T::enable(); |
| 469 | 471 | ||
| 470 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); | 472 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); |
| 471 | 473 | ||
| @@ -536,7 +538,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 536 | self, | 538 | self, |
| 537 | dma: Peri<'a, impl RxDma<T>>, | 539 | dma: Peri<'a, impl RxDma<T>>, |
| 538 | dma_buf: &'a mut [u16], | 540 | dma_buf: &'a mut [u16], |
| 539 | regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>, | 541 | regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>, |
| 540 | regular_conversion_mode: RegularConversionMode, | 542 | regular_conversion_mode: RegularConversionMode, |
| 541 | injected_sequence: [(AnyAdcChannel<T>, SampleTime); N], | 543 | injected_sequence: [(AnyAdcChannel<T>, SampleTime); N], |
| 542 | injected_trigger: ConversionTrigger, | 544 | injected_trigger: ConversionTrigger, |
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index 7bb3a541c..ccaa5d1b2 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs | |||
| @@ -5,9 +5,9 @@ use core::sync::atomic::{Ordering, compiler_fence}; | |||
| 5 | use embassy_hal_internal::Peri; | 5 | use embassy_hal_internal::Peri; |
| 6 | 6 | ||
| 7 | use super::{AnyAdcChannel, SampleTime}; | 7 | use super::{AnyAdcChannel, SampleTime}; |
| 8 | use crate::adc::Adc; | ||
| 9 | #[allow(unused_imports)] | 8 | #[allow(unused_imports)] |
| 10 | use crate::adc::Instance; | 9 | use crate::adc::Instance; |
| 10 | use crate::adc::{Adc, AnyInstance}; | ||
| 11 | 11 | ||
| 12 | /// Injected ADC sequence with owned channels. | 12 | /// Injected ADC sequence with owned channels. |
| 13 | pub struct InjectedAdc<T: Instance, const N: usize> { | 13 | pub struct InjectedAdc<T: Instance, const N: usize> { |
| @@ -36,9 +36,9 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> { | |||
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> { | 39 | impl<T: Instance + AnyInstance, const N: usize> Drop for InjectedAdc<T, N> { |
| 40 | fn drop(&mut self) { | 40 | fn drop(&mut self) { |
| 41 | Adc::<T>::stop(); | 41 | T::stop(); |
| 42 | compiler_fence(Ordering::SeqCst); | 42 | compiler_fence(Ordering::SeqCst); |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index bf404d6ef..856c2e61e 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -41,15 +41,10 @@ pub use crate::pac::adc::vals::Res as Resolution; | |||
| 41 | pub use crate::pac::adc::vals::SampleTime; | 41 | pub use crate::pac::adc::vals::SampleTime; |
| 42 | use crate::peripherals; | 42 | use crate::peripherals; |
| 43 | 43 | ||
| 44 | #[cfg(not(adc_wba))] | 44 | dma_trait!(RxDma, AnyInstance); |
| 45 | dma_trait!(RxDma, Instance); | ||
| 46 | #[cfg(adc_u5)] | ||
| 47 | dma_trait!(RxDma4, adc4::Instance); | ||
| 48 | #[cfg(adc_wba)] | ||
| 49 | dma_trait!(RxDma4, adc4::Instance); | ||
| 50 | 45 | ||
| 51 | /// Analog to Digital driver. | 46 | /// Analog to Digital driver. |
| 52 | pub struct Adc<'d, T: Instance> { | 47 | pub struct Adc<'d, T: AnyInstance> { |
| 53 | #[allow(unused)] | 48 | #[allow(unused)] |
| 54 | adc: crate::Peri<'d, T>, | 49 | adc: crate::Peri<'d, T>, |
| 55 | } | 50 | } |
| @@ -92,6 +87,49 @@ pub(crate) trait SealedAdcChannel<T> { | |||
| 92 | } | 87 | } |
| 93 | } | 88 | } |
| 94 | 89 | ||
| 90 | // Temporary patch for ADCs that have not implemented the standard iface yet | ||
| 91 | #[cfg(not(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4)))] | ||
| 92 | trait_set::trait_set! { | ||
| 93 | pub trait AnyInstance = Instance; | ||
| 94 | } | ||
| 95 | |||
| 96 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | ||
| 97 | #[allow(dead_code)] | ||
| 98 | pub trait BasicAnyInstance { | ||
| 99 | type SampleTime; | ||
| 100 | } | ||
| 101 | |||
| 102 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | ||
| 103 | #[allow(dead_code)] | ||
| 104 | pub(self) trait SealedAnyInstance: BasicAnyInstance { | ||
| 105 | fn enable(); | ||
| 106 | fn start(); | ||
| 107 | fn stop(); | ||
| 108 | fn convert() -> u16; | ||
| 109 | fn configure_dma(conversion_mode: ConversionMode); | ||
| 110 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); | ||
| 111 | fn dr() -> *mut u16; | ||
| 112 | } | ||
| 113 | |||
| 114 | // On chips without ADC4, AnyInstance is an Instance | ||
| 115 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4))] | ||
| 116 | #[allow(private_bounds)] | ||
| 117 | pub trait AnyInstance: SealedAnyInstance + Instance {} | ||
| 118 | |||
| 119 | // On chips with ADC4, AnyInstance is an Instance or adc4::Instance | ||
| 120 | #[cfg(any(adc_v4, adc_u5, adc_wba))] | ||
| 121 | #[allow(private_bounds)] | ||
| 122 | pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} | ||
| 123 | |||
| 124 | // Implement AnyInstance automatically for SealedAnyInstance | ||
| 125 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | ||
| 126 | impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { | ||
| 127 | type SampleTime = SampleTime; | ||
| 128 | } | ||
| 129 | |||
| 130 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | ||
| 131 | impl<T: SealedAnyInstance + Instance> AnyInstance for T {} | ||
| 132 | |||
| 95 | /// Performs a busy-wait delay for a specified number of microseconds. | 133 | /// Performs a busy-wait delay for a specified number of microseconds. |
| 96 | #[allow(unused)] | 134 | #[allow(unused)] |
| 97 | pub(crate) fn blocking_delay_us(us: u32) { | 135 | pub(crate) fn blocking_delay_us(us: u32) { |
| @@ -110,16 +148,18 @@ pub(crate) fn blocking_delay_us(us: u32) { | |||
| 110 | } | 148 | } |
| 111 | } | 149 | } |
| 112 | 150 | ||
| 113 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] | 151 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] |
| 114 | pub(self) enum ConversionMode { | 152 | #[allow(dead_code)] |
| 115 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] | 153 | pub(crate) enum ConversionMode { |
| 154 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | ||
| 116 | Singular, | 155 | Singular, |
| 117 | #[allow(dead_code)] | 156 | #[allow(dead_code)] |
| 118 | Repeated(RegularConversionMode), | 157 | Repeated(RegularConversionMode), |
| 119 | } | 158 | } |
| 120 | 159 | ||
| 121 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] | 160 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] |
| 122 | // Conversion mode for regular ADC channels | 161 | // Conversion mode for regular ADC channels |
| 162 | #[allow(dead_code)] | ||
| 123 | #[derive(Copy, Clone)] | 163 | #[derive(Copy, Clone)] |
| 124 | pub enum RegularConversionMode { | 164 | pub enum RegularConversionMode { |
| 125 | // Samples as fast as possible | 165 | // Samples as fast as possible |
| @@ -129,21 +169,21 @@ pub enum RegularConversionMode { | |||
| 129 | Triggered(ConversionTrigger), | 169 | Triggered(ConversionTrigger), |
| 130 | } | 170 | } |
| 131 | 171 | ||
| 132 | impl<'d, T: Instance> Adc<'d, T> { | 172 | impl<'d, T: AnyInstance> Adc<'d, T> { |
| 133 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4))] | 173 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba))] |
| 134 | /// Read an ADC pin. | 174 | /// Read an ADC pin. |
| 135 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { | 175 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { |
| 136 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 176 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] |
| 137 | channel.setup(); | 177 | channel.setup(); |
| 138 | 178 | ||
| 139 | #[cfg(not(adc_v4))] | 179 | #[cfg(not(adc_v4))] |
| 140 | Self::enable(); | 180 | T::enable(); |
| 141 | Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); | 181 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); |
| 142 | 182 | ||
| 143 | Self::convert() | 183 | T::convert() |
| 144 | } | 184 | } |
| 145 | 185 | ||
| 146 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] | 186 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] |
| 147 | /// Read one or multiple ADC regular channels using DMA. | 187 | /// Read one or multiple ADC regular channels using DMA. |
| 148 | /// | 188 | /// |
| 149 | /// `sequence` iterator and `readings` must have the same length. | 189 | /// `sequence` iterator and `readings` must have the same length. |
| @@ -175,7 +215,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 175 | pub async fn read( | 215 | pub async fn read( |
| 176 | &mut self, | 216 | &mut self, |
| 177 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, | 217 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, |
| 178 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, | 218 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, T::SampleTime)>, |
| 179 | readings: &mut [u16], | 219 | readings: &mut [u16], |
| 180 | ) { | 220 | ) { |
| 181 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | 221 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); |
| @@ -189,33 +229,26 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 189 | ); | 229 | ); |
| 190 | 230 | ||
| 191 | // Ensure no conversions are ongoing and ADC is enabled. | 231 | // Ensure no conversions are ongoing and ADC is enabled. |
| 192 | Self::stop(); | 232 | T::stop(); |
| 193 | Self::enable(); | 233 | T::enable(); |
| 194 | 234 | ||
| 195 | Self::configure_sequence( | 235 | T::configure_sequence( |
| 196 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 236 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 197 | ); | 237 | ); |
| 198 | 238 | ||
| 199 | Self::configure_dma(ConversionMode::Singular); | 239 | T::configure_dma(ConversionMode::Singular); |
| 200 | 240 | ||
| 201 | let request = rx_dma.request(); | 241 | let request = rx_dma.request(); |
| 202 | let transfer = unsafe { | 242 | let transfer = |
| 203 | crate::dma::Transfer::new_read( | 243 | unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::dr(), readings, Default::default()) }; |
| 204 | rx_dma, | ||
| 205 | request, | ||
| 206 | T::regs().dr().as_ptr() as *mut u16, | ||
| 207 | readings, | ||
| 208 | Default::default(), | ||
| 209 | ) | ||
| 210 | }; | ||
| 211 | 244 | ||
| 212 | Self::start(); | 245 | T::start(); |
| 213 | 246 | ||
| 214 | // Wait for conversion sequence to finish. | 247 | // Wait for conversion sequence to finish. |
| 215 | transfer.await; | 248 | transfer.await; |
| 216 | 249 | ||
| 217 | // Ensure conversions are finished. | 250 | // Ensure conversions are finished. |
| 218 | Self::stop(); | 251 | T::stop(); |
| 219 | } | 252 | } |
| 220 | 253 | ||
| 221 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | 254 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] |
| @@ -244,7 +277,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 244 | self, | 277 | self, |
| 245 | dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, | 278 | dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, |
| 246 | dma_buf: &'a mut [u16], | 279 | dma_buf: &'a mut [u16], |
| 247 | sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>, | 280 | sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>, |
| 248 | mode: RegularConversionMode, | 281 | mode: RegularConversionMode, |
| 249 | ) -> RingBufferedAdc<'a, T> { | 282 | ) -> RingBufferedAdc<'a, T> { |
| 250 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | 283 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); |
| @@ -254,15 +287,15 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 254 | "Asynchronous read sequence cannot be more than 16 in length" | 287 | "Asynchronous read sequence cannot be more than 16 in length" |
| 255 | ); | 288 | ); |
| 256 | // reset conversions and enable the adc | 289 | // reset conversions and enable the adc |
| 257 | Self::stop(); | 290 | T::stop(); |
| 258 | Self::enable(); | 291 | T::enable(); |
| 259 | 292 | ||
| 260 | //adc side setup | 293 | //adc side setup |
| 261 | Self::configure_sequence( | 294 | T::configure_sequence( |
| 262 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 295 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 263 | ); | 296 | ); |
| 264 | 297 | ||
| 265 | Self::configure_dma(ConversionMode::Repeated(mode)); | 298 | T::configure_dma(ConversionMode::Repeated(mode)); |
| 266 | 299 | ||
| 267 | core::mem::forget(self); | 300 | core::mem::forget(self); |
| 268 | 301 | ||
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 62ea0d3a2..a56f8ca0b 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs | |||
| @@ -4,7 +4,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; | |||
| 4 | #[allow(unused_imports)] | 4 | #[allow(unused_imports)] |
| 5 | use embassy_hal_internal::Peri; | 5 | use embassy_hal_internal::Peri; |
| 6 | 6 | ||
| 7 | use crate::adc::Adc; | 7 | use crate::adc::AnyInstance; |
| 8 | #[allow(unused_imports)] | 8 | #[allow(unused_imports)] |
| 9 | use crate::adc::{Instance, RxDma}; | 9 | use crate::adc::{Instance, RxDma}; |
| 10 | #[allow(unused_imports)] | 10 | #[allow(unused_imports)] |
| @@ -19,7 +19,7 @@ pub struct RingBufferedAdc<'d, T: Instance> { | |||
| 19 | ring_buf: ReadableRingBuffer<'d, u16>, | 19 | ring_buf: ReadableRingBuffer<'d, u16>, |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | impl<'d, T: Instance> RingBufferedAdc<'d, T> { | 22 | impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { |
| 23 | pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self { | 23 | pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self { |
| 24 | //dma side setup | 24 | //dma side setup |
| 25 | let opts = TransferOptions { | 25 | let opts = TransferOptions { |
| @@ -45,11 +45,11 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { | |||
| 45 | compiler_fence(Ordering::SeqCst); | 45 | compiler_fence(Ordering::SeqCst); |
| 46 | self.ring_buf.start(); | 46 | self.ring_buf.start(); |
| 47 | 47 | ||
| 48 | Adc::<T>::start(); | 48 | T::start(); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | pub fn stop(&mut self) { | 51 | pub fn stop(&mut self) { |
| 52 | Adc::<T>::stop(); | 52 | T::stop(); |
| 53 | 53 | ||
| 54 | self.ring_buf.request_pause(); | 54 | self.ring_buf.request_pause(); |
| 55 | 55 | ||
| @@ -170,9 +170,9 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { | |||
| 170 | } | 170 | } |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | impl<T: Instance> Drop for RingBufferedAdc<'_, T> { | 173 | impl<T: Instance + AnyInstance> Drop for RingBufferedAdc<'_, T> { |
| 174 | fn drop(&mut self) { | 174 | fn drop(&mut self) { |
| 175 | Adc::<T>::stop(); | 175 | T::stop(); |
| 176 | 176 | ||
| 177 | compiler_fence(Ordering::SeqCst); | 177 | compiler_fence(Ordering::SeqCst); |
| 178 | 178 | ||
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 2f9fabafb..4065f89a7 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -91,35 +91,14 @@ pub struct AdcConfig { | |||
| 91 | resolution: Option<Resolution>, | 91 | resolution: Option<Resolution>, |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | impl<'d, T> Adc<'d, T> | 94 | impl<T: Instance> super::SealedAnyInstance for T { |
| 95 | where | 95 | fn dr() -> *mut u16 { |
| 96 | T: Instance, | 96 | T::regs().dr().as_ptr() as *mut u16 |
| 97 | { | ||
| 98 | pub fn new(adc: Peri<'d, T>) -> Self { | ||
| 99 | Self::new_with_config(adc, Default::default()) | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | ||
| 103 | rcc::enable_and_reset::<T>(); | ||
| 104 | |||
| 105 | let presc = Prescaler::from_pclk2(T::frequency()); | ||
| 106 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | ||
| 107 | T::regs().cr2().modify(|reg| { | ||
| 108 | reg.set_adon(true); | ||
| 109 | }); | ||
| 110 | |||
| 111 | blocking_delay_us(3); | ||
| 112 | |||
| 113 | if let Some(resolution) = config.resolution { | ||
| 114 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 115 | } | ||
| 116 | |||
| 117 | Self { adc } | ||
| 118 | } | 97 | } |
| 119 | 98 | ||
| 120 | pub(super) fn enable() {} | 99 | fn enable() {} |
| 121 | 100 | ||
| 122 | pub(super) fn start() { | 101 | fn start() { |
| 123 | // Begin ADC conversions | 102 | // Begin ADC conversions |
| 124 | T::regs().cr2().modify(|reg| { | 103 | T::regs().cr2().modify(|reg| { |
| 125 | reg.set_adon(true); | 104 | reg.set_adon(true); |
| @@ -127,7 +106,7 @@ where | |||
| 127 | }); | 106 | }); |
| 128 | } | 107 | } |
| 129 | 108 | ||
| 130 | pub(super) fn stop() { | 109 | fn stop() { |
| 131 | let r = T::regs(); | 110 | let r = T::regs(); |
| 132 | 111 | ||
| 133 | // Stop ADC | 112 | // Stop ADC |
| @@ -152,7 +131,7 @@ where | |||
| 152 | compiler_fence(Ordering::SeqCst); | 131 | compiler_fence(Ordering::SeqCst); |
| 153 | } | 132 | } |
| 154 | 133 | ||
| 155 | pub(super) fn convert() -> u16 { | 134 | fn convert() -> u16 { |
| 156 | // clear end of conversion flag | 135 | // clear end of conversion flag |
| 157 | T::regs().sr().modify(|reg| { | 136 | T::regs().sr().modify(|reg| { |
| 158 | reg.set_eoc(false); | 137 | reg.set_eoc(false); |
| @@ -173,7 +152,7 @@ where | |||
| 173 | T::regs().dr().read().0 as u16 | 152 | T::regs().dr().read().0 as u16 |
| 174 | } | 153 | } |
| 175 | 154 | ||
| 176 | pub(super) fn configure_dma(conversion_mode: ConversionMode) { | 155 | fn configure_dma(conversion_mode: ConversionMode) { |
| 177 | match conversion_mode { | 156 | match conversion_mode { |
| 178 | ConversionMode::Repeated(_) => { | 157 | ConversionMode::Repeated(_) => { |
| 179 | let r = T::regs(); | 158 | let r = T::regs(); |
| @@ -210,7 +189,7 @@ where | |||
| 210 | } | 189 | } |
| 211 | } | 190 | } |
| 212 | 191 | ||
| 213 | pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 192 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 214 | T::regs().cr2().modify(|reg| { | 193 | T::regs().cr2().modify(|reg| { |
| 215 | reg.set_adon(true); | 194 | reg.set_adon(true); |
| 216 | }); | 195 | }); |
| @@ -232,6 +211,33 @@ where | |||
| 232 | } | 211 | } |
| 233 | } | 212 | } |
| 234 | } | 213 | } |
| 214 | } | ||
| 215 | |||
| 216 | impl<'d, T> Adc<'d, T> | ||
| 217 | where | ||
| 218 | T: Instance, | ||
| 219 | { | ||
| 220 | pub fn new(adc: Peri<'d, T>) -> Self { | ||
| 221 | Self::new_with_config(adc, Default::default()) | ||
| 222 | } | ||
| 223 | |||
| 224 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | ||
| 225 | rcc::enable_and_reset::<T>(); | ||
| 226 | |||
| 227 | let presc = Prescaler::from_pclk2(T::frequency()); | ||
| 228 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | ||
| 229 | T::regs().cr2().modify(|reg| { | ||
| 230 | reg.set_adon(true); | ||
| 231 | }); | ||
| 232 | |||
| 233 | blocking_delay_us(3); | ||
| 234 | |||
| 235 | if let Some(resolution) = config.resolution { | ||
| 236 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 237 | } | ||
| 238 | |||
| 239 | Self { adc } | ||
| 240 | } | ||
| 235 | 241 | ||
| 236 | /// Enables internal voltage reference and returns [VrefInt], which can be used in | 242 | /// Enables internal voltage reference and returns [VrefInt], which can be used in |
| 237 | /// [Adc::read_internal()] to perform conversion. | 243 | /// [Adc::read_internal()] to perform conversion. |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 62b5043ee..4cce1dac3 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -161,152 +161,13 @@ pub struct AdcConfig { | |||
| 161 | pub averaging: Option<Averaging>, | 161 | pub averaging: Option<Averaging>, |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | impl<'d, T: Instance> Adc<'d, T> { | 164 | impl<T: Instance> super::SealedAnyInstance for T { |
| 165 | /// Enable the voltage regulator | 165 | fn dr() -> *mut u16 { |
| 166 | fn init_regulator() { | 166 | T::regs().dr().as_ptr() as *mut u16 |
| 167 | rcc::enable_and_reset::<T>(); | ||
| 168 | T::regs().cr().modify(|reg| { | ||
| 169 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 170 | reg.set_deeppwd(false); | ||
| 171 | reg.set_advregen(true); | ||
| 172 | }); | ||
| 173 | |||
| 174 | // If this is false then each ADC_CHSELR bit enables an input channel. | ||
| 175 | // This is the reset value, so has no effect. | ||
| 176 | #[cfg(any(adc_g0, adc_u0))] | ||
| 177 | T::regs().cfgr1().modify(|reg| { | ||
| 178 | reg.set_chselrmod(false); | ||
| 179 | }); | ||
| 180 | |||
| 181 | blocking_delay_us(20); | ||
| 182 | } | ||
| 183 | |||
| 184 | /// Calibrate to remove conversion offset | ||
| 185 | fn init_calibrate() { | ||
| 186 | T::regs().cr().modify(|reg| { | ||
| 187 | reg.set_adcal(true); | ||
| 188 | }); | ||
| 189 | |||
| 190 | while T::regs().cr().read().adcal() { | ||
| 191 | // spin | ||
| 192 | } | ||
| 193 | |||
| 194 | blocking_delay_us(1); | ||
| 195 | } | ||
| 196 | |||
| 197 | /// Initialize the ADC leaving any analog clock at reset value. | ||
| 198 | /// For G0 and WL, this is the async clock without prescaler. | ||
| 199 | pub fn new(adc: Peri<'d, T>) -> Self { | ||
| 200 | Self::init_regulator(); | ||
| 201 | Self::init_calibrate(); | ||
| 202 | Self { adc } | ||
| 203 | } | ||
| 204 | |||
| 205 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | ||
| 206 | #[cfg(not(adc_g0))] | ||
| 207 | let s = Self::new(adc); | ||
| 208 | |||
| 209 | #[cfg(adc_g0)] | ||
| 210 | let s = match config.clock { | ||
| 211 | Some(clock) => Self::new_with_clock(adc, clock), | ||
| 212 | None => Self::new(adc), | ||
| 213 | }; | ||
| 214 | |||
| 215 | #[cfg(any(adc_g0, adc_u0, adc_v3))] | ||
| 216 | if let Some(shift) = config.oversampling_shift { | ||
| 217 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 218 | } | ||
| 219 | |||
| 220 | #[cfg(any(adc_g0, adc_u0, adc_v3))] | ||
| 221 | if let Some(ratio) = config.oversampling_ratio { | ||
| 222 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 223 | } | ||
| 224 | |||
| 225 | #[cfg(any(adc_g0, adc_u0))] | ||
| 226 | if let Some(enable) = config.oversampling_enable { | ||
| 227 | T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); | ||
| 228 | } | ||
| 229 | |||
| 230 | #[cfg(adc_v3)] | ||
| 231 | if let Some((mode, trig_mode, enable)) = config.oversampling_mode { | ||
| 232 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 233 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 234 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 235 | } | ||
| 236 | |||
| 237 | if let Some(resolution) = config.resolution { | ||
| 238 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 239 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 240 | #[cfg(any(adc_g0, adc_u0))] | ||
| 241 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 242 | } | ||
| 243 | |||
| 244 | if let Some(averaging) = config.averaging { | ||
| 245 | let (enable, samples, right_shift) = match averaging { | ||
| 246 | Averaging::Disabled => (false, 0, 0), | ||
| 247 | Averaging::Samples2 => (true, 0, 1), | ||
| 248 | Averaging::Samples4 => (true, 1, 2), | ||
| 249 | Averaging::Samples8 => (true, 2, 3), | ||
| 250 | Averaging::Samples16 => (true, 3, 4), | ||
| 251 | Averaging::Samples32 => (true, 4, 5), | ||
| 252 | Averaging::Samples64 => (true, 5, 6), | ||
| 253 | Averaging::Samples128 => (true, 6, 7), | ||
| 254 | Averaging::Samples256 => (true, 7, 8), | ||
| 255 | }; | ||
| 256 | T::regs().cfgr2().modify(|reg| { | ||
| 257 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 258 | reg.set_rovse(enable); | ||
| 259 | #[cfg(any(adc_g0, adc_u0))] | ||
| 260 | reg.set_ovse(enable); | ||
| 261 | #[cfg(any(adc_h5, adc_h7rs))] | ||
| 262 | reg.set_ovsr(samples.into()); | ||
| 263 | #[cfg(not(any(adc_h5, adc_h7rs)))] | ||
| 264 | reg.set_ovsr(samples.into()); | ||
| 265 | reg.set_ovss(right_shift.into()); | ||
| 266 | }) | ||
| 267 | } | ||
| 268 | |||
| 269 | s | ||
| 270 | } | ||
| 271 | |||
| 272 | #[cfg(adc_g0)] | ||
| 273 | /// Initialize ADC with explicit clock for the analog ADC | ||
| 274 | pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { | ||
| 275 | Self::init_regulator(); | ||
| 276 | |||
| 277 | #[cfg(any(stm32wl5x))] | ||
| 278 | { | ||
| 279 | // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual | ||
| 280 | let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0; | ||
| 281 | match clock { | ||
| 282 | Clock::Async { div: _ } => { | ||
| 283 | assert!(async_clock_available); | ||
| 284 | } | ||
| 285 | Clock::Sync { div: _ } => { | ||
| 286 | if async_clock_available { | ||
| 287 | warn!("Not using configured ADC clock"); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | match clock { | ||
| 293 | Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)), | ||
| 294 | Clock::Sync { div } => T::regs().cfgr2().modify(|reg| { | ||
| 295 | reg.set_ckmode(match div { | ||
| 296 | CkModePclk::DIV1 => Ckmode::PCLK, | ||
| 297 | CkModePclk::DIV2 => Ckmode::PCLK_DIV2, | ||
| 298 | CkModePclk::DIV4 => Ckmode::PCLK_DIV4, | ||
| 299 | }) | ||
| 300 | }), | ||
| 301 | } | ||
| 302 | |||
| 303 | Self::init_calibrate(); | ||
| 304 | |||
| 305 | Self { adc } | ||
| 306 | } | 167 | } |
| 307 | 168 | ||
| 308 | // Enable ADC only when it is not already running. | 169 | // Enable ADC only when it is not already running. |
| 309 | pub(super) fn enable() { | 170 | fn enable() { |
| 310 | // Make sure bits are off | 171 | // Make sure bits are off |
| 311 | while T::regs().cr().read().addis() { | 172 | while T::regs().cr().read().addis() { |
| 312 | // spin | 173 | // spin |
| @@ -327,7 +188,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 327 | } | 188 | } |
| 328 | } | 189 | } |
| 329 | 190 | ||
| 330 | pub(super) fn start() { | 191 | fn start() { |
| 331 | #[cfg(any(adc_v3, adc_g0, adc_u0))] | 192 | #[cfg(any(adc_v3, adc_g0, adc_u0))] |
| 332 | { | 193 | { |
| 333 | // Start adc conversion | 194 | // Start adc conversion |
| @@ -337,7 +198,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 337 | } | 198 | } |
| 338 | } | 199 | } |
| 339 | 200 | ||
| 340 | pub(super) fn stop() { | 201 | fn stop() { |
| 341 | #[cfg(any(adc_v3, adc_g0, adc_u0))] | 202 | #[cfg(any(adc_v3, adc_g0, adc_u0))] |
| 342 | { | 203 | { |
| 343 | // Ensure conversions are finished. | 204 | // Ensure conversions are finished. |
| @@ -363,7 +224,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 363 | } | 224 | } |
| 364 | 225 | ||
| 365 | /// Perform a single conversion. | 226 | /// Perform a single conversion. |
| 366 | pub(super) fn convert() -> u16 { | 227 | fn convert() -> u16 { |
| 367 | // Some models are affected by an erratum: | 228 | // Some models are affected by an erratum: |
| 368 | // If we perform conversions slower than 1 kHz, the first read ADC value can be | 229 | // If we perform conversions slower than 1 kHz, the first read ADC value can be |
| 369 | // corrupted, so we discard it and measure again. | 230 | // corrupted, so we discard it and measure again. |
| @@ -395,7 +256,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 395 | T::regs().dr().read().0 as u16 | 256 | T::regs().dr().read().0 as u16 |
| 396 | } | 257 | } |
| 397 | 258 | ||
| 398 | pub(super) fn configure_dma(conversion_mode: ConversionMode) { | 259 | fn configure_dma(conversion_mode: ConversionMode) { |
| 399 | // Set continuous mode with oneshot dma. | 260 | // Set continuous mode with oneshot dma. |
| 400 | // Clear overrun flag before starting transfer. | 261 | // Clear overrun flag before starting transfer. |
| 401 | T::regs().isr().modify(|reg| { | 262 | T::regs().isr().modify(|reg| { |
| @@ -419,7 +280,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 419 | }); | 280 | }); |
| 420 | } | 281 | } |
| 421 | 282 | ||
| 422 | pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 283 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 423 | // Set sequence length | 284 | // Set sequence length |
| 424 | #[cfg(not(any(adc_g0, adc_u0)))] | 285 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 425 | T::regs().sqr1().modify(|w| { | 286 | T::regs().sqr1().modify(|w| { |
| @@ -532,6 +393,151 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 532 | }); | 393 | }); |
| 533 | } | 394 | } |
| 534 | } | 395 | } |
| 396 | } | ||
| 397 | |||
| 398 | impl<'d, T: Instance> Adc<'d, T> { | ||
| 399 | /// Enable the voltage regulator | ||
| 400 | fn init_regulator() { | ||
| 401 | rcc::enable_and_reset::<T>(); | ||
| 402 | T::regs().cr().modify(|reg| { | ||
| 403 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 404 | reg.set_deeppwd(false); | ||
| 405 | reg.set_advregen(true); | ||
| 406 | }); | ||
| 407 | |||
| 408 | // If this is false then each ADC_CHSELR bit enables an input channel. | ||
| 409 | // This is the reset value, so has no effect. | ||
| 410 | #[cfg(any(adc_g0, adc_u0))] | ||
| 411 | T::regs().cfgr1().modify(|reg| { | ||
| 412 | reg.set_chselrmod(false); | ||
| 413 | }); | ||
| 414 | |||
| 415 | blocking_delay_us(20); | ||
| 416 | } | ||
| 417 | |||
| 418 | /// Calibrate to remove conversion offset | ||
| 419 | fn init_calibrate() { | ||
| 420 | T::regs().cr().modify(|reg| { | ||
| 421 | reg.set_adcal(true); | ||
| 422 | }); | ||
| 423 | |||
| 424 | while T::regs().cr().read().adcal() { | ||
| 425 | // spin | ||
| 426 | } | ||
| 427 | |||
| 428 | blocking_delay_us(1); | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Initialize the ADC leaving any analog clock at reset value. | ||
| 432 | /// For G0 and WL, this is the async clock without prescaler. | ||
| 433 | pub fn new(adc: Peri<'d, T>) -> Self { | ||
| 434 | Self::init_regulator(); | ||
| 435 | Self::init_calibrate(); | ||
| 436 | Self { adc } | ||
| 437 | } | ||
| 438 | |||
| 439 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | ||
| 440 | #[cfg(not(adc_g0))] | ||
| 441 | let s = Self::new(adc); | ||
| 442 | |||
| 443 | #[cfg(adc_g0)] | ||
| 444 | let s = match config.clock { | ||
| 445 | Some(clock) => Self::new_with_clock(adc, clock), | ||
| 446 | None => Self::new(adc), | ||
| 447 | }; | ||
| 448 | |||
| 449 | #[cfg(any(adc_g0, adc_u0, adc_v3))] | ||
| 450 | if let Some(shift) = config.oversampling_shift { | ||
| 451 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 452 | } | ||
| 453 | |||
| 454 | #[cfg(any(adc_g0, adc_u0, adc_v3))] | ||
| 455 | if let Some(ratio) = config.oversampling_ratio { | ||
| 456 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 457 | } | ||
| 458 | |||
| 459 | #[cfg(any(adc_g0, adc_u0))] | ||
| 460 | if let Some(enable) = config.oversampling_enable { | ||
| 461 | T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); | ||
| 462 | } | ||
| 463 | |||
| 464 | #[cfg(adc_v3)] | ||
| 465 | if let Some((mode, trig_mode, enable)) = config.oversampling_mode { | ||
| 466 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 467 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 468 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 469 | } | ||
| 470 | |||
| 471 | if let Some(resolution) = config.resolution { | ||
| 472 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 473 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 474 | #[cfg(any(adc_g0, adc_u0))] | ||
| 475 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 476 | } | ||
| 477 | |||
| 478 | if let Some(averaging) = config.averaging { | ||
| 479 | let (enable, samples, right_shift) = match averaging { | ||
| 480 | Averaging::Disabled => (false, 0, 0), | ||
| 481 | Averaging::Samples2 => (true, 0, 1), | ||
| 482 | Averaging::Samples4 => (true, 1, 2), | ||
| 483 | Averaging::Samples8 => (true, 2, 3), | ||
| 484 | Averaging::Samples16 => (true, 3, 4), | ||
| 485 | Averaging::Samples32 => (true, 4, 5), | ||
| 486 | Averaging::Samples64 => (true, 5, 6), | ||
| 487 | Averaging::Samples128 => (true, 6, 7), | ||
| 488 | Averaging::Samples256 => (true, 7, 8), | ||
| 489 | }; | ||
| 490 | T::regs().cfgr2().modify(|reg| { | ||
| 491 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 492 | reg.set_rovse(enable); | ||
| 493 | #[cfg(any(adc_g0, adc_u0))] | ||
| 494 | reg.set_ovse(enable); | ||
| 495 | #[cfg(any(adc_h5, adc_h7rs))] | ||
| 496 | reg.set_ovsr(samples.into()); | ||
| 497 | #[cfg(not(any(adc_h5, adc_h7rs)))] | ||
| 498 | reg.set_ovsr(samples.into()); | ||
| 499 | reg.set_ovss(right_shift.into()); | ||
| 500 | }) | ||
| 501 | } | ||
| 502 | |||
| 503 | s | ||
| 504 | } | ||
| 505 | |||
| 506 | #[cfg(adc_g0)] | ||
| 507 | /// Initialize ADC with explicit clock for the analog ADC | ||
| 508 | pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { | ||
| 509 | Self::init_regulator(); | ||
| 510 | |||
| 511 | #[cfg(any(stm32wl5x))] | ||
| 512 | { | ||
| 513 | // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual | ||
| 514 | let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0; | ||
| 515 | match clock { | ||
| 516 | Clock::Async { div: _ } => { | ||
| 517 | assert!(async_clock_available); | ||
| 518 | } | ||
| 519 | Clock::Sync { div: _ } => { | ||
| 520 | if async_clock_available { | ||
| 521 | warn!("Not using configured ADC clock"); | ||
| 522 | } | ||
| 523 | } | ||
| 524 | } | ||
| 525 | } | ||
| 526 | match clock { | ||
| 527 | Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)), | ||
| 528 | Clock::Sync { div } => T::regs().cfgr2().modify(|reg| { | ||
| 529 | reg.set_ckmode(match div { | ||
| 530 | CkModePclk::DIV1 => Ckmode::PCLK, | ||
| 531 | CkModePclk::DIV2 => Ckmode::PCLK_DIV2, | ||
| 532 | CkModePclk::DIV4 => Ckmode::PCLK_DIV4, | ||
| 533 | }) | ||
| 534 | }), | ||
| 535 | } | ||
| 536 | |||
| 537 | Self::init_calibrate(); | ||
| 538 | |||
| 539 | Self { adc } | ||
| 540 | } | ||
| 535 | 541 | ||
| 536 | pub fn enable_vrefint(&self) -> VrefInt { | 542 | pub fn enable_vrefint(&self) -> VrefInt { |
| 537 | #[cfg(not(any(adc_g0, adc_u0)))] | 543 | #[cfg(not(any(adc_g0, adc_u0)))] |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 9be6bcd0b..43eb16fd5 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -151,124 +151,26 @@ pub struct AdcConfig { | |||
| 151 | pub averaging: Option<Averaging>, | 151 | pub averaging: Option<Averaging>, |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | impl<'d, T: Instance> Adc<'d, T> { | 154 | impl<T: Instance> super::SealedAnyInstance for T { |
| 155 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 155 | fn dr() -> *mut u16 { |
| 156 | let s = Self::new(adc); | 156 | T::regs().dr().as_ptr() as *mut u16 |
| 157 | |||
| 158 | // Set the ADC resolution. | ||
| 159 | if let Some(resolution) = config.resolution { | ||
| 160 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 161 | } | ||
| 162 | |||
| 163 | // Set hardware averaging. | ||
| 164 | if let Some(averaging) = config.averaging { | ||
| 165 | let (enable, samples, right_shift) = match averaging { | ||
| 166 | Averaging::Disabled => (false, 0, 0), | ||
| 167 | Averaging::Samples2 => (true, 1, 1), | ||
| 168 | Averaging::Samples4 => (true, 3, 2), | ||
| 169 | Averaging::Samples8 => (true, 7, 3), | ||
| 170 | Averaging::Samples16 => (true, 15, 4), | ||
| 171 | Averaging::Samples32 => (true, 31, 5), | ||
| 172 | Averaging::Samples64 => (true, 63, 6), | ||
| 173 | Averaging::Samples128 => (true, 127, 7), | ||
| 174 | Averaging::Samples256 => (true, 255, 8), | ||
| 175 | Averaging::Samples512 => (true, 511, 9), | ||
| 176 | Averaging::Samples1024 => (true, 1023, 10), | ||
| 177 | }; | ||
| 178 | |||
| 179 | T::regs().cfgr2().modify(|reg| { | ||
| 180 | reg.set_rovse(enable); | ||
| 181 | reg.set_ovsr(samples); | ||
| 182 | reg.set_ovss(right_shift); | ||
| 183 | }) | ||
| 184 | } | ||
| 185 | |||
| 186 | s | ||
| 187 | } | 157 | } |
| 188 | 158 | ||
| 189 | /// Create a new ADC driver. | 159 | fn enable() { |
| 190 | pub fn new(adc: Peri<'d, T>) -> Self { | ||
| 191 | rcc::enable_and_reset::<T>(); | ||
| 192 | |||
| 193 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | ||
| 194 | |||
| 195 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | ||
| 196 | |||
| 197 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | ||
| 198 | info!("ADC frequency set to {}", frequency); | ||
| 199 | |||
| 200 | if frequency > MAX_ADC_CLK_FREQ { | ||
| 201 | panic!( | ||
| 202 | "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", | ||
| 203 | MAX_ADC_CLK_FREQ.0 / 1_000_000 | ||
| 204 | ); | ||
| 205 | } | ||
| 206 | |||
| 207 | #[cfg(stm32h7)] | ||
| 208 | { | ||
| 209 | let boost = if frequency < Hertz::khz(6_250) { | ||
| 210 | Boost::LT6_25 | ||
| 211 | } else if frequency < Hertz::khz(12_500) { | ||
| 212 | Boost::LT12_5 | ||
| 213 | } else if frequency < Hertz::mhz(25) { | ||
| 214 | Boost::LT25 | ||
| 215 | } else { | ||
| 216 | Boost::LT50 | ||
| 217 | }; | ||
| 218 | T::regs().cr().modify(|w| w.set_boost(boost)); | ||
| 219 | } | ||
| 220 | |||
| 221 | T::regs().cr().modify(|reg| { | ||
| 222 | reg.set_deeppwd(false); | ||
| 223 | reg.set_advregen(true); | ||
| 224 | }); | ||
| 225 | |||
| 226 | blocking_delay_us(10); | ||
| 227 | |||
| 228 | T::regs().difsel().modify(|w| { | ||
| 229 | for n in 0..20 { | ||
| 230 | w.set_difsel(n, Difsel::SINGLE_ENDED); | ||
| 231 | } | ||
| 232 | }); | ||
| 233 | |||
| 234 | T::regs().cr().modify(|w| { | ||
| 235 | #[cfg(not(adc_u5))] | ||
| 236 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); | ||
| 237 | w.set_adcallin(true); | ||
| 238 | }); | ||
| 239 | |||
| 240 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 241 | |||
| 242 | while T::regs().cr().read().adcal() {} | ||
| 243 | |||
| 244 | blocking_delay_us(1); | ||
| 245 | |||
| 246 | Self::enable(); | ||
| 247 | |||
| 248 | // single conversion mode, software trigger | ||
| 249 | T::regs().cfgr().modify(|w| { | ||
| 250 | w.set_cont(false); | ||
| 251 | w.set_exten(Exten::DISABLED); | ||
| 252 | }); | ||
| 253 | |||
| 254 | Self { adc } | ||
| 255 | } | ||
| 256 | |||
| 257 | pub(super) fn enable() { | ||
| 258 | T::regs().isr().write(|w| w.set_adrdy(true)); | 160 | T::regs().isr().write(|w| w.set_adrdy(true)); |
| 259 | T::regs().cr().modify(|w| w.set_aden(true)); | 161 | T::regs().cr().modify(|w| w.set_aden(true)); |
| 260 | while !T::regs().isr().read().adrdy() {} | 162 | while !T::regs().isr().read().adrdy() {} |
| 261 | T::regs().isr().write(|w| w.set_adrdy(true)); | 163 | T::regs().isr().write(|w| w.set_adrdy(true)); |
| 262 | } | 164 | } |
| 263 | 165 | ||
| 264 | pub(super) fn start() { | 166 | fn start() { |
| 265 | // Start conversion | 167 | // Start conversion |
| 266 | T::regs().cr().modify(|reg| { | 168 | T::regs().cr().modify(|reg| { |
| 267 | reg.set_adstart(true); | 169 | reg.set_adstart(true); |
| 268 | }); | 170 | }); |
| 269 | } | 171 | } |
| 270 | 172 | ||
| 271 | pub(super) fn stop() { | 173 | fn stop() { |
| 272 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 174 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
| 273 | T::regs().cr().modify(|reg| { | 175 | T::regs().cr().modify(|reg| { |
| 274 | reg.set_adstp(Adstp::STOP); | 176 | reg.set_adstp(Adstp::STOP); |
| @@ -283,7 +185,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 283 | }); | 185 | }); |
| 284 | } | 186 | } |
| 285 | 187 | ||
| 286 | pub(super) fn convert() -> u16 { | 188 | fn convert() -> u16 { |
| 287 | T::regs().isr().modify(|reg| { | 189 | T::regs().isr().modify(|reg| { |
| 288 | reg.set_eos(true); | 190 | reg.set_eos(true); |
| 289 | reg.set_eoc(true); | 191 | reg.set_eoc(true); |
| @@ -301,7 +203,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 301 | T::regs().dr().read().0 as u16 | 203 | T::regs().dr().read().0 as u16 |
| 302 | } | 204 | } |
| 303 | 205 | ||
| 304 | pub(super) fn configure_dma(conversion_mode: ConversionMode) { | 206 | fn configure_dma(conversion_mode: ConversionMode) { |
| 305 | match conversion_mode { | 207 | match conversion_mode { |
| 306 | ConversionMode::Singular => { | 208 | ConversionMode::Singular => { |
| 307 | T::regs().isr().modify(|reg| { | 209 | T::regs().isr().modify(|reg| { |
| @@ -316,7 +218,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 316 | } | 218 | } |
| 317 | } | 219 | } |
| 318 | 220 | ||
| 319 | pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 221 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 320 | // Set sequence length | 222 | // Set sequence length |
| 321 | T::regs().sqr1().modify(|w| { | 223 | T::regs().sqr1().modify(|w| { |
| 322 | w.set_l(sequence.len() as u8 - 1); | 224 | w.set_l(sequence.len() as u8 - 1); |
| @@ -366,6 +268,110 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 366 | } | 268 | } |
| 367 | } | 269 | } |
| 368 | } | 270 | } |
| 271 | } | ||
| 272 | |||
| 273 | impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { | ||
| 274 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | ||
| 275 | let s = Self::new(adc); | ||
| 276 | |||
| 277 | // Set the ADC resolution. | ||
| 278 | if let Some(resolution) = config.resolution { | ||
| 279 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 280 | } | ||
| 281 | |||
| 282 | // Set hardware averaging. | ||
| 283 | if let Some(averaging) = config.averaging { | ||
| 284 | let (enable, samples, right_shift) = match averaging { | ||
| 285 | Averaging::Disabled => (false, 0, 0), | ||
| 286 | Averaging::Samples2 => (true, 1, 1), | ||
| 287 | Averaging::Samples4 => (true, 3, 2), | ||
| 288 | Averaging::Samples8 => (true, 7, 3), | ||
| 289 | Averaging::Samples16 => (true, 15, 4), | ||
| 290 | Averaging::Samples32 => (true, 31, 5), | ||
| 291 | Averaging::Samples64 => (true, 63, 6), | ||
| 292 | Averaging::Samples128 => (true, 127, 7), | ||
| 293 | Averaging::Samples256 => (true, 255, 8), | ||
| 294 | Averaging::Samples512 => (true, 511, 9), | ||
| 295 | Averaging::Samples1024 => (true, 1023, 10), | ||
| 296 | }; | ||
| 297 | |||
| 298 | T::regs().cfgr2().modify(|reg| { | ||
| 299 | reg.set_rovse(enable); | ||
| 300 | reg.set_ovsr(samples); | ||
| 301 | reg.set_ovss(right_shift); | ||
| 302 | }) | ||
| 303 | } | ||
| 304 | |||
| 305 | s | ||
| 306 | } | ||
| 307 | |||
| 308 | /// Create a new ADC driver. | ||
| 309 | pub fn new(adc: Peri<'d, T>) -> Self { | ||
| 310 | rcc::enable_and_reset::<T>(); | ||
| 311 | |||
| 312 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | ||
| 313 | |||
| 314 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | ||
| 315 | |||
| 316 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | ||
| 317 | info!("ADC frequency set to {}", frequency); | ||
| 318 | |||
| 319 | if frequency > MAX_ADC_CLK_FREQ { | ||
| 320 | panic!( | ||
| 321 | "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", | ||
| 322 | MAX_ADC_CLK_FREQ.0 / 1_000_000 | ||
| 323 | ); | ||
| 324 | } | ||
| 325 | |||
| 326 | #[cfg(stm32h7)] | ||
| 327 | { | ||
| 328 | let boost = if frequency < Hertz::khz(6_250) { | ||
| 329 | Boost::LT6_25 | ||
| 330 | } else if frequency < Hertz::khz(12_500) { | ||
| 331 | Boost::LT12_5 | ||
| 332 | } else if frequency < Hertz::mhz(25) { | ||
| 333 | Boost::LT25 | ||
| 334 | } else { | ||
| 335 | Boost::LT50 | ||
| 336 | }; | ||
| 337 | T::regs().cr().modify(|w| w.set_boost(boost)); | ||
| 338 | } | ||
| 339 | |||
| 340 | T::regs().cr().modify(|reg| { | ||
| 341 | reg.set_deeppwd(false); | ||
| 342 | reg.set_advregen(true); | ||
| 343 | }); | ||
| 344 | |||
| 345 | blocking_delay_us(10); | ||
| 346 | |||
| 347 | T::regs().difsel().modify(|w| { | ||
| 348 | for n in 0..20 { | ||
| 349 | w.set_difsel(n, Difsel::SINGLE_ENDED); | ||
| 350 | } | ||
| 351 | }); | ||
| 352 | |||
| 353 | T::regs().cr().modify(|w| { | ||
| 354 | #[cfg(not(adc_u5))] | ||
| 355 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); | ||
| 356 | w.set_adcallin(true); | ||
| 357 | }); | ||
| 358 | |||
| 359 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 360 | |||
| 361 | while T::regs().cr().read().adcal() {} | ||
| 362 | |||
| 363 | blocking_delay_us(1); | ||
| 364 | |||
| 365 | T::enable(); | ||
| 366 | |||
| 367 | // single conversion mode, software trigger | ||
| 368 | T::regs().cfgr().modify(|w| { | ||
| 369 | w.set_cont(false); | ||
| 370 | w.set_exten(Exten::DISABLED); | ||
| 371 | }); | ||
| 372 | |||
| 373 | Self { adc } | ||
| 374 | } | ||
| 369 | 375 | ||
| 370 | /// Enable reading the voltage reference internal channel. | 376 | /// Enable reading the voltage reference internal channel. |
| 371 | pub fn enable_vrefint(&self) -> VrefInt { | 377 | pub fn enable_vrefint(&self) -> VrefInt { |
diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 6b9a91d6e..ad59c0bea 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::adc::{self, AdcChannel, AdcConfig, SampleTime, adc4}; | 5 | use embassy_stm32::adc::{self, Adc, AdcChannel, AdcConfig, SampleTime, adc4}; |
| 6 | use {defmt_rtt as _, panic_probe as _}; | 6 | use {defmt_rtt as _, panic_probe as _}; |
| 7 | 7 | ||
| 8 | #[embassy_executor::main] | 8 | #[embassy_executor::main] |
| @@ -15,7 +15,7 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 15 | let mut config = AdcConfig::default(); | 15 | let mut config = AdcConfig::default(); |
| 16 | config.averaging = Some(adc::Averaging::Samples1024); | 16 | config.averaging = Some(adc::Averaging::Samples1024); |
| 17 | config.resolution = Some(adc::Resolution::BITS14); | 17 | config.resolution = Some(adc::Resolution::BITS14); |
| 18 | let mut adc1 = adc::Adc::new_with_config(p.ADC1, config); | 18 | let mut adc1 = Adc::new_with_config(p.ADC1, config); |
| 19 | let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 | 19 | let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 |
| 20 | let mut adc1_pin2 = p.PA2; // A1 | 20 | let mut adc1_pin2 = p.PA2; // A1 |
| 21 | let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); | 21 | let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); |
| @@ -24,17 +24,17 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 24 | let mut config = AdcConfig::default(); | 24 | let mut config = AdcConfig::default(); |
| 25 | config.averaging = Some(adc::Averaging::Samples1024); | 25 | config.averaging = Some(adc::Averaging::Samples1024); |
| 26 | config.resolution = Some(adc::Resolution::BITS14); | 26 | config.resolution = Some(adc::Resolution::BITS14); |
| 27 | let mut adc2 = adc::Adc::new_with_config(p.ADC2, config); | 27 | let mut adc2 = Adc::new_with_config(p.ADC2, config); |
| 28 | let mut adc2_pin1 = p.PC3; // A2 | 28 | let mut adc2_pin1 = p.PC3; // A2 |
| 29 | let mut adc2_pin2 = p.PB0; // A3 | 29 | let mut adc2_pin2 = p.PB0; // A3 |
| 30 | let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); | 30 | let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); |
| 31 | 31 | ||
| 32 | // **** ADC4 init **** | 32 | // **** ADC4 init **** |
| 33 | let mut adc4 = adc4::Adc4::new(p.ADC4); | 33 | let mut adc4 = Adc::new_adc4(p.ADC4); |
| 34 | let mut adc4_pin1 = p.PC1; // A4 | 34 | let mut adc4_pin1 = p.PC1; // A4 |
| 35 | let mut adc4_pin2 = p.PC0; // A5 | 35 | let mut adc4_pin2 = p.PC0; // A5 |
| 36 | adc4.set_resolution(adc4::Resolution::BITS12); | 36 | adc4.set_resolution_adc4(adc4::Resolution::BITS12); |
| 37 | adc4.set_averaging(adc4::Averaging::Samples256); | 37 | adc4.set_averaging_adc4(adc4::Averaging::Samples256); |
| 38 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); | 38 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); |
| 39 | 39 | ||
| 40 | // **** ADC1 blocking read **** | 40 | // **** ADC1 blocking read **** |
| @@ -95,11 +95,14 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 95 | // The channels must be in ascending order and can't repeat for ADC4 | 95 | // The channels must be in ascending order and can't repeat for ADC4 |
| 96 | adc4.read( | 96 | adc4.read( |
| 97 | p.GPDMA1_CH1.reborrow(), | 97 | p.GPDMA1_CH1.reborrow(), |
| 98 | [&mut degraded42, &mut degraded41].into_iter(), | 98 | [ |
| 99 | (&mut degraded42, adc4::SampleTime::CYCLES1_5), | ||
| 100 | (&mut degraded41, adc4::SampleTime::CYCLES1_5), | ||
| 101 | ] | ||
| 102 | .into_iter(), | ||
| 99 | &mut measurements, | 103 | &mut measurements, |
| 100 | ) | 104 | ) |
| 101 | .await | 105 | .await; |
| 102 | .unwrap(); | ||
| 103 | let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; | 106 | let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; |
| 104 | let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32; | 107 | let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32; |
| 105 | info!("Async read 4 pin 1 {}", volt1); | 108 | info!("Async read 4 pin 1 {}", volt1); |
diff --git a/examples/stm32wba/src/bin/adc.rs b/examples/stm32wba/src/bin/adc.rs index 177aab3f3..ade3f5d6a 100644 --- a/examples/stm32wba/src/bin/adc.rs +++ b/examples/stm32wba/src/bin/adc.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::adc::{AdcChannel, adc4}; | 5 | use embassy_stm32::adc::{Adc, AdcChannel, SampleTime, adc4}; |
| 6 | use {defmt_rtt as _, panic_probe as _}; | 6 | use {defmt_rtt as _, panic_probe as _}; |
| 7 | 7 | ||
| 8 | #[embassy_executor::main] | 8 | #[embassy_executor::main] |
| @@ -12,11 +12,11 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 12 | let mut p = embassy_stm32::init(config); | 12 | let mut p = embassy_stm32::init(config); |
| 13 | 13 | ||
| 14 | // **** ADC4 init **** | 14 | // **** ADC4 init **** |
| 15 | let mut adc4 = adc4::Adc4::new(p.ADC4); | 15 | let mut adc4 = Adc::new_adc4(p.ADC4); |
| 16 | let mut adc4_pin1 = p.PA0; // A4 | 16 | let mut adc4_pin1 = p.PA0; // A4 |
| 17 | let mut adc4_pin2 = p.PA1; // A5 | 17 | let mut adc4_pin2 = p.PA1; // A5 |
| 18 | adc4.set_resolution(adc4::Resolution::BITS12); | 18 | adc4.set_resolution_adc4(adc4::Resolution::BITS12); |
| 19 | adc4.set_averaging(adc4::Averaging::Samples256); | 19 | adc4.set_averaging_adc4(adc4::Averaging::Samples256); |
| 20 | 20 | ||
| 21 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); | 21 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); |
| 22 | 22 | ||
| @@ -37,11 +37,14 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 37 | // The channels must be in ascending order and can't repeat for ADC4 | 37 | // The channels must be in ascending order and can't repeat for ADC4 |
| 38 | adc4.read( | 38 | adc4.read( |
| 39 | p.GPDMA1_CH1.reborrow(), | 39 | p.GPDMA1_CH1.reborrow(), |
| 40 | [&mut degraded42, &mut degraded41].into_iter(), | 40 | [ |
| 41 | (&mut degraded42, SampleTime::CYCLES12_5), | ||
| 42 | (&mut degraded41, SampleTime::CYCLES12_5), | ||
| 43 | ] | ||
| 44 | .into_iter(), | ||
| 41 | &mut measurements, | 45 | &mut measurements, |
| 42 | ) | 46 | ) |
| 43 | .await | 47 | .await; |
| 44 | .unwrap(); | ||
| 45 | let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; | 48 | let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; |
| 46 | let volt1: f32 = 3.0 * measurements[1] as f32 / max4 as f32; | 49 | let volt1: f32 = 3.0 * measurements[1] as f32 / max4 as f32; |
| 47 | info!("Async read 4 pin 1 {}", volt1); | 50 | info!("Async read 4 pin 1 {}", volt1); |
diff --git a/examples/stm32wba6/src/bin/adc.rs b/examples/stm32wba6/src/bin/adc.rs index 0887e124c..9d1f39419 100644 --- a/examples/stm32wba6/src/bin/adc.rs +++ b/examples/stm32wba6/src/bin/adc.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::adc::{AdcChannel, adc4}; | 5 | use embassy_stm32::adc::{Adc, AdcChannel, SampleTime, adc4}; |
| 6 | use {defmt_rtt as _, panic_probe as _}; | 6 | use {defmt_rtt as _, panic_probe as _}; |
| 7 | 7 | ||
| 8 | #[embassy_executor::main] | 8 | #[embassy_executor::main] |
| @@ -12,11 +12,11 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 12 | let mut p = embassy_stm32::init(config); | 12 | let mut p = embassy_stm32::init(config); |
| 13 | 13 | ||
| 14 | // **** ADC4 init **** | 14 | // **** ADC4 init **** |
| 15 | let mut adc4 = adc4::Adc4::new(p.ADC4); | 15 | let mut adc4 = Adc::new_adc4(p.ADC4); |
| 16 | let mut adc4_pin1 = p.PA0; // A4 | 16 | let mut adc4_pin1 = p.PA0; // A4 |
| 17 | let mut adc4_pin2 = p.PA1; // A5 | 17 | let mut adc4_pin2 = p.PA1; // A5 |
| 18 | adc4.set_resolution(adc4::Resolution::BITS12); | 18 | adc4.set_resolution_adc4(adc4::Resolution::BITS12); |
| 19 | adc4.set_averaging(adc4::Averaging::Samples256); | 19 | adc4.set_averaging_adc4(adc4::Averaging::Samples256); |
| 20 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); | 20 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); |
| 21 | 21 | ||
| 22 | // **** ADC4 blocking read **** | 22 | // **** ADC4 blocking read **** |
| @@ -36,11 +36,14 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 36 | // The channels must be in ascending order and can't repeat for ADC4 | 36 | // The channels must be in ascending order and can't repeat for ADC4 |
| 37 | adc4.read( | 37 | adc4.read( |
| 38 | p.GPDMA1_CH1.reborrow(), | 38 | p.GPDMA1_CH1.reborrow(), |
| 39 | [&mut degraded42, &mut degraded41].into_iter(), | 39 | [ |
| 40 | (&mut degraded42, SampleTime::CYCLES12_5), | ||
| 41 | (&mut degraded41, SampleTime::CYCLES12_5), | ||
| 42 | ] | ||
| 43 | .into_iter(), | ||
| 40 | &mut measurements, | 44 | &mut measurements, |
| 41 | ) | 45 | ) |
| 42 | .await | 46 | .await; |
| 43 | .unwrap(); | ||
| 44 | let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; | 47 | let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; |
| 45 | let volt1: f32 = 3.0 * measurements[1] as f32 / max4 as f32; | 48 | let volt1: f32 = 3.0 * measurements[1] as f32 / max4 as f32; |
| 46 | info!("Async read 4 pin 1 {}", volt1); | 49 | info!("Async read 4 pin 1 {}", volt1); |
