Skip to content

Commit

Permalink
Wait for the peripheral to become idle
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Sep 24, 2024
1 parent 3904927 commit d705a4f
Showing 1 changed file with 50 additions and 0 deletions.
50 changes: 50 additions & 0 deletions esp-hal/src/spi/master.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<SpiInterrupt>) {
self.wait_for_idle();
self.spi.listen(interrupts);
}

/// Unlisten the given interrupts
#[cfg(gdma)]
pub fn unlisten(&mut self, interrupts: EnumSet<SpiInterrupt>) {
self.wait_for_idle();
self.spi.unlisten(interrupts);
}

/// Gets asserted interrupts
#[cfg(gdma)]
pub fn interrupts(&mut self) -> EnumSet<SpiInterrupt> {
self.wait_for_idle();
self.spi.interrupts()
}

/// Resets asserted interrupts
#[cfg(gdma)]
pub fn clear_interrupts(&mut self, interrupts: EnumSet<SpiInterrupt>) {
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>
Expand Down Expand Up @@ -1540,6 +1553,8 @@ mod dma {
self,
buffer: TX,
) -> Result<SpiDmaTransfer<'d, Self, TX>, (Error, Self, TX)> {
self.wait_for_idle();

self.do_dma_write(buffer)
}

Expand All @@ -1554,6 +1569,8 @@ mod dma {
self,
buffer: RX,
) -> Result<SpiDmaTransfer<'d, Self, RX>, (Error, Self, RX)> {
self.wait_for_idle();

self.do_dma_read(buffer)
}

Expand All @@ -1568,6 +1585,8 @@ mod dma {
rx_buffer: RX,
tx_buffer: TX,
) -> Result<SpiDmaTransfer<'d, Self, (RX, TX)>, (Error, Self, RX, TX)> {
self.wait_for_idle();

self.do_dma_transfer(rx_buffer, tx_buffer)
}
}
Expand All @@ -1590,6 +1609,8 @@ mod dma {
dummy: u8,
buffer: RX,
) -> Result<SpiDmaTransfer<'d, Self, RX>, (Error, Self, RX)> {
self.wait_for_idle();

self.do_half_duplex_read(data_mode, cmd, address, dummy, buffer)
}

Expand All @@ -1604,6 +1625,8 @@ mod dma {
dummy: u8,
buffer: TX,
) -> Result<SpiDmaTransfer<'d, Self, TX>, (Error, Self, TX)> {
self.wait_for_idle();

self.do_half_duplex_write(data_mode, cmd, address, dummy, buffer)
}
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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());

Expand All @@ -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);

Expand All @@ -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());
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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());
Expand Down Expand Up @@ -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());
Expand Down

0 comments on commit d705a4f

Please sign in to comment.