Fix build errors

Add empty checks/peripheral busy waits
This commit is contained in:
Karun 2024-04-03 16:36:02 -04:00
parent 80aeea93fd
commit 4ea7dfce17

View file

@ -7,7 +7,6 @@ pub mod enums;
use embassy_embedded_hal::{GetConfig, SetConfig}; use embassy_embedded_hal::{GetConfig, SetConfig};
use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_hal_internal::{into_ref, PeripheralRef};
use embedded_hal_1::spi::ErrorKind;
pub use enums::*; pub use enums::*;
use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits};
@ -144,11 +143,14 @@ impl Default for TransferConfig {
/// Error used for Octospi implementation /// Error used for Octospi implementation
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum OspiError { pub enum OspiError {
/// Peripheral configuration is invalid /// Peripheral configuration is invalid
InvalidConfiguration, InvalidConfiguration,
/// Operation configuration is invalid /// Operation configuration is invalid
InvalidCommand, InvalidCommand,
/// Size zero buffer passed to instruction
EmptyBuffer,
} }
/// OSPI driver. /// OSPI driver.
@ -627,10 +629,7 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
/// 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 async fn command(&mut self, command: &TransferConfig) -> Result<(), OspiError> { pub async fn command(&mut self, command: &TransferConfig) -> Result<(), OspiError> {
// Prevent a transaction from being set with expected data transmission or reception // Wait for peripheral to be free
if let Some(_) = command.data_len {
return Err(OspiError::InvalidCommand);
};
while T::REGS.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
@ -647,6 +646,10 @@ 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<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> { pub fn blocking_read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> {
if buf.is_empty() {
return Err(OspiError::EmptyBuffer);
}
// Wait for peripheral to be free // Wait for peripheral to be free
while T::REGS.sr().read().busy() {} while T::REGS.sr().read().busy() {}
@ -657,22 +660,20 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
if let Some(len) = transaction.data_len { let current_address = T::REGS.ar().read().address();
let current_address = T::REGS.ar().read().address(); let current_instruction = T::REGS.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.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD));
if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE {
T::REGS.ir().write(|v| v.set_instruction(current_instruction)); T::REGS.ir().write(|v| v.set_instruction(current_instruction));
} else { } else {
T::REGS.ar().write(|v| v.set_address(current_address)); T::REGS.ar().write(|v| v.set_address(current_address));
} }
for idx in 0..len { for idx in 0..buf.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 W).read_volatile() }; buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() };
}
} }
while !T::REGS.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
@ -683,20 +684,26 @@ 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<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> { pub fn blocking_write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> {
if buf.is_empty() {
return Err(OspiError::EmptyBuffer);
}
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}
T::REGS.cr().modify(|w| { T::REGS.cr().modify(|w| {
w.set_dmaen(false); w.set_dmaen(false);
}); });
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
if let Some(len) = transaction.data_len { T::REGS
T::REGS .cr()
.cr() .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE));
.modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE));
for idx in 0..len { for idx in 0..buf.len() {
while !T::REGS.sr().read().ftf() {} while !T::REGS.sr().read().ftf() {}
unsafe { (T::REGS.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.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
@ -710,6 +717,13 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
where where
Dma: OctoDma<T>, Dma: OctoDma<T>,
{ {
if buf.is_empty() {
return Err(OspiError::EmptyBuffer);
}
// Wait for peripheral to be free
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.ar().read().address(); let current_address = T::REGS.ar().read().address();
@ -748,6 +762,13 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
where where
Dma: OctoDma<T>, Dma: OctoDma<T>,
{ {
if buf.is_empty() {
return Err(OspiError::EmptyBuffer);
}
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
T::REGS T::REGS
.cr() .cr()
@ -778,6 +799,13 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
where where
Dma: OctoDma<T>, Dma: OctoDma<T>,
{ {
if buf.is_empty() {
return Err(OspiError::EmptyBuffer);
}
// Wait for peripheral to be free
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.ar().read().address(); let current_address = T::REGS.ar().read().address();
@ -816,6 +844,13 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
where where
Dma: OctoDma<T>, Dma: OctoDma<T>,
{ {
if buf.is_empty() {
return Err(OspiError::EmptyBuffer);
}
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}
self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len()))?;
T::REGS T::REGS
.cr() .cr()
@ -888,10 +923,6 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
w.set_prescaler(config.clock_prescaler); w.set_prescaler(config.clock_prescaler);
}); });
T::REGS.cr().modify(|w| {
w.set_dmm(config.dual_quad);
});
T::REGS.tcr().modify(|w| { T::REGS.tcr().modify(|w| {
w.set_sshift(match config.sample_shifting { w.set_sshift(match config.sample_shifting {
true => vals::SampleShift::HALFCYCLE, true => vals::SampleShift::HALFCYCLE,