From 02b096915fbf138602e2ad8c6e1d85d531882daf Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Fri, 21 Jun 2024 23:37:58 +0300 Subject: [PATCH 1/6] add asynchrous sequence read support to adc v4 --- embassy-stm32/build.rs | 1 + embassy-stm32/src/adc/v4.rs | 139 ++++++++++++++++++++++++++++++++---- 2 files changed, 127 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 24e2226a2..df866b5ff 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1182,6 +1182,7 @@ fn main() { (("adc", "ADC1"), quote!(crate::adc::RxDma)), (("adc", "ADC2"), quote!(crate::adc::RxDma)), (("adc", "ADC3"), quote!(crate::adc::RxDma)), + (("adc", "ADC4"), quote!(crate::adc::RxDma)), (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), (("usart", "RX"), quote!(crate::usart::RxDma)), diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 50db646fe..f4b62d80e 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,8 +1,12 @@ #[allow(unused)] use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; +use pac::adc::vals::{Adstp, Dmngt}; use pac::adccommon::vals::Presc; -use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; +use super::{ + blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, +}; +use crate::dma::Transfer; use crate::time::Hertz; use crate::{pac, rcc, Peripheral}; @@ -34,7 +38,7 @@ const VBAT_CHANNEL: u8 = 17; /// Internal voltage reference channel. pub struct VrefInt; impl AdcChannel for VrefInt {} -impl super::SealedAdcChannel for VrefInt { +impl SealedAdcChannel for VrefInt { fn channel(&self) -> u8 { VREF_CHANNEL } @@ -43,7 +47,7 @@ impl super::SealedAdcChannel for VrefInt { /// Internal temperature channel. pub struct Temperature; impl AdcChannel for Temperature {} -impl super::SealedAdcChannel for Temperature { +impl SealedAdcChannel for Temperature { fn channel(&self) -> u8 { TEMP_CHANNEL } @@ -52,7 +56,7 @@ impl super::SealedAdcChannel for Temperature { /// Internal battery voltage channel. pub struct Vbat; impl AdcChannel for Vbat {} -impl super::SealedAdcChannel for Vbat { +impl SealedAdcChannel for Vbat { fn channel(&self) -> u8 { VBAT_CHANNEL } @@ -247,6 +251,11 @@ impl<'d, T: Instance> Adc<'d, T> { self.sample_time = sample_time; } + /// Get the ADC sample time. + pub fn sample_time(&self) -> SampleTime { + self.sample_time + } + /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); @@ -273,25 +282,120 @@ impl<'d, T: Instance> Adc<'d, T> { /// Read an ADC channel. pub fn read(&mut self, channel: &mut impl AdcChannel) -> u16 { - channel.setup(); - - self.read_channel(channel.channel()) + self.read_channel(channel) } - fn read_channel(&mut self, channel: u8) -> u16 { - // Configure channel - Self::set_channel_sample_time(channel, self.sample_time); + /// Asynchronously read from sequence of ADC channels. + pub async fn read_async( + &mut self, + rx_dma: &mut impl RxDma, + sequence: impl ExactSizeIterator, SampleTime)>, + data: &mut [u16], + ) { + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + + assert!( + sequence.len() <= 16, + "Asynchronous read sequence cannot be more than 16 in length" + ); + + // Ensure no conversions are ongoing + Self::cancel_conversions(); + + // Set sequence length + T::regs().sqr1().modify(|w| { + w.set_l(sequence.len() as u8 - 1); + }); + + // Configure channels and ranks + for (i, (channel, sample_time)) in sequence.enumerate() { + Self::configure_channel(channel, sample_time); + match i { + 0..=3 => { + T::regs().sqr1().modify(|w| { + w.set_sq(i, channel.channel()); + }); + } + 4..=8 => { + T::regs().sqr2().modify(|w| { + w.set_sq(i - 4, channel.channel()); + }); + } + 9..=13 => { + T::regs().sqr3().modify(|w| { + w.set_sq(i - 9, channel.channel()); + }); + } + 14..=15 => { + T::regs().sqr4().modify(|w| { + w.set_sq(i - 14, channel.channel()); + }); + } + _ => unreachable!(), + } + } + + // Set continuous mode with oneshot dma. + // Clear overrun flag before starting transfer. + + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + }); + T::regs().cfgr().modify(|reg| { + reg.set_cont(true); + reg.set_dmngt(Dmngt::DMA_ONESHOT); + }); + + let request = rx_dma.request(); + let transfer = unsafe { + Transfer::new_read( + rx_dma, + request, + T::regs().dr().as_ptr() as *mut u16, + data, + Default::default(), + ) + }; + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + // Wait for conversion sequence to finish. + transfer.await; + + // Ensure conversions are finished. + Self::cancel_conversions(); + + // Reset configuration. + T::regs().cfgr().modify(|reg| { + reg.set_cont(false); + reg.set_dmngt(Dmngt::from_bits(0)); + }); + } + + fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { + channel.setup(); + + let channel = channel.channel(); + + Self::set_channel_sample_time(channel, sample_time); #[cfg(stm32h7)] { T::regs().cfgr2().modify(|w| w.set_lshift(0)); T::regs() .pcsel() - .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); } + } - T::regs().sqr1().write(|reg| { - reg.set_sq(0, channel); + fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { + Self::configure_channel(channel, self.sample_time); + + T::regs().sqr1().modify(|reg| { + reg.set_sq(0, channel.channel()); reg.set_l(0); }); @@ -306,4 +410,13 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); } } + + fn cancel_conversions() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(Adstp::STOP); + }); + while T::regs().cr().read().adstart() {} + } + } } From 70061e74b2b4e4ca513bcefa5c3bebbb52538e5d Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Wed, 26 Jun 2024 19:06:20 +0300 Subject: [PATCH 2/6] add async dma read example --- examples/stm32h7/src/bin/adc_dma.rs | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 examples/stm32h7/src/bin/adc_dma.rs diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs new file mode 100644 index 000000000..6c0240453 --- /dev/null +++ b/examples/stm32h7/src/bin/adc_dma.rs @@ -0,0 +1,76 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".ram_d3"] +static mut DMA_BUF: [u16; 2] = [0; 2]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut read_buffer = unsafe { &mut DMA_BUF[..] }; + + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // SPI1 cksel defaults to pll1_q + divr: None, + }); + config.rcc.pll2 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV8), // 100mhz + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; + } + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + let mut adc = Adc::new(p.ADC3); + + let mut dma = p.DMA1_CH1; + let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); + let mut pc0 = p.PC0.degrade_adc(); + + loop { + adc.read_async( + &mut dma, + [ + (&mut vrefint_channel, SampleTime::CYCLES387_5), + (&mut pc0, SampleTime::CYCLES810_5), + ] + .into_iter(), + &mut read_buffer, + ) + .await; + + let vrefint = read_buffer[0]; + let measured = read_buffer[1]; + info!("vrefint: {}", vrefint); + info!("measured: {}", measured); + Timer::after_millis(500).await; + } +} From 5e2fd8623a01e8c026ba2057dd017b4d4bca3acb Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Wed, 26 Jun 2024 23:50:12 +0300 Subject: [PATCH 3/6] stm32 adc v3 read_async --- embassy-stm32/src/adc/v3.rs | 192 +++++++++++++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 16 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 398c57a92..559751555 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,8 +1,10 @@ use cfg_if::cfg_if; use embassy_hal_internal::into_ref; -use super::blocking_delay_us; -use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; +use super::{ + blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, +}; +use crate::dma::Transfer; use crate::{rcc, Peripheral}; /// Default VREF voltage used for sample conversion to millivolts. @@ -12,7 +14,7 @@ pub const VREF_CALIB_MV: u32 = 3000; pub struct VrefInt; impl AdcChannel for VrefInt {} -impl super::SealedAdcChannel for VrefInt { +impl SealedAdcChannel for VrefInt { fn channel(&self) -> u8 { cfg_if! { if #[cfg(adc_g0)] { @@ -31,7 +33,7 @@ impl super::SealedAdcChannel for VrefInt { pub struct Temperature; impl AdcChannel for Temperature {} -impl super::SealedAdcChannel for Temperature { +impl SealedAdcChannel for Temperature { fn channel(&self) -> u8 { cfg_if! { if #[cfg(adc_g0)] { @@ -50,7 +52,7 @@ impl super::SealedAdcChannel for Temperature { pub struct Vbat; impl AdcChannel for Vbat {} -impl super::SealedAdcChannel for Vbat { +impl SealedAdcChannel for Vbat { fn channel(&self) -> u8 { cfg_if! { if #[cfg(adc_g0)] { @@ -101,6 +103,7 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_advregen(true); }); + // If this is false then each ADC_CHSELR bit enables an input channel. #[cfg(any(adc_g0, adc_u0))] T::regs().cfgr1().modify(|reg| { reg.set_chselrmod(false); @@ -124,6 +127,28 @@ impl<'d, T: Instance> Adc<'d, T> { } } + // Enable ADC only when it is not already running. + fn enable(&mut self) { + // Make sure bits are off + while T::regs().cr().read().addis() { + // spin + } + + if !T::regs().cr().read().aden() { + // Enable ADC + T::regs().isr().modify(|reg| { + reg.set_adrdy(true); + }); + T::regs().cr().modify(|reg| { + reg.set_aden(true); + }); + + while !T::regs().isr().read().adrdy() { + // spin + } + } + } + pub fn enable_vrefint(&self) -> VrefInt { #[cfg(not(any(adc_g0, adc_u0)))] T::common_regs().ccr().modify(|reg| { @@ -181,10 +206,17 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat {} } + /// Set the ADC sample time. pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; } + /// Get the ADC sample time. + pub fn sample_time(&self) -> SampleTime { + self.sample_time + } + + /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { #[cfg(not(any(adc_g0, adc_u0)))] T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); @@ -220,24 +252,139 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().0 as u16 } + /// Read an ADC channel. pub fn read(&mut self, channel: &mut impl AdcChannel) -> u16 { - // Make sure bits are off - while T::regs().cr().read().addis() { - // spin + self.read_channel(channel) + } + + /// Asynchronously read from sequence of ADC channels. + pub async fn read_async( + &mut self, + rx_dma: &mut impl RxDma, + sequence: impl ExactSizeIterator, SampleTime)>, + data: &mut [u16], + ) { + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + + assert!( + sequence.len() <= 16, + "Asynchronous read sequence cannot be more than 16 in length" + ); + + // Ensure no conversions are ongoing and ADC is enabled. + Self::cancel_conversions(); + self.enable(); + + // Set sequence length + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().sqr1().modify(|w| { + w.set_l(sequence.len() as u8 - 1); + }); + + #[cfg(any(adc_g0, adc_u0))] + let mut channel_mask = 0; + + // Configure channels and ranks + for (_i, (channel, sample_time)) in sequence.enumerate() { + Self::configure_channel(channel, sample_time); + + // Each channel is sampled according to sequence + #[cfg(not(any(adc_g0, adc_u0)))] + match _i { + 0..=3 => { + T::regs().sqr1().modify(|w| { + w.set_sq(_i, channel.channel()); + }); + } + 4..=8 => { + T::regs().sqr2().modify(|w| { + w.set_sq(_i - 4, channel.channel()); + }); + } + 9..=13 => { + T::regs().sqr3().modify(|w| { + w.set_sq(_i - 9, channel.channel()); + }); + } + 14..=15 => { + T::regs().sqr4().modify(|w| { + w.set_sq(_i - 14, channel.channel()); + }); + } + _ => unreachable!(), + } + + #[cfg(any(adc_g0, adc_u0))] + { + channel_mask |= 1 << channel.channel(); + } } - // Enable ADC + // On G0 and U0 enabled channels are sampled from 0 to last channel. + // It is possible to add up to 8 sequences if CHSELRMOD = 1. + // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. + #[cfg(any(adc_g0, adc_u0))] + T::regs().chselr().modify(|reg| { + reg.set_chsel(channel_mask); + }); + + // Set continuous mode with oneshot dma. + // Clear overrun flag before starting transfer. T::regs().isr().modify(|reg| { - reg.set_adrdy(true); + reg.set_ovr(true); }); + + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| { + reg.set_discen(false); + reg.set_cont(true); + // Oneshot mode + reg.set_dmacfg(false); + reg.set_dmaen(true); + }); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| { + reg.set_discen(false); + reg.set_cont(true); + // Oneshot mode + reg.set_dmacfg(false); + reg.set_dmaen(true); + }); + + let request = rx_dma.request(); + let transfer = unsafe { + Transfer::new_read( + rx_dma, + request, + T::regs().dr().as_ptr() as *mut u16, + data, + Default::default(), + ) + }; + + // Start conversion T::regs().cr().modify(|reg| { - reg.set_aden(true); + reg.set_adstart(true); }); - while !T::regs().isr().read().adrdy() { - // spin - } + // Wait for conversion sequence to finish. + transfer.await; + // Ensure conversions are finished. + Self::cancel_conversions(); + + // Reset configuration. + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| { + reg.set_cont(false); + }); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| { + reg.set_cont(false); + }); + } + + fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { // RM0492, RM0481, etc. // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." #[cfg(adc_h5)] @@ -246,7 +393,12 @@ impl<'d, T: Instance> Adc<'d, T> { } // Configure channel - Self::set_channel_sample_time(channel.channel(), self.sample_time); + Self::set_channel_sample_time(channel.channel(), sample_time); + } + + fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { + self.enable(); + Self::configure_channel(channel, self.sample_time); // Select channel #[cfg(not(any(adc_g0, adc_u0)))] @@ -262,7 +414,6 @@ impl<'d, T: Instance> Adc<'d, T> { // STM32G4: Section 2.7.3 #[cfg(any(rcc_l4, rcc_g4))] let _ = self.convert(); - let val = self.convert(); T::regs().cr().modify(|reg| reg.set_addis(true)); @@ -294,4 +445,13 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + + 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() {} + } + } } From c120efad5bbd7f95615e913100874d27c34cb389 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Tue, 2 Jul 2024 14:23:44 +0300 Subject: [PATCH 4/6] stm32 adc read_async: add asserts for buf len --- embassy-stm32/src/adc/v3.rs | 10 +++++++--- embassy-stm32/src/adc/v4.rs | 9 ++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 559751555..afdfc4e4c 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -262,10 +262,13 @@ impl<'d, T: Instance> Adc<'d, T> { &mut self, rx_dma: &mut impl RxDma, sequence: impl ExactSizeIterator, SampleTime)>, - data: &mut [u16], + readings: &mut [u16], ) { assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - + assert!( + sequence.len() == readings.len(), + "Sequence length must be equal to readings length" + ); assert!( sequence.len() <= 16, "Asynchronous read sequence cannot be more than 16 in length" @@ -357,7 +360,7 @@ impl<'d, T: Instance> Adc<'d, T> { rx_dma, request, T::regs().dr().as_ptr() as *mut u16, - data, + readings, Default::default(), ) }; @@ -431,6 +434,7 @@ impl<'d, T: Instance> Adc<'d, T> { fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { cfg_if! { if #[cfg(any(adc_g0, adc_u0))] { + // On G0 and U6 all channels use the same sampling time. T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); } else if #[cfg(adc_h5)] { match _ch { diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index f4b62d80e..4261b9b14 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -290,10 +290,13 @@ impl<'d, T: Instance> Adc<'d, T> { &mut self, rx_dma: &mut impl RxDma, sequence: impl ExactSizeIterator, SampleTime)>, - data: &mut [u16], + readings: &mut [u16], ) { assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); - + assert!( + sequence.len() == readings.len(), + "Sequence length must be equal to readings length" + ); assert!( sequence.len() <= 16, "Asynchronous read sequence cannot be more than 16 in length" @@ -352,7 +355,7 @@ impl<'d, T: Instance> Adc<'d, T> { rx_dma, request, T::regs().dr().as_ptr() as *mut u16, - data, + readings, Default::default(), ) }; From a4e62314af50d58eb42689e095ffc4a117aad35d Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Tue, 2 Jul 2024 17:15:22 +0300 Subject: [PATCH 5/6] stm32: adc v3: fix for newest pac --- embassy-stm32/src/adc/v3.rs | 9 ++++----- embassy-stm32/src/adc/v4.rs | 3 +-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index afdfc4e4c..6703268ee 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,11 +1,12 @@ use cfg_if::cfg_if; use embassy_hal_internal::into_ref; +use pac::adc::vals::Dmacfg; use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; use crate::dma::Transfer; -use crate::{rcc, Peripheral}; +use crate::{pac, rcc, Peripheral}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -341,16 +342,14 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr().modify(|reg| { reg.set_discen(false); reg.set_cont(true); - // Oneshot mode - reg.set_dmacfg(false); + reg.set_dmacfg(Dmacfg::ONESHOT); reg.set_dmaen(true); }); #[cfg(any(adc_g0, adc_u0))] T::regs().cfgr1().modify(|reg| { reg.set_discen(false); reg.set_cont(true); - // Oneshot mode - reg.set_dmacfg(false); + reg.set_dmacfg(Dmacfg::ONESHOT); reg.set_dmaen(true); }); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 4261b9b14..344bf89af 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,6 +1,5 @@ #[allow(unused)] -use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; -use pac::adc::vals::{Adstp, Dmngt}; +use pac::adc::vals::{Adcaldif, Adstp, Boost, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; use super::{ From 09cfa28a218a65cf756ffde4403806aa7e2613ed Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Wed, 3 Jul 2024 10:59:20 +0300 Subject: [PATCH 6/6] stm32g0: add adc_dma example --- examples/stm32g0/src/bin/adc_dma.rs | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 examples/stm32g0/src/bin/adc_dma.rs diff --git a/examples/stm32g0/src/bin/adc_dma.rs b/examples/stm32g0/src/bin/adc_dma.rs new file mode 100644 index 000000000..42d1e729b --- /dev/null +++ b/examples/stm32g0/src/bin/adc_dma.rs @@ -0,0 +1,44 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +static mut DMA_BUF: [u16; 2] = [0; 2]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut read_buffer = unsafe { &mut DMA_BUF[..] }; + + let p = embassy_stm32::init(Default::default()); + + info!("Hello World!"); + + let mut adc = Adc::new(p.ADC1); + + let mut dma = p.DMA1_CH1; + let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); + let mut pa0 = p.PA0.degrade_adc(); + + loop { + adc.read_async( + &mut dma, + [ + (&mut vrefint_channel, SampleTime::CYCLES160_5), + (&mut pa0, SampleTime::CYCLES160_5), + ] + .into_iter(), + &mut read_buffer, + ) + .await; + + let vrefint = read_buffer[0]; + let measured = read_buffer[1]; + info!("vrefint: {}", vrefint); + info!("measured: {}", measured); + Timer::after_millis(500).await; + } +}