diff --git a/embassy-stm32/src/ospi/enums.rs b/embassy-stm32/src/ospi/enums.rs index e52f1f54d..4021f7ce3 100644 --- a/embassy-stm32/src/ospi/enums.rs +++ b/embassy-stm32/src/ospi/enums.rs @@ -69,6 +69,7 @@ impl Into<bool> for FlashSelection { /// Wrap Size #[allow(dead_code)] +#[allow(missing_docs)] #[derive(Copy, Clone)] pub enum WrapSize { None, @@ -90,6 +91,32 @@ impl Into<u8> for WrapSize { } } +/// Memory Type +#[allow(missing_docs)] +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub enum MemoryType { + Micron, + Macronix, + Standard, + MacronixRam, + HyperBusMemory, + HyperBusRegister, +} + +impl Into<u8> for MemoryType { + fn into(self) -> u8 { + match self { + MemoryType::Micron => 0x00, + MemoryType::Macronix => 0x01, + MemoryType::Standard => 0x02, + MemoryType::MacronixRam => 0x03, + MemoryType::HyperBusMemory => 0x04, + MemoryType::HyperBusRegister => 0x04, + } + } +} + /// Ospi memory size. #[allow(missing_docs)] #[derive(Copy, Clone)] diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 8fb5f06e4..3d458ba79 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -5,13 +5,9 @@ pub mod enums; -use core::ops::Add; -use core::ptr; - use embassy_embedded_hal::{GetConfig, SetConfig}; -use embassy_futures::join::join; use embassy_hal_internal::{into_ref, PeripheralRef}; -// use embedded_hal_02::spi; +use embedded_hal_1::spi::ErrorKind; pub use enums::*; use stm32_metapac::octospi::vals::{MemType, PhaseMode, SizeInBits}; @@ -32,7 +28,7 @@ pub struct Config { /// increase throughput pub dual_quad: bool, /// Indicates the type of external device connected - pub memory_type: MemType, // Need to add an additional enum to provide this public interface + pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface /// Defines the size of the external device connected to the OSPI corresponding /// to the number of address bits required to access the device pub device_size: MemorySize, @@ -70,7 +66,7 @@ impl Default for Config { Self { fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity dual_quad: false, - memory_type: MemType::B_STANDARD, + memory_type: MemoryType::Micron, device_size: MemorySize::Other(0), chip_select_high_time: ChipSelectHighTime::_5Cycle, free_running_clock: false, @@ -154,23 +150,17 @@ impl Default for TransferConfig { } } +/// Error used for Octospi implementation +#[derive(Debug)] pub enum OspiError { + /// Peripheral configuration is invalid InvalidConfiguration, + /// Operation configuration is invalid InvalidCommand, } -pub trait Error {} - -pub trait ErrorType { - type Error: Error; -} - -impl<T: ErrorType + ?Sized> ErrorType for &mut T { - type Error = T::Error; -} - /// MultiSpi interface trait -pub trait MultiSpi: ErrorType { +pub trait MultiSpiBus<Word: Copy + 'static = u8>: embedded_hal_1::spi::ErrorType { /// Transaction configuration for specific multispi implementation type Config; @@ -180,11 +170,27 @@ pub trait MultiSpi: ErrorType { /// Read function used to read data from the target device following the supplied transaction /// configuration. - async fn read(&mut self, data: &mut [u8], config: Self::Config) -> Result<(), Self::Error>; + async fn read(&mut self, data: &mut [Word], config: Self::Config) -> Result<(), Self::Error>; /// Write function used to send data to the target device following the supplied transaction /// configuration. - async fn write(&mut self, data: &[u8], config: Self::Config) -> Result<(), Self::Error>; + async fn write(&mut self, data: &[Word], config: Self::Config) -> Result<(), Self::Error>; +} + +impl<T: MultiSpiBus<Word> + ?Sized, Word: Copy + 'static> MultiSpiBus<Word> for &mut T { + type Config = T::Config; + #[inline] + async fn command(&mut self, config: Self::Config) -> Result<(), Self::Error> { + T::command(self, config).await + } + + async fn read(&mut self, data: &mut [Word], config: Self::Config) -> Result<(), Self::Error> { + T::read(self, data, config).await + } + + async fn write(&mut self, data: &[Word], config: Self::Config) -> Result<(), Self::Error> { + T::write(self, data, config).await + } } /// OSPI driver. @@ -206,24 +212,28 @@ pub struct Ospi<'d, T: Instance, Dma> { width: OspiWidth, } -impl Error for OspiError {} +impl embedded_hal_1::spi::Error for OspiError { + fn kind(&self) -> ErrorKind { + ErrorKind::Other + } +} -impl<'d, T: Instance, Dma> ErrorType for Ospi<'d, T, Dma> { +impl<'d, T: Instance, Dma> embedded_hal_1::spi::ErrorType for Ospi<'d, T, Dma> { type Error = OspiError; } -impl<'d, T: Instance, Dma: OctoDma<T>> MultiSpi for Ospi<'d, T, Dma> { +impl<'d, T: Instance, Dma: OctoDma<T>, W: Word> MultiSpiBus<W> for Ospi<'d, T, Dma> { type Config = TransferConfig; async fn command(&mut self, config: Self::Config) -> Result<(), Self::Error> { self.command(&config).await } - async fn read(&mut self, data: &mut [u8], config: Self::Config) -> Result<(), Self::Error> { + async fn read(&mut self, data: &mut [W], config: Self::Config) -> Result<(), Self::Error> { self.read(data, config).await } - async fn write(&mut self, data: &[u8], config: Self::Config) -> Result<(), Self::Error> { + async fn write(&mut self, data: &[W], config: Self::Config) -> Result<(), Self::Error> { self.write(data, config).await } } @@ -497,7 +507,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { // Device configuration T::REGS.dcr1().modify(|w| { w.set_devsize(config.device_size.into()); - w.set_mtyp(config.memory_type); + w.set_mtyp(vals::MemType::from_bits(config.memory_type.into())); w.set_csht(config.chip_select_high_time.into()); w.set_dlybyp(config.delay_block_bypass); w.set_frck(false); @@ -681,7 +691,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { } /// Blocking read with byte by byte data transfer - pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) -> Result<(), OspiError> { + pub fn blocking_read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> { // Wait for peripheral to be free while T::REGS.sr().read().busy() {} @@ -706,7 +716,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { for idx in 0..len { while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} - buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; + buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() }; } } @@ -717,7 +727,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { } /// Blocking write with byte by byte data transfer - pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) -> Result<(), OspiError> { + pub fn blocking_write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> { T::REGS.cr().modify(|w| { w.set_dmaen(false); }); @@ -730,7 +740,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { for idx in 0..len { while !T::REGS.sr().read().ftf() {} - unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; + unsafe { (T::REGS.dr().as_ptr() as *mut W).write_volatile(buf[idx]) }; } } @@ -741,7 +751,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { } /// Blocking read with DMA transfer - pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) -> Result<(), OspiError> + pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> where Dma: OctoDma<T>, { @@ -763,7 +773,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { Transfer::new_read( &mut self.dma, request, - T::REGS.dr().as_ptr() as *mut u8, + T::REGS.dr().as_ptr() as *mut W, buf, Default::default(), ) @@ -779,7 +789,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { } /// Blocking write with DMA transfer - pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) -> Result<(), OspiError> + pub fn blocking_write_dma<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> where Dma: OctoDma<T>, { @@ -794,7 +804,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { &mut self.dma, request, buf, - T::REGS.dr().as_ptr() as *mut u8, + T::REGS.dr().as_ptr() as *mut W, Default::default(), ) }; @@ -809,7 +819,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { } /// Asynchronous read from external device - pub async fn read(&mut self, buf: &mut [u8], transaction: TransferConfig) -> Result<(), OspiError> + pub async fn read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> where Dma: OctoDma<T>, { @@ -831,7 +841,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { Transfer::new_read( &mut self.dma, request, - T::REGS.dr().as_ptr() as *mut u8, + T::REGS.dr().as_ptr() as *mut W, buf, Default::default(), ) @@ -847,7 +857,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { } /// Asynchronous write to external device - pub async fn write(&mut self, buf: &[u8], transaction: TransferConfig) -> Result<(), OspiError> + pub async fn write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> where Dma: OctoDma<T>, { @@ -862,7 +872,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { &mut self.dma, request, buf, - T::REGS.dr().as_ptr() as *mut u8, + T::REGS.dr().as_ptr() as *mut W, Default::default(), ) }; @@ -889,7 +899,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { // Device configuration T::REGS.dcr1().modify(|w| { w.set_devsize(config.device_size.into()); - w.set_mtyp(config.memory_type); + w.set_mtyp(vals::MemType::from_bits(config.memory_type.into())); w.set_csht(config.chip_select_high_time.into()); w.set_dlybyp(config.delay_block_bypass); w.set_frck(false); @@ -998,6 +1008,10 @@ pub(crate) mod sealed { pub trait Instance { const REGS: Regs; } + + pub trait Word { + const CONFIG: word_impl::Config; + } } /// OSPI instance trait. @@ -1041,3 +1055,25 @@ impl<'d, T: Instance, Dma> GetConfig for Ospi<'d, T, Dma> { self.get_config() } } + +/// Word sizes usable for OSPI. +pub trait Word: word::Word + sealed::Word {} + +macro_rules! impl_word { + ($T:ty, $config:expr) => { + impl sealed::Word for $T { + const CONFIG: Config = $config; + } + impl Word for $T {} + }; +} + +mod word_impl { + use super::*; + + pub type Config = u8; + + impl_word!(u8, 8); + impl_word!(u16, 16); + impl_word!(u32, 32); +}