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