diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index c25ac4d24..536da4ca0 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -5,13 +5,16 @@ pub mod enums; +use core::marker::PhantomData; + use embassy_embedded_hal::{GetConfig, SetConfig}; use embassy_hal_internal::{into_ref, PeripheralRef}; pub use enums::*; use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; -use crate::dma::{word, Transfer}; -use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; +use crate::dma::{word, ChannelAndRequest}; +use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; +use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::octospi::{vals, Octospi as Regs}; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -154,7 +157,7 @@ pub enum OspiError { } /// OSPI driver. -pub struct Ospi<'d, T: Instance, Dma> { +pub struct Ospi<'d, T: Instance, M: PeriMode> { _peri: PeripheralRef<'d, T>, sck: Option>, d0: Option>, @@ -167,259 +170,13 @@ pub struct Ospi<'d, T: Instance, Dma> { d7: Option>, nss: Option>, dqs: Option>, - dma: PeripheralRef<'d, Dma>, + dma: Option>, + _phantom: PhantomData, config: Config, width: OspiWidth, } -impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { - /// Create new OSPI driver for a single spi external chip - pub fn new_singlespi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - config: Config, - ) -> Self { - into_ref!(peri, sck, d0, d1, nss); - - sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); - sck.set_speed(crate::gpio::Speed::VeryHigh); - nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); - nss.set_speed(crate::gpio::Speed::VeryHigh); - d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); - d0.set_speed(crate::gpio::Speed::VeryHigh); - d1.set_as_af_pull(d1.af_num(), AFType::Input, Pull::None); - d1.set_speed(crate::gpio::Speed::VeryHigh); - - Self::new_inner( - peri, - Some(d0.map_into()), - Some(d1.map_into()), - None, - None, - None, - None, - None, - None, - Some(sck.map_into()), - Some(nss.map_into()), - None, - dma, - config, - OspiWidth::SING, - false, - ) - } - - /// Create new OSPI driver for a dualspi external chip - pub fn new_dualspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - config: Config, - ) -> Self { - into_ref!(peri, sck, d0, d1, nss); - - sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); - sck.set_speed(crate::gpio::Speed::VeryHigh); - nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); - nss.set_speed(crate::gpio::Speed::VeryHigh); - d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); - d0.set_speed(crate::gpio::Speed::VeryHigh); - d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); - d1.set_speed(crate::gpio::Speed::VeryHigh); - - Self::new_inner( - peri, - Some(d0.map_into()), - Some(d1.map_into()), - None, - None, - None, - None, - None, - None, - Some(sck.map_into()), - Some(nss.map_into()), - None, - dma, - config, - OspiWidth::DUAL, - false, - ) - } - - /// Create new OSPI driver for a quadspi external chip - pub fn new_quadspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - config: Config, - ) -> Self { - into_ref!(peri, sck, d0, d1, d2, d3, nss); - - sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); - sck.set_speed(crate::gpio::Speed::VeryHigh); - nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); - nss.set_speed(crate::gpio::Speed::VeryHigh); - d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); - d0.set_speed(crate::gpio::Speed::VeryHigh); - d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); - d1.set_speed(crate::gpio::Speed::VeryHigh); - d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); - d2.set_speed(crate::gpio::Speed::VeryHigh); - d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); - d3.set_speed(crate::gpio::Speed::VeryHigh); - - Self::new_inner( - peri, - Some(d0.map_into()), - Some(d1.map_into()), - Some(d2.map_into()), - Some(d3.map_into()), - None, - None, - None, - None, - Some(sck.map_into()), - Some(nss.map_into()), - None, - dma, - config, - OspiWidth::QUAD, - false, - ) - } - - /// Create new OSPI driver for two quadspi external chips - pub fn new_dualquadspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - config: Config, - ) -> Self { - into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss); - - sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); - sck.set_speed(crate::gpio::Speed::VeryHigh); - nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); - nss.set_speed(crate::gpio::Speed::VeryHigh); - d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); - d0.set_speed(crate::gpio::Speed::VeryHigh); - d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); - d1.set_speed(crate::gpio::Speed::VeryHigh); - d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); - d2.set_speed(crate::gpio::Speed::VeryHigh); - d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); - d3.set_speed(crate::gpio::Speed::VeryHigh); - d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None); - d4.set_speed(crate::gpio::Speed::VeryHigh); - d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None); - d5.set_speed(crate::gpio::Speed::VeryHigh); - d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None); - d6.set_speed(crate::gpio::Speed::VeryHigh); - d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None); - d7.set_speed(crate::gpio::Speed::VeryHigh); - - Self::new_inner( - peri, - Some(d0.map_into()), - Some(d1.map_into()), - Some(d2.map_into()), - Some(d3.map_into()), - Some(d4.map_into()), - Some(d5.map_into()), - Some(d6.map_into()), - Some(d7.map_into()), - Some(sck.map_into()), - Some(nss.map_into()), - None, - dma, - config, - OspiWidth::QUAD, - true, - ) - } - - /// Create new OSPI driver for octospi external chips - pub fn new_octospi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - config: Config, - ) -> Self { - into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss); - - sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); - sck.set_speed(crate::gpio::Speed::VeryHigh); - nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); - nss.set_speed(crate::gpio::Speed::VeryHigh); - d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); - d0.set_speed(crate::gpio::Speed::VeryHigh); - d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); - d1.set_speed(crate::gpio::Speed::VeryHigh); - d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); - d2.set_speed(crate::gpio::Speed::VeryHigh); - d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); - d3.set_speed(crate::gpio::Speed::VeryHigh); - d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None); - d4.set_speed(crate::gpio::Speed::VeryHigh); - d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None); - d5.set_speed(crate::gpio::Speed::VeryHigh); - d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None); - d6.set_speed(crate::gpio::Speed::VeryHigh); - d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None); - d7.set_speed(crate::gpio::Speed::VeryHigh); - - Self::new_inner( - peri, - Some(d0.map_into()), - Some(d1.map_into()), - Some(d2.map_into()), - Some(d3.map_into()), - Some(d4.map_into()), - Some(d5.map_into()), - Some(d6.map_into()), - Some(d7.map_into()), - Some(sck.map_into()), - Some(nss.map_into()), - None, - dma, - config, - OspiWidth::OCTO, - false, - ) - } - +impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { fn new_inner( peri: impl Peripheral

