diff options
| author | klownfish <[email protected]> | 2024-12-27 00:24:47 +0100 |
|---|---|---|
| committer | klownfish <[email protected]> | 2024-12-27 00:24:47 +0100 |
| commit | 4f4740eeb25e0db607a7f700e29efd313dd1942d (patch) | |
| tree | bfa53c957225cb3c3afade50eaedfd3df24465b4 | |
| parent | d1692494823c2be9423d74d446f555a879344a0c (diff) | |
add async read for u5 ADC4
| -rw-r--r-- | embassy-stm32/src/adc/u5_adc4.rs | 120 | ||||
| -rw-r--r-- | examples/stm32u5/src/bin/adc.rs | 102 |
2 files changed, 177 insertions, 45 deletions
diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index 8d0c1abed..ddc1b58a2 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs | |||
| @@ -4,13 +4,14 @@ pub use crate::pac::adc::vals::Adc4Presc as Presc; | |||
| 4 | pub use crate::pac::adc::regs::Adc4Chselrmod0; | 4 | pub use crate::pac::adc::regs::Adc4Chselrmod0; |
| 5 | 5 | ||
| 6 | #[allow(unused)] | 6 | #[allow(unused)] |
| 7 | use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio}; | 7 | use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio, Adc4Dmacfg}; |
| 8 | 8 | ||
| 9 | use super::{ | 9 | use super::{ |
| 10 | blocking_delay_us, AdcChannel, SealedAdcChannel | 10 | blocking_delay_us, AdcChannel, SealedAdcChannel, AnyAdcChannel, RxDma4 |
| 11 | }; | 11 | }; |
| 12 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use crate::{pac, rcc, Peripheral}; | 13 | use crate::{pac, rcc, Peripheral}; |
| 14 | use crate::dma::Transfer; | ||
| 14 | 15 | ||
| 15 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); | 16 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); |
| 16 | 17 | ||
| @@ -182,6 +183,12 @@ pub struct Adc4<'d, T: Instance> { | |||
| 182 | adc: crate::PeripheralRef<'d, T>, | 183 | adc: crate::PeripheralRef<'d, T>, |
| 183 | } | 184 | } |
| 184 | 185 | ||
| 186 | #[derive(Debug)] | ||
| 187 | pub enum Adc4Error { | ||
| 188 | InvalidSequence, | ||
| 189 | DMAError | ||
| 190 | } | ||
| 191 | |||
| 185 | impl<'d, T: Instance> Adc4<'d, T> { | 192 | impl<'d, T: Instance> Adc4<'d, T> { |
| 186 | /// Create a new ADC driver. | 193 | /// Create a new ADC driver. |
| 187 | pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { | 194 | pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { |
| @@ -244,6 +251,7 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 244 | // single conversion mode, software trigger | 251 | // single conversion mode, software trigger |
| 245 | T::regs().cfgr1().modify(|w| { | 252 | T::regs().cfgr1().modify(|w| { |
| 246 | w.set_cont(false); | 253 | w.set_cont(false); |
| 254 | w.set_discen(false); | ||
| 247 | w.set_exten(Adc4Exten::DISABLED); | 255 | w.set_exten(Adc4Exten::DISABLED); |
| 248 | }); | 256 | }); |
| 249 | 257 | ||
| @@ -336,8 +344,18 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 336 | }) | 344 | }) |
| 337 | } | 345 | } |
| 338 | 346 | ||
| 339 | /// Perform a single conversion. | 347 | /// Read an ADC channel. |
| 340 | fn convert(&mut self) -> u16 { | 348 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16{ |
| 349 | channel.setup(); | ||
| 350 | T::regs().cfgr1().modify(|reg| { | ||
| 351 | reg.set_chselrmod(false); | ||
| 352 | }); | ||
| 353 | |||
| 354 | T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); | ||
| 355 | T::regs().chselrmod0().modify(|w| { | ||
| 356 | w.set_chsel(channel.channel() as usize, true); | ||
| 357 | }); | ||
| 358 | |||
| 341 | T::regs().isr().modify(|reg| { | 359 | T::regs().isr().modify(|reg| { |
| 342 | reg.set_eos(true); | 360 | reg.set_eos(true); |
| 343 | reg.set_eoc(true); | 361 | reg.set_eoc(true); |
| @@ -355,22 +373,92 @@ impl<'d, T: Instance> Adc4<'d, T> { | |||
| 355 | T::regs().dr().read().0 as u16 | 373 | T::regs().dr().read().0 as u16 |
| 356 | } | 374 | } |
| 357 | 375 | ||
| 358 | /// Read an ADC channel. | 376 | /// Channels can not be repeated and must be in ascending order! |
| 359 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | 377 | /// TODO: broken |
| 360 | self.read_channel(channel) | 378 | pub async fn read( |
| 361 | } | 379 | &mut self, |
| 380 | rx_dma: &mut impl RxDma4<T>, | ||
| 381 | sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>, | ||
| 382 | readings: &mut [u16], | ||
| 383 | ) -> Result<(), Adc4Error> { | ||
| 384 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | ||
| 385 | assert!( | ||
| 386 | sequence.len() == readings.len(), | ||
| 387 | "Sequence length must be equal to readings length" | ||
| 388 | ); | ||
| 389 | |||
| 390 | // Ensure no conversions are ongoing | ||
| 391 | Self::cancel_conversions(); | ||
| 362 | 392 | ||
| 363 | fn configure_channel(channel: &mut impl AdcChannel<T>) { | 393 | T::regs().isr().modify(|reg| { |
| 364 | channel.setup(); | 394 | reg.set_ovr(true); |
| 395 | reg.set_eos(true); | ||
| 396 | reg.set_eoc(true); | ||
| 397 | }); | ||
| 398 | |||
| 399 | T::regs().cfgr1().modify(|reg| { | ||
| 400 | reg.set_dmaen(true); | ||
| 401 | reg.set_dmacfg(Adc4Dmacfg::ONESHOT); | ||
| 402 | reg.set_chselrmod(false); | ||
| 403 | }); | ||
| 404 | |||
| 405 | |||
| 406 | let mut prev_channel: i16 = -1; | ||
| 365 | T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); | 407 | T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); |
| 366 | T::regs().chselrmod0().modify(|w| { | 408 | for channel in sequence { |
| 367 | w.set_chsel(channel.channel() as usize, true); | 409 | let channel_num = channel.channel; |
| 410 | if channel_num as i16 <= prev_channel { | ||
| 411 | return Err(Adc4Error::InvalidSequence); | ||
| 412 | }; | ||
| 413 | prev_channel = channel_num as i16; | ||
| 414 | |||
| 415 | T::regs().chselrmod0().modify(|w| { | ||
| 416 | w.set_chsel(channel.channel as usize, true); | ||
| 417 | }); | ||
| 418 | }; | ||
| 419 | |||
| 420 | let request = rx_dma.request(); | ||
| 421 | let transfer = unsafe { | ||
| 422 | Transfer::new_read( | ||
| 423 | rx_dma, | ||
| 424 | request, | ||
| 425 | T::regs().dr().as_ptr() as *mut u16, | ||
| 426 | readings, | ||
| 427 | Default::default(), | ||
| 428 | ) | ||
| 429 | }; | ||
| 430 | |||
| 431 | // Start conversion | ||
| 432 | T::regs().cr().modify(|reg| { | ||
| 433 | reg.set_adstart(true); | ||
| 368 | }); | 434 | }); |
| 435 | |||
| 436 | // Wait for conversion sequence to finish. | ||
| 437 | transfer.await; | ||
| 438 | |||
| 439 | blocking_delay_us(10); | ||
| 440 | |||
| 441 | // Ensure conversions are finished. | ||
| 442 | Self::cancel_conversions(); | ||
| 443 | |||
| 444 | // Reset configuration. | ||
| 445 | T::regs().cfgr1().modify(|reg| { | ||
| 446 | reg.set_dmaen(false); | ||
| 447 | }); | ||
| 448 | |||
| 449 | if T::regs().isr().read().ovr() { | ||
| 450 | Err(Adc4Error::DMAError) | ||
| 451 | } else { | ||
| 452 | Ok(()) | ||
| 453 | } | ||
| 369 | } | 454 | } |
| 370 | 455 | ||
| 371 | fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | 456 | fn cancel_conversions() { |
| 372 | Self::configure_channel(channel); | 457 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
| 373 | let ret = self.convert(); | 458 | T::regs().cr().modify(|reg| { |
| 374 | ret | 459 | reg.set_adstp(true); |
| 460 | }); | ||
| 461 | while T::regs().cr().read().adstart() {} | ||
| 462 | } | ||
| 375 | } | 463 | } |
| 376 | } \ No newline at end of file | 464 | } \ No newline at end of file |
diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 049b985cf..4632f2cd1 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs | |||
| @@ -36,55 +36,99 @@ async fn main(spawner: embassy_executor::Spawner) { | |||
| 36 | 36 | ||
| 37 | let mut p = embassy_stm32::init(config); | 37 | let mut p = embassy_stm32::init(config); |
| 38 | 38 | ||
| 39 | let mut adc = adc::Adc::new(p.ADC1); | 39 | // **** ADC1 init **** |
| 40 | let mut adc_pin1 = p.PA3; // A0 on nucleo u5a5 | 40 | let mut adc1 = adc::Adc::new(p.ADC1); |
| 41 | let mut adc_pin2 = p.PA2; // A1 on nucleo u5a5 | 41 | let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 |
| 42 | adc.set_resolution(adc::Resolution::BITS14); | 42 | let mut adc1_pin2 = p.PA2; // A1 |
| 43 | adc.set_averaging(adc::Averaging::Samples1024); | 43 | adc1.set_resolution(adc::Resolution::BITS14); |
| 44 | adc.set_sample_time(adc::SampleTime::CYCLES160_5); | 44 | adc1.set_averaging(adc::Averaging::Samples1024); |
| 45 | let max = adc::resolution_to_max_count(adc::Resolution::BITS14); | 45 | adc1.set_sample_time(adc::SampleTime::CYCLES160_5); |
| 46 | 46 | let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); | |
| 47 | |||
| 48 | // **** ADC2 init **** | ||
| 49 | let mut adc2 = adc::Adc::new(p.ADC2); | ||
| 50 | let mut adc2_pin1 = p.PC3; // A2 | ||
| 51 | let mut adc2_pin2 = p.PB0; // A3 | ||
| 52 | adc2.set_resolution(adc::Resolution::BITS14); | ||
| 53 | adc2.set_averaging(adc::Averaging::Samples1024); | ||
| 54 | adc2.set_sample_time(adc::SampleTime::CYCLES160_5); | ||
| 55 | let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); | ||
| 56 | |||
| 57 | // **** ADC4 init **** | ||
| 47 | let mut adc4 = adc4::Adc4::new(p.ADC4); | 58 | let mut adc4 = adc4::Adc4::new(p.ADC4); |
| 48 | let mut adc4_pin1 = p.PD11; | 59 | let mut adc4_pin1 = p.PC1; // A4 |
| 49 | let mut adc4_pin2 = p.PC0; | 60 | let mut adc4_pin2 = p.PC0; // A5 |
| 50 | adc4.set_resolution(adc4::Resolution::BITS12); | 61 | adc4.set_resolution(adc4::Resolution::BITS12); |
| 51 | adc4.set_averaging(adc4::Averaging::Samples256); | 62 | adc4.set_averaging(adc4::Averaging::Samples256); |
| 52 | adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); | 63 | adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); |
| 53 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); | 64 | let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); |
| 54 | 65 | ||
| 55 | let raw: u16 = adc.blocking_read(&mut adc_pin1); | 66 | // **** ADC1 blocking read **** |
| 56 | let volt: f32 = 3.3 * raw as f32 / max as f32; | 67 | let raw: u16 = adc1.blocking_read(&mut adc1_pin1); |
| 57 | info!("Read 1 pin 1 {}", volt); | 68 | let volt: f32 = 3.3 * raw as f32 / max1 as f32; |
| 69 | info!("Read adc1 pin 1 {}", volt); | ||
| 70 | |||
| 71 | let raw: u16 = adc1.blocking_read(&mut adc1_pin2); | ||
| 72 | let volt: f32 = 3.3 * raw as f32 / max1 as f32; | ||
| 73 | info!("Read adc1 pin 2 {}", volt); | ||
| 74 | |||
| 75 | // **** ADC2 blocking read **** | ||
| 76 | let raw: u16 = adc2.blocking_read(&mut adc2_pin1); | ||
| 77 | let volt: f32 = 3.3 * raw as f32 / max2 as f32; | ||
| 78 | info!("Read adc2 pin 1 {}", volt); | ||
| 58 | 79 | ||
| 59 | let raw: u16 = adc.blocking_read(&mut adc_pin2); | 80 | let raw: u16 = adc2.blocking_read(&mut adc2_pin2); |
| 60 | let volt: f32 = 3.3 * raw as f32 / max as f32; | 81 | let volt: f32 = 3.3 * raw as f32 / max2 as f32; |
| 61 | info!("Read 1 pin 2 {}", volt); | 82 | info!("Read adc2 pin 2 {}", volt); |
| 62 | 83 | ||
| 63 | let raw4: u16 = adc4.blocking_read(&mut adc4_pin1); | 84 | // **** ADC4 blocking read **** |
| 64 | let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; | 85 | let raw: u16 = adc4.blocking_read(&mut adc4_pin1); |
| 65 | info!("Read 4 pin 1 {}", volt4); | 86 | let volt: f32 = 3.3 * raw as f32 / max4 as f32; |
| 87 | info!("Read adc4 pin 1 {}", volt); | ||
| 66 | 88 | ||
| 67 | let raw4: u16 = adc4.blocking_read(&mut adc4_pin2); | 89 | let raw: u16 = adc4.blocking_read(&mut adc4_pin2); |
| 68 | let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; | 90 | let volt: f32 = 3.3 * raw as f32 / max4 as f32; |
| 69 | info!("Read 4 pin 2 {}", volt4); | 91 | info!("Read adc4 pin 2 {}", volt); |
| 70 | 92 | ||
| 71 | let mut degraded1 = adc_pin1.degrade_adc(); | 93 | // **** ADC1 async read **** |
| 72 | let mut degraded2 = adc_pin2.degrade_adc(); | 94 | let mut degraded11 = adc1_pin1.degrade_adc(); |
| 95 | let mut degraded12 = adc1_pin2.degrade_adc(); | ||
| 73 | let mut measurements = [0u16; 2]; | 96 | let mut measurements = [0u16; 2]; |
| 74 | 97 | ||
| 75 | adc.read( | 98 | adc1.read( |
| 76 | &mut p.GPDMA1_CH0, | 99 | &mut p.GPDMA1_CH0, |
| 77 | [ | 100 | [ |
| 78 | (&mut degraded2, adc::SampleTime::CYCLES160_5), | 101 | (&mut degraded11, adc::SampleTime::CYCLES160_5), |
| 79 | (&mut degraded1, adc::SampleTime::CYCLES160_5), | 102 | (&mut degraded12, adc::SampleTime::CYCLES160_5), |
| 80 | ] | 103 | ] |
| 81 | .into_iter(), | 104 | .into_iter(), |
| 82 | &mut measurements, | 105 | &mut measurements, |
| 83 | ).await; | 106 | ).await; |
| 84 | let volt1: f32 = 3.3 * measurements[1] as f32 / max as f32; | 107 | let volt1: f32 = 3.3 * measurements[0] as f32 / max1 as f32; |
| 85 | let volt2: f32 = 3.3 * measurements[0] as f32 / max as f32; | 108 | let volt2: f32 = 3.3 * measurements[1] as f32 / max1 as f32; |
| 86 | 109 | ||
| 87 | info!("Async read 1 pin 1 {}", volt1); | 110 | info!("Async read 1 pin 1 {}", volt1); |
| 88 | info!("Async read 1 pin 2 {}", volt2); | 111 | info!("Async read 1 pin 2 {}", volt2); |
| 89 | 112 | ||
| 113 | // **** ADC2 does not support async read **** | ||
| 114 | |||
| 115 | // **** ADC4 async read **** | ||
| 116 | let mut degraded41 = adc4_pin1.degrade_adc(); | ||
| 117 | let mut degraded42 = adc4_pin2.degrade_adc(); | ||
| 118 | let mut measurements = [0u16; 2]; | ||
| 119 | |||
| 120 | // The channels must be in ascending order and can't repeat for ADC4 | ||
| 121 | adc4.read( | ||
| 122 | &mut p.GPDMA1_CH1, | ||
| 123 | [ | ||
| 124 | &mut degraded42, | ||
| 125 | &mut degraded41, | ||
| 126 | ] | ||
| 127 | .into_iter(), | ||
| 128 | &mut measurements, | ||
| 129 | ).await.unwrap(); | ||
| 130 | let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; | ||
| 131 | let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32; | ||
| 132 | info!("Async read 4 pin 1 {}", volt1); | ||
| 133 | info!("Async read 4 pin 2 {}", volt2); | ||
| 90 | } \ No newline at end of file | 134 | } \ No newline at end of file |
