Skip to content

Commit

Permalink
Add support for using different modes for each phase of an xspi opera…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
dne committed Mar 20, 2024
1 parent 6c76647 commit e94add8
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 31 deletions.
93 changes: 68 additions & 25 deletions src/xspi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,9 @@
//! interface. Automatic polling or memory-mapped modes are not supported,
//! except for the OCTOSPI Hyperbus mode.
//!
//! Using different operational modes (1-bit/2-bit/4-bit etc.) for different
//! phases of a single transaction is not supported. It is possible to change
//! operational mode between transactions by calling
//! [`configure_mode`](#method.configure_mode).
//! It is possible to change operational mode between transactions by
//! calling [`configure_mode`](#method.configure_mode) or
//! [`configure_modes`](#method.configure_modes)

// Parts of the Quad and Octo SPI support are shared (this file), but they are
// different enough to require different initialisation routines and pin
Expand All @@ -117,7 +116,7 @@ mod qspi;
#[cfg(any(feature = "rm0433", feature = "rm0399"))]
pub use common::{
Bank, BankError, BankSelect, Xspi as Qspi, XspiError as QspiError,
XspiMode as QspiMode, XspiWord as QspiWord,
XspiMode as QspiMode, XspiModes as QspiModes, XspiWord as QspiWord,
};
#[cfg(any(feature = "rm0433", feature = "rm0399"))]
pub use qspi::QspiExt as XspiExt;
Expand All @@ -128,7 +127,7 @@ mod octospi;
#[cfg(any(feature = "rm0455", feature = "rm0468"))]
pub use common::{
Xspi as Octospi, XspiError as OctospiError, XspiMode as OctospiMode,
XspiWord as OctospiWord,
XspiModes as OctospiModes, XspiWord as OctospiWord,
};
#[cfg(any(feature = "rm0455", feature = "rm0468"))]
pub use octospi::{Hyperbus, HyperbusConfig, OctospiExt as XspiExt};
Expand Down Expand Up @@ -176,6 +175,28 @@ mod common {
}
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct XspiModes {
/// IO lines used for the instruction phase.
pub instruction: XspiMode,
/// IO lines used for the address phase.
pub address: XspiMode,
/// IO lines used for the alternate byte phase.
pub alt_byte: XspiMode,
/// IO lines used for the data phase.
pub data: XspiMode,
}
impl XspiModes {
pub fn new(mode: XspiMode) -> Self {
Self {
instruction: mode,
address: mode,
alt_byte: mode,
data: mode,
}
}
}
/// Indicates an error with the XSPI peripheral.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down Expand Up @@ -308,7 +329,7 @@ mod common {
/// ```
#[derive(Copy, Clone)]
pub struct Config {
pub(super) mode: XspiMode,
pub(super) modes: XspiModes,
pub(super) frequency: Hertz,
pub(super) dummy_cycles: u8,
pub(super) sampling_edge: SamplingEdge,
Expand All @@ -323,21 +344,32 @@ mod common {
/// * Sample on falling edge
pub fn new(frequency: Hertz) -> Self {
Config {
mode: XspiMode::OneBit,
modes: XspiModes::new(XspiMode::OneBit),
frequency,
dummy_cycles: 0,
sampling_edge: SamplingEdge::Falling,
fifo_threshold: 1,
}
}

/// Specify the operating mode of the XSPI bus. Can be 1-bit, 2-bit or
/// 4-bit for Quadspi; 1-bit, 2-bit, 4-bit or 8-bit for Octospi.
/// Specify the operating mode for all phases of the XSPI bus
/// operation. Can be 1-bit, 2-bit or 4-bit for Quadspi;
/// 1-bit, 2-bit, 4-bit or 8-bit for Octospi.
///
/// The operating mode can also be changed using the
/// [`configure_mode`](Xspi#method.configure_mode) method
pub fn mode(mut self, mode: XspiMode) -> Self {
self.mode = mode;
pub fn mode(self, mode: XspiMode) -> Self {
self.modes(XspiModes::new(mode))
}

/// Specify the operating mode separately for each phase of
/// the XSPI bus operation. Can be 1-bit, 2-bit or 4-bit for
/// Quadspi; 1-bit, 2-bit, 4-bit or 8-bit for Octospi.
///
/// The operating modes can also be changed using the
/// [`configure_modes`](Xspi#method.configure_modes) method
pub fn modes(mut self, modes: XspiModes) -> Self {
self.modes = modes;
self
}

Expand Down Expand Up @@ -406,10 +438,10 @@ mod common {
pub struct Xspi<XSPI> {
pub(super) rb: XSPI,

/// We store the current mode here because for extended transactions
/// We store the current modes here because for extended transactions
/// various phases may be removed. Therefore we need to restore them
/// after each transaction.
pub(super) mode: XspiMode,
pub(super) modes: XspiModes,
}

#[cfg(any(feature = "rm0433", feature = "rm0399"))]
Expand Down Expand Up @@ -514,17 +546,29 @@ mod common {
}
}

/// Configure the operational mode (number of bits) of the XSPI
/// interface.
/// Configure the common mode (number of bits) for all phases of the XSPI
/// operation.
///
/// # Args
/// * `mode` - The newly desired mode of the interface.
/// * `mode` - The newly desired mode for the operation.
///
/// # Errors
/// Returns XspiError::Busy if an operation is ongoing
pub fn configure_mode(&mut self, mode: XspiMode) -> Result<(), XspiError> {
self.configure_modes(XspiModes::new(mode))
}

/// Configure the operational mode (number of bits), separately for each phase
/// of the XSPI interface.
///
/// # Args
/// * `modes` - The newly desired modes for each phase of the operation.
///
/// # Errors
/// Returns XspiError::Busy if an operation is ongoing
pub fn configure_modes(&mut self, modes: XspiModes) -> Result<(), XspiError> {
self.is_busy()?;
self.mode = mode;
self.modes = modes;
self.set_mode_address_data_only();

Ok(())
Expand All @@ -537,13 +581,13 @@ mod common {
w.imode() // NO instruction phase
.bits(0)
.admode() // address phase
.bits(self.mode.reg_value())
.bits(self.modes.address.reg_value())
.adsize()
.bits(0) // 8-bit address
.abmode() // NO alternate-bytes phase
.bits(0)
.dmode() // data phase
.bits(self.mode.reg_value())
.bits(self.modes.data.reg_value())
});
}

Expand All @@ -560,11 +604,10 @@ mod common {
alternate_bytes: XspiWord, dummy_cycles: u8, data: bool, read: bool) {

let fmode = if read { 0b01 } else { 0b00 };
let mode = self.mode.reg_value();
let imode = if instruction != XspiWord::None { mode } else { 0 };
let admode = if address != XspiWord::None { mode } else { 0 };
let abmode = if alternate_bytes != XspiWord::None { mode } else { 0 };
let dmode = if data { mode } else { 0 };
let imode = if instruction != XspiWord::None { self.modes.instruction.reg_value() } else { 0 };
let admode = if address != XspiWord::None { self.modes.address.reg_value() } else { 0 };
let abmode = if alternate_bytes != XspiWord::None { self.modes.alt_byte.reg_value() } else { 0 };
let dmode = if data { self.modes.data.reg_value() } else { 0 };

//writing to ccr will trigger the start of a transaction if there is no address or
//data rm0433 pg 894, so we do it all in one go
Expand Down
6 changes: 3 additions & 3 deletions src/xspi/octospi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,9 +459,9 @@ macro_rules! octospi_impl {
// Communications configuration register
regs.ccr.write(|w| unsafe {
w.dmode()
.bits(config.mode.reg_value())
.bits(config.modes.data.reg_value())
.admode()
.bits(config.mode.reg_value())
.bits(config.modes.address.reg_value())
.adsize()
.bits(0) // Eight-bit address
.imode()
Expand Down Expand Up @@ -498,7 +498,7 @@ macro_rules! octospi_impl {

Octospi {
rb: regs,
mode: config.mode,
modes: config.modes,
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/xspi/qspi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,9 @@ impl Qspi<stm32::QUADSPI> {
w.fmode()
.bits(0) // indirect mode
.dmode()
.bits(config.mode.reg_value())
.bits(config.modes.data.reg_value())
.admode()
.bits(config.mode.reg_value())
.bits(config.modes.address.reg_value())
.adsize()
.bits(0) // Eight-bit address
.imode()
Expand Down Expand Up @@ -338,7 +338,7 @@ impl Qspi<stm32::QUADSPI> {

Qspi {
rb: regs,
mode: config.mode,
modes: config.modes,
}
}
}
Expand Down

0 comments on commit e94add8

Please sign in to comment.