diff options
| author | xoviat <[email protected]> | 2025-11-21 18:55:27 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-11-21 18:55:27 -0600 |
| commit | 5d3d485a73cd1b1cff4077914ca1103e0cf6b84b (patch) | |
| tree | a0c8c2ac500f07f4ae7de87d72f8ff32d2ef7313 /embassy-stm32 | |
| parent | 96a026c73bad2ebb8dfc78e88c9690611bf2cb97 (diff) | |
low power: store stop mode for dma channels
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 15 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dma_bdma.rs | 16 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma/mod.rs | 13 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma/ringbuffered.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 66 | ||||
| -rw-r--r-- | embassy-stm32/src/low_power.rs | 42 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 59 |
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 | ||
| 9 | use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; | 9 | use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; |
| 10 | use super::word::{Word, WordSize}; | 10 | use super::word::{Word, WordSize}; |
| 11 | use super::{AnyChannel, Channel, Dir, Request, STATE}; | 11 | use super::{AnyChannel, BusyChannel, Channel, Dir, Request, STATE}; |
| 12 | use crate::interrupt::typelevel::Interrupt; | 12 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::{interrupt, pac}; | 13 | use 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"] |
| 604 | pub struct Transfer<'a> { | 604 | pub struct Transfer<'a> { |
| 605 | channel: Peri<'a, AnyChannel>, | 605 | channel: BusyChannel<'a>, |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | impl<'a> Transfer<'a> { | 608 | impl<'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. |
| 818 | pub struct ReadableRingBuffer<'a, W: Word> { | 820 | pub 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. |
| 974 | pub struct WritableRingBuffer<'a, W: Word> { | 976 | pub 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 | ||
| 12 | use super::word::{Word, WordSize}; | 12 | use super::word::{Word, WordSize}; |
| 13 | use super::{AnyChannel, Channel, Dir, Request, STATE}; | 13 | use super::{AnyChannel, Channel, Dir, Request, STATE}; |
| 14 | use crate::dma::BusyChannel; | ||
| 14 | use crate::interrupt::typelevel::Interrupt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 15 | use crate::pac; | 16 | use crate::pac; |
| 16 | use crate::pac::gpdma::vals; | 17 | use 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"] |
| 410 | pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { | 411 | pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { |
| 411 | channel: Peri<'a, AnyChannel>, | 412 | channel: BusyChannel<'a>, |
| 412 | } | 413 | } |
| 413 | 414 | ||
| 414 | impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { | 415 | impl<'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"] |
| 507 | pub struct Transfer<'a> { | 510 | pub struct Transfer<'a> { |
| 508 | channel: Peri<'a, AnyChannel>, | 511 | channel: BusyChannel<'a>, |
| 509 | } | 512 | } |
| 510 | 513 | ||
| 511 | impl<'a> Transfer<'a> { | 514 | impl<'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}; | |||
| 12 | use crate::dma::gpdma::linked_list::{RunMode, Table}; | 12 | use crate::dma::gpdma::linked_list::{RunMode, Table}; |
| 13 | use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; | 13 | use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; |
| 14 | use crate::dma::word::Word; | 14 | use crate::dma::word::Word; |
| 15 | use crate::dma::{Channel, Dir, Request}; | 15 | use crate::dma::{BusyChannel, Channel, Dir, Request}; |
| 16 | 16 | ||
| 17 | struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); | 17 | struct 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. |
| 51 | pub struct ReadableRingBuffer<'a, W: Word> { | 51 | pub 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. |
| 191 | pub struct WritableRingBuffer<'a, W: Word> { | 191 | pub 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))] |
| 5 | mod dma_bdma; | 5 | mod dma_bdma; |
| 6 | use core::ops; | ||
| 7 | |||
| 6 | #[cfg(any(bdma, dma))] | 8 | #[cfg(any(bdma, dma))] |
| 7 | pub use dma_bdma::*; | 9 | pub use dma_bdma::*; |
| 8 | 10 | ||
| 9 | #[cfg(gpdma)] | 11 | #[cfg(gpdma)] |
| 10 | pub(crate) mod gpdma; | 12 | pub(crate) mod gpdma; |
| 13 | use embassy_hal_internal::Peri; | ||
| 11 | #[cfg(gpdma)] | 14 | #[cfg(gpdma)] |
| 12 | pub use gpdma::ringbuffered::*; | 15 | pub use gpdma::ringbuffered::*; |
| 13 | #[cfg(gpdma)] | 16 | #[cfg(gpdma)] |
| @@ -48,6 +51,8 @@ pub type Request = (); | |||
| 48 | pub(crate) trait SealedChannel { | 51 | pub(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))] |
| 64 | macro_rules! dma_channel_impl { | 69 | macro_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 | ||
| 106 | pub(crate) struct BusyChannel<'a> { | ||
| 107 | channel: Peri<'a, AnyChannel>, | ||
| 108 | } | ||
| 109 | |||
| 110 | impl<'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 | |||
| 121 | impl<'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 | |||
| 130 | impl<'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 | |||
| 138 | impl<'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. |
| 90 | pub struct AnyChannel { | 145 | pub 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 | } |
| 93 | impl_peripheral!(AnyChannel); | 150 | impl_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 | } |
| 107 | impl Channel for AnyChannel {} | 169 | impl 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; | |||
| 50 | use embassy_executor::*; | 50 | use embassy_executor::*; |
| 51 | 51 | ||
| 52 | use crate::interrupt; | 52 | use crate::interrupt; |
| 53 | use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2}; | 53 | pub use crate::rcc::StopMode; |
| 54 | use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2, decrement_stop_refcount, increment_stop_refcount}; | ||
| 54 | use crate::time_driver::get_driver; | 55 | use crate::time_driver::get_driver; |
| 55 | 56 | ||
| 56 | const THREAD_PENDER: usize = usize::MAX; | 57 | const 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 | ||
| 91 | impl Drop for DeviceBusy { | 85 | impl 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. |
| 132 | pub fn stop_ready(stop_mode: StopMode) -> bool { | 119 | pub 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)] | ||
| 143 | pub 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))] |
| 151 | use crate::pac::pwr::vals::Lpms; | 128 | use 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")] | ||
| 115 | pub(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")] | ||
| 128 | pub(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 | |||
| 114 | pub(crate) trait SealedRccPeripheral { | 140 | pub(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)] |
| 146 | pub(crate) enum StopMode { | 174 | #[derive(Debug, Clone, Copy, PartialEq, Default)] |
| 147 | Standby, | 175 | pub 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 | ||
| 152 | impl RccInfo { | 185 | impl 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(); |
