Merge pull request #3128 from andresv/stm32-adc-dma-v3
STM32 ADC v3 and V4 DMA support
This commit is contained in:
		
						commit
						914d7c7919
					
				| @ -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)), | ||||
|  | ||||
| @ -1,9 +1,12 @@ | ||||
| use cfg_if::cfg_if; | ||||
| use embassy_hal_internal::into_ref; | ||||
| use pac::adc::vals::Dmacfg; | ||||
| 
 | ||||
| use super::blocking_delay_us; | ||||
| use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; | ||||
| use crate::{rcc, Peripheral}; | ||||
| use super::{ | ||||
|     blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, | ||||
| }; | ||||
| use crate::dma::Transfer; | ||||
| use crate::{pac, rcc, Peripheral}; | ||||
| 
 | ||||
| /// Default VREF voltage used for sample conversion to millivolts.
 | ||||
| pub const VREF_DEFAULT_MV: u32 = 3300; | ||||
| @ -12,7 +15,7 @@ pub const VREF_CALIB_MV: u32 = 3000; | ||||
| 
 | ||||
| pub struct VrefInt; | ||||
| impl<T: Instance> AdcChannel<T> for VrefInt {} | ||||
| impl<T: Instance> super::SealedAdcChannel<T> for VrefInt { | ||||
| impl<T: Instance> SealedAdcChannel<T> for VrefInt { | ||||
|     fn channel(&self) -> u8 { | ||||
|         cfg_if! { | ||||
|             if #[cfg(adc_g0)] { | ||||
| @ -31,7 +34,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for VrefInt { | ||||
| 
 | ||||
| pub struct Temperature; | ||||
| impl<T: Instance> AdcChannel<T> for Temperature {} | ||||
| impl<T: Instance> super::SealedAdcChannel<T> for Temperature { | ||||
| impl<T: Instance> SealedAdcChannel<T> for Temperature { | ||||
|     fn channel(&self) -> u8 { | ||||
|         cfg_if! { | ||||
|             if #[cfg(adc_g0)] { | ||||
| @ -50,7 +53,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature { | ||||
| 
 | ||||
| pub struct Vbat; | ||||
| impl<T: Instance> AdcChannel<T> for Vbat {} | ||||
| impl<T: Instance> super::SealedAdcChannel<T> for Vbat { | ||||
| impl<T: Instance> SealedAdcChannel<T> for Vbat { | ||||
|     fn channel(&self) -> u8 { | ||||
|         cfg_if! { | ||||
|             if #[cfg(adc_g0)] { | ||||
| @ -101,6 +104,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 +128,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 +207,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 +253,140 @@ 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<T>) -> 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<T>, | ||||
|         sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, | ||||
|         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" | ||||
|         ); | ||||
| 
 | ||||
|         // 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); | ||||
|             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); | ||||
|             reg.set_dmacfg(Dmacfg::ONESHOT); | ||||
|             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, | ||||
|                 readings, | ||||
|                 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<T>, 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 +395,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<T>) -> u16 { | ||||
|         self.enable(); | ||||
|         Self::configure_channel(channel, self.sample_time); | ||||
| 
 | ||||
|         // Select channel
 | ||||
|         #[cfg(not(any(adc_g0, adc_u0)))] | ||||
| @ -262,7 +416,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)); | ||||
| @ -295,6 +448,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 { | ||||
| @ -309,4 +463,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() {} | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,11 @@ | ||||
| #[allow(unused)] | ||||
| use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; | ||||
| use pac::adc::vals::{Adcaldif, Adstp, Boost, Difsel, Dmngt, Exten, Pcsel}; | ||||
| 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 +37,7 @@ const VBAT_CHANNEL: u8 = 17; | ||||
| /// Internal voltage reference channel.
 | ||||
| pub struct VrefInt; | ||||
| impl<T: Instance> AdcChannel<T> for VrefInt {} | ||||
| impl<T: Instance> super::SealedAdcChannel<T> for VrefInt { | ||||
| impl<T: Instance> SealedAdcChannel<T> for VrefInt { | ||||
|     fn channel(&self) -> u8 { | ||||
|         VREF_CHANNEL | ||||
|     } | ||||
| @ -43,7 +46,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for VrefInt { | ||||
| /// Internal temperature channel.
 | ||||
| pub struct Temperature; | ||||
| impl<T: Instance> AdcChannel<T> for Temperature {} | ||||
| impl<T: Instance> super::SealedAdcChannel<T> for Temperature { | ||||
| impl<T: Instance> SealedAdcChannel<T> for Temperature { | ||||
|     fn channel(&self) -> u8 { | ||||
|         TEMP_CHANNEL | ||||
|     } | ||||
| @ -52,7 +55,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature { | ||||
| /// Internal battery voltage channel.
 | ||||
| pub struct Vbat; | ||||
| impl<T: Instance> AdcChannel<T> for Vbat {} | ||||
| impl<T: Instance> super::SealedAdcChannel<T> for Vbat { | ||||
| impl<T: Instance> SealedAdcChannel<T> for Vbat { | ||||
|     fn channel(&self) -> u8 { | ||||
|         VBAT_CHANNEL | ||||
|     } | ||||
| @ -262,6 +265,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())); | ||||
| @ -311,25 +319,123 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
| 
 | ||||
|     /// Read an ADC channel.
 | ||||
|     pub fn read(&mut self, channel: &mut impl AdcChannel<T>) -> 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<T>, | ||||
|         sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, | ||||
|         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" | ||||
|         ); | ||||
| 
 | ||||
|         // 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, | ||||
|                 readings, | ||||
|                 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<T>, 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<T>) -> u16 { | ||||
|         Self::configure_channel(channel, self.sample_time); | ||||
| 
 | ||||
|         T::regs().sqr1().modify(|reg| { | ||||
|             reg.set_sq(0, channel.channel()); | ||||
|             reg.set_l(0); | ||||
|         }); | ||||
| 
 | ||||
| @ -344,4 +450,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() {} | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										44
									
								
								examples/stm32g0/src/bin/adc_dma.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								examples/stm32g0/src/bin/adc_dma.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										76
									
								
								examples/stm32h7/src/bin/adc_dma.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								examples/stm32h7/src/bin/adc_dma.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user