stm32: Update xspi for stm32-metapac changes

This is now closer to the original ospi, using more idiomatic naming.

Some dead code is removed (previously was hidden by [allow(dead_code)]).
This commit is contained in:
Matt Johnston 2025-04-02 11:16:31 +08:00
parent 6d384a1a39
commit 36a5b02774
3 changed files with 175 additions and 223 deletions

View File

@ -62,7 +62,13 @@ fn main() {
// generate one singleton per peripheral (with many exceptions...) // generate one singleton per peripheral (with many exceptions...)
for p in METADATA.peripherals { for p in METADATA.peripherals {
if let Some(r) = &p.registers { if let Some(r) = &p.registers {
if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" || r.kind == "octospi" { if r.kind == "adccommon"
|| r.kind == "sai"
|| r.kind == "ucpd"
|| r.kind == "otg"
|| r.kind == "octospi"
|| r.kind == "xspi"
{
// TODO: should we emit this for all peripherals? if so, we will need a list of all // TODO: should we emit this for all peripherals? if so, we will need a list of all
// possible peripherals across all chips, so that we can declare the configs // possible peripherals across all chips, so that we can declare the configs
// (replacing the hard-coded list of `peri_*` cfgs below) // (replacing the hard-coded list of `peri_*` cfgs below)

View File

@ -1,10 +1,11 @@
//! Enums used in Xspi configuration. //! Enums used in Xspi configuration.
#[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub(crate) enum XspiMode { pub(crate) enum XspiMode {
IndirectWrite, IndirectWrite,
IndirectRead, IndirectRead,
#[expect(dead_code)]
AutoPolling, AutoPolling,
#[expect(dead_code)]
MemoryMapped, MemoryMapped,
} }
@ -20,7 +21,6 @@ impl Into<u8> for XspiMode {
} }
/// Xspi lane width /// Xspi lane width
#[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum XspiWidth { pub enum XspiWidth {
/// None /// None
@ -47,27 +47,7 @@ impl Into<u8> for XspiWidth {
} }
} }
/// Flash bank selection
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum FlashSelection {
/// Bank 1
Flash1,
/// Bank 2
Flash2,
}
impl Into<bool> for FlashSelection {
fn into(self) -> bool {
match self {
FlashSelection::Flash1 => false,
FlashSelection::Flash2 => true,
}
}
}
/// Wrap Size /// Wrap Size
#[allow(dead_code)]
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum WrapSize { pub enum WrapSize {
@ -92,7 +72,6 @@ impl Into<u8> for WrapSize {
/// Memory Type /// Memory Type
#[allow(missing_docs)] #[allow(missing_docs)]
#[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum MemoryType { pub enum MemoryType {
Micron, Micron,

View File

@ -14,8 +14,9 @@ pub use enums::*;
use crate::dma::{word, ChannelAndRequest}; use crate::dma::{word, ChannelAndRequest};
use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::mode::{Async, Blocking, Mode as PeriMode};
use crate::pac::xspi::{vals::*, Xspi as Regs}; use crate::pac::xspi::vals::*;
#[cfg(xspim_v2_1)] use crate::pac::xspi::Xspi as Regs;
#[cfg(xspim_v1)]
use crate::pac::xspim::Xspim; use crate::pac::xspim::Xspim;
use crate::rcc::{self, RccPeripheral}; use crate::rcc::{self, RccPeripheral};
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
@ -41,7 +42,7 @@ pub struct Config {
/// Indicates the wrap size corresponding to the external device configuration /// Indicates the wrap size corresponding to the external device configuration
pub wrap_size: WrapSize, pub wrap_size: WrapSize,
/// Specified the prescaler factor used for generating the external clock based /// Specified the prescaler factor used for generating the external clock based
/// on the AHB clock /// on the AHB clock. 0 = Fkernel, 1 = Fkernel/2, 2 = Fkernel/3 etc.
pub clock_prescaler: u8, pub clock_prescaler: u8,
/// Allows the delay of 1/2 cycle the data sampling to account for external /// Allows the delay of 1/2 cycle the data sampling to account for external
/// signal delays /// signal delays
@ -196,47 +197,35 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
self.configure_command(&read_config, None)?; self.configure_command(&read_config, None)?;
let reg = T::REGS; let reg = T::REGS;
while reg.xspi_sr().read().busy() {} while reg.sr().read().busy() {}
reg.xspi_ccr().modify(|r| { reg.ccr().modify(|r| {
r.set_dqse(XspiCcrDqse::B_0X0); r.set_dqse(false);
}); });
// Set wrting configurations, there are separate registers for write configurations in memory mapped mode // Set wrting configurations, there are separate registers for write configurations in memory mapped mode
reg.xspi_wccr().modify(|w| { reg.wccr().modify(|w| {
w.set_imode(XspiWccrImode::from_bits(write_config.iwidth.into())); w.set_imode(WccrImode::from_bits(write_config.iwidth.into()));
let idtr = match write_config.idtr { w.set_idtr(write_config.idtr);
true => XspiWccrIdtr::B_0X1, w.set_isize(WccrIsize::from_bits(write_config.isize.into()));
false => XspiWccrIdtr::B_0X0,
};
w.set_idtr(idtr);
w.set_isize(XspiWccrIsize::from_bits(write_config.isize.into()));
w.set_admode(XspiWccrAdmode::from_bits(write_config.adwidth.into())); w.set_admode(WccrAdmode::from_bits(write_config.adwidth.into()));
let addtr = match write_config.idtr { w.set_addtr(write_config.idtr);
true => XspiWccrAddtr::B_0X1, w.set_adsize(WccrAdsize::from_bits(write_config.adsize.into()));
false => XspiWccrAddtr::B_0X0,
};
w.set_addtr(addtr);
w.set_adsize(XspiWccrAdsize::from_bits(write_config.adsize.into()));
w.set_dmode(XspiWccrDmode::from_bits(write_config.dwidth.into())); w.set_dmode(WccrDmode::from_bits(write_config.dwidth.into()));
let ddtr = match write_config.idtr { w.set_ddtr(write_config.idtr);
true => XspiWccrDdtr::B_0X1,
false => XspiWccrDdtr::B_0X0,
};
w.set_ddtr(ddtr);
w.set_abmode(XspiWccrAbmode::from_bits(write_config.abwidth.into())); w.set_abmode(WccrAbmode::from_bits(write_config.abwidth.into()));
w.set_dqse(XspiWccrDqse::B_0X1); w.set_dqse(true);
}); });
reg.xspi_wtcr().modify(|w| w.set_dcyc(write_config.dummy.into())); reg.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into()));
// Enable memory mapped mode // Enable memory mapped mode
reg.xspi_cr().modify(|r| { reg.cr().modify(|r| {
r.set_fmode(Fmode::B_0X3); r.set_fmode(Fmode::B_0X3);
r.set_tcen(Tcen::B_0X0); r.set_tcen(false);
}); });
Ok(()) Ok(())
} }
@ -245,19 +234,19 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
pub fn disable_memory_mapped_mode(&mut self) { pub fn disable_memory_mapped_mode(&mut self) {
let reg = T::REGS; let reg = T::REGS;
reg.xspi_cr().modify(|r| { reg.cr().modify(|r| {
r.set_fmode(Fmode::B_0X0); r.set_fmode(Fmode::B_0X0);
r.set_abort(Abort::B_0X1); r.set_abort(true);
r.set_dmaen(Dmaen::B_0X0); r.set_dmaen(false);
r.set_en(En::B_0X0); r.set_en(false);
}); });
// Clear transfer complete flag // Clear transfer complete flag
reg.xspi_fcr().write(|w| w.set_ctcf(true)); reg.fcr().write(|w| w.set_ctcf(true));
// Re-enable ospi // Re-enable ospi
reg.xspi_cr().modify(|r| { reg.cr().modify(|r| {
r.set_en(En::B_0X1); r.set_en(true);
}); });
} }
@ -291,18 +280,18 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
) -> Self { ) -> Self {
into_ref!(peri); into_ref!(peri);
#[cfg(xspim_v2_1)] #[cfg(xspim_v1)]
{ {
// RCC for xspim should be enabled before writing register // RCC for xspim should be enabled before writing register
crate::pac::RCC.ahb5enr().modify(|w| w.set_iomngren(true)); crate::pac::RCC.ahb5enr().modify(|w| w.set_iomngren(true));
// Disable XSPI peripheral first // Disable XSPI peripheral first
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_en(En::B_0X0); w.set_en(false);
}); });
// XSPI IO Manager has been enabled before // XSPI IO Manager has been enabled before
T::SPIM_REGS.xspim_cr().modify(|w| { T::SPIM_REGS.cr().modify(|w| {
w.set_muxen(false); w.set_muxen(false);
w.set_req2ack_time(0xff); w.set_req2ack_time(0xff);
}); });
@ -310,74 +299,70 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
// System configuration // System configuration
rcc::enable_and_reset::<T>(); rcc::enable_and_reset::<T>();
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
// Device configuration // Device configuration
T::REGS.xspi_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(Mtyp::from_bits(config.memory_type.into())); w.set_mtyp(Mtyp::from_bits(config.memory_type.into()));
w.set_csht(Csht::from_bits(config.chip_select_high_time.into())); w.set_csht(Csht::from_bits(config.chip_select_high_time.into()));
w.set_frck(Frck::B_0X0); w.set_frck(false);
w.set_ckmode(Ckmode::from_bits(config.clock_mode.into())); w.set_ckmode(Ckmode::from_bits(config.clock_mode.into()));
}); });
T::REGS.xspi_dcr2().modify(|w| { T::REGS.dcr2().modify(|w| {
w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into())); w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into()));
}); });
T::REGS.xspi_dcr3().modify(|w| { T::REGS.dcr3().modify(|w| {
w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into())); w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into()));
#[cfg(xspi_v2_1)] #[cfg(xspi_v1)]
{ {
w.set_maxtran(Maxtran::from_bits(config.max_transfer.into())); w.set_maxtran(Maxtran::from_bits(config.max_transfer.into()));
} }
}); });
T::REGS.xspi_dcr4().modify(|w| { T::REGS.dcr4().modify(|w| {
w.set_refresh(Refresh::from_bits(config.refresh.into())); w.set_refresh(Refresh::from_bits(config.refresh.into()));
}); });
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_fthres(Fthres::from_bits(config.fifo_threshold.into())); w.set_fthres(Fthres::from_bits(config.fifo_threshold.into()));
}); });
// Wait for busy flag to clear // Wait for busy flag to clear
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
T::REGS.xspi_dcr2().modify(|w| { T::REGS.dcr2().modify(|w| {
w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into())); w.set_prescaler(config.clock_prescaler);
}); });
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_dmm(match dual_quad { w.set_dmm(dual_quad);
true => Dmm::B_0X1,
false => Dmm::B_0X0,
});
}); });
T::REGS.xspi_tcr().modify(|w| { T::REGS.tcr().modify(|w| {
w.set_sshift(match config.sample_shifting { w.set_sshift(config.sample_shifting);
true => XspiTcrSshift::B_0X1, w.set_dhqc(config.delay_hold_quarter_cycle);
false => XspiTcrSshift::B_0X0, });
});
w.set_dhqc(match config.delay_hold_quarter_cycle { // TODO: at the moment only ncs1 seems to get passed in?
true => XspiTcrDhqc::B_0X1, // Only one must be selected
false => XspiTcrDhqc::B_0X0, assert!(!(ncs1.is_some() && ncs2.is_some()));
}); assert!(!(ncs1.is_none() && ncs2.is_none()));
T::REGS.cr().modify(|w| {
w.set_cssel(if ncs1.is_some() { Cssel::B_0X0 } else { Cssel::B_0X1 });
}); });
// Enable peripheral // Enable peripheral
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_en(En::B_0X1); w.set_en(true);
}); });
// Free running clock needs to be set after peripheral enable // Free running clock needs to be set after peripheral enable
if config.free_running_clock { if config.free_running_clock {
T::REGS.xspi_dcr1().modify(|w| { T::REGS.dcr1().modify(|w| {
w.set_frck(match config.free_running_clock { w.set_frck(config.free_running_clock);
true => Frck::B_0X1,
false => Frck::B_0X0,
});
}); });
} }
@ -422,87 +407,78 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
return Err(XspiError::InvalidCommand); return Err(XspiError::InvalidCommand);
} }
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_fmode(0.into()); w.set_fmode(0.into());
}); });
// Configure alternate bytes // Configure alternate bytes
if let Some(ab) = command.alternate_bytes { if let Some(ab) = command.alternate_bytes {
T::REGS.xspi_abr().write(|v| v.set_alternate(ab)); T::REGS.abr().write(|v| v.set_alternate(ab));
T::REGS.xspi_ccr().modify(|w| { T::REGS.ccr().modify(|w| {
w.set_abmode(XspiCcrAbmode::from_bits(command.abwidth.into())); w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
w.set_abdtr(XspiCcrAbdtr::from_bits(command.abdtr.into())); w.set_abdtr(command.abdtr);
w.set_absize(XspiCcrAbsize::from_bits(command.absize.into())); w.set_absize(CcrAbsize::from_bits(command.absize.into()));
}) })
} }
// Configure dummy cycles // Configure dummy cycles
T::REGS.xspi_tcr().modify(|w| { T::REGS.tcr().modify(|w| {
w.set_dcyc(command.dummy.into()); w.set_dcyc(command.dummy.into());
}); });
// Configure data // Configure data
if let Some(data_length) = data_len { if let Some(data_length) = data_len {
T::REGS.xspi_dlr().write(|v| { T::REGS.dlr().write(|v| {
v.set_dl((data_length - 1) as u32); v.set_dl((data_length - 1) as u32);
}) })
} else { } else {
T::REGS.xspi_dlr().write(|v| { T::REGS.dlr().write(|v| {
v.set_dl((0) as u32); v.set_dl((0) as u32);
}) })
} }
// Configure instruction/address/data modes // Configure instruction/address/data modes
T::REGS.xspi_ccr().modify(|w| { T::REGS.ccr().modify(|w| {
w.set_imode(XspiCcrImode::from_bits(command.iwidth.into())); w.set_imode(CcrImode::from_bits(command.iwidth.into()));
w.set_idtr(match command.idtr { w.set_idtr(command.idtr);
true => XspiCcrIdtr::B_0X1, w.set_isize(CcrIsize::from_bits(command.isize.into()));
false => XspiCcrIdtr::B_0X0,
});
w.set_isize(XspiCcrIsize::from_bits(command.isize.into()));
w.set_admode(XspiCcrAdmode::from_bits(command.adwidth.into())); w.set_admode(CcrAdmode::from_bits(command.adwidth.into()));
w.set_addtr(match command.idtr { w.set_addtr(command.idtr);
true => XspiCcrAddtr::B_0X1, w.set_adsize(CcrAdsize::from_bits(command.adsize.into()));
false => XspiCcrAddtr::B_0X0,
});
w.set_adsize(XspiCcrAdsize::from_bits(command.adsize.into()));
w.set_dmode(XspiCcrDmode::from_bits(command.dwidth.into())); w.set_dmode(CcrDmode::from_bits(command.dwidth.into()));
w.set_ddtr(match command.ddtr { w.set_ddtr(command.ddtr);
true => XspiCcrDdtr::B_0X1,
false => XspiCcrDdtr::B_0X0,
});
}); });
// Set information required to initiate transaction // Set information required to initiate transaction
if let Some(instruction) = command.instruction { if let Some(instruction) = command.instruction {
if let Some(address) = command.address { if let Some(address) = command.address {
T::REGS.xspi_ir().write(|v| { T::REGS.ir().write(|v| {
v.set_instruction(instruction); v.set_instruction(instruction);
}); });
T::REGS.xspi_ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(address); v.set_address(address);
}); });
} else { } else {
// Double check requirements for delay hold and sample shifting // Double check requirements for delay hold and sample shifting
// if let None = command.data_len { // if let None = command.data_len {
// if self.config.delay_hold_quarter_cycle && command.idtr { // if self.config.delay_hold_quarter_cycle && command.idtr {
// T::REGS.xspi_ccr().modify(|w| { // T::REGS.ccr().modify(|w| {
// w.set_ddtr(true); // w.set_ddtr(true);
// }); // });
// } // }
// } // }
warn!("instruction: {:#x}", instruction); // warn!("instruction: {:#x}", instruction);
T::REGS.xspi_ir().write(|v| { T::REGS.ir().write(|v| {
v.set_instruction(instruction); v.set_instruction(instruction);
}); });
} }
} else { } else {
if let Some(address) = command.address { if let Some(address) = command.address {
T::REGS.xspi_ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(address); v.set_address(address);
}); });
} else { } else {
@ -517,14 +493,14 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
/// Function used to control or configure the target device without data transfer /// Function used to control or configure the target device without data transfer
pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), XspiError> { pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), XspiError> {
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
// Need additional validation that command configuration doesn't have data set // Need additional validation that command configuration doesn't have data set
self.configure_command(command, None)?; self.configure_command(command, None)?;
// Transaction initiated by setting final configuration, i.e the instruction register // Transaction initiated by setting final configuration, i.e the instruction register
while !T::REGS.xspi_sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.xspi_fcr().write(|w| { T::REGS.fcr().write(|w| {
w.set_ctcf(true); w.set_ctcf(true);
}); });
@ -538,36 +514,36 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
} }
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
// Ensure DMA is not enabled for this transaction // Ensure DMA is not enabled for this transaction
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_dmaen(Dmaen::B_0X0); w.set_dmaen(false);
}); });
// self.configure_command(&transaction, Some(buf.len()))?; // self.configure_command(&transaction, Some(buf.len()))?;
self.configure_command(&transaction, Some(buf.len())).unwrap(); self.configure_command(&transaction, Some(buf.len())).unwrap();
let current_address = T::REGS.xspi_ar().read().address(); let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.xspi_ir().read().instruction(); let current_instruction = T::REGS.ir().read().instruction();
// For a indirect read transaction, the transaction begins when the instruction/address is set // For a indirect read transaction, the transaction begins when the instruction/address is set
T::REGS T::REGS
.xspi_cr() .cr()
.modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 {
T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); T::REGS.ir().write(|v| v.set_instruction(current_instruction));
} else { } else {
T::REGS.xspi_ar().write(|v| v.set_address(current_address)); T::REGS.ar().write(|v| v.set_address(current_address));
} }
for idx in 0..buf.len() { for idx in 0..buf.len() {
while !T::REGS.xspi_sr().read().tcf() && !T::REGS.xspi_sr().read().ftf() {} while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
buf[idx] = unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).read_volatile() }; buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() };
} }
while !T::REGS.xspi_sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.xspi_fcr().write(|v| v.set_ctcf(true)); T::REGS.fcr().write(|v| v.set_ctcf(true));
Ok(()) Ok(())
} }
@ -579,25 +555,25 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
} }
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_dmaen(Dmaen::B_0X0); w.set_dmaen(false);
}); });
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
T::REGS T::REGS
.xspi_cr() .cr()
.modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
for idx in 0..buf.len() { for idx in 0..buf.len() {
while !T::REGS.xspi_sr().read().ftf() {} while !T::REGS.sr().read().ftf() {}
unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).write_volatile(buf[idx]) }; unsafe { (T::REGS.dr().as_ptr() as *mut W).write_volatile(buf[idx]) };
} }
while !T::REGS.xspi_sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.xspi_fcr().write(|v| v.set_ctcf(true)); T::REGS.fcr().write(|v| v.set_ctcf(true));
Ok(()) Ok(())
} }
@ -605,75 +581,66 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
/// Set new bus configuration /// Set new bus configuration
pub fn set_config(&mut self, config: &Config) { pub fn set_config(&mut self, config: &Config) {
// Wait for busy flag to clear // Wait for busy flag to clear
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
// Disable DMA channel while configuring the peripheral // Disable DMA channel while configuring the peripheral
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_dmaen(Dmaen::B_0X0); w.set_dmaen(false);
}); });
// Device configuration // Device configuration
T::REGS.xspi_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(Mtyp::from_bits(config.memory_type.into())); w.set_mtyp(Mtyp::from_bits(config.memory_type.into()));
w.set_csht(Csht::from_bits(config.chip_select_high_time.into())); w.set_csht(Csht::from_bits(config.chip_select_high_time.into()));
w.set_frck(Frck::B_0X0); w.set_frck(false);
w.set_ckmode(match config.clock_mode { w.set_ckmode(match config.clock_mode {
true => Ckmode::B_0X1, true => Ckmode::B_0X1,
false => Ckmode::B_0X0, false => Ckmode::B_0X0,
}); });
}); });
T::REGS.xspi_dcr2().modify(|w| { T::REGS.dcr2().modify(|w| {
w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into())); w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into()));
}); });
T::REGS.xspi_dcr3().modify(|w| { T::REGS.dcr3().modify(|w| {
w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into())); w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into()));
#[cfg(xspi_v2_1)] #[cfg(xspi_v1)]
{ {
w.set_maxtran(Maxtran::from_bits(config.max_transfer.into())); w.set_maxtran(Maxtran::from_bits(config.max_transfer.into()));
} }
}); });
T::REGS.xspi_dcr4().modify(|w| { T::REGS.dcr4().modify(|w| {
w.set_refresh(Refresh::from_bits(config.refresh.into())); w.set_refresh(Refresh::from_bits(config.refresh.into()));
}); });
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_fthres(Fthres::from_bits(config.fifo_threshold.into())); w.set_fthres(Fthres::from_bits(config.fifo_threshold.into()));
}); });
// Wait for busy flag to clear // Wait for busy flag to clear
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
T::REGS.xspi_dcr2().modify(|w| { T::REGS.dcr2().modify(|w| {
w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into())); w.set_prescaler(config.clock_prescaler);
}); });
T::REGS.xspi_tcr().modify(|w| { T::REGS.tcr().modify(|w| {
w.set_sshift(match config.sample_shifting { w.set_sshift(config.sample_shifting);
true => XspiTcrSshift::B_0X1, w.set_dhqc(config.delay_hold_quarter_cycle);
false => XspiTcrSshift::B_0X0,
});
w.set_dhqc(match config.delay_hold_quarter_cycle {
true => XspiTcrDhqc::B_0X1,
false => XspiTcrDhqc::B_0X0,
});
}); });
// Enable peripheral // Enable peripheral
T::REGS.xspi_cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_en(En::B_0X1); w.set_en(true);
}); });
// Free running clock needs to be set after peripheral enable // Free running clock needs to be set after peripheral enable
if config.free_running_clock { if config.free_running_clock {
T::REGS.xspi_dcr1().modify(|w| { T::REGS.dcr1().modify(|w| {
w.set_frck(match config.free_running_clock { w.set_frck(config.free_running_clock);
true => Frck::B_0X1,
false => Frck::B_0X0,
});
}); });
} }
@ -1143,31 +1110,31 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
} }
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
let current_address = T::REGS.xspi_ar().read().address(); let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.xspi_ir().read().instruction(); let current_instruction = T::REGS.ir().read().instruction();
// For a indirect read transaction, the transaction begins when the instruction/address is set // For a indirect read transaction, the transaction begins when the instruction/address is set
T::REGS T::REGS
.xspi_cr() .cr()
.modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 {
T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); T::REGS.ir().write(|v| v.set_instruction(current_instruction));
} else { } else {
T::REGS.xspi_ar().write(|v| v.set_address(current_address)); T::REGS.ar().write(|v| v.set_address(current_address));
} }
let transfer = unsafe { let transfer = unsafe {
self.dma self.dma
.as_mut() .as_mut()
.unwrap() .unwrap()
.read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default()) .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
}; };
T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); T::REGS.cr().modify(|w| w.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
@ -1183,21 +1150,21 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
} }
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
T::REGS T::REGS
.xspi_cr() .cr()
.modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
let transfer = unsafe { let transfer = unsafe {
self.dma self.dma
.as_mut() .as_mut()
.unwrap() .unwrap()
.write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default()) .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
}; };
T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); T::REGS.cr().modify(|w| w.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
@ -1213,31 +1180,31 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
} }
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
let current_address = T::REGS.xspi_ar().read().address(); let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.xspi_ir().read().instruction(); let current_instruction = T::REGS.ir().read().instruction();
// For a indirect read transaction, the transaction begins when the instruction/address is set // For a indirect read transaction, the transaction begins when the instruction/address is set
T::REGS T::REGS
.xspi_cr() .cr()
.modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 {
T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); T::REGS.ir().write(|v| v.set_instruction(current_instruction));
} else { } else {
T::REGS.xspi_ar().write(|v| v.set_address(current_address)); T::REGS.ar().write(|v| v.set_address(current_address));
} }
let transfer = unsafe { let transfer = unsafe {
self.dma self.dma
.as_mut() .as_mut()
.unwrap() .unwrap()
.read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default()) .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
}; };
T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); T::REGS.cr().modify(|w| w.set_dmaen(true));
transfer.await; transfer.await;
@ -1253,21 +1220,21 @@ impl<'d, T: Instance> Xspi<'d, T, Async> {
} }
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.xspi_sr().read().busy() {} while T::REGS.sr().read().busy() {}
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
T::REGS T::REGS
.xspi_cr() .cr()
.modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
let transfer = unsafe { let transfer = unsafe {
self.dma self.dma
.as_mut() .as_mut()
.unwrap() .unwrap()
.write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default()) .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
}; };
T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); T::REGS.cr().modify(|w| w.set_dmaen(true));
transfer.await; transfer.await;
@ -1306,16 +1273,16 @@ impl<'d, T: Instance, M: PeriMode> Drop for Xspi<'d, T, M> {
} }
fn finish_dma(regs: Regs) { fn finish_dma(regs: Regs) {
while !regs.xspi_sr().read().tcf() {} while !regs.sr().read().tcf() {}
regs.xspi_fcr().write(|v| v.set_ctcf(true)); regs.fcr().write(|v| v.set_ctcf(true));
regs.xspi_cr().modify(|w| { regs.cr().modify(|w| {
w.set_dmaen(Dmaen::B_0X0); w.set_dmaen(false);
}); });
} }
/// XSPI I/O manager instance trait. /// XSPI I/O manager instance trait.
#[cfg(xspim_v2_1)] #[cfg(xspim_v1)]
pub(crate) trait SealedXspimInstance { pub(crate) trait SealedXspimInstance {
const SPIM_REGS: Xspim; const SPIM_REGS: Xspim;
const SPI_IDX: u8; const SPI_IDX: u8;
@ -1327,12 +1294,12 @@ pub(crate) trait SealedInstance {
} }
/// XSPI instance trait. /// XSPI instance trait.
#[cfg(xspim_v2_1)] #[cfg(xspim_v1)]
#[allow(private_bounds)] #[allow(private_bounds)]
pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + SealedXspimInstance {} pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + SealedXspimInstance {}
/// XSPI instance trait. /// XSPI instance trait.
#[cfg(not(xspim_v2_1))] #[cfg(not(xspim_v1))]
#[allow(private_bounds)] #[allow(private_bounds)]
pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
@ -1361,20 +1328,20 @@ pin_trait!(NCLKPin, Instance);
dma_trait!(XDma, Instance); dma_trait!(XDma, Instance);
// Hard-coded the xspi index, for SPIM // Hard-coded the xspi index, for SPIM
#[cfg(xspim_v2_1)] #[cfg(xspim_v1)]
impl SealedXspimInstance for peripherals::XSPI1 { impl SealedXspimInstance for peripherals::XSPI1 {
const SPIM_REGS: Xspim = crate::pac::XSPIM; const SPIM_REGS: Xspim = crate::pac::XSPIM;
const SPI_IDX: u8 = 1; const SPI_IDX: u8 = 1;
} }
// #[cfg(all(xspim_v2_1, peri_xspi2))] // Some cubedb files are missing XSPI2, for example STM32H7R3Z8
#[cfg(xspim_v2_1)] #[cfg(all(xspim_v1, peri_xspi2))]
impl SealedXspimInstance for peripherals::XSPI2 { impl SealedXspimInstance for peripherals::XSPI2 {
const SPIM_REGS: Xspim = crate::pac::XSPIM; const SPIM_REGS: Xspim = crate::pac::XSPIM;
const SPI_IDX: u8 = 2; const SPI_IDX: u8 = 2;
} }
#[cfg(xspim_v2_1)] #[cfg(xspim_v1)]
foreach_peripheral!( foreach_peripheral!(
(xspi, $inst:ident) => { (xspi, $inst:ident) => {
impl SealedInstance for peripherals::$inst { impl SealedInstance for peripherals::$inst {
@ -1385,7 +1352,7 @@ foreach_peripheral!(
}; };
); );
#[cfg(not(xspim_v2_1))] #[cfg(not(xspim_v1))]
foreach_peripheral!( foreach_peripheral!(
(xspi, $inst:ident) => { (xspi, $inst:ident) => {
impl SealedInstance for peripherals::$inst { impl SealedInstance for peripherals::$inst {