aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
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
parent96a026c73bad2ebb8dfc78e88c9690611bf2cb97 (diff)
low power: store stop mode for dma channels
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/build.rs15
-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
-rw-r--r--embassy-stm32/src/low_power.rs42
-rw-r--r--embassy-stm32/src/rcc/mod.rs59
8 files changed, 150 insertions, 72 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 87a8ef7c9..6e1381925 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9 9
10- change: low power: store stop mode for dma channels
10- fix: Fixed ADC4 enable() for WBA 11- fix: Fixed ADC4 enable() for WBA
11- feat: allow use of anyadcchannel for adc4 12- feat: allow use of anyadcchannel for adc4
12- fix: fix incorrect logic for buffered usart transmission complete. 13- fix: fix incorrect logic for buffered usart transmission complete.
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 8cbd38e10..3277ba440 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1947,6 +1947,19 @@ fn main() {
1947 continue; 1947 continue;
1948 } 1948 }
1949 1949
1950 let stop_mode = METADATA
1951 .peripherals
1952 .iter()
1953 .find(|p| p.name == ch.dma)
1954 .map(|p| p.rcc.as_ref().map(|rcc| rcc.stop_mode.clone()).unwrap_or_default())
1955 .unwrap_or_default();
1956
1957 let stop_mode = match stop_mode {
1958 StopMode::Standby => quote! { Standby },
1959 StopMode::Stop2 => quote! { Stop2 },
1960 StopMode::Stop1 => quote! { Stop1 },
1961 };
1962
1950 let name = format_ident!("{}", ch.name); 1963 let name = format_ident!("{}", ch.name);
1951 let idx = ch_idx as u8; 1964 let idx = ch_idx as u8;
1952 #[cfg(feature = "_dual-core")] 1965 #[cfg(feature = "_dual-core")]
@@ -1959,7 +1972,7 @@ fn main() {
1959 quote!(crate::pac::Interrupt::#irq_name) 1972 quote!(crate::pac::Interrupt::#irq_name)
1960 }; 1973 };
1961 1974
1962 g.extend(quote!(dma_channel_impl!(#name, #idx);)); 1975 g.extend(quote!(dma_channel_impl!(#name, #idx, #stop_mode);));
1963 1976
1964 let dma = format_ident!("{}", ch.dma); 1977 let dma = format_ident!("{}", ch.dma);
1965 let ch_num = ch.channel as usize; 1978 let ch_num = ch.channel as usize;
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
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 9de49c867..bd8290da0 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -50,7 +50,8 @@ use critical_section::CriticalSection;
50use embassy_executor::*; 50use embassy_executor::*;
51 51
52use crate::interrupt; 52use crate::interrupt;
53use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2}; 53pub use crate::rcc::StopMode;
54use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2, decrement_stop_refcount, increment_stop_refcount};
54use crate::time_driver::get_driver; 55use crate::time_driver::get_driver;
55 56
56const THREAD_PENDER: usize = usize::MAX; 57const THREAD_PENDER: usize = usize::MAX;
@@ -73,15 +74,8 @@ impl DeviceBusy {
73 74
74 /// Create a new DeviceBusy. 75 /// Create a new DeviceBusy.
75 pub fn new(stop_mode: StopMode) -> Self { 76 pub fn new(stop_mode: StopMode) -> Self {
76 critical_section::with(|_| unsafe { 77 critical_section::with(|cs| {
77 match stop_mode { 78 increment_stop_refcount(cs, stop_mode);
78 StopMode::Stop1 => {
79 crate::rcc::REFCOUNT_STOP1 += 1;
80 }
81 StopMode::Stop2 => {
82 crate::rcc::REFCOUNT_STOP2 += 1;
83 }
84 }
85 }); 79 });
86 80
87 Self(stop_mode) 81 Self(stop_mode)
@@ -90,15 +84,8 @@ impl DeviceBusy {
90 84
91impl Drop for DeviceBusy { 85impl Drop for DeviceBusy {
92 fn drop(&mut self) { 86 fn drop(&mut self) {
93 critical_section::with(|_| unsafe { 87 critical_section::with(|cs| {
94 match self.0 { 88 decrement_stop_refcount(cs, self.0);
95 StopMode::Stop1 => {
96 crate::rcc::REFCOUNT_STOP1 -= 1;
97 }
98 StopMode::Stop2 => {
99 crate::rcc::REFCOUNT_STOP2 -= 1;
100 }
101 }
102 }); 89 });
103 } 90 }
104} 91}
@@ -131,22 +118,12 @@ foreach_interrupt! {
131/// prevents entering the given stop mode. 118/// prevents entering the given stop mode.
132pub fn stop_ready(stop_mode: StopMode) -> bool { 119pub fn stop_ready(stop_mode: StopMode) -> bool {
133 critical_section::with(|cs| match Executor::stop_mode(cs) { 120 critical_section::with(|cs| match Executor::stop_mode(cs) {
134 Some(StopMode::Stop2) => true, 121 Some(StopMode::Standby | StopMode::Stop2) => true,
135 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, 122 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
136 None => false, 123 None => false,
137 }) 124 })
138} 125}
139 126
140/// Available Stop modes.
141#[non_exhaustive]
142#[derive(PartialEq)]
143pub enum StopMode {
144 /// STOP 1
145 Stop1,
146 /// STOP 2
147 Stop2,
148}
149
150#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))] 127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))]
151use crate::pac::pwr::vals::Lpms; 128use crate::pac::pwr::vals::Lpms;
152 129
@@ -156,9 +133,9 @@ impl Into<Lpms> for StopMode {
156 match self { 133 match self {
157 StopMode::Stop1 => Lpms::STOP1, 134 StopMode::Stop1 => Lpms::STOP1,
158 #[cfg(not(any(stm32wb, stm32wba)))] 135 #[cfg(not(any(stm32wb, stm32wba)))]
159 StopMode::Stop2 => Lpms::STOP2, 136 StopMode::Standby | StopMode::Stop2 => Lpms::STOP2,
160 #[cfg(any(stm32wb, stm32wba))] 137 #[cfg(any(stm32wb, stm32wba))]
161 StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2? 138 StopMode::Standby | StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2?
162 } 139 }
163 } 140 }
164} 141}
@@ -230,6 +207,7 @@ impl Executor {
230 } 207 }
231 208
232 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { 209 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> {
210 // We cannot enter standby because we will lose program state.
233 if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } { 211 if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } {
234 trace!("low power: stop 2"); 212 trace!("low power: stop 2");
235 Some(StopMode::Stop2) 213 Some(StopMode::Stop2)
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 66ee06e17..85434fa83 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -111,6 +111,32 @@ pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clo
111 unsafe { get_freqs() } 111 unsafe { get_freqs() }
112} 112}
113 113
114#[cfg(feature = "low-power")]
115pub(crate) fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
116 match stop_mode {
117 StopMode::Standby => {}
118 StopMode::Stop2 => unsafe {
119 REFCOUNT_STOP2 += 1;
120 },
121 StopMode::Stop1 => unsafe {
122 REFCOUNT_STOP1 += 1;
123 },
124 }
125}
126
127#[cfg(feature = "low-power")]
128pub(crate) fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
129 match stop_mode {
130 StopMode::Standby => {}
131 StopMode::Stop2 => unsafe {
132 REFCOUNT_STOP2 -= 1;
133 },
134 StopMode::Stop1 => unsafe {
135 REFCOUNT_STOP1 -= 1;
136 },
137 }
138}
139
114pub(crate) trait SealedRccPeripheral { 140pub(crate) trait SealedRccPeripheral {
115 fn frequency() -> Hertz; 141 fn frequency() -> Hertz;
116 #[allow(dead_code)] 142 #[allow(dead_code)]
@@ -141,12 +167,19 @@ pub(crate) struct RccInfo {
141 stop_mode: StopMode, 167 stop_mode: StopMode,
142} 168}
143 169
170/// Specifies a limit for the stop mode of the peripheral or the stop mode to be entered.
171/// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode.
144#[cfg(feature = "low-power")] 172#[cfg(feature = "low-power")]
145#[allow(dead_code)] 173#[allow(dead_code)]
146pub(crate) enum StopMode { 174#[derive(Debug, Clone, Copy, PartialEq, Default)]
147 Standby, 175pub enum StopMode {
148 Stop2, 176 #[default]
177 /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1
149 Stop1, 178 Stop1,
179 /// Peripheral prevents chip from entering Stop2 or executor will enter Stop2
180 Stop2,
181 /// Peripheral does not prevent chip from entering Stop
182 Standby,
150} 183}
151 184
152impl RccInfo { 185impl RccInfo {
@@ -202,15 +235,7 @@ impl RccInfo {
202 } 235 }
203 236
204 #[cfg(feature = "low-power")] 237 #[cfg(feature = "low-power")]
205 match self.stop_mode { 238 increment_stop_refcount(_cs, self.stop_mode);
206 StopMode::Standby => {}
207 StopMode::Stop2 => unsafe {
208 REFCOUNT_STOP2 += 1;
209 },
210 StopMode::Stop1 => unsafe {
211 REFCOUNT_STOP1 += 1;
212 },
213 }
214 239
215 // set the xxxRST bit 240 // set the xxxRST bit
216 let reset_ptr = self.reset_ptr(); 241 let reset_ptr = self.reset_ptr();
@@ -268,15 +293,7 @@ impl RccInfo {
268 } 293 }
269 294
270 #[cfg(feature = "low-power")] 295 #[cfg(feature = "low-power")]
271 match self.stop_mode { 296 decrement_stop_refcount(_cs, self.stop_mode);
272 StopMode::Standby => {}
273 StopMode::Stop2 => unsafe {
274 REFCOUNT_STOP2 -= 1;
275 },
276 StopMode::Stop1 => unsafe {
277 REFCOUNT_STOP1 -= 1;
278 },
279 }
280 297
281 // clear the xxxEN bit 298 // clear the xxxEN bit
282 let enable_ptr = self.enable_ptr(); 299 let enable_ptr = self.enable_ptr();