diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 5102330c..39a743e0 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -1,6 +1,6 @@ //! Basic Direct Memory Acccess (BDMA) -use core::future::Future; +use core::future::{poll_fn, Future}; use core::pin::Pin; use core::sync::atomic::{fence, AtomicUsize, Ordering}; use core::task::{Context, Poll, Waker}; @@ -431,6 +431,45 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { } } +struct RingBuffer {} + +impl RingBuffer { + fn is_running(ch: &pac::bdma::Ch) -> bool { + ch.cr().read().en() + } + + fn request_stop(ch: &pac::bdma::Ch) { + // Disable the channel. Keep the IEs enabled so the irqs still fire. + // If the channel is enabled and transfer is not completed, we need to perform + // two separate write access to the CR register to disable the channel. + ch.cr().write(|w| { + w.set_teie(true); + w.set_htie(true); + w.set_tcie(true); + }); + } + + async fn stop(ch: &pac::bdma::Ch, set_waker: &mut dyn FnMut(&Waker)) { + use core::sync::atomic::compiler_fence; + + Self::request_stop(ch); + + //wait until cr.susp reads as true + poll_fn(|cx| { + set_waker(cx.waker()); + + compiler_fence(Ordering::SeqCst); + + if !Self::is_running(ch) { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await + } +} + /// Ringbuffer for reading data using DMA circular mode. pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, @@ -508,6 +547,13 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } + pub async fn stop(&mut self) { + RingBuffer::stop(&self.channel.regs().ch(self.channel.num()), &mut |waker| { + self.set_waker(waker) + }) + .await + } + /// Read elements from the ring buffer /// Return a tuple of the length read and the length remaining in the buffer /// If not all of the elements were read, then there will be some elements in the buffer remaining @@ -557,16 +603,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - // If the channel is enabled and transfer is not completed, we need to perform - // two separate write access to the CR register to disable the channel. - ch.cr().write(|w| { - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - }); + RingBuffer::request_stop(&self.channel.regs().ch(self.channel.num())); } /// Return whether DMA is still running. @@ -574,8 +611,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { /// If this returns `false`, it can be because either the transfer finished, or /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().ch(self.channel.num()); - ch.cr().read().en() + RingBuffer::is_running(&self.channel.regs().ch(self.channel.num())) } } @@ -666,6 +702,20 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); } + /// Write elements directly to the raw buffer. + /// This can be used to fill the buffer before starting the DMA transfer. + #[allow(dead_code)] + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + self.ringbuf.write_immediate(buf) + } + + pub async fn stop(&mut self) { + RingBuffer::stop(&self.channel.regs().ch(self.channel.num()), &mut |waker| { + self.set_waker(waker) + }) + .await + } + /// Write elements to the ring buffer /// Return a tuple of the length written and the length remaining in the buffer pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { @@ -702,16 +752,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { - let ch = self.channel.regs().ch(self.channel.num()); - - // Disable the channel. Keep the IEs enabled so the irqs still fire. - // If the channel is enabled and transfer is not completed, we need to perform - // two separate write access to the CR register to disable the channel. - ch.cr().write(|w| { - w.set_teie(true); - w.set_htie(true); - w.set_tcie(true); - }); + RingBuffer::request_stop(&self.channel.regs().ch(self.channel.num())); } /// Return whether DMA is still running. @@ -719,8 +760,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { /// If this returns `false`, it can be because either the transfer finished, or /// it was requested to stop early with [`request_stop`](Self::request_stop). pub fn is_running(&mut self) -> bool { - let ch = self.channel.regs().ch(self.channel.num()); - ch.cr().read().en() + RingBuffer::is_running(&self.channel.regs().ch(self.channel.num())) } } diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 32586801..29345fa4 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -1,4 +1,4 @@ -use core::future::Future; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::pin::Pin; use core::sync::atomic::{fence, AtomicUsize, Ordering}; @@ -668,6 +668,42 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { } } +struct RingBuffer {} + +impl RingBuffer { + fn is_running(ch: &pac::dma::St) -> bool { + ch.cr().read().en() + } + + fn request_stop(ch: &pac::dma::St) { + ch.cr().write(|w| { + w.set_teie(true); + w.set_htie(true); + w.set_tcie(true); + }); + } + + async fn stop(ch: &pac::dma::St, set_waker: &mut dyn FnMut(&Waker)) { + use core::sync::atomic::compiler_fence; + + Self::request_stop(ch); + + //wait until cr.susp reads as true + poll_fn(|cx| { + set_waker(cx.waker()); + + compiler_fence(Ordering::SeqCst); + + if !Self::is_running(ch) { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await + } +} + /// Ringbuffer for receiving data using DMA circular mode. pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { cr: regs::Cr, @@ -755,6 +791,17 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { ch.cr().write_value(self.cr); } + pub async fn stop(&mut self) { + RingBuffer::stop(&self.channel.regs().st(self.channel.num()), &mut |waker| { + self.set_waker(waker) + }) + .await + } + + pub fn resume(&mut self) { + self.start(); + } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); @@ -930,6 +977,13 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { ch.cr().write_value(self.cr); } + pub async fn stop(&mut self) { + RingBuffer::stop(&self.channel.regs().st(self.channel.num()), &mut |waker| { + self.set_waker(waker) + }) + .await + } + /// Clear all data in the ring buffer. pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); @@ -937,14 +991,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { /// Write elements directly to the raw buffer. /// This can be used to fill the buffer before starting the DMA transfer. + #[allow(dead_code)] pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.write_immediate( - &mut DmaCtrlImpl { - channel: self.channel.reborrow(), - word_size: W::size(), - }, - buf, - ) + self.ringbuf.write_immediate(buf) } /// Write elements from the ring buffer diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index fac9f9ab..29916890 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -491,7 +491,7 @@ impl RingBuffer { }); } - async fn suspend(ch: &pac::gpdma::Channel, set_waker: &mut dyn FnMut(&Waker)) { + async fn stop(ch: &pac::gpdma::Channel, set_waker: &mut dyn FnMut(&Waker)) { use core::sync::atomic::compiler_fence; Self::request_suspend(ch); @@ -504,17 +504,15 @@ impl RingBuffer { let cr = ch.cr().read(); if cr.susp() { - defmt::info!("Ready {}", cr.susp()); Poll::Ready(()) } else { - defmt::info!("still pending {}", cr.susp()); Poll::Pending } }) .await } - fn resume(ch: &pac::gpdma::Channel) { + fn start(ch: &pac::gpdma::Channel) { Self::clear_irqs(ch); ch.cr().modify(|w| { w.set_susp(false); @@ -534,7 +532,7 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { - pub unsafe fn new_read( + pub unsafe fn new( channel: impl Peripheral

