stm32: document hrtim, qspi, sdmmc, spi.
This commit is contained in:
		
							parent
							
								
									c995732b0e
								
							
						
					
					
						commit
						1ea87ec6e7
					
				@ -15,38 +15,42 @@ use crate::rcc::get_freqs;
 | 
				
			|||||||
use crate::time::Hertz;
 | 
					use crate::time::Hertz;
 | 
				
			||||||
use crate::Peripheral;
 | 
					use crate::Peripheral;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub enum Source {
 | 
					/// HRTIM burst controller instance.
 | 
				
			||||||
    Master,
 | 
					 | 
				
			||||||
    ChA,
 | 
					 | 
				
			||||||
    ChB,
 | 
					 | 
				
			||||||
    ChC,
 | 
					 | 
				
			||||||
    ChD,
 | 
					 | 
				
			||||||
    ChE,
 | 
					 | 
				
			||||||
    #[cfg(hrtim_v2)]
 | 
					 | 
				
			||||||
    ChF,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct BurstController<T: Instance> {
 | 
					pub struct BurstController<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM master instance.
 | 
				
			||||||
pub struct Master<T: Instance> {
 | 
					pub struct Master<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM channel A instance.
 | 
				
			||||||
pub struct ChA<T: Instance> {
 | 
					pub struct ChA<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM channel B instance.
 | 
				
			||||||
pub struct ChB<T: Instance> {
 | 
					pub struct ChB<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM channel C instance.
 | 
				
			||||||
pub struct ChC<T: Instance> {
 | 
					pub struct ChC<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM channel D instance.
 | 
				
			||||||
pub struct ChD<T: Instance> {
 | 
					pub struct ChD<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM channel E instance.
 | 
				
			||||||
pub struct ChE<T: Instance> {
 | 
					pub struct ChE<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM channel F instance.
 | 
				
			||||||
#[cfg(hrtim_v2)]
 | 
					#[cfg(hrtim_v2)]
 | 
				
			||||||
pub struct ChF<T: Instance> {
 | 
					pub struct ChF<T: Instance> {
 | 
				
			||||||
    phantom: PhantomData<T>,
 | 
					    phantom: PhantomData<T>,
 | 
				
			||||||
@ -60,13 +64,16 @@ mod sealed {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Advanced channel instance trait.
 | 
				
			||||||
pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
 | 
					pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM PWM pin.
 | 
				
			||||||
pub struct PwmPin<'d, Perip, Channel> {
 | 
					pub struct PwmPin<'d, Perip, Channel> {
 | 
				
			||||||
    _pin: PeripheralRef<'d, AnyPin>,
 | 
					    _pin: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
    phantom: PhantomData<(Perip, Channel)>,
 | 
					    phantom: PhantomData<(Perip, Channel)>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM complementary PWM pin.
 | 
				
			||||||
pub struct ComplementaryPwmPin<'d, Perip, Channel> {
 | 
					pub struct ComplementaryPwmPin<'d, Perip, Channel> {
 | 
				
			||||||
    _pin: PeripheralRef<'d, AnyPin>,
 | 
					    _pin: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
    phantom: PhantomData<(Perip, Channel)>,
 | 
					    phantom: PhantomData<(Perip, Channel)>,
 | 
				
			||||||
@ -75,6 +82,7 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> {
 | 
				
			|||||||
macro_rules! advanced_channel_impl {
 | 
					macro_rules! advanced_channel_impl {
 | 
				
			||||||
    ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
 | 
					    ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
 | 
				
			||||||
        impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> {
 | 
					        impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> {
 | 
				
			||||||
 | 
					            #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
 | 
				
			||||||
            pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
 | 
					            pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
 | 
				
			||||||
                into_ref!(pin);
 | 
					                into_ref!(pin);
 | 
				
			||||||
                critical_section::with(|_| {
 | 
					                critical_section::with(|_| {
 | 
				
			||||||
@ -91,6 +99,7 @@ macro_rules! advanced_channel_impl {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> {
 | 
					        impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> {
 | 
				
			||||||
 | 
					            #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
 | 
				
			||||||
            pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
 | 
					            pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
 | 
				
			||||||
                into_ref!(pin);
 | 
					                into_ref!(pin);
 | 
				
			||||||
                critical_section::with(|_| {
 | 
					                critical_section::with(|_| {
 | 
				
			||||||
@ -126,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin);
 | 
				
			|||||||
/// Struct used to divide a high resolution timer into multiple channels
 | 
					/// Struct used to divide a high resolution timer into multiple channels
 | 
				
			||||||
pub struct AdvancedPwm<'d, T: Instance> {
 | 
					pub struct AdvancedPwm<'d, T: Instance> {
 | 
				
			||||||
    _inner: PeripheralRef<'d, T>,
 | 
					    _inner: PeripheralRef<'d, T>,
 | 
				
			||||||
 | 
					    /// Master instance.
 | 
				
			||||||
    pub master: Master<T>,
 | 
					    pub master: Master<T>,
 | 
				
			||||||
 | 
					    /// Burst controller.
 | 
				
			||||||
    pub burst_controller: BurstController<T>,
 | 
					    pub burst_controller: BurstController<T>,
 | 
				
			||||||
 | 
					    /// Channel A.
 | 
				
			||||||
    pub ch_a: ChA<T>,
 | 
					    pub ch_a: ChA<T>,
 | 
				
			||||||
 | 
					    /// Channel B.
 | 
				
			||||||
    pub ch_b: ChB<T>,
 | 
					    pub ch_b: ChB<T>,
 | 
				
			||||||
 | 
					    /// Channel C.
 | 
				
			||||||
    pub ch_c: ChC<T>,
 | 
					    pub ch_c: ChC<T>,
 | 
				
			||||||
 | 
					    /// Channel D.
 | 
				
			||||||
    pub ch_d: ChD<T>,
 | 
					    pub ch_d: ChD<T>,
 | 
				
			||||||
 | 
					    /// Channel E.
 | 
				
			||||||
    pub ch_e: ChE<T>,
 | 
					    pub ch_e: ChE<T>,
 | 
				
			||||||
 | 
					    /// Channel F.
 | 
				
			||||||
    #[cfg(hrtim_v2)]
 | 
					    #[cfg(hrtim_v2)]
 | 
				
			||||||
    pub ch_f: ChF<T>,
 | 
					    pub ch_f: ChF<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d, T: Instance> AdvancedPwm<'d, T> {
 | 
					impl<'d, T: Instance> AdvancedPwm<'d, T> {
 | 
				
			||||||
 | 
					    /// Create a new HRTIM driver.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This splits the HRTIM into its constituent parts, which you can then use individually.
 | 
				
			||||||
    pub fn new(
 | 
					    pub fn new(
 | 
				
			||||||
        tim: impl Peripheral<P = T> + 'd,
 | 
					        tim: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        _cha: Option<PwmPin<'d, T, ChA<T>>>,
 | 
					        _cha: Option<PwmPin<'d, T, ChA<T>>>,
 | 
				
			||||||
@ -200,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Instance> BurstController<T> {
 | 
					/// Fixed-frequency bridge converter driver.
 | 
				
			||||||
    pub fn set_source(&mut self, _source: Source) {
 | 
					 | 
				
			||||||
        todo!("burst mode control registers not implemented")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Represents a fixed-frequency bridge converter
 | 
					 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Our implementation of the bridge converter uses a single channel and three compare registers,
 | 
					/// Our implementation of the bridge converter uses a single channel and three compare registers,
 | 
				
			||||||
/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous
 | 
					/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous
 | 
				
			||||||
@ -225,6 +239,7 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
 | 
					impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
 | 
				
			||||||
 | 
					    /// Create a new HRTIM bridge converter driver.
 | 
				
			||||||
    pub fn new(_channel: C, frequency: Hertz) -> Self {
 | 
					    pub fn new(_channel: C, frequency: Hertz) -> Self {
 | 
				
			||||||
        use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
 | 
					        use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -281,14 +296,17 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Start HRTIM.
 | 
				
			||||||
    pub fn start(&mut self) {
 | 
					    pub fn start(&mut self) {
 | 
				
			||||||
        T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
 | 
					        T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Stop HRTIM.
 | 
				
			||||||
    pub fn stop(&mut self) {
 | 
					    pub fn stop(&mut self) {
 | 
				
			||||||
        T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
 | 
					        T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Enable burst mode.
 | 
				
			||||||
    pub fn enable_burst_mode(&mut self) {
 | 
					    pub fn enable_burst_mode(&mut self) {
 | 
				
			||||||
        T::regs().tim(C::raw()).outr().modify(|w| {
 | 
					        T::regs().tim(C::raw()).outr().modify(|w| {
 | 
				
			||||||
            // Enable Burst Mode
 | 
					            // Enable Burst Mode
 | 
				
			||||||
@ -301,6 +319,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disable burst mode.
 | 
				
			||||||
    pub fn disable_burst_mode(&mut self) {
 | 
					    pub fn disable_burst_mode(&mut self) {
 | 
				
			||||||
        T::regs().tim(C::raw()).outr().modify(|w| {
 | 
					        T::regs().tim(C::raw()).outr().modify(|w| {
 | 
				
			||||||
            // Disable Burst Mode
 | 
					            // Disable Burst Mode
 | 
				
			||||||
@ -357,7 +376,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents a variable-frequency resonant converter
 | 
					/// Variable-frequency resonant converter driver.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This implementation of a resonsant converter is appropriate for a half or full bridge,
 | 
					/// This implementation of a resonsant converter is appropriate for a half or full bridge,
 | 
				
			||||||
/// but does not include secondary rectification, which is appropriate for applications
 | 
					/// but does not include secondary rectification, which is appropriate for applications
 | 
				
			||||||
@ -370,6 +389,7 @@ pub struct ResonantConverter<T: Instance, C: AdvancedChannel<T>> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
 | 
					impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
 | 
				
			||||||
 | 
					    /// Create a new variable-frequency resonant converter driver.
 | 
				
			||||||
    pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
 | 
					    pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
 | 
				
			||||||
        T::set_channel_frequency(C::raw(), min_frequency);
 | 
					        T::set_channel_frequency(C::raw(), min_frequency);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -408,6 +428,7 @@ impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
 | 
				
			|||||||
        T::set_channel_dead_time(C::raw(), value);
 | 
					        T::set_channel_dead_time(C::raw(), value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set the timer period.
 | 
				
			||||||
    pub fn set_period(&mut self, period: u16) {
 | 
					    pub fn set_period(&mut self, period: u16) {
 | 
				
			||||||
        assert!(period < self.max_period);
 | 
					        assert!(period < self.max_period);
 | 
				
			||||||
        assert!(period > self.min_period);
 | 
					        assert!(period > self.min_period);
 | 
				
			||||||
 | 
				
			|||||||
@ -125,7 +125,6 @@ pub(crate) mod sealed {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Set the dead time as a proportion of max_duty
 | 
					        /// Set the dead time as a proportion of max_duty
 | 
				
			||||||
 | 
					 | 
				
			||||||
        fn set_channel_dead_time(channel: usize, dead_time: u16) {
 | 
					        fn set_channel_dead_time(channel: usize, dead_time: u16) {
 | 
				
			||||||
            let regs = Self::regs();
 | 
					            let regs = Self::regs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -148,13 +147,10 @@ pub(crate) mod sealed {
 | 
				
			|||||||
                w.set_dtr(dt_val as u16);
 | 
					                w.set_dtr(dt_val as u16);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        //        fn enable_outputs(enable: bool);
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        //        fn enable_channel(&mut self, channel: usize, enable: bool);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// HRTIM instance trait.
 | 
				
			||||||
pub trait Instance: sealed::Instance + 'static {}
 | 
					pub trait Instance: sealed::Instance + 'static {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
foreach_interrupt! {
 | 
					foreach_interrupt! {
 | 
				
			||||||
 | 
				
			|||||||
@ -149,33 +149,15 @@ use crate::interrupt::Priority;
 | 
				
			|||||||
pub use crate::pac::NVIC_PRIO_BITS;
 | 
					pub use crate::pac::NVIC_PRIO_BITS;
 | 
				
			||||||
use crate::rcc::sealed::RccPeripheral;
 | 
					use crate::rcc::sealed::RccPeripheral;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// `embassy-stm32` global configuration.
 | 
					 | 
				
			||||||
#[non_exhaustive]
 | 
					#[non_exhaustive]
 | 
				
			||||||
pub struct Config {
 | 
					pub struct Config {
 | 
				
			||||||
    /// RCC config.
 | 
					 | 
				
			||||||
    pub rcc: rcc::Config,
 | 
					    pub rcc: rcc::Config,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Enable debug during sleep.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// May incrase power consumption. Defaults to true.
 | 
					 | 
				
			||||||
    #[cfg(dbgmcu)]
 | 
					    #[cfg(dbgmcu)]
 | 
				
			||||||
    pub enable_debug_during_sleep: bool,
 | 
					    pub enable_debug_during_sleep: bool,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// BDMA interrupt priority.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// Defaults to P0 (highest).
 | 
					 | 
				
			||||||
    #[cfg(bdma)]
 | 
					    #[cfg(bdma)]
 | 
				
			||||||
    pub bdma_interrupt_priority: Priority,
 | 
					    pub bdma_interrupt_priority: Priority,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// DMA interrupt priority.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// Defaults to P0 (highest).
 | 
					 | 
				
			||||||
    #[cfg(dma)]
 | 
					    #[cfg(dma)]
 | 
				
			||||||
    pub dma_interrupt_priority: Priority,
 | 
					    pub dma_interrupt_priority: Priority,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// GPDMA interrupt priority.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// Defaults to P0 (highest).
 | 
					 | 
				
			||||||
    #[cfg(gpdma)]
 | 
					    #[cfg(gpdma)]
 | 
				
			||||||
    pub gpdma_interrupt_priority: Priority,
 | 
					    pub gpdma_interrupt_priority: Priority,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -196,11 +178,7 @@ impl Default for Config {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Initialize the `embassy-stm32` HAL with the provided configuration.
 | 
					/// Initialize embassy.
 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// This returns the peripheral singletons that can be used for creating drivers.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// This should only be called once at startup, otherwise it panics.
 | 
					 | 
				
			||||||
pub fn init(config: Config) -> Peripherals {
 | 
					pub fn init(config: Config) -> Peripherals {
 | 
				
			||||||
    critical_section::with(|cs| {
 | 
					    critical_section::with(|cs| {
 | 
				
			||||||
        let p = Peripherals::take_with_cs(cs);
 | 
					        let p = Peripherals::take_with_cs(cs);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					//! Enums used in QSPI configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(dead_code)]
 | 
					#[allow(dead_code)]
 | 
				
			||||||
#[derive(Copy, Clone)]
 | 
					#[derive(Copy, Clone)]
 | 
				
			||||||
pub(crate) enum QspiMode {
 | 
					pub(crate) enum QspiMode {
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs;
 | 
				
			|||||||
use crate::rcc::RccPeripheral;
 | 
					use crate::rcc::RccPeripheral;
 | 
				
			||||||
use crate::{peripherals, Peripheral};
 | 
					use crate::{peripherals, Peripheral};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// QSPI transfer configuration.
 | 
				
			||||||
pub struct TransferConfig {
 | 
					pub struct TransferConfig {
 | 
				
			||||||
    /// Instraction width (IMODE)
 | 
					    /// Instraction width (IMODE)
 | 
				
			||||||
    pub iwidth: QspiWidth,
 | 
					    pub iwidth: QspiWidth,
 | 
				
			||||||
@ -45,6 +46,7 @@ impl Default for TransferConfig {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// QSPI driver configuration.
 | 
				
			||||||
pub struct Config {
 | 
					pub struct Config {
 | 
				
			||||||
    /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
 | 
					    /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
 | 
				
			||||||
    /// If you need other value the whose predefined use `Other` variant.
 | 
					    /// If you need other value the whose predefined use `Other` variant.
 | 
				
			||||||
@ -71,6 +73,7 @@ impl Default for Config {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// QSPI driver.
 | 
				
			||||||
#[allow(dead_code)]
 | 
					#[allow(dead_code)]
 | 
				
			||||||
pub struct Qspi<'d, T: Instance, Dma> {
 | 
					pub struct Qspi<'d, T: Instance, Dma> {
 | 
				
			||||||
    _peri: PeripheralRef<'d, T>,
 | 
					    _peri: PeripheralRef<'d, T>,
 | 
				
			||||||
@ -85,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
					impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
				
			||||||
 | 
					    /// Create a new QSPI driver for bank 1.
 | 
				
			||||||
    pub fn new_bk1(
 | 
					    pub fn new_bk1(
 | 
				
			||||||
        peri: impl Peripheral<P = T> + 'd,
 | 
					        peri: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
 | 
					        d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
 | 
				
			||||||
@ -125,6 +129,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Create a new QSPI driver for bank 2.
 | 
				
			||||||
    pub fn new_bk2(
 | 
					    pub fn new_bk2(
 | 
				
			||||||
        peri: impl Peripheral<P = T> + 'd,
 | 
					        peri: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
 | 
					        d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
 | 
				
			||||||
@ -223,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Do a QSPI command.
 | 
				
			||||||
    pub fn command(&mut self, transaction: TransferConfig) {
 | 
					    pub fn command(&mut self, transaction: TransferConfig) {
 | 
				
			||||||
        #[cfg(not(stm32h7))]
 | 
					        #[cfg(not(stm32h7))]
 | 
				
			||||||
        T::REGS.cr().modify(|v| v.set_dmaen(false));
 | 
					        T::REGS.cr().modify(|v| v.set_dmaen(false));
 | 
				
			||||||
@ -232,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
				
			|||||||
        T::REGS.fcr().modify(|v| v.set_ctcf(true));
 | 
					        T::REGS.fcr().modify(|v| v.set_ctcf(true));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking read data.
 | 
				
			||||||
    pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
 | 
					    pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
 | 
				
			||||||
        #[cfg(not(stm32h7))]
 | 
					        #[cfg(not(stm32h7))]
 | 
				
			||||||
        T::REGS.cr().modify(|v| v.set_dmaen(false));
 | 
					        T::REGS.cr().modify(|v| v.set_dmaen(false));
 | 
				
			||||||
@ -256,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
				
			|||||||
        T::REGS.fcr().modify(|v| v.set_ctcf(true));
 | 
					        T::REGS.fcr().modify(|v| v.set_ctcf(true));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking write data.
 | 
				
			||||||
    pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
 | 
					    pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
 | 
				
			||||||
        // STM32H7 does not have dmaen
 | 
					        // STM32H7 does not have dmaen
 | 
				
			||||||
        #[cfg(not(stm32h7))]
 | 
					        #[cfg(not(stm32h7))]
 | 
				
			||||||
@ -278,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
				
			|||||||
        T::REGS.fcr().modify(|v| v.set_ctcf(true));
 | 
					        T::REGS.fcr().modify(|v| v.set_ctcf(true));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking read data, using DMA.
 | 
				
			||||||
    pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
 | 
					    pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        Dma: QuadDma<T>,
 | 
					        Dma: QuadDma<T>,
 | 
				
			||||||
@ -310,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
 | 
				
			|||||||
        transfer.blocking_wait();
 | 
					        transfer.blocking_wait();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking write data, using DMA.
 | 
				
			||||||
    pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
 | 
					    pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        Dma: QuadDma<T>,
 | 
					        Dma: QuadDma<T>,
 | 
				
			||||||
@ -379,6 +389,7 @@ pub(crate) mod sealed {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// QSPI instance trait.
 | 
				
			||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
 | 
					pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pin_trait!(SckPin, Instance);
 | 
					pin_trait!(SckPin, Instance);
 | 
				
			||||||
 | 
				
			|||||||
@ -54,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// The signalling scheme used on the SDMMC bus
 | 
					/// The signalling scheme used on the SDMMC bus
 | 
				
			||||||
#[non_exhaustive]
 | 
					#[non_exhaustive]
 | 
				
			||||||
 | 
					#[allow(missing_docs)]
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 | 
					#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
pub enum Signalling {
 | 
					pub enum Signalling {
 | 
				
			||||||
@ -70,6 +71,9 @@ impl Default for Signalling {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Aligned data block for SDMMC transfers.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements.
 | 
				
			||||||
#[repr(align(4))]
 | 
					#[repr(align(4))]
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
					#[derive(Debug, Clone, PartialEq, Eq)]
 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
@ -94,17 +98,23 @@ impl DerefMut for DataBlock {
 | 
				
			|||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 | 
					#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
pub enum Error {
 | 
					pub enum Error {
 | 
				
			||||||
 | 
					    /// Timeout reported by the hardware
 | 
				
			||||||
    Timeout,
 | 
					    Timeout,
 | 
				
			||||||
 | 
					    /// Timeout reported by the software driver.
 | 
				
			||||||
    SoftwareTimeout,
 | 
					    SoftwareTimeout,
 | 
				
			||||||
 | 
					    /// Unsupported card version.
 | 
				
			||||||
    UnsupportedCardVersion,
 | 
					    UnsupportedCardVersion,
 | 
				
			||||||
 | 
					    /// Unsupported card type.
 | 
				
			||||||
    UnsupportedCardType,
 | 
					    UnsupportedCardType,
 | 
				
			||||||
 | 
					    /// CRC error.
 | 
				
			||||||
    Crc,
 | 
					    Crc,
 | 
				
			||||||
    DataCrcFail,
 | 
					    /// No card inserted.
 | 
				
			||||||
    RxOverFlow,
 | 
					 | 
				
			||||||
    NoCard,
 | 
					    NoCard,
 | 
				
			||||||
 | 
					    /// Bad clock supplied to the SDMMC peripheral.
 | 
				
			||||||
    BadClock,
 | 
					    BadClock,
 | 
				
			||||||
 | 
					    /// Signaling switch failed.
 | 
				
			||||||
    SignalingSwitchFailed,
 | 
					    SignalingSwitchFailed,
 | 
				
			||||||
    PeripheralBusy,
 | 
					    /// ST bit error.
 | 
				
			||||||
    #[cfg(sdmmc_v1)]
 | 
					    #[cfg(sdmmc_v1)]
 | 
				
			||||||
    StBitErr,
 | 
					    StBitErr,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -363,6 +373,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[cfg(sdmmc_v2)]
 | 
					#[cfg(sdmmc_v2)]
 | 
				
			||||||
impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
 | 
					impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
 | 
				
			||||||
 | 
					    /// Create a new SDMMC driver, with 1 data lane.
 | 
				
			||||||
    pub fn new_1bit(
 | 
					    pub fn new_1bit(
 | 
				
			||||||
        sdmmc: impl Peripheral<P = T> + 'd,
 | 
					        sdmmc: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
 | 
					        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
 | 
				
			||||||
@ -396,6 +407,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Create a new SDMMC driver, with 4 data lanes.
 | 
				
			||||||
    pub fn new_4bit(
 | 
					    pub fn new_4bit(
 | 
				
			||||||
        sdmmc: impl Peripheral<P = T> + 'd,
 | 
					        sdmmc: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
 | 
					        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
 | 
				
			||||||
@ -497,7 +509,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Data transfer is in progress
 | 
					    /// Data transfer is in progress
 | 
				
			||||||
    #[inline(always)]
 | 
					    #[inline]
 | 
				
			||||||
    fn data_active() -> bool {
 | 
					    fn data_active() -> bool {
 | 
				
			||||||
        let regs = T::regs();
 | 
					        let regs = T::regs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -509,7 +521,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Coammand transfer is in progress
 | 
					    /// Coammand transfer is in progress
 | 
				
			||||||
    #[inline(always)]
 | 
					    #[inline]
 | 
				
			||||||
    fn cmd_active() -> bool {
 | 
					    fn cmd_active() -> bool {
 | 
				
			||||||
        let regs = T::regs();
 | 
					        let regs = T::regs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -521,7 +533,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
 | 
					    /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
 | 
				
			||||||
    #[inline(always)]
 | 
					    #[inline]
 | 
				
			||||||
    fn wait_idle() {
 | 
					    fn wait_idle() {
 | 
				
			||||||
        while Self::data_active() || Self::cmd_active() {}
 | 
					        while Self::data_active() || Self::cmd_active() {}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -837,7 +849,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Clear flags in interrupt clear register
 | 
					    /// Clear flags in interrupt clear register
 | 
				
			||||||
    #[inline(always)]
 | 
					    #[inline]
 | 
				
			||||||
    fn clear_interrupt_flags() {
 | 
					    fn clear_interrupt_flags() {
 | 
				
			||||||
        let regs = T::regs();
 | 
					        let regs = T::regs();
 | 
				
			||||||
        regs.icr().write(|w| {
 | 
					        regs.icr().write(|w| {
 | 
				
			||||||
@ -1152,7 +1164,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline(always)]
 | 
					    /// Read a data block.
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
    pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
 | 
					    pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
 | 
				
			||||||
        let card_capacity = self.card()?.card_type;
 | 
					        let card_capacity = self.card()?.card_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1204,6 +1217,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
        res
 | 
					        res
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Write a data block.
 | 
				
			||||||
    pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
 | 
					    pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
 | 
				
			||||||
        let card = self.card.as_mut().ok_or(Error::NoCard)?;
 | 
					        let card = self.card.as_mut().ok_or(Error::NoCard)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1283,7 +1297,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Returns Error::NoCard if [`init_card`](#method.init_card)
 | 
					    /// Returns Error::NoCard if [`init_card`](#method.init_card)
 | 
				
			||||||
    /// has not previously succeeded
 | 
					    /// has not previously succeeded
 | 
				
			||||||
    #[inline(always)]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn card(&self) -> Result<&Card, Error> {
 | 
					    pub fn card(&self) -> Result<&Card, Error> {
 | 
				
			||||||
        self.card.as_ref().ok_or(Error::NoCard)
 | 
					        self.card.as_ref().ok_or(Error::NoCard)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1419,7 +1433,9 @@ pub(crate) mod sealed {
 | 
				
			|||||||
    pub trait Pins<T: Instance> {}
 | 
					    pub trait Pins<T: Instance> {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// SDMMC instance trait.
 | 
				
			||||||
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
 | 
					pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pin_trait!(CkPin, Instance);
 | 
					pin_trait!(CkPin, Instance);
 | 
				
			||||||
pin_trait!(CmdPin, Instance);
 | 
					pin_trait!(CmdPin, Instance);
 | 
				
			||||||
pin_trait!(D0Pin, Instance);
 | 
					pin_trait!(D0Pin, Instance);
 | 
				
			||||||
@ -1434,7 +1450,10 @@ pin_trait!(D7Pin, Instance);
 | 
				
			|||||||
#[cfg(sdmmc_v1)]
 | 
					#[cfg(sdmmc_v1)]
 | 
				
			||||||
dma_trait!(SdmmcDma, Instance);
 | 
					dma_trait!(SdmmcDma, Instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SDMMCv2 uses internal DMA
 | 
					/// DMA instance trait.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of
 | 
				
			||||||
 | 
					/// using ST's system-wide DMA peripheral.
 | 
				
			||||||
#[cfg(sdmmc_v2)]
 | 
					#[cfg(sdmmc_v2)]
 | 
				
			||||||
pub trait SdmmcDma<T: Instance> {}
 | 
					pub trait SdmmcDma<T: Instance> {}
 | 
				
			||||||
#[cfg(sdmmc_v2)]
 | 
					#[cfg(sdmmc_v2)]
 | 
				
			||||||
 | 
				
			|||||||
@ -16,27 +16,38 @@ use crate::rcc::RccPeripheral;
 | 
				
			|||||||
use crate::time::Hertz;
 | 
					use crate::time::Hertz;
 | 
				
			||||||
use crate::{peripherals, Peripheral};
 | 
					use crate::{peripherals, Peripheral};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// SPI error.
 | 
				
			||||||
#[derive(Debug, PartialEq, Eq)]
 | 
					#[derive(Debug, PartialEq, Eq)]
 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
pub enum Error {
 | 
					pub enum Error {
 | 
				
			||||||
 | 
					    /// Invalid framing.
 | 
				
			||||||
    Framing,
 | 
					    Framing,
 | 
				
			||||||
 | 
					    /// CRC error (only if hardware CRC checking is enabled).
 | 
				
			||||||
    Crc,
 | 
					    Crc,
 | 
				
			||||||
 | 
					    /// Mode fault
 | 
				
			||||||
    ModeFault,
 | 
					    ModeFault,
 | 
				
			||||||
 | 
					    /// Overrun.
 | 
				
			||||||
    Overrun,
 | 
					    Overrun,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO move upwards in the tree
 | 
					/// SPI bit order
 | 
				
			||||||
#[derive(Copy, Clone)]
 | 
					#[derive(Copy, Clone)]
 | 
				
			||||||
pub enum BitOrder {
 | 
					pub enum BitOrder {
 | 
				
			||||||
 | 
					    /// Least significant bit first.
 | 
				
			||||||
    LsbFirst,
 | 
					    LsbFirst,
 | 
				
			||||||
 | 
					    /// Most significant bit first.
 | 
				
			||||||
    MsbFirst,
 | 
					    MsbFirst,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// SPI configuration.
 | 
				
			||||||
#[non_exhaustive]
 | 
					#[non_exhaustive]
 | 
				
			||||||
#[derive(Copy, Clone)]
 | 
					#[derive(Copy, Clone)]
 | 
				
			||||||
pub struct Config {
 | 
					pub struct Config {
 | 
				
			||||||
 | 
					    /// SPI mode.
 | 
				
			||||||
    pub mode: Mode,
 | 
					    pub mode: Mode,
 | 
				
			||||||
 | 
					    /// Bit order.
 | 
				
			||||||
    pub bit_order: BitOrder,
 | 
					    pub bit_order: BitOrder,
 | 
				
			||||||
 | 
					    /// Clock frequency.
 | 
				
			||||||
    pub frequency: Hertz,
 | 
					    pub frequency: Hertz,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -73,6 +84,7 @@ impl Config {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// SPI driver.
 | 
				
			||||||
pub struct Spi<'d, T: Instance, Tx, Rx> {
 | 
					pub struct Spi<'d, T: Instance, Tx, Rx> {
 | 
				
			||||||
    _peri: PeripheralRef<'d, T>,
 | 
					    _peri: PeripheralRef<'d, T>,
 | 
				
			||||||
    sck: Option<PeripheralRef<'d, AnyPin>>,
 | 
					    sck: Option<PeripheralRef<'d, AnyPin>>,
 | 
				
			||||||
@ -84,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
					impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			||||||
 | 
					    /// Create a new SPI driver.
 | 
				
			||||||
    pub fn new(
 | 
					    pub fn new(
 | 
				
			||||||
        peri: impl Peripheral<P = T> + 'd,
 | 
					        peri: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        sck: impl Peripheral<P = impl SckPin<T>> + 'd,
 | 
					        sck: impl Peripheral<P = impl SckPin<T>> + 'd,
 | 
				
			||||||
@ -118,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
 | 
				
			||||||
    pub fn new_rxonly(
 | 
					    pub fn new_rxonly(
 | 
				
			||||||
        peri: impl Peripheral<P = T> + 'd,
 | 
					        peri: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        sck: impl Peripheral<P = impl SckPin<T>> + 'd,
 | 
					        sck: impl Peripheral<P = impl SckPin<T>> + 'd,
 | 
				
			||||||
@ -143,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
 | 
				
			||||||
    pub fn new_txonly(
 | 
					    pub fn new_txonly(
 | 
				
			||||||
        peri: impl Peripheral<P = T> + 'd,
 | 
					        peri: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        sck: impl Peripheral<P = impl SckPin<T>> + 'd,
 | 
					        sck: impl Peripheral<P = impl SckPin<T>> + 'd,
 | 
				
			||||||
@ -168,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Create a new SPI driver, in TX-only mode, without SCK pin.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This can be useful for bit-banging non-SPI protocols.
 | 
				
			||||||
    pub fn new_txonly_nosck(
 | 
					    pub fn new_txonly_nosck(
 | 
				
			||||||
        peri: impl Peripheral<P = T> + 'd,
 | 
					        peri: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
 | 
					        mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
 | 
				
			||||||
@ -355,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get current SPI configuration.
 | 
				
			||||||
    pub fn get_current_config(&self) -> Config {
 | 
					    pub fn get_current_config(&self) -> Config {
 | 
				
			||||||
        #[cfg(any(spi_v1, spi_f1, spi_v2))]
 | 
					        #[cfg(any(spi_v1, spi_f1, spi_v2))]
 | 
				
			||||||
        let cfg = T::REGS.cr1().read();
 | 
					        let cfg = T::REGS.cr1().read();
 | 
				
			||||||
@ -444,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        self.current_word_size = word_size;
 | 
					        self.current_word_size = word_size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// SPI write, using DMA.
 | 
				
			||||||
    pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
 | 
					    pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        Tx: TxDma<T>,
 | 
					        Tx: TxDma<T>,
 | 
				
			||||||
@ -477,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// SPI read, using DMA.
 | 
				
			||||||
    pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
 | 
					    pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        Tx: TxDma<T>,
 | 
					        Tx: TxDma<T>,
 | 
				
			||||||
@ -580,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Bidirectional transfer, using DMA.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
 | 
				
			||||||
 | 
					    /// If `write` is shorter it is padded with zero bytes.
 | 
				
			||||||
    pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error>
 | 
					    pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error>
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        Tx: TxDma<T>,
 | 
					        Tx: TxDma<T>,
 | 
				
			||||||
@ -588,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        self.transfer_inner(read, write).await
 | 
					        self.transfer_inner(read, write).await
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// In-place bidirectional transfer, using DMA.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
 | 
				
			||||||
    pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
 | 
					    pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        Tx: TxDma<T>,
 | 
					        Tx: TxDma<T>,
 | 
				
			||||||
@ -596,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        self.transfer_inner(data, data).await
 | 
					        self.transfer_inner(data, data).await
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking write.
 | 
				
			||||||
    pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
 | 
					    pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
 | 
				
			||||||
        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
					        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
				
			||||||
        flush_rx_fifo(T::REGS);
 | 
					        flush_rx_fifo(T::REGS);
 | 
				
			||||||
@ -606,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking read.
 | 
				
			||||||
    pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
 | 
					    pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
 | 
				
			||||||
        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
					        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
				
			||||||
        flush_rx_fifo(T::REGS);
 | 
					        flush_rx_fifo(T::REGS);
 | 
				
			||||||
@ -616,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking in-place bidirectional transfer.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
 | 
				
			||||||
    pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
 | 
					    pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
 | 
				
			||||||
        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
					        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
				
			||||||
        flush_rx_fifo(T::REGS);
 | 
					        flush_rx_fifo(T::REGS);
 | 
				
			||||||
@ -626,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Blocking bidirectional transfer.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
 | 
				
			||||||
 | 
					    /// If `write` is shorter it is padded with zero bytes.
 | 
				
			||||||
    pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
 | 
					    pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
 | 
				
			||||||
        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
					        T::REGS.cr1().modify(|w| w.set_spe(true));
 | 
				
			||||||
        flush_rx_fifo(T::REGS);
 | 
					        flush_rx_fifo(T::REGS);
 | 
				
			||||||
@ -946,6 +987,7 @@ pub(crate) mod sealed {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Word sizes usable for SPI.
 | 
				
			||||||
pub trait Word: word::Word + sealed::Word {}
 | 
					pub trait Word: word::Word + sealed::Word {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! impl_word {
 | 
					macro_rules! impl_word {
 | 
				
			||||||
@ -1025,7 +1067,9 @@ mod word_impl {
 | 
				
			|||||||
    impl_word!(u32, 32 - 1);
 | 
					    impl_word!(u32, 32 - 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// SPI instance trait.
 | 
				
			||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
 | 
					pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pin_trait!(SckPin, Instance);
 | 
					pin_trait!(SckPin, Instance);
 | 
				
			||||||
pin_trait!(MosiPin, Instance);
 | 
					pin_trait!(MosiPin, Instance);
 | 
				
			||||||
pin_trait!(MisoPin, Instance);
 | 
					pin_trait!(MisoPin, Instance);
 | 
				
			||||||
 | 
				
			|||||||
@ -8,14 +8,17 @@ use core::ops::{Div, Mul};
 | 
				
			|||||||
pub struct Hertz(pub u32);
 | 
					pub struct Hertz(pub u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Hertz {
 | 
					impl Hertz {
 | 
				
			||||||
 | 
					    /// Create a `Hertz` from the given hertz.
 | 
				
			||||||
    pub const fn hz(hertz: u32) -> Self {
 | 
					    pub const fn hz(hertz: u32) -> Self {
 | 
				
			||||||
        Self(hertz)
 | 
					        Self(hertz)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Create a `Hertz` from the given kilohertz.
 | 
				
			||||||
    pub const fn khz(kilohertz: u32) -> Self {
 | 
					    pub const fn khz(kilohertz: u32) -> Self {
 | 
				
			||||||
        Self(kilohertz * 1_000)
 | 
					        Self(kilohertz * 1_000)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Create a `Hertz` from the given megahertz.
 | 
				
			||||||
    pub const fn mhz(megahertz: u32) -> Self {
 | 
					    pub const fn mhz(megahertz: u32) -> Self {
 | 
				
			||||||
        Self(megahertz * 1_000_000)
 | 
					        Self(megahertz * 1_000_000)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user