From 3466c9cfa93cbcd796cd9125e4035e35546c3e9c Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 13:47:02 -0500 Subject: [PATCH 1/6] stm32: refcount peripheral enable/disable --- embassy-stm32/build.rs | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 6c364f7bb..2b66e7dad 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,6 +308,9 @@ fn main() { // ======== // Generate RccPeripheral impls + let refcounted_peripherals = HashSet::from(["ADC", "USART", "SPI", "I2C"]); + 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 +347,40 @@ fn main() { TokenStream::new() }; + let ptype = p + .name + .replace(&['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'][..], ""); 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.trim_start_matches("LP")) { + let refcount_static = + format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); + + refcount_statics.insert(refcount_static.clone()); + + ( + quote! { + use atomic_polyfill::Ordering; + + if refcount_statics::#refcount_static.fetch_add(1, Ordering::SeqCst) > 0 { + return; + } + }, + quote! { + use atomic_polyfill::Ordering; + + if refcount_statics::#refcount_static.fetch_sub(1, Ordering::SeqCst) > 1 { + return; + } + }, + ) + } else { + (TokenStream::new(), TokenStream::new()) + }; + g.extend(quote! { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { fn frequency() -> crate::time::Hertz { @@ -356,6 +388,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 +397,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 +413,21 @@ fn main() { } } + let mut refcount_mod = TokenStream::new(); + for refcount_static in refcount_statics { + refcount_mod.extend(quote! { + pub(crate) static #refcount_static: AtomicU8 = AtomicU8::new(0); + }); + } + + g.extend(quote! { + mod refcount_statics { + use atomic_polyfill::AtomicU8; + + #refcount_mod + } + }); + // ======== // Generate fns to enable GPIO, DMA in RCC From 274f63a879353923feac87f399aae9c5cadd4aa3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 15:47:33 -0500 Subject: [PATCH 2/6] stm32: fix refcounts for usart, spi, and i2c --- embassy-stm32/build.rs | 18 ++++++------------ embassy-stm32/src/i2c/v1.rs | 6 ++++++ embassy-stm32/src/i2c/v2.rs | 6 ++++++ embassy-stm32/src/spi/mod.rs | 2 ++ embassy-stm32/src/usart/buffered.rs | 10 ++++++++++ embassy-stm32/src/usart/mod.rs | 18 ++++++++++++++++++ embassy-stm32/src/usart/ringbuffered.rs | 17 ++++++++++++----- 7 files changed, 60 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 2b66e7dad..d3f6452b4 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -347,9 +347,7 @@ fn main() { TokenStream::new() }; - let ptype = p - .name - .replace(&['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'][..], ""); + let ptype = p.name.replace(|c| char::is_numeric(c), ""); 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()); @@ -363,16 +361,14 @@ fn main() { ( quote! { - use atomic_polyfill::Ordering; - - if refcount_statics::#refcount_static.fetch_add(1, Ordering::SeqCst) > 0 { + unsafe { refcount_statics::#refcount_static += 1 }; + if unsafe { refcount_statics::#refcount_static } > 1 { return; } }, quote! { - use atomic_polyfill::Ordering; - - if refcount_statics::#refcount_static.fetch_sub(1, Ordering::SeqCst) > 1 { + unsafe { refcount_statics::#refcount_static -= 1 }; + if unsafe { refcount_statics::#refcount_static } > 0 { return; } }, @@ -416,14 +412,12 @@ fn main() { let mut refcount_mod = TokenStream::new(); for refcount_static in refcount_statics { refcount_mod.extend(quote! { - pub(crate) static #refcount_static: AtomicU8 = AtomicU8::new(0); + pub(crate) static mut #refcount_static: u8 = 0; }); } g.extend(quote! { mod refcount_statics { - use atomic_polyfill::AtomicU8; - #refcount_mod } }); diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 618d85af2..f32dd0f0c 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 4327899bb..36f70e32e 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 e2bc8d7f2..853de98f9 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 596d40bf9..989c88205 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 255ddfd4b..bfb056718 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 b3f570624..e990eaca8 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> UartRx<'d, T, RxDma> { let request = self.rx_dma.request(); let opts = Default::default(); - let ring_buf = unsafe { ReadableRingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + // Safety: we forget the struct before this function returns. + let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; + let _peri = unsafe { self._peri.clone_unchecked() }; - RingBufferedUartRx { - _peri: self._peri, - ring_buf, - } + let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + + // Don't disable the clock + mem::forget(self); + + RingBufferedUartRx { _peri, ring_buf } } } @@ -186,6 +191,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD impl> Drop for RingBufferedUartRx<'_, T, RxDma> { fn drop(&mut self) { self.teardown_uart(); + + T::disable(); } } /// Return an error result if the Sr register has errors From bfb4cf775a81a5a674c1f80ecd68425ee2410081 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 15:54:00 -0500 Subject: [PATCH 3/6] remove adc refcount --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d3f6452b4..09a029525 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,7 +308,7 @@ fn main() { // ======== // Generate RccPeripheral impls - let refcounted_peripherals = HashSet::from(["ADC", "USART", "SPI", "I2C"]); + let refcounted_peripherals = HashSet::from(["USART", "SPI", "I2C"]); let mut refcount_statics = HashSet::new(); for p in METADATA.peripherals { From 394503ab69129e79b4fe78653c67337ec4e7346e Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 15:54:23 -0500 Subject: [PATCH 4/6] ci: run HIL --- ci.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci.sh b/ci.sh index 4112144bc..db00c406c 100755 --- a/ci.sh +++ b/ci.sh @@ -180,9 +180,4 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then exit fi -rm out/tests/rpi-pico/ethernet_w5100s_perf -rm out/tests/nrf52840-dk/ethernet_enc28j60_perf -rm out/tests/nrf52840-dk/wifi_esp_hosted_perf -rm out/tests/rpi-pico/cyw43-perf - teleprobe client run -r out/tests From 6dc56d2b35d065ba0023fb0bcad27ecd2602fb0e Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 16:04:29 -0500 Subject: [PATCH 5/6] stm32: include uart-named peripherals --- embassy-stm32/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 09a029525..7da3cdffb 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,7 +308,8 @@ fn main() { // ======== // Generate RccPeripheral impls - let refcounted_peripherals = HashSet::from(["USART", "SPI", "I2C"]); + // TODO: maybe get this from peripheral kind? Not sure + let refcounted_peripherals = HashSet::from(["UART", "USART", "SPI", "I2C"]); let mut refcount_statics = HashSet::new(); for p in METADATA.peripherals { From d19e1c1dd1c8c514c375bca3ba69f636a0b19f88 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 16:18:31 -0500 Subject: [PATCH 6/6] stm32: only refcount usart and use kind direclty --- embassy-stm32/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 7da3cdffb..aef0668a2 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -309,7 +309,7 @@ fn main() { // Generate RccPeripheral impls // TODO: maybe get this from peripheral kind? Not sure - let refcounted_peripherals = HashSet::from(["UART", "USART", "SPI", "I2C"]); + let refcounted_peripherals = HashSet::from(["USART"]); let mut refcount_statics = HashSet::new(); for p in METADATA.peripherals { @@ -348,13 +348,13 @@ fn main() { TokenStream::new() }; - let ptype = p.name.replace(|c| char::is_numeric(c), ""); + 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.trim_start_matches("LP")) { + 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());