+ 'a, request: Request, peri_addr: *mut W, @@ -564,25 +562,21 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { pub fn start(&mut self) { let ch = &self.channel.regs().ch(self.channel.num()); - RingBuffer::clear_irqs(ch); - ch.cr().modify(|w| w.set_en(true)); + RingBuffer::start(ch); + //ch.cr().modify(|w| w.set_en(true)); } - pub fn request_stop(&mut self, ch: &pac::gpdma::Channel) { - ch.cr().modify(|w| w.set_en(false)); + pub fn request_stop(&mut self) { + RingBuffer::request_suspend(&self.channel.regs().ch(self.channel.num())); } - pub async fn suspend(&mut self) { - RingBuffer::suspend(&self.channel.regs().ch(self.channel.num()), &mut |waker| { + pub async fn stop(&mut self) { + RingBuffer::stop(&self.channel.regs().ch(self.channel.num()), &mut |waker| { self.set_waker(waker) }) .await } - pub fn resume(&mut self) { - RingBuffer::resume(&self.channel.regs().ch(self.channel.num())); - } - pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl { channel: self.channel.reborrow(), @@ -648,7 +642,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { fn drop(&mut self) { - RingBuffer::request_suspend(&self.channel.regs().ch(self.channel.num())); + self.request_stop(); while self.is_running() {} // "Subsequent reads and writes cannot be moved ahead of preceding reads." @@ -663,7 +657,7 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> { } impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { - pub unsafe fn new_write( + pub unsafe fn new( channel: impl Peripheral

