From 4f66b2f2090e2fcfd7d92f9ebd07cc9048eb70d7 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 6 Dec 2025 12:17:00 -0600 Subject: adc: type-erase regs instance --- embassy-stm32/src/adc/adc4.rs | 207 ++++++++++++++----------------- embassy-stm32/src/adc/c0.rs | 64 +++++----- embassy-stm32/src/adc/g4.rs | 100 ++++++++------- embassy-stm32/src/adc/injected.rs | 12 +- embassy-stm32/src/adc/mod.rs | 223 ++++++++++++++++++++-------------- embassy-stm32/src/adc/ringbuffered.rs | 48 ++++---- embassy-stm32/src/adc/v2.rs | 58 ++++----- embassy-stm32/src/adc/v3.rs | 91 +++++++------- embassy-stm32/src/adc/v4.rs | 76 ++++++------ examples/stm32h5/src/bin/adc_dma.rs | 2 +- 10 files changed, 442 insertions(+), 439 deletions(-) diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 453513309..43509873f 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -5,7 +5,7 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; use super::blocking_delay_us; -use crate::adc::ConversionMode; +use crate::adc::{AdcRegs, ConversionMode, Instance}; #[cfg(stm32u5)] pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; #[cfg(stm32wba)] @@ -90,135 +90,112 @@ fn from_ker_ck(frequency: Hertz) -> Presc { } } -pub trait SealedInstance { - #[allow(unused)] - fn regs() -> crate::pac::adc::Adc4; -} +impl AdcRegs for crate::pac::adc::Adc4 { + fn data(&self) -> *mut u16 { + crate::pac::adc::Adc4::dr(*self).as_ptr() as *mut u16 + } -pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { - type Interrupt: crate::interrupt::typelevel::Interrupt; -} + fn enable(&self) { + if !self.cr().read().aden() || !self.isr().read().adrdy() { + self.isr().write(|w| w.set_adrdy(true)); + self.cr().modify(|w| w.set_aden(true)); + while !self.isr().read().adrdy() {} + } + } -foreach_adc!( - (ADC4, $common_inst:ident, $clock:ident) => { - use crate::peripherals::ADC4; + fn start(&self) { + // Start conversion + self.cr().modify(|reg| { + reg.set_adstart(true); + }); + } - impl super::BasicAnyInstance for ADC4 { - type SampleTime = SampleTime; + fn stop(&self) { + let cr = self.cr().read(); + if cr.adstart() { + self.cr().modify(|w| w.set_adstp(true)); + while self.cr().read().adstart() {} } - impl super::SealedAnyInstance for ADC4 { - fn dr() -> *mut u16 { - ADC4::regs().dr().as_ptr() as *mut u16 - } + if cr.aden() || cr.adstart() { + self.cr().modify(|w| w.set_addis(true)); + while self.cr().read().aden() {} + } - fn enable() { - if !ADC4::regs().cr().read().aden() || !ADC4::regs().isr().read().adrdy() { - ADC4::regs().isr().write(|w| w.set_adrdy(true)); - ADC4::regs().cr().modify(|w| w.set_aden(true)); - while !ADC4::regs().isr().read().adrdy() {} - } - } + // Reset configuration. + self.cfgr1().modify(|reg| { + reg.set_dmaen(false); + }); + } - fn start() { - // Start conversion - ADC4::regs().cr().modify(|reg| { - reg.set_adstart(true); + fn configure_dma(&self, conversion_mode: ConversionMode) { + match conversion_mode { + ConversionMode::Singular => { + self.isr().modify(|reg| { + reg.set_ovr(true); + reg.set_eos(true); + reg.set_eoc(true); }); - } - fn stop() { - let cr = ADC4::regs().cr().read(); - if cr.adstart() { - ADC4::regs().cr().modify(|w| w.set_adstp(true)); - while ADC4::regs().cr().read().adstart() {} - } - - if cr.aden() || cr.adstart() { - ADC4::regs().cr().modify(|w| w.set_addis(true)); - while ADC4::regs().cr().read().aden() {} - } - - // Reset configuration. - ADC4::regs().cfgr1().modify(|reg| { - reg.set_dmaen(false); + self.cfgr1().modify(|reg| { + reg.set_dmaen(true); + reg.set_dmacfg(Dmacfg::ONE_SHOT); + #[cfg(stm32u5)] + reg.set_chselrmod(false); + #[cfg(stm32wba)] + reg.set_chselrmod(Chselrmod::ENABLE_INPUT) }); } + #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] + _ => unreachable!(), + } + } - fn configure_dma(conversion_mode: ConversionMode) { - match conversion_mode { - ConversionMode::Singular => { - ADC4::regs().isr().modify(|reg| { - reg.set_ovr(true); - reg.set_eos(true); - reg.set_eoc(true); - }); - - ADC4::regs().cfgr1().modify(|reg| { - reg.set_dmaen(true); - reg.set_dmacfg(Dmacfg::ONE_SHOT); - #[cfg(stm32u5)] - reg.set_chselrmod(false); - #[cfg(stm32wba)] - reg.set_chselrmod(Chselrmod::ENABLE_INPUT) - }); - } - #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] - _ => unreachable!(), - } - } - - fn configure_sequence(sequence: impl ExactSizeIterator) { - let mut prev_channel: i16 = -1; - #[cfg(stm32wba)] - ADC4::regs().chselr().write_value(Chselr(0_u32)); - #[cfg(stm32u5)] - ADC4::regs().chselrmod0().write_value(Chselr(0_u32)); - for (_i, ((channel, _), sample_time)) in sequence.enumerate() { - ADC4::regs().smpr().modify(|w| { - w.set_smp(_i, sample_time); - }); - - let channel_num = channel; - if channel_num as i16 <= prev_channel { - return; - }; - prev_channel = channel_num as i16; - - #[cfg(stm32wba)] - ADC4::regs().chselr().modify(|w| { - w.set_chsel0(channel as usize, true); - }); - #[cfg(stm32u5)] - ADC4::regs().chselrmod0().modify(|w| { - w.set_chsel(channel as usize, true); - }); - } - } + fn configure_sequence(&self, sequence: impl ExactSizeIterator) { + let mut prev_channel: i16 = -1; + #[cfg(stm32wba)] + self.chselr().write_value(Chselr(0_u32)); + #[cfg(stm32u5)] + self.chselrmod0().write_value(Chselr(0_u32)); + for (_i, ((channel, _), sample_time)) in sequence.enumerate() { + self.smpr().modify(|w| { + w.set_smp(_i, sample_time); + }); + + let channel_num = channel; + if channel_num as i16 <= prev_channel { + return; + }; + prev_channel = channel_num as i16; - fn convert() -> u16 { - // Reset interrupts - ADC4::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); + #[cfg(stm32wba)] + self.chselr().modify(|w| { + w.set_chsel0(channel as usize, true); + }); + #[cfg(stm32u5)] + self.chselrmod0().modify(|w| { + w.set_chsel(channel as usize, true); + }); + } + } - // Start conversion - ADC4::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); + fn convert(&self) { + // Reset interrupts + self.isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); + }); - while !ADC4::regs().isr().read().eos() { - // spin - } + // Start conversion + self.cr().modify(|reg| { + reg.set_adstart(true); + }); - ADC4::regs().dr().read().0 as u16 - } + while !self.isr().read().eos() { + // spin } - - impl super::AnyInstance for ADC4 {} - }; -); + } +} pub struct Adc4<'d, T: Instance> { #[allow(unused)] @@ -231,7 +208,7 @@ pub enum Adc4Error { DMAError, } -impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { +impl<'d, T: Instance> super::Adc<'d, T> { /// Create a new ADC driver. pub fn new_adc4(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); @@ -267,7 +244,7 @@ impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { blocking_delay_us(1); - T::enable(); + T::regs().enable(); // single conversion mode, software trigger T::regs().cfgr1().modify(|w| { diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 3e109e429..2f0f326af 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc; use stm32_metapac::adc::vals::{SampleTime, Scandir}; use super::{Adc, Instance, Resolution, blocking_delay_us}; -use crate::adc::{AnyInstance, ConversionMode}; +use crate::adc::{AdcRegs, ConversionMode}; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -43,52 +43,52 @@ fn from_ker_ck(frequency: Hertz) -> Presc { } } -impl super::SealedAnyInstance for T { - fn dr() -> *mut u16 { - T::regs().dr().as_ptr() as *mut u16 +impl AdcRegs for crate::pac::adc::Adc { + fn data(&self) -> *mut u16 { + crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 } - fn enable() { - T::regs().isr().modify(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); + fn enable(&self) { + self.isr().modify(|w| w.set_adrdy(true)); + self.cr().modify(|w| w.set_aden(true)); // ADRDY is "ADC ready". Wait until it will be True. - while !T::regs().isr().read().adrdy() {} + while !self.isr().read().adrdy() {} } - fn start() { + fn start(&self) { // Start conversion - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_adstart(true); }); } - fn stop() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { + fn stop(&self) { + if self.cr().read().adstart() && !self.cr().read().addis() { + self.cr().modify(|reg| { reg.set_adstp(Adstp::STOP); }); - while T::regs().cr().read().adstart() {} + while self.cr().read().adstart() {} } // Reset configuration. - T::regs().cfgr1().modify(|reg| { + self.cfgr1().modify(|reg| { reg.set_cont(false); reg.set_dmacfg(Dmacfg::from_bits(0)); reg.set_dmaen(false); }); } - fn configure_dma(conversion_mode: super::ConversionMode) { + fn configure_dma(&self, conversion_mode: super::ConversionMode) { match conversion_mode { ConversionMode::Singular => { // Enable overrun control, so no new DMA requests will be generated until // previous DR values is read. - T::regs().isr().modify(|reg| { + self.isr().modify(|reg| { reg.set_ovr(true); }); // Set continuous mode with oneshot dma. - T::regs().cfgr1().modify(|reg| { + self.cfgr1().modify(|reg| { reg.set_discen(false); reg.set_cont(true); reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); @@ -99,7 +99,7 @@ impl super::SealedAnyInstance for T { } } - fn configure_sequence(sequence: impl ExactSizeIterator) { + fn configure_sequence(&self, sequence: impl ExactSizeIterator) { let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE; let mut is_ordered_up = true; let mut is_ordered_down = true; @@ -109,7 +109,7 @@ impl super::SealedAnyInstance for T { let mut last_channel: u8 = 0; let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5; - T::regs().chselr_sq().write(|w| { + self.chselr_sq().write(|w| { for (i, ((channel, _), _sample_time)) in sequence.enumerate() { assert!( sample_time == _sample_time || i == 0, @@ -146,42 +146,40 @@ impl super::SealedAnyInstance for T { ); // Set required channels for multi-convert. - unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } + unsafe { (self.chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } } - T::regs().smpr().modify(|w| { + self.smpr().modify(|w| { w.smpsel(0); w.set_smp1(sample_time); }); - T::regs().cfgr1().modify(|reg| { + self.cfgr1().modify(|reg| { reg.set_chselrmod(!needs_hw); reg.set_align(Align::RIGHT); reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK }); }); // Trigger and wait for the channel selection procedure to complete. - T::regs().isr().modify(|w| w.set_ccrdy(false)); - while !T::regs().isr().read().ccrdy() {} + self.isr().modify(|w| w.set_ccrdy(false)); + while !self.isr().read().ccrdy() {} } - fn convert() -> u16 { + fn convert(&self) { // Set single conversion mode. - T::regs().cfgr1().modify(|w| w.set_cont(false)); + self.cfgr1().modify(|w| w.set_cont(false)); // Start conversion - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_adstart(true); }); // Waiting for End Of Conversion (EOC). - while !T::regs().isr().read().eoc() {} - - T::regs().dr().read().data() as u16 + while !self.isr().read().eoc() {} } } -impl<'d, T: AnyInstance> Adc<'d, T> { +impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { rcc::enable_and_reset::(); @@ -225,7 +223,7 @@ impl<'d, T: AnyInstance> Adc<'d, T> { T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); - T::enable(); + T::regs().enable(); // single conversion mode, software trigger T::regs().cfgr1().modify(|w| { diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index d4e526061..53c1ecd31 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -12,7 +12,7 @@ use super::{ Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, blocking_delay_us, }; -use crate::adc::{AnyInstance, SealedAdcChannel}; +use crate::adc::{AdcRegs, BasicAdcRegs, SealedAdcChannel}; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -68,79 +68,77 @@ pub struct ConversionTrigger { pub edge: Exten, } -impl super::SealedAnyInstance for T { - fn dr() -> *mut u16 { - T::regs().dr().as_ptr() as *mut u16 +impl super::AdcRegs for crate::pac::adc::Adc { + fn data(&self) -> *mut u16 { + crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 } - fn enable() { + fn enable(&self) { // Make sure bits are off - while T::regs().cr().read().addis() { + while self.cr().read().addis() { // spin } - if !T::regs().cr().read().aden() { + if !self.cr().read().aden() { // Enable ADC - T::regs().isr().modify(|reg| { + self.isr().modify(|reg| { reg.set_adrdy(true); }); - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_aden(true); }); - while !T::regs().isr().read().adrdy() { + while !self.isr().read().adrdy() { // spin } } } - fn start() { - T::regs().cr().modify(|reg| { + fn start(&self) { + self.cr().modify(|reg| { reg.set_adstart(true); }); } - fn stop() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { + fn stop(&self) { + if self.cr().read().adstart() && !self.cr().read().addis() { + self.cr().modify(|reg| { reg.set_adstp(Adstp::STOP); }); // The software must poll ADSTART until the bit is reset before assuming the // ADC is completely stopped - while T::regs().cr().read().adstart() {} + while self.cr().read().adstart() {} } // Disable dma control and continuous conversion, if enabled - T::regs().cfgr().modify(|reg| { + self.cfgr().modify(|reg| { reg.set_cont(false); reg.set_dmaen(Dmaen::DISABLE); }); } - fn convert() -> u16 { - T::regs().isr().modify(|reg| { + fn convert(&self) { + self.isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); }); // Start conversion - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_adstart(true); }); - while !T::regs().isr().read().eos() { + while !self.isr().read().eos() { // spin } - - T::regs().dr().read().0 as u16 } - fn configure_dma(conversion_mode: ConversionMode) { - T::regs().isr().modify(|reg| { + fn configure_dma(&self, conversion_mode: ConversionMode) { + self.isr().modify(|reg| { reg.set_ovr(true); }); - T::regs().cfgr().modify(|reg| { + self.cfgr().modify(|reg| { reg.set_discen(false); // Convert all channels for each trigger reg.set_dmacfg(match conversion_mode { ConversionMode::Singular => Dmacfg::ONE_SHOT, @@ -152,43 +150,43 @@ impl super::SealedAnyInstance for T { if let ConversionMode::Repeated(mode) = conversion_mode { match mode { RegularConversionMode::Continuous => { - T::regs().cfgr().modify(|reg| { + self.cfgr().modify(|reg| { reg.set_cont(true); }); } RegularConversionMode::Triggered(trigger) => { - T::regs().cfgr().modify(|r| { + self.cfgr().modify(|r| { r.set_cont(false); // New trigger is neede for each sample to be read }); - T::regs().cfgr().modify(|r| { + self.cfgr().modify(|r| { r.set_extsel(trigger.channel); r.set_exten(trigger.edge); }); // Regular conversions uses DMA so no need to generate interrupt - T::regs().ier().modify(|r| r.set_eosie(false)); + self.ier().modify(|r| r.set_eosie(false)); } } } } - fn configure_sequence(sequence: impl ExactSizeIterator) { - T::regs().cr().modify(|w| w.set_aden(false)); + fn configure_sequence(&self, sequence: impl ExactSizeIterator) { + self.cr().modify(|w| w.set_aden(false)); // Set sequence length - T::regs().sqr1().modify(|w| { + self.sqr1().modify(|w| { w.set_l(sequence.len() as u8 - 1); }); #[cfg(stm32g4)] let mut difsel = DifselReg::default(); - let mut smpr = T::regs().smpr().read(); - let mut smpr2 = T::regs().smpr2().read(); - let mut sqr1 = T::regs().sqr1().read(); - let mut sqr2 = T::regs().sqr2().read(); - let mut sqr3 = T::regs().sqr3().read(); - let mut sqr4 = T::regs().sqr4().read(); + let mut smpr = self.smpr().read(); + let mut smpr2 = self.smpr2().read(); + let mut sqr1 = self.sqr1().read(); + let mut sqr2 = self.sqr2().read(); + let mut sqr3 = self.sqr3().read(); + let mut sqr4 = self.sqr4().read(); // Configure channels and ranks for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { @@ -230,18 +228,18 @@ impl super::SealedAnyInstance for T { } } - T::regs().smpr().write_value(smpr); - T::regs().smpr2().write_value(smpr2); - T::regs().sqr1().write_value(sqr1); - T::regs().sqr2().write_value(sqr2); - T::regs().sqr3().write_value(sqr3); - T::regs().sqr4().write_value(sqr4); + self.smpr().write_value(smpr); + self.smpr2().write_value(smpr2); + self.sqr1().write_value(sqr1); + self.sqr2().write_value(sqr2); + self.sqr3().write_value(sqr3); + self.sqr4().write_value(sqr4); #[cfg(stm32g4)] - T::regs().difsel().write_value(difsel); + self.difsel().write_value(difsel); } } -impl<'d, T: Instance + AnyInstance> Adc<'d, T> { +impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { rcc::enable_and_reset::(); @@ -293,7 +291,7 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { blocking_delay_us(20); - T::enable(); + T::regs().enable(); // single conversion mode, software trigger T::regs().cfgr().modify(|w| { @@ -420,7 +418,7 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { NR_INJECTED_RANKS ); - T::enable(); + T::regs().enable(); T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); @@ -491,7 +489,7 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { self, dma: Peri<'a, impl RxDma>, dma_buf: &'a mut [u16], - regular_sequence: impl ExactSizeIterator, T::SampleTime)>, + regular_sequence: impl ExactSizeIterator, ::SampleTime)>, regular_conversion_mode: RegularConversionMode, injected_sequence: [(AnyAdcChannel<'b, T>, SampleTime); N], injected_trigger: ConversionTrigger, @@ -531,7 +529,7 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { } } -impl<'a, T: Instance, const N: usize> InjectedAdc<'a, T, N> { +impl<'a, T: Instance, const N: usize> InjectedAdc<'a, T, N> { /// Read sampled data from all injected ADC injected ranks /// Clear the JEOS flag to allow a new injected sequence pub(super) fn read_injected_data() -> [u16; N] { diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index 1af055644..029722b84 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs @@ -4,18 +4,18 @@ use core::sync::atomic::{Ordering, compiler_fence}; #[allow(unused_imports)] use embassy_hal_internal::Peri; -use super::{AnyAdcChannel, SampleTime}; +use super::{AdcRegs, AnyAdcChannel, SampleTime}; +use crate::adc::Adc; #[allow(unused_imports)] use crate::adc::Instance; -use crate::adc::{Adc, AnyInstance}; /// Injected ADC sequence with owned channels. -pub struct InjectedAdc<'a, T: Instance, const N: usize> { +pub struct InjectedAdc<'a, T: Instance, const N: usize> { _channels: [(AnyAdcChannel<'a, T>, SampleTime); N], _phantom: PhantomData, } -impl<'a, T: Instance, const N: usize> InjectedAdc<'a, T, N> { +impl<'a, T: Instance, const N: usize> InjectedAdc<'a, T, N> { pub(crate) fn new(channels: [(AnyAdcChannel<'a, T>, SampleTime); N]) -> Self { Self { _channels: channels, @@ -36,9 +36,9 @@ impl<'a, T: Instance, const N: usize> InjectedAdc<'a, T, N> { } } -impl<'a, T: Instance + AnyInstance, const N: usize> Drop for InjectedAdc<'a, T, N> { +impl<'a, T: Instance, const N: usize> Drop for InjectedAdc<'a, T, N> { fn drop(&mut self) { - T::stop(); + T::regs().stop(); compiler_fence(Ordering::SeqCst); } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 9040eefe5..a6af1175a 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -32,6 +32,11 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] pub use ringbuffered::RingBufferedAdc; +#[cfg(adc_u5)] +use crate::pac::adc::vals::Adc4SampleTime; +#[cfg(adc_wba)] +use crate::pac::adc::vals::SampleTime as Adc4SampleTime; + #[cfg(any(adc_u5, adc_wba))] #[path = "adc4.rs"] pub mod adc4; @@ -44,10 +49,10 @@ pub use crate::pac::adc::vals::Res as Resolution; pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; -dma_trait!(RxDma, AnyInstance); +dma_trait!(RxDma, Instance); /// Analog to Digital driver. -pub struct Adc<'d, T: AnyInstance> { +pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::Peri<'d, T>, } @@ -66,10 +71,53 @@ impl State { } } -trait SealedInstance { - #[cfg(not(adc_wba))] - #[allow(unused)] +#[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] +trait_set::trait_set! { + pub trait DefaultInstance = Instance; +} + +#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_g4, adc_c0))] +trait_set::trait_set! { + pub trait DefaultInstance = Instance; +} + +#[cfg(adc_wba)] +trait_set::trait_set! { + pub trait DefaultInstance = Instance; +} + +pub trait BasicAdcRegs { + type SampleTime; +} + +#[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 +))] +trait AdcRegs: BasicAdcRegs { + fn enable(&self); + fn start(&self); + fn stop(&self); + fn convert(&self); + fn configure_dma(&self, conversion_mode: ConversionMode); + fn configure_sequence(&self, sequence: impl ExactSizeIterator); + fn data(&self) -> *mut u16; +} + +#[allow(private_bounds)] +pub trait BasicInstance { + #[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 + ))] + type Regs: AdcRegs; +} + +trait SealedInstance: BasicInstance { + #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] fn regs() -> crate::pac::adc::Adc; + #[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 + ))] + fn regs() -> Self::Regs; #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] #[allow(unused)] fn common_regs() -> crate::pac::adccommon::AdcCommon; @@ -90,56 +138,6 @@ pub(crate) trait SealedAdcChannel { } } -// Temporary patch for ADCs that have not implemented the standard iface yet -#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))] -trait_set::trait_set! { - pub trait AnyInstance = Instance; -} - -#[cfg(any( - adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 -))] -pub trait BasicAnyInstance { - type SampleTime; -} - -#[cfg(any( - adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 -))] -pub(self) trait SealedAnyInstance: BasicAnyInstance { - fn enable(); - fn start(); - fn stop(); - fn convert() -> u16; - fn configure_dma(conversion_mode: ConversionMode); - fn configure_sequence(sequence: impl ExactSizeIterator); - #[allow(dead_code)] - fn dr() -> *mut u16; -} - -// On chips without ADC4, AnyInstance is an Instance -#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))] -#[allow(private_bounds)] -pub trait AnyInstance: SealedAnyInstance + Instance {} - -// On chips with ADC4, AnyInstance is an Instance or adc4::Instance -#[cfg(any(adc_v4, adc_u5, adc_wba))] -#[allow(private_bounds)] -pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} - -// Implement AnyInstance automatically for SealedAnyInstance -#[cfg(any( - adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 -))] -impl BasicAnyInstance for T { - type SampleTime = SampleTime; -} - -#[cfg(any( - adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 -))] -impl AnyInstance for T {} - #[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] /// Number of samples used for averaging. #[derive(Copy, Clone, Debug)] @@ -184,28 +182,33 @@ pub enum RegularConversionMode { Triggered(ConversionTrigger), } -impl<'d, T: AnyInstance> Adc<'d, T> { +impl<'d, T: Instance> Adc<'d, T> { #[cfg(any( adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v3, adc_v4, adc_wba, adc_c0 ))] /// Read an ADC pin. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: T::SampleTime) -> u16 { + pub fn blocking_read( + &mut self, + channel: &mut impl AdcChannel, + sample_time: ::SampleTime, + ) -> u16 { #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] channel.setup(); // Ensure no conversions are ongoing - T::stop(); + T::regs().stop(); #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))] - T::enable(); - T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); + T::regs().enable(); + T::regs().configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); // On chips with differential channels, enable after configure_sequence to allow setting differential channels // // TODO: If hardware allows, enable after configure_sequence on all chips #[cfg(any(adc_g4, adc_h5))] - T::enable(); + T::regs().enable(); + T::regs().convert(); - T::convert() + unsafe { *T::regs().data() } } #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] @@ -245,7 +248,7 @@ impl<'d, T: AnyInstance> Adc<'d, T> { pub async fn read<'a, 'b: 'a>( &mut self, rx_dma: embassy_hal_internal::Peri<'_, impl RxDma>, - sequence: impl ExactSizeIterator, T::SampleTime)>, + sequence: impl ExactSizeIterator, ::SampleTime)>, readings: &mut [u16], ) { assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); @@ -259,11 +262,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { ); // Ensure no conversions are ongoing - T::stop(); + T::regs().stop(); #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] - T::enable(); + T::regs().enable(); - T::configure_sequence( + T::regs().configure_sequence( sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), ); @@ -271,20 +274,20 @@ impl<'d, T: AnyInstance> Adc<'d, T> { // // TODO: If hardware allows, enable after configure_sequence on all chips #[cfg(any(adc_g4, adc_h5))] - T::enable(); - T::configure_dma(ConversionMode::Singular); + T::regs().enable(); + T::regs().configure_dma(ConversionMode::Singular); let request = rx_dma.request(); let transfer = - unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::dr(), readings, Default::default()) }; + unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::regs().data(), readings, Default::default()) }; - T::start(); + T::regs().start(); // Wait for conversion sequence to finish. transfer.await; // Ensure conversions are finished. - T::stop(); + T::regs().stop(); } #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] @@ -318,7 +321,7 @@ impl<'d, T: AnyInstance> Adc<'d, T> { self, dma: embassy_hal_internal::Peri<'a, impl RxDma>, dma_buf: &'a mut [u16], - sequence: impl ExactSizeIterator, T::SampleTime)>, + sequence: impl ExactSizeIterator, ::SampleTime)>, mode: RegularConversionMode, ) -> RingBufferedAdc<'a, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); @@ -328,11 +331,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { "Asynchronous read sequence cannot be more than 16 in length" ); // Ensure no conversions are ongoing - T::stop(); + T::regs().stop(); #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] - T::enable(); + T::regs().enable(); - T::configure_sequence( + T::regs().configure_sequence( sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), ); @@ -340,8 +343,8 @@ impl<'d, T: AnyInstance> Adc<'d, T> { // // TODO: If hardware allows, enable after configure_sequence on all chips #[cfg(any(adc_g4, adc_h5))] - T::enable(); - T::configure_dma(ConversionMode::Repeated(mode)); + T::regs().enable(); + T::regs().configure_dma(ConversionMode::Repeated(mode)); core::mem::forget(self); @@ -442,8 +445,8 @@ pub struct AnyAdcChannel<'a, T> { is_differential: bool, _phantom: PhantomData<&'a mut T>, } -impl AdcChannel for AnyAdcChannel<'_, T> {} -impl SealedAdcChannel for AnyAdcChannel<'_, T> { +impl AdcChannel for AnyAdcChannel<'_, T> {} +impl SealedAdcChannel for AnyAdcChannel<'_, T> { fn channel(&self) -> u8 { self.channel } @@ -459,16 +462,35 @@ impl AnyAdcChannel<'_, T> { self.channel } } + +#[cfg(not(adc_wba))] +impl BasicAdcRegs for crate::pac::adc::Adc { + type SampleTime = SampleTime; +} + +#[cfg(any(adc_wba, adc_u5))] +impl BasicAdcRegs for crate::pac::adc::Adc4 { + type SampleTime = Adc4SampleTime; +} + #[cfg(adc_wba)] foreach_adc!( (ADC4, $common_inst:ident, $clock:ident) => { - impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { - fn regs() -> crate::pac::adc::Adc4 { + impl crate::adc::BasicInstance for peripherals::ADC4 { + type Regs = crate::pac::adc::Adc4; + } + + impl crate::adc::SealedInstance for peripherals::ADC4 { + fn regs() -> Self::Regs { crate::pac::ADC4 } + + fn common_regs() -> crate::pac::adccommon::AdcCommon { + return crate::pac::$common_inst + } } - impl crate::adc::adc4::Instance for peripherals::ADC4 { + impl crate::adc::Instance for peripherals::ADC4 { type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; } }; @@ -493,20 +515,32 @@ foreach_adc!( #[cfg(adc_u5)] foreach_adc!( (ADC4, $common_inst:ident, $clock:ident) => { - impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { - fn regs() -> crate::pac::adc::Adc4 { + impl crate::adc::BasicInstance for peripherals::ADC4 { + type Regs = crate::pac::adc::Adc4; + } + + impl crate::adc::SealedInstance for peripherals::ADC4 { + fn regs() -> Self::Regs { crate::pac::ADC4 } + + fn common_regs() -> crate::pac::adccommon::AdcCommon { + return crate::pac::$common_inst + } } - impl crate::adc::adc4::Instance for peripherals::ADC4 { + impl crate::adc::Instance for peripherals::ADC4 { type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; } }; ($inst:ident, $common_inst:ident, $clock:ident) => { + impl crate::adc::BasicInstance for peripherals::$inst { + type Regs = crate::pac::adc::Adc; + } + impl crate::adc::SealedInstance for peripherals::$inst { - fn regs() -> crate::pac::adc::Adc { + fn regs() -> Self::Regs { crate::pac::$inst } @@ -524,14 +558,23 @@ foreach_adc!( #[cfg(not(any(adc_u5, adc_wba)))] foreach_adc!( ($inst:ident, $common_inst:ident, $clock:ident) => { + impl crate::adc::BasicInstance for peripherals::$inst { + #[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 + ))] + type Regs = crate::pac::adc::Adc; + } + impl crate::adc::SealedInstance for peripherals::$inst { - #[cfg(not(adc_wba))] - fn regs() -> crate::pac::adc::Adc { + #[cfg(any( + adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 + ))] + fn regs() -> Self::Regs { crate::pac::$inst } - #[cfg(adc_wba)] - fn regs() -> crate::pac::adc::Adc4 { + #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] + fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 5437866d3..242a1a89c 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; #[allow(unused_imports)] use embassy_hal_internal::Peri; -use crate::adc::AnyInstance; +use super::AdcRegs; #[allow(unused_imports)] use crate::adc::{Instance, RxDma}; #[allow(unused_imports)] @@ -19,7 +19,7 @@ pub struct RingBufferedAdc<'d, T: Instance> { ring_buf: ReadableRingBuffer<'d, u16>, } -impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { +impl<'d, T: Instance> RingBufferedAdc<'d, T> { pub(crate) fn new(dma: Peri<'d, impl RxDma>, dma_buf: &'d mut [u16]) -> Self { //dma side setup let opts = TransferOptions { @@ -31,8 +31,7 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { // Safety: we forget the struct before this function returns. let request = dma.request(); - let ring_buf = - unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) }; + let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, T::regs().data(), dma_buf, opts) }; Self { _phantom: PhantomData, @@ -45,7 +44,7 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { compiler_fence(Ordering::SeqCst); self.ring_buf.start(); - T::start(); + T::regs().start(); } pub fn stop(&mut self) { @@ -117,15 +116,15 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { self.start(); } - #[cfg(adc_v2)] - { - // Clear overrun flag if set. - if T::regs().sr().read().ovr() { - self.stop(); - - return Err(OverrunError); - } - } + // #[cfg(adc_v2)] + // { + // // Clear overrun flag if set. + // if T::regs().sr().read().ovr() { + // self.stop(); + // + // return Err(OverrunError); + // } + // } self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) } @@ -143,15 +142,16 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { self.start(); } - #[cfg(adc_v2)] - { - // Clear overrun flag if set. - if T::regs().sr().read().ovr() { - self.stop(); + // #[cfg(adc_v2)] + // { + // // Clear overrun flag if set. + // if T::regs().sr().read().ovr() { + // self.stop(); + // + // return Err(OverrunError); + // } + // } - return Err(OverrunError); - } - } loop { match self.ring_buf.read(buf) { Ok((0, _)) => {} @@ -168,9 +168,9 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { } } -impl Drop for RingBufferedAdc<'_, T> { +impl Drop for RingBufferedAdc<'_, T> { fn drop(&mut self) { - T::stop(); + T::regs().stop(); compiler_fence(Ordering::SeqCst); diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index e18098281..b026383d5 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,7 +1,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; -use crate::adc::{Adc, Instance, Resolution, SampleTime}; +use crate::adc::{Adc, AdcRegs, Instance, Resolution, SampleTime}; use crate::pac::adc::vals; pub use crate::pac::adccommon::vals::Adcpre; use crate::time::Hertz; @@ -74,28 +74,28 @@ pub struct AdcConfig { pub resolution: Option, } -impl super::SealedAnyInstance for T { - fn dr() -> *mut u16 { - T::regs().dr().as_ptr() as *mut u16 +impl super::AdcRegs for crate::pac::adc::Adc { + fn data(&self) -> *mut u16 { + crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 } - fn enable() { - T::regs().cr2().modify(|reg| { + fn enable(&self) { + self.cr2().modify(|reg| { reg.set_adon(true); }); blocking_delay_us(3); } - fn start() { + fn start(&self) { // Begin ADC conversions - T::regs().cr2().modify(|reg| { + self.cr2().modify(|reg| { reg.set_swstart(true); }); } - fn stop() { - let r = T::regs(); + fn stop(&self) { + let r = self; // Stop ADC r.cr2().modify(|reg| { @@ -114,36 +114,34 @@ impl super::SealedAnyInstance for T { w.set_ovrie(false); }); - clear_interrupt_flags(r); + clear_interrupt_flags(*r); compiler_fence(Ordering::SeqCst); } - fn convert() -> u16 { + fn convert(&self) { // clear end of conversion flag - T::regs().sr().modify(|reg| { + self.sr().modify(|reg| { reg.set_eoc(false); }); // Start conversion - T::regs().cr2().modify(|reg| { + self.cr2().modify(|reg| { reg.set_swstart(true); }); - while T::regs().sr().read().strt() == false { + while self.sr().read().strt() == false { // spin //wait for actual start } - while T::regs().sr().read().eoc() == false { + while self.sr().read().eoc() == false { // spin //wait for finish } - - T::regs().dr().read().0 as u16 } - fn configure_dma(conversion_mode: ConversionMode) { + fn configure_dma(&self, conversion_mode: ConversionMode) { match conversion_mode { ConversionMode::Repeated(_) => { - let r = T::regs(); + let r = self; // Clear all interrupts r.sr().modify(|regs| { @@ -177,25 +175,25 @@ impl super::SealedAnyInstance for T { } } - fn configure_sequence(sequence: impl ExactSizeIterator) { - T::regs().cr2().modify(|reg| { + fn configure_sequence(&self, sequence: impl ExactSizeIterator) { + self.cr2().modify(|reg| { reg.set_adon(true); }); // Check the sequence is long enough - T::regs().sqr1().modify(|r| { + self.sqr1().modify(|r| { r.set_l((sequence.len() - 1).try_into().unwrap()); }); for (i, ((ch, _), sample_time)) in sequence.enumerate() { // Set the channel in the right sequence field. - T::regs().sqr3().modify(|w| w.set_sq(i, ch)); + self.sqr3().modify(|w| w.set_sq(i, ch)); let sample_time = sample_time.into(); if ch <= 9 { - T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); + self.smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); } else { - T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + self.smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); } } } @@ -203,7 +201,7 @@ impl super::SealedAnyInstance for T { impl<'d, T> Adc<'d, T> where - T: Instance + super::AnyInstance, + T: Instance, { pub fn new(adc: Peri<'d, T>) -> Self { Self::new_with_config(adc, Default::default()) @@ -214,7 +212,7 @@ where let presc = from_pclk2(T::frequency()); T::common_regs().ccr().modify(|w| w.set_adcpre(presc)); - T::enable(); + T::regs().enable(); if let Some(resolution) = config.resolution { T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); @@ -259,9 +257,7 @@ where impl<'d, T: Instance> Drop for Adc<'d, T> { fn drop(&mut self) { - T::regs().cr2().modify(|reg| { - reg.set_adon(false); - }); + T::regs().stop(); rcc::disable::(); } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index b270588c4..9cc44aa9a 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -146,63 +146,63 @@ pub struct AdcConfig { pub averaging: Option, } -impl super::SealedAnyInstance for T { - fn dr() -> *mut u16 { - T::regs().dr().as_ptr() as *mut u16 +impl super::AdcRegs for crate::pac::adc::Adc { + fn data(&self) -> *mut u16 { + crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 } // Enable ADC only when it is not already running. - fn enable() { + fn enable(&self) { // Make sure bits are off - while T::regs().cr().read().addis() { + while self.cr().read().addis() { // spin } - if !T::regs().cr().read().aden() { + if !self.cr().read().aden() { // Enable ADC - T::regs().isr().modify(|reg| { + self.isr().modify(|reg| { reg.set_adrdy(true); }); - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_aden(true); }); - while !T::regs().isr().read().adrdy() { + while !self.isr().read().adrdy() { // spin } } } - fn start() { - T::regs().cr().modify(|reg| { + fn start(&self) { + self.cr().modify(|reg| { reg.set_adstart(true); }); } - fn stop() { + fn stop(&self) { // Ensure conversions are finished. - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { + if self.cr().read().adstart() && !self.cr().read().addis() { + self.cr().modify(|reg| { reg.set_adstp(true); }); - while T::regs().cr().read().adstart() {} + while self.cr().read().adstart() {} } // Reset configuration. #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| { + self.cfgr().modify(|reg| { reg.set_cont(false); reg.set_dmaen(false); }); #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { + self.cfgr1().modify(|reg| { reg.set_cont(false); reg.set_dmaen(false); }); } /// Perform a single conversion. - fn convert() -> u16 { + fn convert(&self) { // Some models are affected by an erratum: // If we perform conversions slower than 1 kHz, the first read ADC value can be // corrupted, so we discard it and measure again. @@ -216,36 +216,34 @@ impl super::SealedAnyInstance for T { let len = 1; for _ in 0..len { - T::regs().isr().modify(|reg| { + self.isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); }); // Start conversion - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_adstart(true); }); - while !T::regs().isr().read().eos() { + while !self.isr().read().eos() { // spin } } - - T::regs().dr().read().0 as u16 } - fn configure_dma(conversion_mode: ConversionMode) { + fn configure_dma(&self, conversion_mode: ConversionMode) { // Set continuous mode with oneshot dma. // Clear overrun flag before starting transfer. - T::regs().isr().modify(|reg| { + self.isr().modify(|reg| { reg.set_ovr(true); }); #[cfg(not(any(adc_g0, adc_u0)))] - let regs = T::regs().cfgr(); + let regs = self.cfgr(); #[cfg(any(adc_g0, adc_u0))] - let regs = T::regs().cfgr1(); + let regs = self.cfgr1(); regs.modify(|reg| { reg.set_discen(false); @@ -259,13 +257,13 @@ impl super::SealedAnyInstance for T { }); } - fn configure_sequence(sequence: impl ExactSizeIterator) { + fn configure_sequence(&self, sequence: impl ExactSizeIterator) { #[cfg(adc_h5)] - T::regs().cr().modify(|w| w.set_aden(false)); + self.cr().modify(|w| w.set_aden(false)); // Set sequence length #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().sqr1().modify(|w| { + self.sqr1().modify(|w| { w.set_l(sequence.len() as u8 - 1); }); @@ -273,8 +271,8 @@ impl super::SealedAnyInstance for T { { let mut sample_times = Vec::::new(); - T::regs().chselr().write(|chselr| { - T::regs().smpr().write(|smpr| { + self.chselr().write(|chselr| { + self.smpr().write(|smpr| { for ((channel, _), sample_time) in sequence { chselr.set_chsel(channel.into(), true); if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { @@ -306,22 +304,22 @@ impl super::SealedAnyInstance for T { // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." #[cfg(any(adc_h5, adc_h7rs))] if channel == 0 { - T::regs().or().modify(|reg| reg.set_op0(true)); + self.or().modify(|reg| reg.set_op0(true)); } // Configure channel cfg_if! { if #[cfg(adc_u0)] { // On G0 and U6 all channels use the same sampling time. - T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); + self.smpr().modify(|reg| reg.set_smp1(sample_time.into())); } else if #[cfg(any(adc_h5, adc_h7rs))] { match channel { - 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), - _ => T::regs().smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), + 0..=9 => self.smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), + _ => self.smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), } } else { let sample_time = sample_time.into(); - T::regs() + self .smpr(channel as usize / 10) .modify(|reg| reg.set_smp(channel as usize % 10, sample_time)); } @@ -331,9 +329,8 @@ impl super::SealedAnyInstance for T { { use crate::pac::adc::vals::Pcsel; - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() + self.cfgr2().modify(|w| w.set_lshift(0)); + self.pcsel() .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); } @@ -341,22 +338,22 @@ impl super::SealedAnyInstance for T { #[cfg(not(any(adc_g0, adc_u0)))] match _i { 0..=3 => { - T::regs().sqr1().modify(|w| { + self.sqr1().modify(|w| { w.set_sq(_i, channel); }); } 4..=8 => { - T::regs().sqr2().modify(|w| { + self.sqr2().modify(|w| { w.set_sq(_i - 4, channel); }); } 9..=13 => { - T::regs().sqr3().modify(|w| { + self.sqr3().modify(|w| { w.set_sq(_i - 9, channel); }); } 14..=15 => { - T::regs().sqr4().modify(|w| { + self.sqr4().modify(|w| { w.set_sq(_i - 14, channel); }); } @@ -375,20 +372,20 @@ impl super::SealedAnyInstance for T { } #[cfg(adc_h5)] - T::regs().difsel().write(|w| w.set_difsel(difsel)); + self.difsel().write(|w| w.set_difsel(difsel)); // 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(adc_u0)] - T::regs().chselr().modify(|reg| { + self.chselr().modify(|reg| { reg.set_chsel(channel_mask); }); } } } -impl<'d, T: Instance> Adc<'d, T> { +impl<'d, T: Instance> Adc<'d, T> { /// Enable the voltage regulator fn init_regulator() { rcc::enable_and_reset::(); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index a3d9e6176..09fc2ab22 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -5,7 +5,7 @@ use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; -use crate::adc::ConversionMode; +use crate::adc::{AdcRegs, ConversionMode}; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -80,65 +80,63 @@ pub struct AdcConfig { pub averaging: Option, } -impl super::SealedAnyInstance for T { - fn dr() -> *mut u16 { - T::regs().dr().as_ptr() as *mut u16 +impl AdcRegs for crate::pac::adc::Adc { + fn data(&self) -> *mut u16 { + crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 } - fn enable() { - T::regs().isr().write(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); - while !T::regs().isr().read().adrdy() {} - T::regs().isr().write(|w| w.set_adrdy(true)); + fn enable(&self) { + self.isr().write(|w| w.set_adrdy(true)); + self.cr().modify(|w| w.set_aden(true)); + while !self.isr().read().adrdy() {} + self.isr().write(|w| w.set_adrdy(true)); } - fn start() { + fn start(&self) { // Start conversion - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_adstart(true); }); } - fn stop() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { + fn stop(&self) { + if self.cr().read().adstart() && !self.cr().read().addis() { + self.cr().modify(|reg| { reg.set_adstp(Adstp::STOP); }); - while T::regs().cr().read().adstart() {} + while self.cr().read().adstart() {} } // Reset configuration. - T::regs().cfgr().modify(|reg| { + self.cfgr().modify(|reg| { reg.set_cont(false); reg.set_dmngt(Dmngt::from_bits(0)); }); } - fn convert() -> u16 { - T::regs().isr().modify(|reg| { + fn convert(&self) { + self.isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); }); // Start conversion - T::regs().cr().modify(|reg| { + self.cr().modify(|reg| { reg.set_adstart(true); }); - while !T::regs().isr().read().eos() { + while !self.isr().read().eos() { // spin } - - T::regs().dr().read().0 as u16 } - fn configure_dma(conversion_mode: ConversionMode) { + fn configure_dma(&self, conversion_mode: ConversionMode) { match conversion_mode { ConversionMode::Singular => { - T::regs().isr().modify(|reg| { + self.isr().modify(|reg| { reg.set_ovr(true); }); - T::regs().cfgr().modify(|reg| { + self.cfgr().modify(|reg| { reg.set_cont(true); reg.set_dmngt(Dmngt::DMA_ONE_SHOT); }); @@ -148,9 +146,9 @@ impl super::SealedAnyInstance for T { } } - fn configure_sequence(sequence: impl ExactSizeIterator) { + fn configure_sequence(&self, sequence: impl ExactSizeIterator) { // Set sequence length - T::regs().sqr1().modify(|w| { + self.sqr1().modify(|w| { w.set_l(sequence.len() as u8 - 1); }); @@ -158,39 +156,35 @@ impl super::SealedAnyInstance for T { for (i, ((channel, _), sample_time)) in sequence.enumerate() { let sample_time = sample_time.into(); if channel <= 9 { - T::regs().smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time)); + self.smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time)); } else { - T::regs() - .smpr(1) - .modify(|reg| reg.set_smp((channel - 10) as _, sample_time)); + self.smpr(1).modify(|reg| reg.set_smp((channel - 10) as _, sample_time)); } #[cfg(any(stm32h7, stm32u5))] { - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() - .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + self.cfgr2().modify(|w| w.set_lshift(0)); + self.pcsel().modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); } match i { 0..=3 => { - T::regs().sqr1().modify(|w| { + self.sqr1().modify(|w| { w.set_sq(i, channel); }); } 4..=8 => { - T::regs().sqr2().modify(|w| { + self.sqr2().modify(|w| { w.set_sq(i - 4, channel); }); } 9..=13 => { - T::regs().sqr3().modify(|w| { + self.sqr3().modify(|w| { w.set_sq(i - 9, channel); }); } 14..=15 => { - T::regs().sqr4().modify(|w| { + self.sqr4().modify(|w| { w.set_sq(i - 14, channel); }); } @@ -200,7 +194,7 @@ impl super::SealedAnyInstance for T { } } -impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { +impl<'d, T: Instance> Adc<'d, T> { pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { let s = Self::new(adc); @@ -292,7 +286,7 @@ impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { blocking_delay_us(1); - T::enable(); + T::regs().enable(); // single conversion mode, software trigger T::regs().cfgr().modify(|w| { diff --git a/examples/stm32h5/src/bin/adc_dma.rs b/examples/stm32h5/src/bin/adc_dma.rs index 2138257f7..e625e3a34 100644 --- a/examples/stm32h5/src/bin/adc_dma.rs +++ b/examples/stm32h5/src/bin/adc_dma.rs @@ -66,7 +66,7 @@ async fn adc2_task( adc_task(adc, dma, pin1, pin2).await; } -async fn adc_task<'a, T: adc::Instance>( +async fn adc_task<'a, T: adc::DefaultInstance>( adc: Peri<'a, T>, mut dma: Peri<'a, impl RxDma>, pin1: impl AdcChannel, -- cgit From fe88223469ca872b9b30b32e1b3f4ad219cfebed Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 6 Dec 2025 12:31:55 -0600 Subject: adc/g4: optimize --- embassy-stm32/src/adc/g4.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 53c1ecd31..e93ed945f 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -13,6 +13,7 @@ use super::{ blocking_delay_us, }; use crate::adc::{AdcRegs, BasicAdcRegs, SealedAdcChannel}; +use crate::pac::adc::regs::{Smpr, Smpr2, Sqr1, Sqr2, Sqr3, Sqr4}; use crate::time::Hertz; use crate::{Peri, pac, rcc}; @@ -174,19 +175,17 @@ impl super::AdcRegs for crate::pac::adc::Adc { fn configure_sequence(&self, sequence: impl ExactSizeIterator) { self.cr().modify(|w| w.set_aden(false)); - // Set sequence length - self.sqr1().modify(|w| { - w.set_l(sequence.len() as u8 - 1); - }); - #[cfg(stm32g4)] let mut difsel = DifselReg::default(); - let mut smpr = self.smpr().read(); - let mut smpr2 = self.smpr2().read(); - let mut sqr1 = self.sqr1().read(); - let mut sqr2 = self.sqr2().read(); - let mut sqr3 = self.sqr3().read(); - let mut sqr4 = self.sqr4().read(); + let mut smpr = Smpr::default(); + let mut smpr2 = Smpr2::default(); + let mut sqr1 = Sqr1::default(); + let mut sqr2 = Sqr2::default(); + let mut sqr3 = Sqr3::default(); + let mut sqr4 = Sqr4::default(); + + // Set sequence length + sqr1.set_l(sequence.len() as u8 - 1); // Configure channels and ranks for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { -- cgit