From 58d98049d84cb2b716aa4fc37d54215bc493c899 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 8 Jun 2026 18:19:10 +0200 Subject: [PATCH] improve Async SPI impl --- vorago-shared-hal/src/spi/asynch.rs | 74 ++++++++++++++++++----------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/vorago-shared-hal/src/spi/asynch.rs b/vorago-shared-hal/src/spi/asynch.rs index 4feef07..bec1e55 100644 --- a/vorago-shared-hal/src/spi/asynch.rs +++ b/vorago-shared-hal/src/spi/asynch.rs @@ -322,13 +322,19 @@ impl TransferContext { pub struct SpiFuture<'spi> { bank: super::Bank, spi: &'spi mut super::Spi, + empty_buffer: bool, finished_regularly: core::cell::Cell, } impl<'spi> SpiFuture<'spi> { fn new_for_read(spi: &'spi mut super::Spi, bank: super::Bank, words: &mut [u8]) -> Self { if words.is_empty() { - panic!("words length unexpectedly 0"); + return Self { + bank, + spi, + empty_buffer: true, + finished_regularly: core::cell::Cell::new(false), + }; } Self::generic_init_transfer(spi, bank); @@ -359,13 +365,19 @@ impl<'spi> SpiFuture<'spi> { Self { bank, spi, + empty_buffer: false, finished_regularly: core::cell::Cell::new(false), } } fn new_for_write(spi: &'spi mut super::Spi, bank: super::Bank, words: &[u8]) -> Self { if words.is_empty() { - panic!("words length unexpectedly 0"); + return Self { + bank, + spi, + empty_buffer: true, + finished_regularly: core::cell::Cell::new(false), + }; } let index = bank as usize; let write_index = Self::generic_init_transfer_write_transfer_in_place(spi, bank, words); @@ -388,6 +400,7 @@ impl<'spi> SpiFuture<'spi> { Self { bank, spi, + empty_buffer: false, finished_regularly: core::cell::Cell::new(false), } } @@ -399,7 +412,12 @@ impl<'spi> SpiFuture<'spi> { write: &[u8], ) -> Self { if read.is_empty() || write.is_empty() { - panic!("read or write buffer unexpectedly empty"); + return Self { + bank, + spi, + empty_buffer: true, + finished_regularly: core::cell::Cell::new(false), + }; } let index = bank as usize; let full_write_len = core::cmp::max(read.len(), write.len()); @@ -433,6 +451,7 @@ impl<'spi> SpiFuture<'spi> { Self { bank, spi, + empty_buffer: false, finished_regularly: core::cell::Cell::new(false), } } @@ -443,7 +462,12 @@ impl<'spi> SpiFuture<'spi> { words: &mut [u8], ) -> Self { if words.is_empty() { - panic!("read and write buffer unexpectedly empty"); + return Self { + bank, + spi, + empty_buffer: true, + finished_regularly: core::cell::Cell::new(false), + }; } let write_idx = Self::generic_init_transfer_write_transfer_in_place(spi, bank, words); critical_section::with(|cs| { @@ -465,6 +489,7 @@ impl<'spi> SpiFuture<'spi> { Self { bank, spi, + empty_buffer: false, finished_regularly: core::cell::Cell::new(false), } } @@ -522,6 +547,9 @@ impl<'spi> Future for SpiFuture<'spi> { self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> core::task::Poll { + if self.empty_buffer { + return core::task::Poll::Ready(Ok(())); + } WAKERS[self.bank as usize].register(cx.waker()); if DONE[self.bank as usize].swap(false, core::sync::atomic::Ordering::Relaxed) { let rx_overrun = critical_section::with(|cs| { @@ -544,7 +572,7 @@ impl<'spi> Future for SpiFuture<'spi> { impl<'spi> Drop for SpiFuture<'spi> { fn drop(&mut self) { - if !self.finished_regularly.get() { + if !self.finished_regularly.get() && !self.empty_buffer { // It might be sufficient to disable and enable the SPI.. But this definitely // ensures the SPI is fully reset. self.spi.regs.write_interrupt_clear(InterruptClear::ALL); @@ -598,12 +626,9 @@ impl SpiAsync { /// This function stores the raw pointer of the passed data buffer. The user MUST ensure /// that the slice outlives the data structure. If the passed slice is stack-allocated, /// the user also MUST ensure that the `Drop` method runs on transfer cancellation. - pub unsafe fn read(&mut self, words: &mut [u8]) -> Option> { - if words.is_empty() { - return None; - } + pub unsafe fn read(&mut self, words: &mut [u8]) -> SpiFuture<'_> { let id = self.0.id; - Some(SpiFuture::new_for_read(&mut self.0, id, words)) + SpiFuture::new_for_read(&mut self.0, id, words) } /// Future which writes `words` to the slave, ignoring all the incoming words. @@ -615,12 +640,9 @@ impl SpiAsync { /// This function stores the raw pointer of the passed data. The user MUST ensure /// that the slice outlives the data structure. If the passed slice is stack-allocated, /// the user also MUST ensure that the `Drop` method runs on transfer cancellation. - pub unsafe fn write(&mut self, words: &[u8]) -> Option> { - if words.is_empty() { - return None; - } + pub unsafe fn write(&mut self, words: &[u8]) -> SpiFuture<'_> { let id = self.0.id; - Some(SpiFuture::new_for_write(&mut self.0, id, words)) + SpiFuture::new_for_write(&mut self.0, id, words) } /// Future which writes and reads simultaneously. `write` is written to the slave on MOSI and @@ -638,12 +660,9 @@ impl SpiAsync { /// This function stores the raw pointer of the passed slices. The user MUST ensure /// that the slice outlives the data structure. If the passed slice is stack-allocated, /// the user also MUST ensure that the `Drop` method runs on transfer cancellation. - pub unsafe fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Option> { - if read.is_empty() || write.is_empty() { - return None; - } + pub unsafe fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> SpiFuture<'_> { let id = self.0.id; - Some(SpiFuture::new_for_transfer(&mut self.0, id, read, write)) + SpiFuture::new_for_transfer(&mut self.0, id, read, write) } /// Future which writes and reads simultaneously. The contents of `words` are @@ -657,12 +676,9 @@ impl SpiAsync { /// This function stores the raw pointer of the passed slice. The user MUST ensure /// that the slice outlives the data structure. If the passed slice is stack-allocated, /// the user also MUST ensure that the `Drop` method runs on transfer cancellation. - pub unsafe fn transfer_in_place(&mut self, words: &mut [u8]) -> Option> { - if words.is_empty() { - return None; - } + pub unsafe fn transfer_in_place(&mut self, words: &mut [u8]) -> SpiFuture<'_> { let id = self.0.id; - Some(SpiFuture::new_for_transfer_in_place(&mut self.0, id, words)) + SpiFuture::new_for_transfer_in_place(&mut self.0, id, words) } } @@ -682,7 +698,7 @@ impl embedded_hal_async::spi::SpiBus for SpiAsync { if words.is_empty() { return Ok(()); } - unsafe { self.read(words).unwrap().await } + unsafe { self.read(words).await } } /// Write `words` to the slave, ignoring all the incoming words. @@ -696,7 +712,7 @@ impl embedded_hal_async::spi::SpiBus for SpiAsync { if words.is_empty() { return Ok(()); } - unsafe { self.write(words).unwrap().await } + unsafe { self.write(words).await } } /// Write and read simultaneously. `write` is written to the slave on MOSI and @@ -716,7 +732,7 @@ impl embedded_hal_async::spi::SpiBus for SpiAsync { if read.is_empty() && write.is_empty() { return Ok(()); } - unsafe { self.transfer(read, write).unwrap().await } + unsafe { self.transfer(read, write).await } } /// Write and read simultaneously. The contents of `words` are @@ -732,7 +748,7 @@ impl embedded_hal_async::spi::SpiBus for SpiAsync { if words.is_empty() { return Ok(()); } - unsafe { self.transfer_in_place(words).unwrap().await } + unsafe { self.transfer_in_place(words).await } } async fn flush(&mut self) -> Result<(), Self::Error> {