aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-30 09:25:58 -0500
committerxoviat <[email protected]>2023-07-30 09:25:58 -0500
commitfd9b6487e12dff80bf9e23cba474af5d8773c8a7 (patch)
tree1eb9b70ce491c9a9ad75729c189ed3c176a8951a /embassy-stm32
parent603c4cb4fa5f3dc2d95c5e47f13149beaa227bf5 (diff)
stm32/dma: impl. wringbuf for bdma
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/src/dma/bdma.rs154
-rw-r--r--embassy-stm32/src/dma/dma.rs4
2 files changed, 155 insertions, 3 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 7b5008f07..2905338de 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -9,7 +9,7 @@ use atomic_polyfill::AtomicUsize;
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer}; 12use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer};
13use super::word::{Word, WordSize}; 13use super::word::{Word, WordSize};
14use super::Dir; 14use super::Dir;
15use crate::_generated::BDMA_CHANNEL_COUNT; 15use crate::_generated::BDMA_CHANNEL_COUNT;
@@ -559,3 +559,155 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
559 fence(Ordering::SeqCst); 559 fence(Ordering::SeqCst);
560 } 560 }
561} 561}
562
563pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
564 cr: regs::Cr,
565 channel: PeripheralRef<'a, C>,
566 ringbuf: WritableDmaRingBuffer<'a, W>,
567}
568
569impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
570 pub unsafe fn new_write(
571 channel: impl Peripheral<P = C> + 'a,
572 _request: Request,
573 peri_addr: *mut W,
574 buffer: &'a mut [W],
575 _options: TransferOptions,
576 ) -> Self {
577 into_ref!(channel);
578
579 let len = buffer.len();
580 assert!(len > 0 && len <= 0xFFFF);
581
582 let dir = Dir::MemoryToPeripheral;
583 let data_size = W::size();
584
585 let channel_number = channel.num();
586 let dma = channel.regs();
587
588 // "Preceding reads and writes cannot be moved past subsequent writes."
589 fence(Ordering::SeqCst);
590
591 #[cfg(bdma_v2)]
592 critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request)));
593
594 let mut w = regs::Cr(0);
595 w.set_psize(data_size.into());
596 w.set_msize(data_size.into());
597 w.set_minc(vals::Inc::ENABLED);
598 w.set_dir(dir.into());
599 w.set_teie(true);
600 w.set_htie(true);
601 w.set_tcie(true);
602 w.set_circ(vals::Circ::ENABLED);
603 w.set_pl(vals::Pl::VERYHIGH);
604 w.set_en(true);
605
606 let buffer_ptr = buffer.as_mut_ptr();
607 let mut this = Self {
608 channel,
609 cr: w,
610 ringbuf: WritableDmaRingBuffer::new(buffer),
611 };
612 this.clear_irqs();
613
614 #[cfg(dmamux)]
615 super::dmamux::configure_dmamux(&mut *this.channel, _request);
616
617 let ch = dma.ch(channel_number);
618 ch.par().write_value(peri_addr as u32);
619 ch.mar().write_value(buffer_ptr as u32);
620 ch.ndtr().write(|w| w.set_ndt(len as u16));
621
622 this
623 }
624
625 pub fn start(&mut self) {
626 let ch = self.channel.regs().ch(self.channel.num());
627 ch.cr().write_value(self.cr)
628 }
629
630 pub fn clear(&mut self) {
631 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
632 }
633
634 /// Write elements from the ring buffer
635 /// Return a tuple of the length written and the length remaining in the buffer
636 pub fn read(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
637 self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf)
638 }
639
640 /// Write an exact number of elements to the ringbuffer.
641 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
642 use core::future::poll_fn;
643 use core::sync::atomic::compiler_fence;
644
645 let mut written_data = 0;
646 let buffer_len = buffer.len();
647
648 poll_fn(|cx| {
649 self.set_waker(cx.waker());
650
651 compiler_fence(Ordering::SeqCst);
652
653 match self.read(&buffer[written_data..buffer_len]) {
654 Ok((len, remaining)) => {
655 written_data += len;
656 if written_data == buffer_len {
657 Poll::Ready(Ok(remaining))
658 } else {
659 Poll::Pending
660 }
661 }
662 Err(e) => Poll::Ready(Err(e)),
663 }
664 })
665 .await
666 }
667
668 /// The capacity of the ringbuffer.
669 pub fn cap(&self) -> usize {
670 self.ringbuf.cap()
671 }
672
673 pub fn set_waker(&mut self, waker: &Waker) {
674 STATE.ch_wakers[self.channel.index()].register(waker);
675 }
676
677 fn clear_irqs(&mut self) {
678 let dma = self.channel.regs();
679 dma.ifcr().write(|w| {
680 w.set_htif(self.channel.num(), true);
681 w.set_tcif(self.channel.num(), true);
682 w.set_teif(self.channel.num(), true);
683 });
684 }
685
686 pub fn request_stop(&mut self) {
687 let ch = self.channel.regs().ch(self.channel.num());
688
689 // Disable the channel. Keep the IEs enabled so the irqs still fire.
690 // If the channel is enabled and transfer is not completed, we need to perform
691 // two separate write access to the CR register to disable the channel.
692 ch.cr().write(|w| {
693 w.set_teie(true);
694 w.set_htie(true);
695 w.set_tcie(true);
696 });
697 }
698
699 pub fn is_running(&mut self) -> bool {
700 let ch = self.channel.regs().ch(self.channel.num());
701 ch.cr().read().en()
702 }
703}
704
705impl<'a, C: Channel, W: Word> Drop for WritableRingBuffer<'a, C, W> {
706 fn drop(&mut self) {
707 self.request_stop();
708 while self.is_running() {}
709
710 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
711 fence(Ordering::SeqCst);
712 }
713}
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 3c5c79fd8..9cd7aa8d5 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -814,7 +814,7 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
814} 814}
815 815
816impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { 816impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
817 pub unsafe fn new_read( 817 pub unsafe fn new_write(
818 channel: impl Peripheral<P = C> + 'a, 818 channel: impl Peripheral<P = C> + 'a,
819 _request: Request, 819 _request: Request,
820 peri_addr: *mut W, 820 peri_addr: *mut W,
@@ -899,7 +899,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
899 self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf) 899 self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf)
900 } 900 }
901 901
902 /// Write an exact number of elements from the ringbuffer. 902 /// Write an exact number of elements to the ringbuffer.
903 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { 903 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
904 use core::future::poll_fn; 904 use core::future::poll_fn;
905 use core::sync::atomic::compiler_fence; 905 use core::sync::atomic::compiler_fence;