Skip to content

chore: Minor QSPI code deduplication #2095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 57 additions & 68 deletions drv/stm32h7-qspi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ impl Qspi {
}

/// Helper for error paths.
///
/// Disables FIFO Threshold, Transfer Complete, Transfer Error, and Timeout
/// interrupts.
fn disable_all_interrupts(&self) {
self.reg.cr.modify(|_, w| {
w.ftie()
Expand All @@ -180,16 +183,58 @@ impl Qspi {
});
}

/// Returns the number of valid bytes being held in the FIFO queue if a
/// QSPI timeout or transfer error hasn't occurred.
fn get_fifo_level(&self) -> Result<usize, QspiError> {
let sr = self.reg.sr.read();

// Check timeout bit.
if sr.tof().bit_is_set() {
// Clear timeout bit and return.
self.reg.fcr.modify(|_, w| w.ctof().set_bit());
return Err(QspiError::Timeout);
}
// Check transfer error bit.
if sr.tef().bit_is_set() {
// Clear transfer error bit and return.
self.reg.fcr.modify(|_, w| w.ctef().set_bit());
return Err(QspiError::TransferError);
}
// Re-enable transfer error and timeout interrupts to make sure we
// catch any future errors.
self.reg
.cr
.modify(|_, w| w.teie().set_bit().toie().set_bit());
Ok(usize::from(sr.flevel().bits()))
}

/// Wait for the Transfer Complete flag to get set.
///
/// Note: this function returning does not guarantee that the BUSY flag is
/// clear.
fn wait_for_transfer_complete(&self) {
// Disable FIFO threshold interrupt, and enable transfer complete
// interrupts.
self.reg
.cr
.modify(|_, w| w.ftie().clear_bit().tcie().set_bit());
while self.transfer_not_complete() {
// Unmask our interrupt.
sys_irq_control(self.interrupt, true);
// And wait for it to arrive.
sys_recv_notification(self.interrupt);
}
}

fn write_impl(
&self,
command: Command,
addr: Option<u32>,
data: &[u8],
) -> Result<(), QspiError> {
let result = self.write_impl_inner(command, addr, data);
if result.is_err() {
self.disable_all_interrupts();
}
// Clean up by disabling our interrupt sources.
self.disable_all_interrupts();
result
}

Expand Down Expand Up @@ -238,24 +283,10 @@ impl Qspi {
// off the front.
let mut data = data;
while !data.is_empty() {
let sr = self.reg.sr.read();

if sr.tof().bit_is_set() {
self.reg.fcr.modify(|_, w| w.ctof().set_bit());
return Err(QspiError::Timeout);
}
if sr.tef().bit_is_set() {
self.reg.fcr.modify(|_, w| w.ctef().set_bit());
return Err(QspiError::TransferError);
}

// Make sure our errors are enabled
self.reg
.cr
.modify(|_, w| w.teie().set_bit().toie().set_bit());
// Check for any errors
let fl = self.get_fifo_level()?;

// How much space is in the FIFO?
let fl = usize::from(sr.flevel().bits());
let ffree = FIFO_SIZE - fl;
if ffree >= FIFO_THRESH.min(data.len()) {
// Calculate the write size. Note that this may be bigger than
Expand Down Expand Up @@ -293,18 +324,8 @@ impl Qspi {
}

// We're now interested in transfer complete, not FIFO ready.
self.reg
.cr
.modify(|_, w| w.ftie().clear_bit().tcie().set_bit());
while self.transfer_not_complete() {
// Unmask our interrupt.
sys_irq_control(self.interrupt, true);
// And wait for it to arrive.
sys_recv_notification(self.interrupt);
}
self.reg.cr.modify(|_, w| {
w.tcie().clear_bit().teie().clear_bit().toie().clear_bit()
});
self.wait_for_transfer_complete();

Ok(())
}

Expand All @@ -315,9 +336,8 @@ impl Qspi {
out: &mut [u8],
) -> Result<(), QspiError> {
let result = self.read_impl_inner(command, addr, out);
if result.is_err() {
self.disable_all_interrupts();
}
// Clean up by disabling our interrupt sources.
self.disable_all_interrupts();
result
}

Expand Down Expand Up @@ -375,22 +395,10 @@ impl Qspi {
// perform transfers.
let mut out = out;
while !out.is_empty() {
let sr = self.reg.sr.read();
// Get the FIFO level if no errors have occurred.
let fl = self.get_fifo_level()?;

if sr.tof().bit_is_set() {
self.reg.fcr.modify(|_, w| w.ctof().set_bit());
return Err(QspiError::Timeout);
}
if sr.tef().bit_is_set() {
self.reg.fcr.modify(|_, w| w.ctef().set_bit());
return Err(QspiError::TransferError);
}
// Make sure our errors are enabled
self.reg
.cr
.modify(|_, w| w.teie().set_bit().toie().set_bit());
// Is there enough to read that we want to bother with it?
let fl = usize::from(sr.flevel().bits());
if fl < FIFO_THRESH.min(out.len()) {
// Nope! Let's wait for more bytes.

Expand Down Expand Up @@ -438,27 +446,8 @@ impl Qspi {
// necessarily imply the BUSY flag is clear, but since commands are
// issued into a FIFO, we can issue the next command even while BUSY is
// set, it appears.
self.reg
.cr
.modify(|_, w| w.ftie().clear_bit().tcie().set_bit());
while self.transfer_not_complete() {
// Unmask our interrupt.
sys_irq_control(self.interrupt, true);
// And wait for it to arrive.
sys_recv_notification(self.interrupt);
}
self.wait_for_transfer_complete();

// Clean up by disabling our interrupt sources.
self.reg.cr.modify(|_, w| {
w.ftie()
.clear_bit()
.tcie()
.clear_bit()
.teie()
.clear_bit()
.toie()
.clear_bit()
});
Ok(())
}

Expand Down
Loading