+ 'd, d0: Option>, @@ -433,12 +190,12 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { sck: Option>, nss: Option>, dqs: Option>, - dma: impl Peripheral

+ 'd, + dma: Option>, config: Config, width: OspiWidth, dual_quad: bool, ) -> Self { - into_ref!(peri, dma); + into_ref!(peri); // System configuration T::enable_and_reset(); @@ -519,6 +276,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { nss, dqs, dma, + _phantom: PhantomData, config, width, } @@ -702,170 +460,6 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { Ok(()) } - /// Blocking read with DMA transfer - pub fn blocking_read_dma(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> - where - Dma: OctoDma, - { - if buf.is_empty() { - return Err(OspiError::EmptyBuffer); - } - - // Wait for peripheral to be free - while T::REGS.sr().read().busy() {} - - self.configure_command(&transaction, Some(buf.len()))?; - - let current_address = T::REGS.ar().read().address(); - let current_instruction = T::REGS.ir().read().instruction(); - - // For a indirect read transaction, the transaction begins when the instruction/address is set - T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); - if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { - T::REGS.ir().write(|v| v.set_instruction(current_instruction)); - } else { - T::REGS.ar().write(|v| v.set_address(current_address)); - } - - let request = self.dma.request(); - let transfer = unsafe { - Transfer::new_read( - &mut self.dma, - request, - T::REGS.dr().as_ptr() as *mut W, - buf, - Default::default(), - ) - }; - - T::REGS.cr().modify(|w| w.set_dmaen(true)); - - transfer.blocking_wait(); - - finish_dma(T::REGS); - - Ok(()) - } - - /// Blocking write with DMA transfer - pub fn blocking_write_dma(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> - where - Dma: OctoDma, - { - if buf.is_empty() { - return Err(OspiError::EmptyBuffer); - } - - // Wait for peripheral to be free - while T::REGS.sr().read().busy() {} - - self.configure_command(&transaction, Some(buf.len()))?; - T::REGS - .cr() - .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); - - let request = self.dma.request(); - let transfer = unsafe { - Transfer::new_write( - &mut self.dma, - request, - buf, - T::REGS.dr().as_ptr() as *mut W, - Default::default(), - ) - }; - - T::REGS.cr().modify(|w| w.set_dmaen(true)); - - transfer.blocking_wait(); - - finish_dma(T::REGS); - - Ok(()) - } - - /// Asynchronous read from external device - pub async fn read(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> - where - Dma: OctoDma, - { - if buf.is_empty() { - return Err(OspiError::EmptyBuffer); - } - - // Wait for peripheral to be free - while T::REGS.sr().read().busy() {} - - self.configure_command(&transaction, Some(buf.len()))?; - - let current_address = T::REGS.ar().read().address(); - let current_instruction = T::REGS.ir().read().instruction(); - - // For a indirect read transaction, the transaction begins when the instruction/address is set - T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); - if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { - T::REGS.ir().write(|v| v.set_instruction(current_instruction)); - } else { - T::REGS.ar().write(|v| v.set_address(current_address)); - } - - let request = self.dma.request(); - let transfer = unsafe { - Transfer::new_read( - &mut self.dma, - request, - T::REGS.dr().as_ptr() as *mut W, - buf, - Default::default(), - ) - }; - - T::REGS.cr().modify(|w| w.set_dmaen(true)); - - transfer.await; - - finish_dma(T::REGS); - - Ok(()) - } - - /// Asynchronous write to external device - pub async fn write(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> - where - Dma: OctoDma, - { - if buf.is_empty() { - return Err(OspiError::EmptyBuffer); - } - - // Wait for peripheral to be free - while T::REGS.sr().read().busy() {} - - self.configure_command(&transaction, Some(buf.len()))?; - T::REGS - .cr() - .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); - - let request = self.dma.request(); - let transfer = unsafe { - Transfer::new_write( - &mut self.dma, - request, - buf, - T::REGS.dr().as_ptr() as *mut W, - Default::default(), - ) - }; - - T::REGS.cr().modify(|w| w.set_dmaen(true)); - - transfer.await; - - finish_dma(T::REGS); - - Ok(()) - } - /// Set new bus configuration pub fn set_config(&mut self, config: &Config) { // Wait for busy flag to clear @@ -942,7 +536,470 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { } } -impl<'d, T: Instance, Dma> Drop for Ospi<'d, T, Dma> { +impl<'d, T: Instance> Ospi<'d, T, Blocking> { + /// Create new blocking OSPI driver for a single spi external chip + pub fn new_blocking_singlespi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::Input, Speed::VeryHigh), + None, + None, + None, + None, + None, + None, + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + None, + config, + OspiWidth::SING, + false, + ) + } + + /// Create new blocking OSPI driver for a dualspi external chip + pub fn new_blocking_dualspi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + None, + None, + None, + None, + None, + None, + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + None, + config, + OspiWidth::DUAL, + false, + ) + } + + /// Create new blocking OSPI driver for a quadspi external chip + pub fn new_blocking_quadspi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh), + None, + None, + None, + None, + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + None, + config, + OspiWidth::QUAD, + false, + ) + } + + /// Create new blocking OSPI driver for two quadspi external chips + pub fn new_blocking_dualquadspi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + None, + config, + OspiWidth::QUAD, + true, + ) + } + + /// Create new blocking OSPI driver for octospi external chips + pub fn new_blocking_octospi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + None, + config, + OspiWidth::OCTO, + false, + ) + } +} + +impl<'d, T: Instance> Ospi<'d, T, Async> { + /// Create new blocking OSPI driver for a single spi external chip + pub fn new_singlespi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::Input, Speed::VeryHigh), + None, + None, + None, + None, + None, + None, + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + new_dma!(dma), + config, + OspiWidth::SING, + false, + ) + } + + /// Create new blocking OSPI driver for a dualspi external chip + pub fn new_dualspi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + None, + None, + None, + None, + None, + None, + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + new_dma!(dma), + config, + OspiWidth::DUAL, + false, + ) + } + + /// Create new blocking OSPI driver for a quadspi external chip + pub fn new_quadspi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh), + None, + None, + None, + None, + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + new_dma!(dma), + config, + OspiWidth::QUAD, + false, + ) + } + + /// Create new blocking OSPI driver for two quadspi external chips + pub fn new_dualquadspi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + new_dma!(dma), + config, + OspiWidth::QUAD, + true, + ) + } + + /// Create new blocking OSPI driver for octospi external chips + pub fn new_octospi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d1, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d2, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d3, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d4, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d5, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d6, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(d7, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + new_dma!(dma), + config, + OspiWidth::OCTO, + false, + ) + } + + /// Blocking read with DMA transfer + pub fn blocking_read_dma(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> { + if buf.is_empty() { + return Err(OspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); + if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.ar().write(|v| v.set_address(current_address)); + } + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.blocking_wait(); + + finish_dma(T::REGS); + + Ok(()) + } + + /// Blocking write with DMA transfer + pub fn blocking_write_dma(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> { + if buf.is_empty() { + return Err(OspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + T::REGS + .cr() + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.blocking_wait(); + + finish_dma(T::REGS); + + Ok(()) + } + + /// Asynchronous read from external device + pub async fn read(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> { + if buf.is_empty() { + return Err(OspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); + if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.ar().write(|v| v.set_address(current_address)); + } + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.await; + + finish_dma(T::REGS); + + Ok(()) + } + + /// Asynchronous write to external device + pub async fn write(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> { + if buf.is_empty() { + return Err(OspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + T::REGS + .cr() + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.await; + + finish_dma(T::REGS); + + Ok(()) + } +} + +impl<'d, T: Instance, M: PeriMode> Drop for Ospi<'d, T, M> { fn drop(&mut self) { self.sck.as_ref().map(|x| x.set_as_disconnected()); self.d0.as_ref().map(|x| x.set_as_disconnected()); @@ -1005,7 +1062,7 @@ foreach_peripheral!( }; ); -impl<'d, T: Instance, Dma> SetConfig for Ospi<'d, T, Dma> { +impl<'d, T: Instance, M: PeriMode> SetConfig for Ospi<'d, T, M> { type Config = Config; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { @@ -1014,7 +1071,7 @@ impl<'d, T: Instance, Dma> SetConfig for Ospi<'d, T, Dma> { } } -impl<'d, T: Instance, Dma> GetConfig for Ospi<'d, T, Dma> { +impl<'d, T: Instance, M: PeriMode> GetConfig for Ospi<'d, T, M> { type Config = Config; fn get_config(&self) -> Self::Config { self.get_config()