From d705a4f5bc5ee23dda08c2d2ac35305af46bdd3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 24 Sep 2024 15:47:07 +0200 Subject: [PATCH] Wait for the peripheral to become idle --- esp-hal/src/spi/master.rs | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 71ec29981d..e114e07e88 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -1276,32 +1276,45 @@ mod dma { /// /// Interrupts are not enabled at the peripheral level here. pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.wait_for_idle(); self.spi.set_interrupt_handler(handler); } /// Listen for the given interrupts #[cfg(gdma)] pub fn listen(&mut self, interrupts: EnumSet) { + self.wait_for_idle(); self.spi.listen(interrupts); } /// Unlisten the given interrupts #[cfg(gdma)] pub fn unlisten(&mut self, interrupts: EnumSet) { + self.wait_for_idle(); self.spi.unlisten(interrupts); } /// Gets asserted interrupts #[cfg(gdma)] pub fn interrupts(&mut self) -> EnumSet { + self.wait_for_idle(); self.spi.interrupts() } /// Resets asserted interrupts #[cfg(gdma)] pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + self.wait_for_idle(); self.spi.clear_interrupts(interrupts); } + + fn wait_for_idle(&self) { + // TODO: don't ignore DMA status. We can move the transfer's logic here. + while self.spi.busy() { + // Wait for the SPI to become idle + } + fence(Ordering::Acquire); + } } impl<'d, T, C, D, M> crate::private::Sealed for SpiDma<'d, T, C, D, M> @@ -1540,6 +1553,8 @@ mod dma { self, buffer: TX, ) -> Result, (Error, Self, TX)> { + self.wait_for_idle(); + self.do_dma_write(buffer) } @@ -1554,6 +1569,8 @@ mod dma { self, buffer: RX, ) -> Result, (Error, Self, RX)> { + self.wait_for_idle(); + self.do_dma_read(buffer) } @@ -1568,6 +1585,8 @@ mod dma { rx_buffer: RX, tx_buffer: TX, ) -> Result, (Error, Self, RX, TX)> { + self.wait_for_idle(); + self.do_dma_transfer(rx_buffer, tx_buffer) } } @@ -1590,6 +1609,8 @@ mod dma { dummy: u8, buffer: RX, ) -> Result, (Error, Self, RX)> { + self.wait_for_idle(); + self.do_half_duplex_read(data_mode, cmd, address, dummy, buffer) } @@ -1604,6 +1625,8 @@ mod dma { dummy: u8, buffer: TX, ) -> Result, (Error, Self, TX)> { + self.wait_for_idle(); + self.do_half_duplex_write(data_mode, cmd, address, dummy, buffer) } } @@ -1643,6 +1666,10 @@ mod dma { } } + fn wait_for_idle(&mut self) { + self.spi_dma.wait_for_idle(); + } + /// Sets the interrupt handler /// /// Interrupts are not enabled at the peripheral level here. @@ -1713,6 +1740,7 @@ mod dma { { /// Reads data from the SPI bus using DMA. pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> { + self.wait_for_idle(); for chunk in words.chunks_mut(self.rx_buf.capacity()) { self.rx_buf.set_length(chunk.len()); @@ -1731,6 +1759,7 @@ mod dma { /// Writes data to the SPI bus using DMA. pub fn write(&mut self, words: &[u8]) -> Result<(), Error> { + self.wait_for_idle(); for chunk in words.chunks(self.tx_buf.capacity()) { self.tx_buf.fill(chunk); @@ -1746,6 +1775,7 @@ mod dma { /// Transfers data to and from the SPI bus simultaneously using DMA. pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { + self.wait_for_idle(); let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity()); let common_length = min(read.len(), write.len()); @@ -1781,6 +1811,7 @@ mod dma { /// Transfers data in place on the SPI bus using DMA. pub fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> { + self.wait_for_idle(); let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity()); for chunk in words.chunks_mut(chunk_size) { @@ -1823,6 +1854,7 @@ mod dma { if buffer.len() > self.rx_buf.capacity() { return Err(Error::DmaError(DmaError::Overflow)); } + self.wait_for_idle(); self.rx_buf.set_length(buffer.len()); let rx_buffer = DmaRxBufferRef::new(&mut self.rx_buf); @@ -1850,6 +1882,7 @@ mod dma { if buffer.len() > self.tx_buf.capacity() { return Err(Error::DmaError(DmaError::Overflow)); } + self.wait_for_idle(); self.tx_buf.fill(buffer); let tx_buffer = DmaTxBufferRef::new(&mut self.tx_buf); @@ -1908,8 +1941,22 @@ mod dma { C: DmaChannel, C::P: SpiPeripheral, { + async fn wait_for_idle_async(&mut self) { + core::future::poll_fn(|cx| { + use core::task::Poll; + if !self.spi_dma.spi().busy() { + Poll::Ready(()) + } else { + cx.waker().wake_by_ref(); + Poll::Pending + } + }) + .await; + } + /// Fill the given buffer with data from the bus. pub async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> { + self.wait_for_idle_async().await; let chunk_size = self.rx_buf.capacity(); for chunk in words.chunks_mut(chunk_size) { @@ -1930,6 +1977,7 @@ mod dma { /// Transmit the given buffer to the bus. pub async fn write_async(&mut self, words: &[u8]) -> Result<(), Error> { + self.wait_for_idle_async().await; let chunk_size = self.tx_buf.capacity(); for chunk in words.chunks(chunk_size) { @@ -1952,6 +2000,7 @@ mod dma { read: &mut [u8], write: &[u8], ) -> Result<(), Error> { + self.wait_for_idle_async().await; let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity()); let common_length = min(read.len(), write.len()); @@ -1988,6 +2037,7 @@ mod dma { /// Transfer by writing out a buffer and reading the response from /// the bus into the same buffer. pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), Error> { + self.wait_for_idle_async().await; for chunk in words.chunks_mut(self.tx_buf.capacity()) { self.tx_buf.fill(chunk); self.rx_buf.set_length(chunk.len());