diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 0a4b4f074..a82e93b5b 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -4,11 +4,14 @@ pub mod enums; +use core::marker::PhantomData; + use embassy_hal_internal::{into_ref, PeripheralRef}; use enums::*; -use crate::dma::Transfer; -use crate::gpio::{AFType, AnyPin, Pull}; +use crate::dma::ChannelAndRequest; +use crate::gpio::{AFType, AnyPin, Pull, Speed}; +use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -71,7 +74,7 @@ impl Default for Config { /// QSPI driver. #[allow(dead_code)] -pub struct Qspi<'d, T: Instance, Dma> { +pub struct Qspi<'d, T: Instance, M: PeriMode> { _peri: PeripheralRef<'d, T>, sck: Option>, d0: Option>, @@ -79,93 +82,12 @@ pub struct Qspi<'d, T: Instance, Dma> { d2: Option>, d3: Option>, nss: Option>, - dma: PeripheralRef<'d, Dma>, + dma: Option>, + _phantom: PhantomData, config: Config, } -impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { - /// Create a new QSPI driver for bank 1. - pub fn new_bk1( - peri: impl Peripheral

+ 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - sck: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - config: Config, - ) -> Self { - into_ref!(peri, d0, d1, d2, d3, sck, 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()), - Some(sck.map_into()), - Some(nss.map_into()), - dma, - config, - FlashSelection::Flash1, - ) - } - - /// Create a new QSPI driver for bank 2. - pub fn new_bk2( - peri: impl Peripheral

+ 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - sck: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

+ 'd, - config: Config, - ) -> Self { - into_ref!(peri, d0, d1, d2, d3, sck, 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()), - Some(sck.map_into()), - Some(nss.map_into()), - dma, - config, - FlashSelection::Flash2, - ) - } - +impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { fn new_inner( peri: impl Peripheral

+ 'd, d0: Option>, @@ -174,11 +96,11 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { d3: Option>, sck: Option>, nss: Option>, - dma: impl Peripheral

+ 'd, + dma: Option>, config: Config, fsel: FlashSelection, ) -> Self { - into_ref!(peri, dma); + into_ref!(peri); T::enable_and_reset(); @@ -220,6 +142,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { d3, nss, dma, + _phantom: PhantomData, config, } } @@ -278,68 +201,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { 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) - where - Dma: QuadDma, - { - self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); - - T::REGS.ccr().modify(|v| { - v.set_fmode(QspiMode::IndirectRead.into()); - }); - let current_ar = T::REGS.ar().read().address(); - T::REGS.ar().write(|v| { - v.set_address(current_ar); - }); - - let request = self.dma.request(); - let transfer = unsafe { - Transfer::new_read( - &mut self.dma, - request, - T::REGS.dr().as_ptr() as *mut u8, - buf, - Default::default(), - ) - }; - - // STM32H7 does not have dmaen - #[cfg(not(stm32h7))] - T::REGS.cr().modify(|v| v.set_dmaen(true)); - - transfer.blocking_wait(); - } - - /// Blocking write data, using DMA. - pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) - where - Dma: QuadDma, - { - self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); - - T::REGS.ccr().modify(|v| { - v.set_fmode(QspiMode::IndirectWrite.into()); - }); - - let request = self.dma.request(); - let transfer = unsafe { - Transfer::new_write( - &mut self.dma, - request, - buf, - T::REGS.dr().as_ptr() as *mut u8, - Default::default(), - ) - }; - - // STM32H7 does not have dmaen - #[cfg(not(stm32h7))] - T::REGS.cr().modify(|v| v.set_dmaen(true)); - - transfer.blocking_wait(); - } - fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option) { T::REGS.fcr().modify(|v| { v.set_csmf(true); @@ -373,6 +234,160 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { } } +impl<'d, T: Instance> Qspi<'d, T, Blocking> { + /// Create a new QSPI driver for bank 1, in blocking mode. + pub fn new_blocking_bank1( + peri: impl Peripheral

+ 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + sck: 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!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + config, + FlashSelection::Flash1, + ) + } + + /// Create a new QSPI driver for bank 2, in blocking mode. + pub fn new_blocking_bank2( + peri: impl Peripheral

+ 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + sck: 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!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + None, + config, + FlashSelection::Flash2, + ) + } +} + +impl<'d, T: Instance> Qspi<'d, T, Async> { + /// Create a new QSPI driver for bank 1. + pub fn new_bank1( + peri: impl Peripheral

+ 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + sck: 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!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + new_dma!(dma), + config, + FlashSelection::Flash1, + ) + } + + /// Create a new QSPI driver for bank 2. + pub fn new_bank2( + peri: impl Peripheral

+ 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + sck: 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!(sck, AFType::OutputPushPull, Speed::VeryHigh), + new_pin!(nss, AFType::OutputPushPull, Speed::VeryHigh, Pull::Up), + new_dma!(dma), + config, + FlashSelection::Flash2, + ) + } + + /// Blocking read data, using DMA. + pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { + self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); + + T::REGS.ccr().modify(|v| { + v.set_fmode(QspiMode::IndirectRead.into()); + }); + let current_ar = T::REGS.ar().read().address(); + T::REGS.ar().write(|v| { + v.set_address(current_ar); + }); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .read(T::REGS.dr().as_ptr() as *mut u8, buf, Default::default()) + }; + + // STM32H7 does not have dmaen + #[cfg(not(stm32h7))] + T::REGS.cr().modify(|v| v.set_dmaen(true)); + + transfer.blocking_wait(); + } + + /// Blocking write data, using DMA. + pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { + self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); + + T::REGS.ccr().modify(|v| { + v.set_fmode(QspiMode::IndirectWrite.into()); + }); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .write(buf, T::REGS.dr().as_ptr() as *mut u8, Default::default()) + }; + + // STM32H7 does not have dmaen + #[cfg(not(stm32h7))] + T::REGS.cr().modify(|v| v.set_dmaen(true)); + + transfer.blocking_wait(); + } +} + trait SealedInstance { const REGS: Regs; } diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs index 005694db3..90d319b7a 100644 --- a/examples/stm32f7/src/bin/qspi.rs +++ b/examples/stm32f7/src/bin/qspi.rs @@ -4,8 +4,9 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::mode::Async; use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; -use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, QuadDma, TransferConfig}; +use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; use embassy_stm32::time::mhz; use embassy_stm32::Config as StmCfg; use {defmt_rtt as _, panic_probe as _}; @@ -43,12 +44,12 @@ const MEMORY_ADDR: u32 = 0x00000000u32; /// Implementation of access to flash chip. /// Chip commands are hardcoded as it depends on used chip. /// This implementation is using chip GD25Q64C from Giga Device -pub struct FlashMemory> { - qspi: Qspi<'static, I, D>, +pub struct FlashMemory { + qspi: Qspi<'static, I, Async>, } -impl> FlashMemory { - pub fn new(qspi: Qspi<'static, I, D>) -> Self { +impl FlashMemory { + pub fn new(qspi: Qspi<'static, I, Async>) -> Self { let mut memory = Self { qspi }; memory.reset_memory(); @@ -279,7 +280,7 @@ async fn main(_spawner: Spawner) -> ! { cs_high_time: ChipSelectHighTime::_1Cycle, fifo_threshold: FIFOThresholdLevel::_16Bytes, }; - let driver = Qspi::new_bk1( + let driver = Qspi::new_bank1( p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config, ); let mut flash = FlashMemory::new(driver);