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; pub use crate::pac::adc::regs::Adc4Chselrmod0; #[allow(unused)] -use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio}; +use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio, Adc4Dmacfg}; use super::{ - blocking_delay_us, AdcChannel, SealedAdcChannel + blocking_delay_us, AdcChannel, SealedAdcChannel, AnyAdcChannel, RxDma4 }; use crate::time::Hertz; use crate::{pac, rcc, Peripheral}; +use crate::dma::Transfer; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); @@ -182,6 +183,12 @@ pub struct Adc4<'d, T: Instance> { adc: crate::PeripheralRef<'d, T>, } +#[derive(Debug)] +pub enum Adc4Error { + InvalidSequence, + DMAError +} + impl<'d, T: Instance> Adc4<'d, T> { /// Create a new ADC driver. pub fn new(adc: impl Peripheral

+ 'd) -> Self { @@ -244,6 +251,7 @@ impl<'d, T: Instance> Adc4<'d, T> { // single conversion mode, software trigger T::regs().cfgr1().modify(|w| { w.set_cont(false); + w.set_discen(false); w.set_exten(Adc4Exten::DISABLED); }); @@ -336,8 +344,18 @@ impl<'d, T: Instance> Adc4<'d, T> { }) } - /// Perform a single conversion. - fn convert(&mut self) -> u16 { + /// Read an ADC channel. + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16{ + channel.setup(); + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(false); + }); + + T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); + T::regs().chselrmod0().modify(|w| { + w.set_chsel(channel.channel() as usize, true); + }); + T::regs().isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); @@ -355,22 +373,92 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().dr().read().0 as u16 } - /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { - self.read_channel(channel) - } + /// Channels can not be repeated and must be in ascending order! + /// TODO: broken + pub async fn read( + &mut self, + rx_dma: &mut impl RxDma4, + sequence: impl ExactSizeIterator>, + readings: &mut [u16], + ) -> Result<(), Adc4Error> { + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + assert!( + sequence.len() == readings.len(), + "Sequence length must be equal to readings length" + ); - fn configure_channel(channel: &mut impl AdcChannel) { - channel.setup(); - T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); - T::regs().chselrmod0().modify(|w| { - w.set_chsel(channel.channel() as usize, true); + // Ensure no conversions are ongoing + Self::cancel_conversions(); + + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + reg.set_eos(true); + reg.set_eoc(true); }); + + T::regs().cfgr1().modify(|reg| { + reg.set_dmaen(true); + reg.set_dmacfg(Adc4Dmacfg::ONESHOT); + reg.set_chselrmod(false); + }); + + + let mut prev_channel: i16 = -1; + T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); + for channel in sequence { + let channel_num = channel.channel; + if channel_num as i16 <= prev_channel { + return Err(Adc4Error::InvalidSequence); + }; + prev_channel = channel_num as i16; + + T::regs().chselrmod0().modify(|w| { + w.set_chsel(channel.channel as usize, true); + }); + }; + + let request = rx_dma.request(); + let transfer = unsafe { + Transfer::new_read( + rx_dma, + request, + T::regs().dr().as_ptr() as *mut u16, + readings, + Default::default(), + ) + }; + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + // Wait for conversion sequence to finish. + transfer.await; + + blocking_delay_us(10); + + // Ensure conversions are finished. + Self::cancel_conversions(); + + // Reset configuration. + T::regs().cfgr1().modify(|reg| { + reg.set_dmaen(false); + }); + + if T::regs().isr().read().ovr() { + Err(Adc4Error::DMAError) + } else { + Ok(()) + } } - fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { - Self::configure_channel(channel); - let ret = self.convert(); - ret + fn cancel_conversions() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); + }); + while T::regs().cr().read().adstart() {} + } } } \ 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) { let mut p = embassy_stm32::init(config); - let mut adc = adc::Adc::new(p.ADC1); - let mut adc_pin1 = p.PA3; // A0 on nucleo u5a5 - let mut adc_pin2 = p.PA2; // A1 on nucleo u5a5 - adc.set_resolution(adc::Resolution::BITS14); - adc.set_averaging(adc::Averaging::Samples1024); - adc.set_sample_time(adc::SampleTime::CYCLES160_5); - let max = adc::resolution_to_max_count(adc::Resolution::BITS14); + // **** ADC1 init **** + let mut adc1 = adc::Adc::new(p.ADC1); + let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 + let mut adc1_pin2 = p.PA2; // A1 + adc1.set_resolution(adc::Resolution::BITS14); + adc1.set_averaging(adc::Averaging::Samples1024); + adc1.set_sample_time(adc::SampleTime::CYCLES160_5); + let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); + // **** ADC2 init **** + let mut adc2 = adc::Adc::new(p.ADC2); + let mut adc2_pin1 = p.PC3; // A2 + let mut adc2_pin2 = p.PB0; // A3 + adc2.set_resolution(adc::Resolution::BITS14); + adc2.set_averaging(adc::Averaging::Samples1024); + adc2.set_sample_time(adc::SampleTime::CYCLES160_5); + let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); + + // **** ADC4 init **** let mut adc4 = adc4::Adc4::new(p.ADC4); - let mut adc4_pin1 = p.PD11; - let mut adc4_pin2 = p.PC0; + let mut adc4_pin1 = p.PC1; // A4 + let mut adc4_pin2 = p.PC0; // A5 adc4.set_resolution(adc4::Resolution::BITS12); adc4.set_averaging(adc4::Averaging::Samples256); adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); - let raw: u16 = adc.blocking_read(&mut adc_pin1); - let volt: f32 = 3.3 * raw as f32 / max as f32; - info!("Read 1 pin 1 {}", volt); + // **** ADC1 blocking read **** + let raw: u16 = adc1.blocking_read(&mut adc1_pin1); + let volt: f32 = 3.3 * raw as f32 / max1 as f32; + info!("Read adc1 pin 1 {}", volt); - let raw: u16 = adc.blocking_read(&mut adc_pin2); - let volt: f32 = 3.3 * raw as f32 / max as f32; - info!("Read 1 pin 2 {}", volt); + let raw: u16 = adc1.blocking_read(&mut adc1_pin2); + let volt: f32 = 3.3 * raw as f32 / max1 as f32; + info!("Read adc1 pin 2 {}", volt); - let raw4: u16 = adc4.blocking_read(&mut adc4_pin1); - let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; - info!("Read 4 pin 1 {}", volt4); + // **** ADC2 blocking read **** + let raw: u16 = adc2.blocking_read(&mut adc2_pin1); + let volt: f32 = 3.3 * raw as f32 / max2 as f32; + info!("Read adc2 pin 1 {}", volt); - let raw4: u16 = adc4.blocking_read(&mut adc4_pin2); - let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; - info!("Read 4 pin 2 {}", volt4); + let raw: u16 = adc2.blocking_read(&mut adc2_pin2); + let volt: f32 = 3.3 * raw as f32 / max2 as f32; + info!("Read adc2 pin 2 {}", volt); - let mut degraded1 = adc_pin1.degrade_adc(); - let mut degraded2 = adc_pin2.degrade_adc(); + // **** ADC4 blocking read **** + let raw: u16 = adc4.blocking_read(&mut adc4_pin1); + let volt: f32 = 3.3 * raw as f32 / max4 as f32; + info!("Read adc4 pin 1 {}", volt); + + let raw: u16 = adc4.blocking_read(&mut adc4_pin2); + let volt: f32 = 3.3 * raw as f32 / max4 as f32; + info!("Read adc4 pin 2 {}", volt); + + // **** ADC1 async read **** + let mut degraded11 = adc1_pin1.degrade_adc(); + let mut degraded12 = adc1_pin2.degrade_adc(); let mut measurements = [0u16; 2]; - adc.read( + adc1.read( &mut p.GPDMA1_CH0, [ - (&mut degraded2, adc::SampleTime::CYCLES160_5), - (&mut degraded1, adc::SampleTime::CYCLES160_5), + (&mut degraded11, adc::SampleTime::CYCLES160_5), + (&mut degraded12, adc::SampleTime::CYCLES160_5), ] .into_iter(), &mut measurements, ).await; - let volt1: f32 = 3.3 * measurements[1] as f32 / max as f32; - let volt2: f32 = 3.3 * measurements[0] as f32 / max as f32; + let volt1: f32 = 3.3 * measurements[0] as f32 / max1 as f32; + let volt2: f32 = 3.3 * measurements[1] as f32 / max1 as f32; info!("Async read 1 pin 1 {}", volt1); info!("Async read 1 pin 2 {}", volt2); + // **** ADC2 does not support async read **** + + // **** ADC4 async read **** + let mut degraded41 = adc4_pin1.degrade_adc(); + let mut degraded42 = adc4_pin2.degrade_adc(); + let mut measurements = [0u16; 2]; + + // The channels must be in ascending order and can't repeat for ADC4 + adc4.read( + &mut p.GPDMA1_CH1, + [ + &mut degraded42, + &mut degraded41, + ] + .into_iter(), + &mut measurements, + ).await.unwrap(); + let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; + let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32; + info!("Async read 4 pin 1 {}", volt1); + info!("Async read 4 pin 2 {}", volt2); } \ No newline at end of file