From 0847f4ca4657ea2174fc160f96a69f4c916d146e Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 25 Nov 2025 16:53:26 -0600 Subject: stm32: extract busychannel into common api --- embassy-stm32/src/dma/dma_bdma.rs | 15 ++++--- embassy-stm32/src/dma/gpdma/mod.rs | 10 ++--- embassy-stm32/src/dma/gpdma/ringbuffered.rs | 11 ++--- embassy-stm32/src/dma/mod.rs | 50 ++++----------------- embassy-stm32/src/low_power.rs | 22 +++------- embassy-stm32/src/rcc/mod.rs | 68 ++++++++++++++++++++++++++++- embassy-stm32/src/usart/mod.rs | 12 ++--- 7 files changed, 105 insertions(+), 83 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index b46ae2813..adc084474 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -8,8 +8,9 @@ use embassy_sync::waitqueue::AtomicWaker; use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; use super::word::{Word, WordSize}; -use super::{AnyChannel, BusyChannel, Channel, Dir, Request, STATE}; +use super::{AnyChannel, Channel, Dir, Request, STATE}; use crate::interrupt::typelevel::Interrupt; +use crate::rcc::BusyPeripheral; use crate::{interrupt, pac}; pub(crate) struct ChannelInfo { @@ -602,7 +603,7 @@ impl AnyChannel { /// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a> { - channel: BusyChannel<'a>, + channel: BusyPeripheral>, } impl<'a> Transfer<'a> { @@ -714,7 +715,7 @@ impl<'a> Transfer<'a> { ); channel.start(); Self { - channel: BusyChannel::new(channel), + channel: BusyPeripheral::new(channel), } } @@ -818,7 +819,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> { /// Ringbuffer for receiving data using DMA circular mode. pub struct ReadableRingBuffer<'a, W: Word> { - channel: BusyChannel<'a>, + channel: BusyPeripheral>, ringbuf: ReadableDmaRingBuffer<'a, W>, } @@ -855,7 +856,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { ); Self { - channel: BusyChannel::new(channel), + channel: BusyPeripheral::new(channel), ringbuf: ReadableDmaRingBuffer::new(buffer), } } @@ -974,7 +975,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { /// Ringbuffer for writing data using DMA circular mode. pub struct WritableRingBuffer<'a, W: Word> { - channel: BusyChannel<'a>, + channel: BusyPeripheral>, ringbuf: WritableDmaRingBuffer<'a, W>, } @@ -1011,7 +1012,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { ); Self { - channel: BusyChannel::new(channel), + channel: BusyPeripheral::new(channel), ringbuf: WritableDmaRingBuffer::new(buffer), } } diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index 383c74a78..bfd0570f8 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs @@ -11,10 +11,10 @@ use linked_list::Table; use super::word::{Word, WordSize}; use super::{AnyChannel, Channel, Dir, Request, STATE}; -use crate::dma::BusyChannel; use crate::interrupt::typelevel::Interrupt; use crate::pac; use crate::pac::gpdma::vals; +use crate::rcc::BusyPeripheral; pub mod linked_list; pub mod ringbuffered; @@ -409,7 +409,7 @@ impl AnyChannel { /// Linked-list DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { - channel: BusyChannel<'a>, + channel: BusyPeripheral>, } impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { @@ -431,7 +431,7 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { channel.start(); Self { - channel: BusyChannel::new(channel), + channel: BusyPeripheral::new(channel), } } @@ -508,7 +508,7 @@ impl<'a, const ITEM_COUNT: usize> Future for LinkedListTransfer<'a, ITEM_COUNT> /// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a> { - channel: BusyChannel<'a>, + channel: BusyPeripheral>, } impl<'a> Transfer<'a> { @@ -629,7 +629,7 @@ impl<'a> Transfer<'a> { channel.start(); Self { - channel: BusyChannel::new(channel), + channel: BusyPeripheral::new(channel), } } diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs index 54e4d5f71..c150d0b95 100644 --- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs +++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs @@ -12,7 +12,8 @@ use super::{AnyChannel, STATE, TransferOptions}; use crate::dma::gpdma::linked_list::{RunMode, Table}; use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; use crate::dma::word::Word; -use crate::dma::{BusyChannel, Channel, Dir, Request}; +use crate::dma::{Channel, Dir, Request}; +use crate::rcc::BusyPeripheral; struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); @@ -49,7 +50,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> { /// Ringbuffer for receiving data using GPDMA linked-list mode. pub struct ReadableRingBuffer<'a, W: Word> { - channel: BusyChannel<'a>, + channel: BusyPeripheral>, ringbuf: ReadableDmaRingBuffer<'a, W>, table: Table<2>, options: TransferOptions, @@ -70,7 +71,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { let table = Table::<2>::new_ping_pong::(request, peri_addr, buffer, Dir::PeripheralToMemory); Self { - channel: BusyChannel::new(channel), + channel: BusyPeripheral::new(channel), ringbuf: ReadableDmaRingBuffer::new(buffer), table, options, @@ -189,7 +190,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { /// Ringbuffer for writing data using GPDMA linked-list mode. pub struct WritableRingBuffer<'a, W: Word> { - channel: BusyChannel<'a>, + channel: BusyPeripheral>, ringbuf: WritableDmaRingBuffer<'a, W>, table: Table<2>, options: TransferOptions, @@ -210,7 +211,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { let table = Table::<2>::new_ping_pong::(request, peri_addr, buffer, Dir::MemoryToPeripheral); Self { - channel: BusyChannel::new(channel), + channel: BusyPeripheral::new(channel), ringbuf: WritableDmaRingBuffer::new(buffer), table, options, diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 4becc2d87..efb324fa6 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -3,14 +3,12 @@ #[cfg(any(bdma, dma))] mod dma_bdma; -use core::ops; #[cfg(any(bdma, dma))] pub use dma_bdma::*; #[cfg(gpdma)] pub(crate) mod gpdma; -use embassy_hal_internal::Peri; #[cfg(gpdma)] pub use gpdma::ringbuffered::*; #[cfg(gpdma)] @@ -27,9 +25,10 @@ pub(crate) use util::*; pub(crate) mod ringbuffer; pub mod word; -use embassy_hal_internal::{PeripheralType, impl_peripheral}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use crate::interrupt; +use crate::rcc::StoppablePeripheral; /// The direction of a DMA transfer. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -48,6 +47,13 @@ pub type Request = u8; #[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))] pub type Request = (); +impl<'a> StoppablePeripheral for Peri<'a, AnyChannel> { + #[cfg(feature = "low-power")] + fn stop_mode(&self) -> crate::rcc::StopMode { + self.stop_mode + } +} + pub(crate) trait SealedChannel { #[cfg(not(stm32n6))] fn id(&self) -> u8; @@ -103,44 +109,6 @@ macro_rules! dma_channel_impl { }; } -pub(crate) struct BusyChannel<'a> { - channel: Peri<'a, AnyChannel>, -} - -impl<'a> BusyChannel<'a> { - pub fn new(channel: Peri<'a, AnyChannel>) -> Self { - #[cfg(feature = "low-power")] - critical_section::with(|cs| { - crate::rcc::increment_stop_refcount(cs, channel.stop_mode); - }); - - Self { channel } - } -} - -impl<'a> Drop for BusyChannel<'a> { - fn drop(&mut self) { - #[cfg(feature = "low-power")] - critical_section::with(|cs| { - crate::rcc::decrement_stop_refcount(cs, self.stop_mode); - }); - } -} - -impl<'a> ops::Deref for BusyChannel<'a> { - type Target = Peri<'a, AnyChannel>; - - fn deref(&self) -> &Self::Target { - &self.channel - } -} - -impl<'a> ops::DerefMut for BusyChannel<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.channel - } -} - /// Type-erased DMA channel. pub struct AnyChannel { pub(crate) id: u8, diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index bd8290da0..cdf3323fb 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -51,7 +51,7 @@ use embassy_executor::*; use crate::interrupt; pub use crate::rcc::StopMode; -use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2, decrement_stop_refcount, increment_stop_refcount}; +use crate::rcc::{BusyPeripheral, RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2}; use crate::time_driver::get_driver; const THREAD_PENDER: usize = usize::MAX; @@ -59,7 +59,9 @@ const THREAD_PENDER: usize = usize::MAX; static mut EXECUTOR_TAKEN: bool = false; /// Prevent the device from going into the stop mode if held -pub struct DeviceBusy(StopMode); +pub struct DeviceBusy { + _stop_mode: BusyPeripheral, +} impl DeviceBusy { /// Create a new DeviceBusy with stop1. @@ -74,19 +76,9 @@ impl DeviceBusy { /// Create a new DeviceBusy. pub fn new(stop_mode: StopMode) -> Self { - critical_section::with(|cs| { - increment_stop_refcount(cs, stop_mode); - }); - - Self(stop_mode) - } -} - -impl Drop for DeviceBusy { - fn drop(&mut self) { - critical_section::with(|cs| { - decrement_stop_refcount(cs, self.0); - }); + Self { + _stop_mode: BusyPeripheral::new(stop_mode), + } } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index b6ecc6c18..1dd634cfe 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -4,6 +4,7 @@ #![allow(missing_docs)] // TODO use core::mem::MaybeUninit; +use core::ops; mod bd; pub use bd::*; @@ -112,7 +113,7 @@ pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clo } #[cfg(feature = "low-power")] -pub(crate) fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { +fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { match stop_mode { StopMode::Standby => {} StopMode::Stop2 => unsafe { @@ -125,7 +126,7 @@ pub(crate) fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) } #[cfg(feature = "low-power")] -pub(crate) fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { +fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) { match stop_mode { StopMode::Standby => {} StopMode::Stop2 => unsafe { @@ -182,6 +183,12 @@ pub enum StopMode { Standby, } +#[cfg(feature = "low-power")] +type BusyRccPeripheral = BusyPeripheral; + +#[cfg(not(feature = "low-power"))] +type BusyRccPeripheral = (); + impl RccInfo { /// Safety: /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit @@ -297,6 +304,7 @@ impl RccInfo { } } + #[allow(dead_code)] pub(crate) fn increment_stop_refcount_with_cs(&self, _cs: CriticalSection) { #[cfg(feature = "low-power")] increment_stop_refcount(_cs, self.stop_mode); @@ -304,9 +312,11 @@ impl RccInfo { #[allow(dead_code)] pub(crate) fn increment_stop_refcount(&self) { + #[cfg(feature = "low-power")] critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs)) } + #[allow(dead_code)] pub(crate) fn decrement_stop_refcount_with_cs(&self, _cs: CriticalSection) { #[cfg(feature = "low-power")] decrement_stop_refcount(_cs, self.stop_mode); @@ -314,6 +324,7 @@ impl RccInfo { #[allow(dead_code)] pub(crate) fn decrement_stop_refcount(&self) { + #[cfg(feature = "low-power")] critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs)) } @@ -344,6 +355,12 @@ impl RccInfo { critical_section::with(|cs| self.disable_with_cs(cs)) } + #[allow(dead_code)] + pub(crate) fn block_stop(&self) -> BusyRccPeripheral { + #[cfg(feature = "low-power")] + BusyPeripheral::new(self.stop_mode) + } + fn reset_ptr(&self) -> Option<*mut u32> { if self.reset_offset_or_0xff != 0xff { Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) }) @@ -357,6 +374,53 @@ impl RccInfo { } } +pub(crate) trait StoppablePeripheral { + #[cfg(feature = "low-power")] + #[allow(dead_code)] + fn stop_mode(&self) -> StopMode; +} + +#[cfg(feature = "low-power")] +impl<'a> StoppablePeripheral for StopMode { + fn stop_mode(&self) -> StopMode { + *self + } +} + +pub(crate) struct BusyPeripheral { + peripheral: T, +} + +impl BusyPeripheral { + pub fn new(peripheral: T) -> Self { + #[cfg(feature = "low-power")] + critical_section::with(|cs| increment_stop_refcount(cs, peripheral.stop_mode())); + + Self { peripheral } + } +} + +impl Drop for BusyPeripheral { + fn drop(&mut self) { + #[cfg(feature = "low-power")] + critical_section::with(|cs| decrement_stop_refcount(cs, self.peripheral.stop_mode())); + } +} + +impl ops::Deref for BusyPeripheral { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.peripheral + } +} + +impl ops::DerefMut for BusyPeripheral { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.peripheral + } +} + #[allow(unused)] mod util { use crate::time::Hertz; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 1af78b358..8047d6005 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -491,8 +491,7 @@ impl<'d> UartTx<'d, Async> { /// Initiate an asynchronous UART write pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { - self.info.rcc.increment_stop_refcount(); - let _ = OnDrop::new(|| self.info.rcc.decrement_stop_refcount()); + let _ = self.info.rcc.block_stop(); let r = self.info.regs; @@ -511,8 +510,7 @@ impl<'d> UartTx<'d, Async> { /// Wait until transmission complete pub async fn flush(&mut self) -> Result<(), Error> { - self.info.rcc.increment_stop_refcount(); - let _ = OnDrop::new(|| self.info.rcc.decrement_stop_refcount()); + let _ = self.info.rcc.block_stop(); flush(&self.info, &self.state).await } @@ -732,8 +730,7 @@ impl<'d> UartRx<'d, Async> { /// Initiate an asynchronous UART read pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - self.info.rcc.increment_stop_refcount(); - let _ = OnDrop::new(|| self.info.rcc.decrement_stop_refcount()); + let _ = self.info.rcc.block_stop(); self.inner_read(buffer, false).await?; @@ -742,8 +739,7 @@ impl<'d> UartRx<'d, Async> { /// Initiate an asynchronous read with idle line detection enabled pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result { - self.info.rcc.increment_stop_refcount(); - let _ = OnDrop::new(|| self.info.rcc.decrement_stop_refcount()); + let _ = self.info.rcc.block_stop(); self.inner_read(buffer, true).await } -- cgit