more SPI cleanup #29

Merged
muellerr merged 1 commits from more-spi-cleanup into main 2026-04-30 11:01:16 +02:00
+69 -49
View File
@@ -8,7 +8,10 @@ use raw_slice::{RawBufSlice, RawBufSliceMut};
use crate::{
shared::{FifoClear, TriggerLevel},
spi::regs::{Data, InterruptClear, InterruptControl},
spi::{
FIFO_DEPTH,
regs::{Data, InterruptClear, InterruptControl},
},
};
#[cfg(feature = "vor1x")]
@@ -159,14 +162,9 @@ fn on_interrupt_transfer(
// Send data first to avoid overwriting data that still needs to be sent.
while context.tx_progress < transfer_len && spi.read_status().tx_not_full() {
if context.tx_progress < write_len {
spi.write_data(Data::new_with_raw_value(
write_slice[context.tx_progress] as u32,
));
} else {
// Dummy write.
spi.write_data(Data::new_with_raw_value(0));
}
spi.write_data(Data::new_with_raw_value(
write_slice.get(context.tx_progress).copied().unwrap_or(0) as u32,
));
// Always increment this.
context.tx_progress += 1;
}
@@ -329,33 +327,30 @@ impl<'spi> SpiFuture<'spi> {
if words.is_empty() {
panic!("words length unexpectedly 0");
}
let idx = bank as usize;
DONE[idx].store(false, core::sync::atomic::Ordering::Relaxed);
spi.regs
.write_interrupt_control(InterruptControl::DISABLE_ALL);
spi.regs.write_fifo_clear(FifoClear::ALL);
spi.regs.modify_ctrl1(|v| v.with_mtxpause(true));
let write_idx = core::cmp::min(super::FIFO_DEPTH, words.len());
Self::generic_init_transfer(spi, bank);
let write_index = core::cmp::min(super::FIFO_DEPTH, words.len());
// Send dummy bytes.
(0..write_idx).for_each(|_| {
(0..write_index).for_each(|_| {
spi.regs.write_data(Data::new_with_raw_value(0));
});
Self::set_triggers(spi, write_idx, words.len());
Self::set_triggers(spi, write_index, words.len());
critical_section::with(|cs| {
let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs);
let context_ref = TRANSFER_CONTEXTS[bank as usize].borrow(cs);
let mut context = context_ref.borrow_mut();
context.transfer_type = Some(TransferType::Read);
unsafe {
context.rx_slice.set(words);
}
context.tx_slice.set_null();
context.tx_progress = write_idx;
context.tx_progress = write_index;
context.rx_progress = 0;
spi.regs.write_interrupt_clear(InterruptClear::ALL);
spi.regs
.write_interrupt_control(InterruptControl::ENABLE_ALL);
spi.regs.write_interrupt_control(
InterruptControl::ENABLE_ALL.with_tx(words.len() > FIFO_DEPTH),
);
spi.regs.modify_ctrl1(|v| v.with_mtxpause(false));
});
Self {
@@ -369,20 +364,22 @@ impl<'spi> SpiFuture<'spi> {
if words.is_empty() {
panic!("words length unexpectedly 0");
}
let (idx, write_idx) = Self::generic_init_transfer(spi, bank, words);
let index = bank as usize;
let write_index = Self::generic_init_transfer_write_transfer_in_place(spi, bank, words);
critical_section::with(|cs| {
let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs);
let context_ref = TRANSFER_CONTEXTS[index].borrow(cs);
let mut context = context_ref.borrow_mut();
context.transfer_type = Some(TransferType::Write);
unsafe {
context.tx_slice.set(words);
}
context.rx_slice.set_null();
context.tx_progress = write_idx;
context.tx_progress = write_index;
context.rx_progress = 0;
spi.regs.write_interrupt_clear(InterruptClear::ALL);
spi.regs
.write_interrupt_control(InterruptControl::ENABLE_ALL);
spi.regs.write_interrupt_control(
InterruptControl::ENABLE_ALL.with_tx(words.len() > FIFO_DEPTH),
);
spi.regs.modify_ctrl1(|v| v.with_mtxpause(false));
});
Self {
@@ -394,16 +391,33 @@ impl<'spi> SpiFuture<'spi> {
fn new_for_transfer(
spi: &'spi mut super::Spi<u8>,
spi_id: super::Bank,
bank: super::Bank,
read: &mut [u8],
write: &[u8],
) -> Self {
if read.is_empty() || write.is_empty() {
panic!("read or write buffer unexpectedly empty");
}
let (idx, write_idx) = Self::generic_init_transfer(spi, spi_id, write);
let index = bank as usize;
let full_write_len = core::cmp::max(read.len(), write.len());
let fifo_prefill = core::cmp::min(
core::cmp::min(super::FIFO_DEPTH, full_write_len),
write.len(),
);
let write_idx = Self::generic_init_transfer_write_transfer_in_place(spi, bank, write);
Self::generic_init_transfer(spi, bank);
for write_index in 0..fifo_prefill {
let value = write.get(write_index).copied().unwrap_or(0);
spi.regs.write_data(Data::new_with_raw_value(value as u32));
}
Self::set_triggers(spi, fifo_prefill, full_write_len);
critical_section::with(|cs| {
let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs);
let context_ref = TRANSFER_CONTEXTS[index].borrow(cs);
let mut context = context_ref.borrow_mut();
context.transfer_type = Some(TransferType::Transfer);
unsafe {
@@ -413,12 +427,13 @@ impl<'spi> SpiFuture<'spi> {
context.tx_progress = write_idx;
context.rx_progress = 0;
spi.regs.write_interrupt_clear(InterruptClear::ALL);
spi.regs
.write_interrupt_control(InterruptControl::ENABLE_ALL);
spi.regs.write_interrupt_control(
InterruptControl::ENABLE_ALL.with_tx(full_write_len > FIFO_DEPTH),
);
spi.regs.modify_ctrl1(|v| v.with_mtxpause(false));
});
Self {
bank: spi_id,
bank,
spi,
finished_regularly: core::cell::Cell::new(false),
}
@@ -426,15 +441,15 @@ impl<'spi> SpiFuture<'spi> {
fn new_for_transfer_in_place(
spi: &'spi mut super::Spi<u8>,
spi_id: super::Bank,
bank: super::Bank,
words: &mut [u8],
) -> Self {
if words.is_empty() {
panic!("read and write buffer unexpectedly empty");
}
let (idx, write_idx) = Self::generic_init_transfer(spi, spi_id, words);
let write_idx = Self::generic_init_transfer_write_transfer_in_place(spi, bank, words);
critical_section::with(|cs| {
let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs);
let context_ref = TRANSFER_CONTEXTS[bank as usize].borrow(cs);
let mut context = context_ref.borrow_mut();
context.transfer_type = Some(TransferType::TransferInPlace);
unsafe {
@@ -444,28 +459,34 @@ impl<'spi> SpiFuture<'spi> {
context.tx_progress = write_idx;
context.rx_progress = 0;
spi.regs.write_interrupt_clear(InterruptClear::ALL);
spi.regs
.write_interrupt_control(InterruptControl::ENABLE_ALL);
spi.regs.write_interrupt_control(
InterruptControl::ENABLE_ALL.with_tx(words.len() > FIFO_DEPTH),
);
spi.regs.modify_ctrl1(|v| v.with_mtxpause(false));
});
Self {
bank: spi_id,
bank,
spi,
finished_regularly: core::cell::Cell::new(false),
}
}
fn generic_init_transfer(
spi: &mut super::Spi<u8>,
bank: super::Bank,
write: &[u8],
) -> (usize, usize) {
fn generic_init_transfer(spi: &mut super::Spi<u8>, bank: super::Bank) {
let idx = bank as usize;
DONE[idx].store(false, core::sync::atomic::Ordering::Relaxed);
spi.regs
.write_interrupt_control(InterruptControl::DISABLE_ALL);
spi.regs.write_fifo_clear(FifoClear::ALL);
spi.regs.modify_ctrl1(|v| v.with_mtxpause(true));
}
// Returns amount of bytes written to FIFO.
fn generic_init_transfer_write_transfer_in_place(
spi: &mut super::Spi<u8>,
bank: super::Bank,
write: &[u8],
) -> usize {
Self::generic_init_transfer(spi, bank);
let write_idx = core::cmp::min(super::FIFO_DEPTH, write.len());
(0..write_idx).for_each(|idx| {
@@ -474,7 +495,7 @@ impl<'spi> SpiFuture<'spi> {
});
Self::set_triggers(spi, write_idx, write.len());
(idx, write_idx)
write_idx
}
fn set_triggers(spi: &mut super::Spi<u8>, write_idx: usize, write_len: usize) {
@@ -482,12 +503,11 @@ impl<'spi> SpiFuture<'spi> {
spi.regs
.write_rx_fifo_trigger(TriggerLevel::new(u5::new(write_idx as u8)));
// We want to re-fill the TX FIFO before it is completely empty if the full transfer size
// is larger than the FIFO depth. I am not sure whether the default value of 1 ensures
// this because the PG says that this interrupt is triggered when the FIFO has less than
// threshold entries.
// is larger than the FIFO depth. Otherwise, set it to 0. Not exactly sure what that does,
// but we do not enable interrupts anyway.
if write_len > super::FIFO_DEPTH {
spi.regs
.write_tx_fifo_trigger(TriggerLevel::new(u5::new(2)));
.write_tx_fifo_trigger(TriggerLevel::new(u5::new(8)));
} else {
spi.regs
.write_tx_fifo_trigger(TriggerLevel::new(u5::new(0)));