diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 6c364f7b..aef0668a 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,6 +308,10 @@ fn main() { // ======== // Generate RccPeripheral impls + // TODO: maybe get this from peripheral kind? Not sure + let refcounted_peripherals = HashSet::from(["USART"]); + let mut refcount_statics = HashSet::new(); + for p in METADATA.peripherals { // generating RccPeripheral impl for H7 ADC3 would result in bad frequency if !singletons.contains(&p.name.to_string()) @@ -344,11 +348,36 @@ fn main() { TokenStream::new() }; + let ptype = (if let Some(reg) = &p.registers { reg.kind } else { "" }).to_ascii_uppercase(); let pname = format_ident!("{}", p.name); let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); + let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype.as_str()) { + let refcount_static = + format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); + + refcount_statics.insert(refcount_static.clone()); + + ( + quote! { + unsafe { refcount_statics::#refcount_static += 1 }; + if unsafe { refcount_statics::#refcount_static } > 1 { + return; + } + }, + quote! { + unsafe { refcount_statics::#refcount_static -= 1 }; + if unsafe { refcount_statics::#refcount_static } > 0 { + return; + } + }, + ) + } else { + (TokenStream::new(), TokenStream::new()) + }; + g.extend(quote! { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { fn frequency() -> crate::time::Hertz { @@ -356,6 +385,7 @@ fn main() { } fn enable() { critical_section::with(|_| { + #before_enable #[cfg(feature = "low-power")] crate::rcc::clock_refcount_add(); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); @@ -364,6 +394,7 @@ fn main() { } fn disable() { critical_section::with(|_| { + #before_disable crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); #[cfg(feature = "low-power")] crate::rcc::clock_refcount_sub(); @@ -379,6 +410,19 @@ fn main() { } } + let mut refcount_mod = TokenStream::new(); + for refcount_static in refcount_statics { + refcount_mod.extend(quote! { + pub(crate) static mut #refcount_static: u8 = 0; + }); + } + + g.extend(quote! { + mod refcount_statics { + #refcount_mod + } + }); + // ======== // Generate fns to enable GPIO, DMA in RCC diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 618d85af..f32dd0f0 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -339,6 +339,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } +impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { + fn drop(&mut self) { + T::disable(); + } +} + impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { type Error = Error; diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 4327899b..36f70e32 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -838,6 +838,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } +impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { + fn drop(&mut self) { + T::disable(); + } +} + mod eh02 { use super::*; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index e2bc8d7f..853de98f 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -646,6 +646,8 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { self.sck.as_ref().map(|x| x.set_as_disconnected()); self.mosi.as_ref().map(|x| x.set_as_disconnected()); self.miso.as_ref().map(|x| x.set_as_disconnected()); + + T::disable(); } } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 596d40bf..989c8820 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -124,6 +124,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { rx_buffer: &'d mut [u8], config: Config, ) -> BufferedUart<'d, T> { + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -143,6 +145,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { ) -> BufferedUart<'d, T> { into_ref!(cts, rts); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -169,6 +173,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { ) -> BufferedUart<'d, T> { into_ref!(de); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -382,6 +388,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { T::Interrupt::disable(); } } + + T::disable(); } } @@ -397,6 +405,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { T::Interrupt::disable(); } } + + T::disable(); } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 255ddfd4..bfb05671 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -618,6 +618,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } +impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> { + fn drop(&mut self) { + T::disable(); + } +} + +impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { + fn drop(&mut self) { + T::disable(); + } +} + impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { pub fn new( peri: impl Peripheral
+ 'd, @@ -628,6 +640,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { rx_dma: impl Peripheral
+ 'd,
config: Config,
) -> Self {
+ // UartRx and UartTx have one refcount ea.
+ T::enable();
T::enable();
T::reset();
@@ -647,6 +661,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
) -> Self {
into_ref!(cts, rts);
+ // UartRx and UartTx have one refcount ea.
+ T::enable();
T::enable();
T::reset();
@@ -672,6 +688,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
) -> Self {
into_ref!(de);
+ // UartRx and UartTx have one refcount ea.
+ T::enable();
T::enable();
T::reset();
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b3f57062..e990eaca 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -1,4 +1,5 @@
use core::future::poll_fn;
+use core::mem;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
@@ -24,12 +25,16 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma