Update trait definitions

Make operations generic against valid data widths
This commit is contained in:
Karun 2024-03-07 12:46:19 -05:00
parent e163572bec
commit 3b1d87050e
2 changed files with 102 additions and 39 deletions

View file

@ -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)]

View file

@ -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);
}