+ 'a, request: Request, peri_addr: *mut W, @@ -692,26 +686,28 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { } pub fn start(&mut self) { - self.resume(); + RingBuffer::start(&self.channel.regs().ch(self.channel.num())); } - pub async fn suspend(&mut self) { - RingBuffer::suspend(&self.channel.regs().ch(self.channel.num()), &mut |waker| { + pub async fn stop(&mut self) { + RingBuffer::stop(&self.channel.regs().ch(self.channel.num()), &mut |waker| { self.set_waker(waker) }) .await } - pub fn resume(&mut self) { - RingBuffer::resume(&self.channel.regs().ch(self.channel.num())); - } - pub fn request_stop(&mut self) { // reads can be stopped by disabling the enable flag let ch = &self.channel.regs().ch(self.channel.num()); ch.cr().modify(|w| w.set_en(false)); } + /// Write elements directly to the raw buffer. + /// This can be used to fill the buffer before starting the DMA transfer. + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + self.ringbuf.write_immediate(buf) + } + pub fn clear(&mut self) { self.ringbuf.clear(&mut DmaCtrlImpl { channel: self.channel.reborrow(), @@ -731,18 +727,6 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { ) } - /// Write elements directly to the raw buffer. - /// This can be used to fill the buffer before starting the DMA transfer. - pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.ringbuf.write_immediate( - &mut DmaCtrlImpl { - channel: self.channel.reborrow(), - word_size: W::size(), - }, - buf, - ) - } - /// Write an exact number of elements to the ringbuffer. pub async fn write_exact(&mut self, buffer: &[W]) -> Result { self.ringbuf @@ -776,7 +760,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { impl<'a, C: Channel, W: Word> Drop for WritableRingBuffer<'a, C, W> { fn drop(&mut self) { - RingBuffer::request_suspend(&self.channel.regs().ch(self.channel.num())); + self.request_stop(); while self.is_running() {} // "Subsequent reads and writes cannot be moved ahead of preceding reads." diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs index 498ea709..ea78f2ae 100644 --- a/embassy-stm32/src/dma/ringbuffer.rs +++ b/embassy-stm32/src/dma/ringbuffer.rs @@ -264,7 +264,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } /// Write elements directl to the buffer. This should be done before the DMA is started. - pub fn write_immediate(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<(usize, usize), OverrunError> { + pub fn write_immediate(&mut self, buffer: &[W]) -> Result<(usize, usize), OverrunError> { if self.end != 0 { return Err(OverrunError); } diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 9d0f3e65..2ff7e7d4 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1008,17 +1008,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } } - pub async fn suspend(&mut self) { + pub async fn stop(&mut self) { match &mut self.ring_buffer { - RingBuffer::Writable(buffer) => buffer.suspend().await, - RingBuffer::Readable(buffer) => buffer.suspend().await, - } - } - - pub fn resume(&mut self) { - match &mut self.ring_buffer { - RingBuffer::Writable(buffer) => buffer.resume(), - RingBuffer::Readable(buffer) => buffer.resume(), + RingBuffer::Writable(buffer) => buffer.stop().await, + RingBuffer::Readable(buffer) => buffer.stop().await, } } diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 839d6472..7594959d 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -28,6 +28,8 @@ async fn main(_spawner: Spawner) { m: Pllm::DIV2, n: Plln::MUL10, r: Plldiv::DIV1, + p: Plldiv::DIV1, + q: Plldiv::DIV1, }); config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB