diff options
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 169 |
1 files changed, 159 insertions, 10 deletions
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 3e9ba8ae2..872cf3f06 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -5,8 +5,11 @@ use pac::adc::vals::{Adcaldif, Difsel, Exten}; | |||
| 5 | #[cfg(stm32g4)] | 5 | #[cfg(stm32g4)] |
| 6 | use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; | 6 | use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; |
| 7 | use pac::adccommon::vals::Presc; | 7 | use pac::adccommon::vals::Presc; |
| 8 | use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; | ||
| 8 | 9 | ||
| 9 | use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; | 10 | use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; |
| 11 | use crate::adc::SealedAdcChannel; | ||
| 12 | use crate::dma::Transfer; | ||
| 10 | use crate::time::Hertz; | 13 | use crate::time::Hertz; |
| 11 | use crate::{pac, rcc, Peripheral}; | 14 | use crate::{pac, rcc, Peripheral}; |
| 12 | 15 | ||
| @@ -191,10 +194,24 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 191 | } | 194 | } |
| 192 | 195 | ||
| 193 | fn enable(&mut self) { | 196 | fn enable(&mut self) { |
| 194 | T::regs().isr().write(|w| w.set_adrdy(true)); | 197 | // Make sure bits are off |
| 195 | T::regs().cr().modify(|w| w.set_aden(true)); | 198 | while T::regs().cr().read().addis() { |
| 196 | while !T::regs().isr().read().adrdy() {} | 199 | // spin |
| 197 | T::regs().isr().write(|w| w.set_adrdy(true)); | 200 | } |
| 201 | |||
| 202 | if !T::regs().cr().read().aden() { | ||
| 203 | // Enable ADC | ||
| 204 | T::regs().isr().modify(|reg| { | ||
| 205 | reg.set_adrdy(true); | ||
| 206 | }); | ||
| 207 | T::regs().cr().modify(|reg| { | ||
| 208 | reg.set_aden(true); | ||
| 209 | }); | ||
| 210 | |||
| 211 | while !T::regs().isr().read().adrdy() { | ||
| 212 | // spin | ||
| 213 | } | ||
| 214 | } | ||
| 198 | } | 215 | } |
| 199 | 216 | ||
| 200 | fn configure(&mut self) { | 217 | fn configure(&mut self) { |
| @@ -327,23 +344,146 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 327 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | 344 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { |
| 328 | channel.setup(); | 345 | channel.setup(); |
| 329 | 346 | ||
| 330 | self.read_channel(channel.channel()) | 347 | self.read_channel(channel) |
| 348 | } | ||
| 349 | |||
| 350 | /// Read one or multiple ADC channels using DMA. | ||
| 351 | /// | ||
| 352 | /// `sequence` iterator and `readings` must have the same length. | ||
| 353 | /// | ||
| 354 | /// Example | ||
| 355 | /// ```rust,ignore | ||
| 356 | /// use embassy_stm32::adc::{Adc, AdcChannel} | ||
| 357 | /// | ||
| 358 | /// let mut adc = Adc::new(p.ADC1); | ||
| 359 | /// let mut adc_pin0 = p.PA0.degrade_adc(); | ||
| 360 | /// let mut adc_pin1 = p.PA1.degrade_adc(); | ||
| 361 | /// let mut measurements = [0u16; 2]; | ||
| 362 | /// | ||
| 363 | /// adc.read_async( | ||
| 364 | /// p.DMA1_CH2, | ||
| 365 | /// [ | ||
| 366 | /// (&mut *adc_pin0, SampleTime::CYCLES160_5), | ||
| 367 | /// (&mut *adc_pin1, SampleTime::CYCLES160_5), | ||
| 368 | /// ] | ||
| 369 | /// .into_iter(), | ||
| 370 | /// &mut measurements, | ||
| 371 | /// ) | ||
| 372 | /// .await; | ||
| 373 | /// defmt::info!("measurements: {}", measurements); | ||
| 374 | /// ``` | ||
| 375 | pub async fn read( | ||
| 376 | &mut self, | ||
| 377 | rx_dma: &mut impl RxDma<T>, | ||
| 378 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, | ||
| 379 | readings: &mut [u16], | ||
| 380 | ) { | ||
| 381 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | ||
| 382 | assert!( | ||
| 383 | sequence.len() == readings.len(), | ||
| 384 | "Sequence length must be equal to readings length" | ||
| 385 | ); | ||
| 386 | assert!( | ||
| 387 | sequence.len() <= 16, | ||
| 388 | "Asynchronous read sequence cannot be more than 16 in length" | ||
| 389 | ); | ||
| 390 | |||
| 391 | // Ensure no conversions are ongoing and ADC is enabled. | ||
| 392 | Self::cancel_conversions(); | ||
| 393 | self.enable(); | ||
| 394 | |||
| 395 | // Set sequence length | ||
| 396 | T::regs().sqr1().modify(|w| { | ||
| 397 | w.set_l(sequence.len() as u8 - 1); | ||
| 398 | }); | ||
| 399 | |||
| 400 | // Configure channels and ranks | ||
| 401 | for (_i, (channel, sample_time)) in sequence.enumerate() { | ||
| 402 | Self::configure_channel(channel, sample_time); | ||
| 403 | |||
| 404 | match _i { | ||
| 405 | 0..=3 => { | ||
| 406 | T::regs().sqr1().modify(|w| { | ||
| 407 | w.set_sq(_i, channel.channel()); | ||
| 408 | }); | ||
| 409 | } | ||
| 410 | 4..=8 => { | ||
| 411 | T::regs().sqr2().modify(|w| { | ||
| 412 | w.set_sq(_i - 4, channel.channel()); | ||
| 413 | }); | ||
| 414 | } | ||
| 415 | 9..=13 => { | ||
| 416 | T::regs().sqr3().modify(|w| { | ||
| 417 | w.set_sq(_i - 9, channel.channel()); | ||
| 418 | }); | ||
| 419 | } | ||
| 420 | 14..=15 => { | ||
| 421 | T::regs().sqr4().modify(|w| { | ||
| 422 | w.set_sq(_i - 14, channel.channel()); | ||
| 423 | }); | ||
| 424 | } | ||
| 425 | _ => unreachable!(), | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | // Set continuous mode with oneshot dma. | ||
| 430 | // Clear overrun flag before starting transfer. | ||
| 431 | T::regs().isr().modify(|reg| { | ||
| 432 | reg.set_ovr(true); | ||
| 433 | }); | ||
| 434 | |||
| 435 | T::regs().cfgr().modify(|reg| { | ||
| 436 | reg.set_discen(false); | ||
| 437 | reg.set_cont(true); | ||
| 438 | reg.set_dmacfg(Dmacfg::ONESHOT); | ||
| 439 | reg.set_dmaen(Dmaen::ENABLE); | ||
| 440 | }); | ||
| 441 | |||
| 442 | let request = rx_dma.request(); | ||
| 443 | let transfer = unsafe { | ||
| 444 | Transfer::new_read( | ||
| 445 | rx_dma, | ||
| 446 | request, | ||
| 447 | T::regs().dr().as_ptr() as *mut u16, | ||
| 448 | readings, | ||
| 449 | Default::default(), | ||
| 450 | ) | ||
| 451 | }; | ||
| 452 | |||
| 453 | // Start conversion | ||
| 454 | T::regs().cr().modify(|reg| { | ||
| 455 | reg.set_adstart(true); | ||
| 456 | }); | ||
| 457 | |||
| 458 | // Wait for conversion sequence to finish. | ||
| 459 | transfer.await; | ||
| 460 | |||
| 461 | // Ensure conversions are finished. | ||
| 462 | Self::cancel_conversions(); | ||
| 463 | |||
| 464 | // Reset configuration. | ||
| 465 | T::regs().cfgr().modify(|reg| { | ||
| 466 | reg.set_cont(false); | ||
| 467 | }); | ||
| 331 | } | 468 | } |
| 332 | 469 | ||
| 333 | fn read_channel(&mut self, channel: u8) -> u16 { | 470 | fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { |
| 334 | // Configure channel | 471 | // Configure channel |
| 335 | Self::set_channel_sample_time(channel, self.sample_time); | 472 | Self::set_channel_sample_time(channel.channel(), sample_time); |
| 473 | } | ||
| 336 | 474 | ||
| 475 | fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | ||
| 476 | Self::configure_channel(channel, self.sample_time); | ||
| 337 | #[cfg(stm32h7)] | 477 | #[cfg(stm32h7)] |
| 338 | { | 478 | { |
| 339 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); | 479 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); |
| 340 | T::regs() | 480 | T::regs() |
| 341 | .pcsel() | 481 | .pcsel() |
| 342 | .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); | 482 | .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); |
| 343 | } | 483 | } |
| 344 | 484 | ||
| 345 | T::regs().sqr1().write(|reg| { | 485 | T::regs().sqr1().write(|reg| { |
| 346 | reg.set_sq(0, channel); | 486 | reg.set_sq(0, channel.channel()); |
| 347 | reg.set_l(0); | 487 | reg.set_l(0); |
| 348 | }); | 488 | }); |
| 349 | 489 | ||
| @@ -358,4 +498,13 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 358 | T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | 498 | T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); |
| 359 | } | 499 | } |
| 360 | } | 500 | } |
| 501 | |||
| 502 | fn cancel_conversions() { | ||
| 503 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | ||
| 504 | T::regs().cr().modify(|reg| { | ||
| 505 | reg.set_adstp(Adstp::STOP); | ||
| 506 | }); | ||
| 507 | while T::regs().cr().read().adstart() {} | ||
| 508 | } | ||
| 509 | } | ||
| 361 | } | 510 | } |
