Update trait definitions
Make operations generic against valid data widths
This commit is contained in:
parent
e163572bec
commit
3b1d87050e
2 changed files with 102 additions and 39 deletions
|
@ -69,6 +69,7 @@ impl Into<bool> for FlashSelection {
|
||||||
|
|
||||||
/// Wrap Size
|
/// Wrap Size
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum WrapSize {
|
pub enum WrapSize {
|
||||||
None,
|
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.
|
/// Ospi memory size.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
|
@ -5,13 +5,9 @@
|
||||||
|
|
||||||
pub mod enums;
|
pub mod enums;
|
||||||
|
|
||||||
use core::ops::Add;
|
|
||||||
use core::ptr;
|
|
||||||
|
|
||||||
use embassy_embedded_hal::{GetConfig, SetConfig};
|
use embassy_embedded_hal::{GetConfig, SetConfig};
|
||||||
use embassy_futures::join::join;
|
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
// use embedded_hal_02::spi;
|
use embedded_hal_1::spi::ErrorKind;
|
||||||
pub use enums::*;
|
pub use enums::*;
|
||||||
use stm32_metapac::octospi::vals::{MemType, PhaseMode, SizeInBits};
|
use stm32_metapac::octospi::vals::{MemType, PhaseMode, SizeInBits};
|
||||||
|
|
||||||
|
@ -32,7 +28,7 @@ pub struct Config {
|
||||||
/// increase throughput
|
/// increase throughput
|
||||||
pub dual_quad: bool,
|
pub dual_quad: bool,
|
||||||
/// Indicates the type of external device connected
|
/// 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
|
/// Defines the size of the external device connected to the OSPI corresponding
|
||||||
/// to the number of address bits required to access the device
|
/// to the number of address bits required to access the device
|
||||||
pub device_size: MemorySize,
|
pub device_size: MemorySize,
|
||||||
|
@ -70,7 +66,7 @@ impl Default for Config {
|
||||||
Self {
|
Self {
|
||||||
fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity
|
fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity
|
||||||
dual_quad: false,
|
dual_quad: false,
|
||||||
memory_type: MemType::B_STANDARD,
|
memory_type: MemoryType::Micron,
|
||||||
device_size: MemorySize::Other(0),
|
device_size: MemorySize::Other(0),
|
||||||
chip_select_high_time: ChipSelectHighTime::_5Cycle,
|
chip_select_high_time: ChipSelectHighTime::_5Cycle,
|
||||||
free_running_clock: false,
|
free_running_clock: false,
|
||||||
|
@ -154,23 +150,17 @@ impl Default for TransferConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error used for Octospi implementation
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum OspiError {
|
pub enum OspiError {
|
||||||
|
/// Peripheral configuration is invalid
|
||||||
InvalidConfiguration,
|
InvalidConfiguration,
|
||||||
|
/// Operation configuration is invalid
|
||||||
InvalidCommand,
|
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
|
/// 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
|
/// Transaction configuration for specific multispi implementation
|
||||||
type Config;
|
type Config;
|
||||||
|
|
||||||
|
@ -180,11 +170,27 @@ pub trait MultiSpi: ErrorType {
|
||||||
|
|
||||||
/// Read function used to read data from the target device following the supplied transaction
|
/// Read function used to read data from the target device following the supplied transaction
|
||||||
/// configuration.
|
/// 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
|
/// Write function used to send data to the target device following the supplied transaction
|
||||||
/// configuration.
|
/// 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.
|
/// OSPI driver.
|
||||||
|
@ -206,24 +212,28 @@ pub struct Ospi<'d, T: Instance, Dma> {
|
||||||
width: OspiWidth,
|
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;
|
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;
|
type Config = TransferConfig;
|
||||||
|
|
||||||
async fn command(&mut self, config: Self::Config) -> Result<(), Self::Error> {
|
async fn command(&mut self, config: Self::Config) -> Result<(), Self::Error> {
|
||||||
self.command(&config).await
|
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
|
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
|
self.write(data, config).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,7 +507,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
// Device configuration
|
// Device configuration
|
||||||
T::REGS.dcr1().modify(|w| {
|
T::REGS.dcr1().modify(|w| {
|
||||||
w.set_devsize(config.device_size.into());
|
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_csht(config.chip_select_high_time.into());
|
||||||
w.set_dlybyp(config.delay_block_bypass);
|
w.set_dlybyp(config.delay_block_bypass);
|
||||||
w.set_frck(false);
|
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
|
/// 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
|
// Wait for peripheral to be free
|
||||||
while T::REGS.sr().read().busy() {}
|
while T::REGS.sr().read().busy() {}
|
||||||
|
|
||||||
|
@ -706,7 +716,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
|
|
||||||
for idx in 0..len {
|
for idx in 0..len {
|
||||||
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
|
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
|
/// 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| {
|
T::REGS.cr().modify(|w| {
|
||||||
w.set_dmaen(false);
|
w.set_dmaen(false);
|
||||||
});
|
});
|
||||||
|
@ -730,7 +740,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
|
|
||||||
for idx in 0..len {
|
for idx in 0..len {
|
||||||
while !T::REGS.sr().read().ftf() {}
|
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
|
/// 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
|
where
|
||||||
Dma: OctoDma<T>,
|
Dma: OctoDma<T>,
|
||||||
{
|
{
|
||||||
|
@ -763,7 +773,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
Transfer::new_read(
|
Transfer::new_read(
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
T::REGS.dr().as_ptr() as *mut u8,
|
T::REGS.dr().as_ptr() as *mut W,
|
||||||
buf,
|
buf,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
|
@ -779,7 +789,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blocking write with DMA transfer
|
/// 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
|
where
|
||||||
Dma: OctoDma<T>,
|
Dma: OctoDma<T>,
|
||||||
{
|
{
|
||||||
|
@ -794,7 +804,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
buf,
|
buf,
|
||||||
T::REGS.dr().as_ptr() as *mut u8,
|
T::REGS.dr().as_ptr() as *mut W,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -809,7 +819,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous read from external device
|
/// 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
|
where
|
||||||
Dma: OctoDma<T>,
|
Dma: OctoDma<T>,
|
||||||
{
|
{
|
||||||
|
@ -831,7 +841,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
Transfer::new_read(
|
Transfer::new_read(
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
T::REGS.dr().as_ptr() as *mut u8,
|
T::REGS.dr().as_ptr() as *mut W,
|
||||||
buf,
|
buf,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
|
@ -847,7 +857,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous write to external device
|
/// 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
|
where
|
||||||
Dma: OctoDma<T>,
|
Dma: OctoDma<T>,
|
||||||
{
|
{
|
||||||
|
@ -862,7 +872,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
buf,
|
buf,
|
||||||
T::REGS.dr().as_ptr() as *mut u8,
|
T::REGS.dr().as_ptr() as *mut W,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -889,7 +899,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
|
||||||
// Device configuration
|
// Device configuration
|
||||||
T::REGS.dcr1().modify(|w| {
|
T::REGS.dcr1().modify(|w| {
|
||||||
w.set_devsize(config.device_size.into());
|
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_csht(config.chip_select_high_time.into());
|
||||||
w.set_dlybyp(config.delay_block_bypass);
|
w.set_dlybyp(config.delay_block_bypass);
|
||||||
w.set_frck(false);
|
w.set_frck(false);
|
||||||
|
@ -998,6 +1008,10 @@ pub(crate) mod sealed {
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
const REGS: Regs;
|
const REGS: Regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Word {
|
||||||
|
const CONFIG: word_impl::Config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OSPI instance trait.
|
/// OSPI instance trait.
|
||||||
|
@ -1041,3 +1055,25 @@ impl<'d, T: Instance, Dma> GetConfig for Ospi<'d, T, Dma> {
|
||||||
self.get_config()
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue