aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/dma
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-21 18:55:27 -0600
committerxoviat <[email protected]>2025-11-21 18:55:27 -0600
commit5d3d485a73cd1b1cff4077914ca1103e0cf6b84b (patch)
treea0c8c2ac500f07f4ae7de87d72f8ff32d2ef7313 /embassy-stm32/src/dma
parent96a026c73bad2ebb8dfc78e88c9690611bf2cb97 (diff)
low power: store stop mode for dma channels
Diffstat (limited to 'embassy-stm32/src/dma')
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs16
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs13
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs10
-rw-r--r--embassy-stm32/src/dma/mod.rs66
4 files changed, 87 insertions, 18 deletions
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index 90dbf4f09..b46ae2813 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -8,7 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 9use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
10use super::word::{Word, WordSize}; 10use super::word::{Word, WordSize};
11use super::{AnyChannel, Channel, Dir, Request, STATE}; 11use super::{AnyChannel, BusyChannel, Channel, Dir, Request, STATE};
12use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac}; 13use crate::{interrupt, pac};
14 14
@@ -602,7 +602,7 @@ impl AnyChannel {
602/// DMA transfer. 602/// DMA transfer.
603#[must_use = "futures do nothing unless you `.await` or poll them"] 603#[must_use = "futures do nothing unless you `.await` or poll them"]
604pub struct Transfer<'a> { 604pub struct Transfer<'a> {
605 channel: Peri<'a, AnyChannel>, 605 channel: BusyChannel<'a>,
606} 606}
607 607
608impl<'a> Transfer<'a> { 608impl<'a> Transfer<'a> {
@@ -713,7 +713,9 @@ impl<'a> Transfer<'a> {
713 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options, 713 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options,
714 ); 714 );
715 channel.start(); 715 channel.start();
716 Self { channel } 716 Self {
717 channel: BusyChannel::new(channel),
718 }
717 } 719 }
718 720
719 /// Request the transfer to pause, keeping the existing configuration for this channel. 721 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -816,7 +818,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
816 818
817/// Ringbuffer for receiving data using DMA circular mode. 819/// Ringbuffer for receiving data using DMA circular mode.
818pub struct ReadableRingBuffer<'a, W: Word> { 820pub struct ReadableRingBuffer<'a, W: Word> {
819 channel: Peri<'a, AnyChannel>, 821 channel: BusyChannel<'a>,
820 ringbuf: ReadableDmaRingBuffer<'a, W>, 822 ringbuf: ReadableDmaRingBuffer<'a, W>,
821} 823}
822 824
@@ -853,7 +855,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
853 ); 855 );
854 856
855 Self { 857 Self {
856 channel, 858 channel: BusyChannel::new(channel),
857 ringbuf: ReadableDmaRingBuffer::new(buffer), 859 ringbuf: ReadableDmaRingBuffer::new(buffer),
858 } 860 }
859 } 861 }
@@ -972,7 +974,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
972 974
973/// Ringbuffer for writing data using DMA circular mode. 975/// Ringbuffer for writing data using DMA circular mode.
974pub struct WritableRingBuffer<'a, W: Word> { 976pub struct WritableRingBuffer<'a, W: Word> {
975 channel: Peri<'a, AnyChannel>, 977 channel: BusyChannel<'a>,
976 ringbuf: WritableDmaRingBuffer<'a, W>, 978 ringbuf: WritableDmaRingBuffer<'a, W>,
977} 979}
978 980
@@ -1009,7 +1011,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
1009 ); 1011 );
1010 1012
1011 Self { 1013 Self {
1012 channel, 1014 channel: BusyChannel::new(channel),
1013 ringbuf: WritableDmaRingBuffer::new(buffer), 1015 ringbuf: WritableDmaRingBuffer::new(buffer),
1014 } 1016 }
1015 } 1017 }
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs
index 106558d20..383c74a78 100644
--- a/embassy-stm32/src/dma/gpdma/mod.rs
+++ b/embassy-stm32/src/dma/gpdma/mod.rs
@@ -11,6 +11,7 @@ use linked_list::Table;
11 11
12use super::word::{Word, WordSize}; 12use super::word::{Word, WordSize};
13use super::{AnyChannel, Channel, Dir, Request, STATE}; 13use super::{AnyChannel, Channel, Dir, Request, STATE};
14use crate::dma::BusyChannel;
14use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
15use crate::pac; 16use crate::pac;
16use crate::pac::gpdma::vals; 17use crate::pac::gpdma::vals;
@@ -408,7 +409,7 @@ impl AnyChannel {
408/// Linked-list DMA transfer. 409/// Linked-list DMA transfer.
409#[must_use = "futures do nothing unless you `.await` or poll them"] 410#[must_use = "futures do nothing unless you `.await` or poll them"]
410pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { 411pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> {
411 channel: Peri<'a, AnyChannel>, 412 channel: BusyChannel<'a>,
412} 413}
413 414
414impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { 415impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
@@ -429,7 +430,9 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
429 channel.configure_linked_list(&table, options); 430 channel.configure_linked_list(&table, options);
430 channel.start(); 431 channel.start();
431 432
432 Self { channel } 433 Self {
434 channel: BusyChannel::new(channel),
435 }
433 } 436 }
434 437
435 /// Request the transfer to pause, keeping the existing configuration for this channel. 438 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -505,7 +508,7 @@ impl<'a, const ITEM_COUNT: usize> Future for LinkedListTransfer<'a, ITEM_COUNT>
505/// DMA transfer. 508/// DMA transfer.
506#[must_use = "futures do nothing unless you `.await` or poll them"] 509#[must_use = "futures do nothing unless you `.await` or poll them"]
507pub struct Transfer<'a> { 510pub struct Transfer<'a> {
508 channel: Peri<'a, AnyChannel>, 511 channel: BusyChannel<'a>,
509} 512}
510 513
511impl<'a> Transfer<'a> { 514impl<'a> Transfer<'a> {
@@ -625,7 +628,9 @@ impl<'a> Transfer<'a> {
625 ); 628 );
626 channel.start(); 629 channel.start();
627 630
628 Self { channel } 631 Self {
632 channel: BusyChannel::new(channel),
633 }
629 } 634 }
630 635
631 /// Request the transfer to pause, keeping the existing configuration for this channel. 636 /// Request the transfer to pause, keeping the existing configuration for this channel.
diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
index 94c597e0d..54e4d5f71 100644
--- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs
+++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
@@ -12,7 +12,7 @@ use super::{AnyChannel, STATE, TransferOptions};
12use crate::dma::gpdma::linked_list::{RunMode, Table}; 12use crate::dma::gpdma::linked_list::{RunMode, Table};
13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
14use crate::dma::word::Word; 14use crate::dma::word::Word;
15use crate::dma::{Channel, Dir, Request}; 15use crate::dma::{BusyChannel, Channel, Dir, Request};
16 16
17struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); 17struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>);
18 18
@@ -49,7 +49,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
49 49
50/// Ringbuffer for receiving data using GPDMA linked-list mode. 50/// Ringbuffer for receiving data using GPDMA linked-list mode.
51pub struct ReadableRingBuffer<'a, W: Word> { 51pub struct ReadableRingBuffer<'a, W: Word> {
52 channel: Peri<'a, AnyChannel>, 52 channel: BusyChannel<'a>,
53 ringbuf: ReadableDmaRingBuffer<'a, W>, 53 ringbuf: ReadableDmaRingBuffer<'a, W>,
54 table: Table<2>, 54 table: Table<2>,
55 options: TransferOptions, 55 options: TransferOptions,
@@ -70,7 +70,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
70 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory); 70 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory);
71 71
72 Self { 72 Self {
73 channel, 73 channel: BusyChannel::new(channel),
74 ringbuf: ReadableDmaRingBuffer::new(buffer), 74 ringbuf: ReadableDmaRingBuffer::new(buffer),
75 table, 75 table,
76 options, 76 options,
@@ -189,7 +189,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
189 189
190/// Ringbuffer for writing data using GPDMA linked-list mode. 190/// Ringbuffer for writing data using GPDMA linked-list mode.
191pub struct WritableRingBuffer<'a, W: Word> { 191pub struct WritableRingBuffer<'a, W: Word> {
192 channel: Peri<'a, AnyChannel>, 192 channel: BusyChannel<'a>,
193 ringbuf: WritableDmaRingBuffer<'a, W>, 193 ringbuf: WritableDmaRingBuffer<'a, W>,
194 table: Table<2>, 194 table: Table<2>,
195 options: TransferOptions, 195 options: TransferOptions,
@@ -210,7 +210,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
210 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral); 210 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral);
211 211
212 Self { 212 Self {
213 channel, 213 channel: BusyChannel::new(channel),
214 ringbuf: WritableDmaRingBuffer::new(buffer), 214 ringbuf: WritableDmaRingBuffer::new(buffer),
215 table, 215 table,
216 options, 216 options,
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index de7a2c175..4becc2d87 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -3,11 +3,14 @@
3 3
4#[cfg(any(bdma, dma))] 4#[cfg(any(bdma, dma))]
5mod dma_bdma; 5mod dma_bdma;
6use core::ops;
7
6#[cfg(any(bdma, dma))] 8#[cfg(any(bdma, dma))]
7pub use dma_bdma::*; 9pub use dma_bdma::*;
8 10
9#[cfg(gpdma)] 11#[cfg(gpdma)]
10pub(crate) mod gpdma; 12pub(crate) mod gpdma;
13use embassy_hal_internal::Peri;
11#[cfg(gpdma)] 14#[cfg(gpdma)]
12pub use gpdma::ringbuffered::*; 15pub use gpdma::ringbuffered::*;
13#[cfg(gpdma)] 16#[cfg(gpdma)]
@@ -48,6 +51,8 @@ pub type Request = ();
48pub(crate) trait SealedChannel { 51pub(crate) trait SealedChannel {
49 #[cfg(not(stm32n6))] 52 #[cfg(not(stm32n6))]
50 fn id(&self) -> u8; 53 fn id(&self) -> u8;
54 #[cfg(feature = "low-power")]
55 fn stop_mode(&self) -> crate::rcc::StopMode;
51} 56}
52 57
53#[cfg(not(stm32n6))] 58#[cfg(not(stm32n6))]
@@ -62,15 +67,25 @@ pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {
62 67
63#[cfg(not(stm32n6))] 68#[cfg(not(stm32n6))]
64macro_rules! dma_channel_impl { 69macro_rules! dma_channel_impl {
65 ($channel_peri:ident, $index:expr) => { 70 ($channel_peri:ident, $index:expr, $stop_mode:ident) => {
66 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { 71 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri {
67 fn id(&self) -> u8 { 72 fn id(&self) -> u8 {
68 $index 73 $index
69 } 74 }
75
76 #[cfg(feature = "low-power")]
77 fn stop_mode(&self) -> crate::rcc::StopMode {
78 crate::rcc::StopMode::$stop_mode
79 }
70 } 80 }
71 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { 81 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri {
72 unsafe fn on_irq() { 82 unsafe fn on_irq() {
73 crate::dma::AnyChannel { id: $index }.on_irq(); 83 crate::dma::AnyChannel {
84 id: $index,
85 #[cfg(feature = "low-power")]
86 stop_mode: crate::rcc::StopMode::$stop_mode,
87 }
88 .on_irq();
74 } 89 }
75 } 90 }
76 91
@@ -80,15 +95,57 @@ macro_rules! dma_channel_impl {
80 fn from(val: crate::peripherals::$channel_peri) -> Self { 95 fn from(val: crate::peripherals::$channel_peri) -> Self {
81 Self { 96 Self {
82 id: crate::dma::SealedChannel::id(&val), 97 id: crate::dma::SealedChannel::id(&val),
98 #[cfg(feature = "low-power")]
99 stop_mode: crate::dma::SealedChannel::stop_mode(&val),
83 } 100 }
84 } 101 }
85 } 102 }
86 }; 103 };
87} 104}
88 105
106pub(crate) struct BusyChannel<'a> {
107 channel: Peri<'a, AnyChannel>,
108}
109
110impl<'a> BusyChannel<'a> {
111 pub fn new(channel: Peri<'a, AnyChannel>) -> Self {
112 #[cfg(feature = "low-power")]
113 critical_section::with(|cs| {
114 crate::rcc::increment_stop_refcount(cs, channel.stop_mode);
115 });
116
117 Self { channel }
118 }
119}
120
121impl<'a> Drop for BusyChannel<'a> {
122 fn drop(&mut self) {
123 #[cfg(feature = "low-power")]
124 critical_section::with(|cs| {
125 crate::rcc::decrement_stop_refcount(cs, self.stop_mode);
126 });
127 }
128}
129
130impl<'a> ops::Deref for BusyChannel<'a> {
131 type Target = Peri<'a, AnyChannel>;
132
133 fn deref(&self) -> &Self::Target {
134 &self.channel
135 }
136}
137
138impl<'a> ops::DerefMut for BusyChannel<'a> {
139 fn deref_mut(&mut self) -> &mut Self::Target {
140 &mut self.channel
141 }
142}
143
89/// Type-erased DMA channel. 144/// Type-erased DMA channel.
90pub struct AnyChannel { 145pub struct AnyChannel {
91 pub(crate) id: u8, 146 pub(crate) id: u8,
147 #[cfg(feature = "low-power")]
148 pub(crate) stop_mode: crate::rcc::StopMode,
92} 149}
93impl_peripheral!(AnyChannel); 150impl_peripheral!(AnyChannel);
94 151
@@ -103,6 +160,11 @@ impl SealedChannel for AnyChannel {
103 fn id(&self) -> u8 { 160 fn id(&self) -> u8 {
104 self.id 161 self.id
105 } 162 }
163
164 #[cfg(feature = "low-power")]
165 fn stop_mode(&self) -> crate::rcc::StopMode {
166 self.stop_mode
167 }
106} 168}
107impl Channel for AnyChannel {} 169impl Channel for AnyChannel {}
108 170