From 6f2ad3b696936ff2a3995fda3c8aee5728bd8f53 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Tue, 25 Nov 2025 11:18:01 +0800 Subject: chore: bump usbd-hid version Signed-off-by: Haobo Gu --- embassy-usb/CHANGELOG.md | 1 + embassy-usb/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp235x/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- 9 files changed, 9 insertions(+), 8 deletions(-) diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index cfb1bf021..3dd71ffbc 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate - Add support for USB HID Boot Protocol Mode +- Bump usbd-hid from 0.8.1 to 0.9.0 ## 0.5.1 - 2025-08-26 diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index aeb7392f1..3d1e005e4 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -69,5 +69,5 @@ heapless = "0.8" embedded-io-async = "0.6.1" # for HID -usbd-hid = { version = "0.8.1", optional = true } +usbd-hid = { version = "0.9.0", optional = true } ssmarshal = { version = "1.0", default-features = false, optional = true } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index a026d6352..1fe3d2419 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -28,7 +28,7 @@ cortex-m-rt = "0.7.0" panic-probe = { version = "1.0.0", features = ["print-defmt"] } rand = { version = "0.9.0", default-features = false } embedded-storage = "0.3.1" -usbd-hid = "0.8.1" +usbd-hid = "0.9.0" serde = { version = "1.0.136", default-features = false } embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 4dcbdd715..97efe58e8 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -23,7 +23,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" panic-probe = { version = "1.0.0", features = ["print-defmt"] } embedded-storage = "0.3.1" -usbd-hid = "0.8.1" +usbd-hid = "0.9.0" serde = { version = "1.0.136", default-features = false } [profile.release] diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 640addb28..9d7d99259 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -45,7 +45,7 @@ display-interface = "0.5.0" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.4.0" heapless = "0.8" -usbd-hid = "0.8.1" +usbd-hid = "0.9.0" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0" diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 39a4f421a..ad396275b 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -46,7 +46,7 @@ display-interface = "0.5.0" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.3.0" heapless = "0.8" -usbd-hid = "0.8.1" +usbd-hid = "0.9.0" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index d06b7505c..b4555045a 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -32,7 +32,7 @@ critical-section = "1.1" nb = "1.0.0" embedded-storage = "0.3.1" micromath = "2.0.0" -usbd-hid = "0.8.1" +usbd-hid = "0.9.0" static_cell = "2" chrono = { version = "^0.4", default-features = false} diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 8bbeb594c..d1c19582b 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -13,7 +13,7 @@ embassy-executor = { path = "../../embassy-executor", features = ["arch-cortex-m embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { path = "../../embassy-futures" } -usbd-hid = "0.8.1" +usbd-hid = "0.9.0" defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index b6158c854..586b00836 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -14,7 +14,7 @@ embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["de embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } -usbd-hid = "0.8.1" +usbd-hid = "0.9.0" defmt = "1.0.1" defmt-rtt = "1.0.0" -- cgit From 3ba8bb866a19a09f25e0b21419a068fd765a9033 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 25 Nov 2025 07:45:01 -0600 Subject: stm32: allow split irqs for time driver --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/build.rs | 49 +++++++++++---- embassy-stm32/src/time_driver.rs | 126 +++------------------------------------ 3 files changed, 46 insertions(+), 130 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index a66b2d437..0f19b14b3 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 ## Unreleased - ReleaseDate +- fix: fix incorrect handling of split interrupts in timer driver - change: low power: store stop mode for dma channels - fix: Fixed ADC4 enable() for WBA - feat: allow use of anyadcchannel for adc4 diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 109571e8f..46d6290e7 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -9,7 +9,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use stm32_metapac::metadata::ir::BitOffset; use stm32_metapac::metadata::{ - ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, + ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, MemoryRegion, MemoryRegionKind, Peripheral, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, }; @@ -133,6 +133,9 @@ fn main() { cfgs.enable("backup_sram") } + // compile a map of peripherals + let peripheral_map: BTreeMap<&str, &Peripheral> = METADATA.peripherals.iter().map(|p| (p.name, p)).collect(); + // generate one singleton per peripheral (with many exceptions...) for p in METADATA.peripherals { if let Some(r) = &p.registers { @@ -319,9 +322,33 @@ fn main() { _ => panic!("unknown time_driver {:?}", time_driver), }; - if !time_driver_singleton.is_empty() { + let time_driver_irq_decl = if !time_driver_singleton.is_empty() { cfgs.enable(format!("time_driver_{}", time_driver_singleton.to_lowercase())); - } + + let p = peripheral_map.get(time_driver_singleton).unwrap(); + let irqs: BTreeSet<_> = p + .interrupts + .iter() + .filter(|i| i.signal == "CC" || i.signal == "UP") + .map(|i| i.interrupt.to_ascii_uppercase()) + .collect(); + + irqs.iter() + .map(|i| { + let irq = format_ident!("{}", i); + quote! { + #[cfg(feature = "rt")] + #[interrupt] + fn #irq() { + crate::time_driver::get_driver().on_interrupt(); + } + } + }) + .collect() + } else { + TokenStream::new() + }; + for tim in [ "tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21", "tim22", "tim23", "tim24", @@ -371,6 +398,8 @@ fn main() { ); }); + g.extend(time_driver_irq_decl); + // ======== // Generate FLASH regions cfgs.declare("flash"); @@ -1862,7 +1891,7 @@ fn main() { flash_regions_table.push(row); } - let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32; + let gpio_base = peripheral_map.get("GPIOA").unwrap().address as u32; let gpio_stride = 0x400; for pin in METADATA.pins { @@ -1980,11 +2009,11 @@ fn main() { continue; } - let stop_mode = METADATA - .peripherals - .iter() - .find(|p| p.name == ch.dma) - .map(|p| p.rcc.as_ref().map(|rcc| rcc.stop_mode.clone()).unwrap_or_default()) + let dma_peri = peripheral_map.get(ch.dma).unwrap(); + let stop_mode = dma_peri + .rcc + .as_ref() + .map(|rcc| rcc.stop_mode.clone()) .unwrap_or_default(); let stop_mode = match stop_mode { @@ -2009,8 +2038,6 @@ fn main() { let dma = format_ident!("{}", ch.dma); let ch_num = ch.channel as usize; - - let dma_peri = METADATA.peripherals.iter().find(|p| p.name == ch.dma).unwrap(); let bi = dma_peri.registers.as_ref().unwrap(); let dma_info = match bi.kind { diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 0b75aef92..cfcf5f3fd 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -14,11 +14,11 @@ use stm32_metapac::timer::{TimGp16, regs}; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; +use crate::peripherals; use crate::rcc::{self, SealedRccPeripheral}; #[cfg(feature = "low-power")] use crate::rtc::Rtc; use crate::timer::{CoreInstance, GeneralInstance1Channel}; -use crate::{interrupt, peripherals}; // NOTE regarding ALARM_COUNT: // @@ -56,121 +56,6 @@ type T = peripherals::TIM23; #[cfg(time_driver_tim24)] type T = peripherals::TIM24; -foreach_interrupt! { - (TIM1, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim1)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM2, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim2)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM3, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim3)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM4, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim4)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM5, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim5)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM8, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim8)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM9, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim9)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM12, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim12)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM15, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim15)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM20, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim20)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM21, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim21)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM22, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim22)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM23, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim23)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; - (TIM24, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim24)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; -} - fn regs_gp16() -> TimGp16 { unsafe { TimGp16::from_ptr(T::regs()) } } @@ -282,7 +167,11 @@ impl RtcDriver { r.cnt().write(|w| w.set_cnt(self.saved_count.load(Ordering::SeqCst))); ::CaptureCompareInterrupt::unpend(); - unsafe { ::CaptureCompareInterrupt::enable() }; + ::UpdateInterrupt::unpend(); + unsafe { + ::CaptureCompareInterrupt::enable(); + ::UpdateInterrupt::enable(); + } } fn init(&'static self, cs: CriticalSection) { @@ -290,7 +179,7 @@ impl RtcDriver { regs_gp16().cr1().modify(|w| w.set_cen(true)); } - fn on_interrupt(&self) { + pub(crate) fn on_interrupt(&self) { let r = regs_gp16(); critical_section::with(|cs| { @@ -508,7 +397,6 @@ impl Driver for RtcDriver { } } -#[cfg(feature = "low-power")] pub(crate) const fn get_driver() -> &'static RtcDriver { &DRIVER } -- cgit From d2d00b57c8bf5b6879c5df5021f44652d1fd52ee Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 25 Nov 2025 11:47:44 -0600 Subject: stm32: allow granular stop for uart --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/rcc/mod.rs | 39 ++++++++++++++++++++++++++++----- embassy-stm32/src/usart/mod.rs | 20 +++++++++++++---- embassy-stm32/src/usart/ringbuffered.rs | 3 +++ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index d3e5ba48d..5c31b5a11 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 ## Unreleased - ReleaseDate +- feat: allow granular stop for regular usart - feat: Add continuous waveform method to SimplePWM - change: remove waveform timer method - change: low power: store stop mode for dma channels diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 85434fa83..f38d9078d 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -234,9 +234,6 @@ impl RccInfo { } } - #[cfg(feature = "low-power")] - increment_stop_refcount(_cs, self.stop_mode); - // set the xxxRST bit let reset_ptr = self.reset_ptr(); if let Some(reset_ptr) = reset_ptr { @@ -292,9 +289,6 @@ impl RccInfo { } } - #[cfg(feature = "low-power")] - decrement_stop_refcount(_cs, self.stop_mode); - // clear the xxxEN bit let enable_ptr = self.enable_ptr(); unsafe { @@ -303,13 +297,46 @@ impl RccInfo { } } + pub(crate) fn increment_stop_refcount_with_cs(&self, _cs: CriticalSection) { + #[cfg(feature = "low-power")] + increment_stop_refcount(_cs, self.stop_mode); + } + + pub(crate) fn increment_stop_refcount(&self) { + critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs)) + } + + pub(crate) fn decrement_stop_refcount_with_cs(&self, _cs: CriticalSection) { + #[cfg(feature = "low-power")] + decrement_stop_refcount(_cs, self.stop_mode); + } + + pub(crate) fn decrement_stop_refcount(&self) { + critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs)) + } + // TODO: should this be `unsafe`? pub(crate) fn enable_and_reset(&self) { + critical_section::with(|cs| { + self.enable_and_reset_with_cs(cs); + self.increment_stop_refcount_with_cs(cs); + }) + } + + pub(crate) fn enable_and_reset_without_stop(&self) { critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) } // TODO: should this be `unsafe`? pub(crate) fn disable(&self) { + critical_section::with(|cs| { + self.disable_with_cs(cs); + self.decrement_stop_refcount_with_cs(cs); + }) + } + + // TODO: should this be `unsafe`? + pub(crate) fn disable_without_stop(&self) { critical_section::with(|cs| self.disable_with_cs(cs)) } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0e7da634d..1af78b358 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -491,6 +491,9 @@ 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 r = self.info.regs; half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); @@ -508,6 +511,9 @@ 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()); + flush(&self.info, &self.state).await } } @@ -569,7 +575,7 @@ impl<'d, M: Mode> UartTx<'d, M> { let state = self.state; state.tx_rx_refcount.store(1, Ordering::Relaxed); - info.rcc.enable_and_reset(); + info.rcc.enable_and_reset_without_stop(); info.regs.cr3().modify(|w| { w.set_ctse(self.cts.is_some()); @@ -726,6 +732,9 @@ 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()); + self.inner_read(buffer, false).await?; Ok(()) @@ -733,6 +742,9 @@ 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()); + self.inner_read(buffer, true).await } @@ -1004,7 +1016,7 @@ impl<'d, M: Mode> UartRx<'d, M> { .eager_reads .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); - info.rcc.enable_and_reset(); + info.rcc.enable_and_reset_without_stop(); info.regs.cr3().write(|w| { w.set_rtse(self.rts.is_some()); @@ -1143,7 +1155,7 @@ fn drop_tx_rx(info: &Info, state: &State) { refcount == 1 }); if is_last_drop { - info.rcc.disable(); + info.rcc.disable_without_stop(); } } @@ -1506,7 +1518,7 @@ impl<'d, M: Mode> Uart<'d, M> { .eager_reads .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); - info.rcc.enable_and_reset(); + info.rcc.enable_and_reset_without_stop(); info.regs.cr3().write(|w| { w.set_rtse(self.rx.rts.is_some()); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index bac570d27..cc5224b69 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -117,6 +117,8 @@ impl<'d> UartRx<'d, Async> { let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) }; let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) }; + info.rcc.increment_stop_refcount(); + // Don't disable the clock mem::forget(self); @@ -324,6 +326,7 @@ impl<'d> RingBufferedUartRx<'d> { impl Drop for RingBufferedUartRx<'_> { fn drop(&mut self) { + self.info.rcc.decrement_stop_refcount(); self.stop_uart(); self.rx.as_ref().map(|x| x.set_as_disconnected()); self.rts.as_ref().map(|x| x.set_as_disconnected()); -- cgit From 5298671b0c132f58f3f76273bcd35656dc6e6d3d Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 25 Nov 2025 11:57:59 -0600 Subject: fmt --- embassy-stm32/src/rcc/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index f38d9078d..b6ecc6c18 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -302,6 +302,7 @@ impl RccInfo { increment_stop_refcount(_cs, self.stop_mode); } + #[allow(dead_code)] pub(crate) fn increment_stop_refcount(&self) { critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs)) } @@ -311,6 +312,7 @@ impl RccInfo { decrement_stop_refcount(_cs, self.stop_mode); } + #[allow(dead_code)] pub(crate) fn decrement_stop_refcount(&self) { critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs)) } @@ -323,6 +325,7 @@ impl RccInfo { }) } + #[allow(dead_code)] pub(crate) fn enable_and_reset_without_stop(&self) { critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) } @@ -336,6 +339,7 @@ impl RccInfo { } // TODO: should this be `unsafe`? + #[allow(dead_code)] pub(crate) fn disable_without_stop(&self) { critical_section::with(|cs| self.disable_with_cs(cs)) } -- cgit From 5792daf3afb9366c362fc57c89870ffb05df8b8c Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:28:55 -0700 Subject: Remove atomic-polyfill --- embassy-rp/Cargo.toml | 3 +-- embassy-rp/src/pio/mod.rs | 26 ++++++++++++++++++-------- embassy-rp/src/uart/buffered.rs | 13 ++++++++++--- embassy-rp/src/uart/mod.rs | 28 +++++++++++++++++++++++----- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 9ad4b47a3..421f0b0f6 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -47,7 +47,7 @@ rt = [ "rp-pac/rt" ] defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] ## Enable log support log = ["dep:log"] -## Enable chrono support +## Enable chrono support chrono = ["dep:chrono"] ## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. @@ -159,7 +159,6 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" } embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } -atomic-polyfill = "1.0.1" defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } nb = "1.1.0" diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 92b2c603e..fd0b4c072 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -1,11 +1,11 @@ //! PIO driver. +use core::cell::Cell; use core::future::Future; use core::marker::PhantomData; use core::pin::Pin as FuturePin; -use core::sync::atomic::{Ordering, compiler_fence}; +use core::sync::atomic::{AtomicU8, Ordering, compiler_fence}; use core::task::{Context, Poll}; -use atomic_polyfill::{AtomicU8, AtomicU64}; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use fixed::FixedU32; @@ -1232,7 +1232,10 @@ impl<'d, PIO: Instance> Common<'d, PIO> { w.set_pde(false); }); // we can be relaxed about this because we're &mut here and nothing is cached - PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); + critical_section::with(|_| { + let val = PIO::state().used_pins.get(); + PIO::state().used_pins.set(val | 1 << pin.pin_bank()); + }); Pin { pin: pin.into(), pio: PhantomData::default(), @@ -1369,7 +1372,7 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { /// Create a new instance of a PIO peripheral. pub fn new(_pio: Peri<'d, PIO>, _irq: impl Binding>) -> Self { PIO::state().users.store(5, Ordering::Release); - PIO::state().used_pins.store(0, Ordering::Release); + critical_section::with(|_| PIO::state().used_pins.set(0)); PIO::Interrupt::unpend(); unsafe { PIO::Interrupt::enable() }; @@ -1413,13 +1416,20 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { // other way. pub struct State { users: AtomicU8, - used_pins: AtomicU64, + used_pins: Cell, } +unsafe impl Sync for State {} + fn on_pio_drop() { let state = PIO::state(); - if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { - let used_pins = state.used_pins.load(Ordering::Relaxed); + let users_state = critical_section::with(|_| { + let val = state.users.load(Ordering::Acquire) - 1; + state.users.store(val, Ordering::Release); + val + }); + if users_state == 1 { + let used_pins = critical_section::with(|_| state.used_pins.get()); let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; for i in 0..crate::gpio::BANK0_PIN_COUNT { if used_pins & (1 << i) != 0 { @@ -1444,7 +1454,7 @@ trait SealedInstance { fn state() -> &'static State { static STATE: State = State { users: AtomicU8::new(0), - used_pins: AtomicU64::new(0), + used_pins: Cell::new(0), }; &STATE diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 02649ad81..fdb8ce776 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -1,8 +1,8 @@ //! Buffered UART driver. use core::future::Future; use core::slice; +use core::sync::atomic::{AtomicU8, Ordering}; -use atomic_polyfill::AtomicU8; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use super::*; @@ -241,7 +241,11 @@ impl BufferedUartRx { } fn get_rx_error(state: &State) -> Option { - let errs = state.rx_error.swap(0, Ordering::Relaxed); + let errs = critical_section::with(|_| { + let val = state.rx_error.load(Ordering::Relaxed); + state.rx_error.store(0, Ordering::Relaxed); + val + }); if errs & RXE_OVERRUN != 0 { Some(Error::Overrun) } else if errs & RXE_BREAK != 0 { @@ -555,7 +559,10 @@ impl interrupt::typelevel::Handler for BufferedInterr } let dr = r.uartdr().read(); if (dr.0 >> 8) != 0 { - s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); + critical_section::with(|_| { + let val = s.rx_error.load(Ordering::Relaxed); + s.rx_error.store(val | ((dr.0 >> 8) as u8), Ordering::Relaxed); + }); error = true; // only fill the buffer with valid characters. the current character is fine // if the error is an overrun, but if we add it to the buffer we'll report diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 8be87a5d2..b7b569dd5 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -1,9 +1,9 @@ //! UART driver. use core::future::poll_fn; use core::marker::PhantomData; +use core::sync::atomic::{AtomicU16, Ordering}; use core::task::Poll; -use atomic_polyfill::{AtomicU16, Ordering}; use embassy_futures::select::{Either, select}; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; @@ -456,7 +456,12 @@ impl<'d> UartRx<'d, Async> { transfer, poll_fn(|cx| { self.dma_state.rx_err_waker.register(cx.waker()); - match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { + let rx_errs = critical_section::with(|_| { + let val = self.dma_state.rx_errs.load(Ordering::Relaxed); + self.dma_state.rx_errs.store(0, Ordering::Relaxed); + val + }); + match rx_errs { 0 => Poll::Pending, e => Poll::Ready(Uartris(e as u32)), } @@ -468,7 +473,11 @@ impl<'d> UartRx<'d, Async> { Either::First(()) => { // We're here because the DMA finished, BUT if an error occurred on the LAST // byte, then we may still need to grab the error state! - Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) + Uartris(critical_section::with(|_| { + let val = self.dma_state.rx_errs.load(Ordering::Relaxed); + self.dma_state.rx_errs.store(0, Ordering::Relaxed); + val + }) as u32) } Either::Second(e) => { // We're here because we errored, which means this is the error that @@ -616,7 +625,12 @@ impl<'d> UartRx<'d, Async> { transfer, poll_fn(|cx| { self.dma_state.rx_err_waker.register(cx.waker()); - match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { + let rx_errs = critical_section::with(|_| { + let val = self.dma_state.rx_errs.load(Ordering::Relaxed); + self.dma_state.rx_errs.store(0, Ordering::Relaxed); + val + }); + match rx_errs { 0 => Poll::Pending, e => Poll::Ready(Uartris(e as u32)), } @@ -629,7 +643,11 @@ impl<'d> UartRx<'d, Async> { Either::First(()) => { // We're here because the DMA finished, BUT if an error occurred on the LAST // byte, then we may still need to grab the error state! - Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) + Uartris(critical_section::with(|_| { + let val = self.dma_state.rx_errs.load(Ordering::Relaxed); + self.dma_state.rx_errs.store(0, Ordering::Relaxed); + val + }) as u32) } Either::Second(e) => { // We're here because we errored, which means this is the error that -- cgit From f8ec795741663f559295327911a51559c526ba8f Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:37:22 -0700 Subject: Update CHANGELOG.md --- embassy-rp/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index fa8609bbf..7480b729f 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add fix #4822 in PIO onewire. Change to disable the state machine before setting y register ([#4824](https://github.com/embassy-rs/embassy/pull/4824)) - Add PIO::Ws2812 color order support - Add TX-only, no SCK SPI support +- Remove atomic-polyfill with critical-section instead ([#4948](https://github.com/embassy-rs/embassy/pull/4948)) ## 0.8.0 - 2025-08-26 @@ -116,4 +117,3 @@ Small release fixing a few gnarly bugs, upgrading is strongly recommended. - rename the Channel trait to Slice and the PwmPin to PwmChannel - i2c: Fix race condition that appears on fast repeated transfers. - Add a basic "read to break" function - -- cgit From edd8878f8cbd15a56a6c845a2a8772a016e24d4b Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Tue, 25 Nov 2025 12:05:52 -0700 Subject: Use two AtomicU32 instead --- embassy-rp/src/pio/mod.rs | 56 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index fd0b4c072..1c370fdfc 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -1,9 +1,8 @@ //! PIO driver. -use core::cell::Cell; use core::future::Future; use core::marker::PhantomData; use core::pin::Pin as FuturePin; -use core::sync::atomic::{AtomicU8, Ordering, compiler_fence}; +use core::sync::atomic::{AtomicU8, AtomicU32, Ordering, compiler_fence}; use core::task::{Context, Poll}; use embassy_hal_internal::{Peri, PeripheralType}; @@ -1233,9 +1232,12 @@ impl<'d, PIO: Instance> Common<'d, PIO> { }); // we can be relaxed about this because we're &mut here and nothing is cached critical_section::with(|_| { - let val = PIO::state().used_pins.get(); - PIO::state().used_pins.set(val | 1 << pin.pin_bank()); + let val = PIO::state().used_pins.load(Ordering::Relaxed); + PIO::state() + .used_pins + .store(val | 1 << pin.pin_bank(), Ordering::Relaxed); }); + Pin { pin: pin.into(), pio: PhantomData::default(), @@ -1372,7 +1374,7 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { /// Create a new instance of a PIO peripheral. pub fn new(_pio: Peri<'d, PIO>, _irq: impl Binding>) -> Self { PIO::state().users.store(5, Ordering::Release); - critical_section::with(|_| PIO::state().used_pins.set(0)); + PIO::state().used_pins.store(0, Ordering::Release); PIO::Interrupt::unpend(); unsafe { PIO::Interrupt::enable() }; @@ -1407,6 +1409,42 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { } } +struct AtomicU64 { + upper_32: AtomicU32, + lower_32: AtomicU32, +} + +impl AtomicU64 { + const fn new(val: u64) -> Self { + let upper_32 = (val >> 32) as u32; + let lower_32 = val as u32; + + Self { + upper_32: AtomicU32::new(upper_32), + lower_32: AtomicU32::new(lower_32), + } + } + + fn load(&self, order: Ordering) -> u64 { + let (upper, lower) = critical_section::with(|_| (self.upper_32.load(order), self.lower_32.load(order))); + + let upper = (upper as u64) << 32; + let lower = lower as u64; + + upper | lower + } + + fn store(&self, val: u64, order: Ordering) { + let upper_32 = (val >> 32) as u32; + let lower_32 = val as u32; + + critical_section::with(|_| { + self.upper_32.store(upper_32, order); + self.lower_32.store(lower_32, order); + }); + } +} + /// Representation of the PIO state keeping a record of which pins are assigned to /// each PIO. // make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin @@ -1416,11 +1454,9 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { // other way. pub struct State { users: AtomicU8, - used_pins: Cell, + used_pins: AtomicU64, } -unsafe impl Sync for State {} - fn on_pio_drop() { let state = PIO::state(); let users_state = critical_section::with(|_| { @@ -1429,7 +1465,7 @@ fn on_pio_drop() { val }); if users_state == 1 { - let used_pins = critical_section::with(|_| state.used_pins.get()); + let used_pins = state.used_pins.load(Ordering::Relaxed); let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; for i in 0..crate::gpio::BANK0_PIN_COUNT { if used_pins & (1 << i) != 0 { @@ -1454,7 +1490,7 @@ trait SealedInstance { fn state() -> &'static State { static STATE: State = State { users: AtomicU8::new(0), - used_pins: Cell::new(0), + used_pins: AtomicU64::new(0), }; &STATE -- cgit 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 From dfd0d31ff61b2efa5561fb44fc08a6d7ea4e5d41 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 26 Nov 2025 09:26:55 -0600 Subject: remove rp test --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index b4ed0dc18..cee761500 100755 --- a/ci.sh +++ b/ci.sh @@ -65,6 +65,7 @@ rm out/tests/pimoroni-pico-plus-2/pwm # flaky rm out/tests/rpi-pico/pwm rm out/tests/rpi-pico/cyw43-perf +rm out/tests/rpi-pico/uart_buffered # tests are implemented but the HIL test farm doesn't actually have these boards, yet rm -rf out/tests/stm32c071rb -- cgit