From 7ae28163414d0042c4e06cc02de900e67b62df01 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 17 Nov 2024 23:09:51 +0100 Subject: [PATCH 1/2] feat: SAI/ringbuffer add function to wait for any write error --- embassy-stm32/src/dma/dma_bdma.rs | 7 +++++++ embassy-stm32/src/dma/ringbuffer/mod.rs | 13 +++++++++++++ embassy-stm32/src/sai/mod.rs | 16 ++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 08c7a5508..90160ed50 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -1006,6 +1006,13 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { .await } + /// Wait for any ring buffer write error. + pub async fn write_error(&mut self) -> Result { + self.ringbuf + .write_error(&mut DmaCtrlImpl(self.channel.reborrow())) + .await + } + /// The current length of the ringbuffer pub fn len(&mut self) -> Result { Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 0da8c374f..b7f98fbce 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -260,6 +260,19 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { Ok((written, self.cap() - written)) } + /// Wait for any ring buffer write error. + pub async fn write_error(&mut self, dma: &mut impl DmaCtrl) -> Result { + poll_fn(|cx| { + dma.set_waker(cx.waker()); + + match self.len(dma) { + Ok(_) => Poll::Pending, + Err(e) => Poll::Ready(Err(e)), + } + }) + .await + } + /// Write an exact number of elements to the ringbuffer. pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result { let mut written_data = 0; diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 057b21980..fd61e5339 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1003,6 +1003,22 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { } } + /// Wait until any SAI write error occurs. + /// + /// One useful application for this is stopping playback as soon as the SAI + /// experiences an overrun of the ring buffer. Then, instead of letting + /// the SAI peripheral play the last written buffer over and over again, SAI + /// can be muted or dropped instead. + pub async fn write_error(&mut self) -> Result<(), Error> { + match &mut self.ring_buffer { + RingBuffer::Writable(buffer) => { + buffer.write_error().await?; + Ok(()) + } + _ => return Err(Error::NotATransmitter), + } + } + /// Write data to the SAI ringbuffer. /// /// The first write starts the DMA after filling the ring buffer with the provided data. From ee9ca4470370ae9e0e98a54ceb94ec83da20eb19 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 17 Nov 2024 23:56:45 +0100 Subject: [PATCH 2/2] refactor: naming of wait functions --- embassy-stm32/src/dma/dma_bdma.rs | 4 ++-- embassy-stm32/src/dma/ringbuffer/mod.rs | 2 +- embassy-stm32/src/sai/mod.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 90160ed50..1945c3587 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -1007,9 +1007,9 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { } /// Wait for any ring buffer write error. - pub async fn write_error(&mut self) -> Result { + pub async fn wait_write_error(&mut self) -> Result { self.ringbuf - .write_error(&mut DmaCtrlImpl(self.channel.reborrow())) + .wait_write_error(&mut DmaCtrlImpl(self.channel.reborrow())) .await } diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index b7f98fbce..25bdc7522 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -261,7 +261,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } /// Wait for any ring buffer write error. - pub async fn write_error(&mut self, dma: &mut impl DmaCtrl) -> Result { + pub async fn wait_write_error(&mut self, dma: &mut impl DmaCtrl) -> Result { poll_fn(|cx| { dma.set_waker(cx.waker()); diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index fd61e5339..a8d02f825 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1009,10 +1009,10 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// experiences an overrun of the ring buffer. Then, instead of letting /// the SAI peripheral play the last written buffer over and over again, SAI /// can be muted or dropped instead. - pub async fn write_error(&mut self) -> Result<(), Error> { + pub async fn wait_write_error(&mut self) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Writable(buffer) => { - buffer.write_error().await?; + buffer.wait_write_error().await?; Ok(()) } _ => return Err(Error::NotATransmitter),