From 4e808345883ae64099135a8384f774c44feccc5c Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 18 Nov 2025 16:27:10 -0600 Subject: fix: fix incorrect logic for buffered usart transmission complete. --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/usart/buffered.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index b6caf8f65..5fd43744e 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 logic for buffered usart transmission complete. - change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871)) - feat: allow embassy_executor::main for low power - feat: Add waveform methods to ComplementaryPwm diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 69c3a740f..26d2b8991 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -87,7 +87,7 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) { // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC) // indicates that all bytes are pushed out from the FIFO. // For other usart variants it shows that last byte from the buffer was just sent. - if sr_val.tc() { + if sr_val.tc() && r.cr1().read().tcie() { // For others it is cleared above with `clear_interrupt_flags`. #[cfg(any(usart_v1, usart_v2))] sr(r).modify(|w| w.set_tc(false)); -- cgit From 19e61543198e2d15fd4c7aef9377c8f40ae86ae0 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 19 Nov 2025 16:14:23 -0600 Subject: stm32: impl. low power test for stm32wb55 --- embassy-stm32/src/hsem/mod.rs | 9 +++++++-- embassy-stm32/src/low_power.rs | 24 ++++++++++++++++-------- tests/stm32/Cargo.toml | 2 +- tests/stm32/src/bin/hsem.rs | 3 +++ 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs index 5f1ed9b09..e62de0454 100644 --- a/embassy-stm32/src/hsem/mod.rs +++ b/embassy-stm32/src/hsem/mod.rs @@ -293,8 +293,13 @@ impl HardwareSemaphore { } #[cfg(all(stm32wb, feature = "low-power"))] -pub(crate) fn init_hsem(_cs: CriticalSection) { - rcc::enable_and_reset::(); +pub(crate) fn init_hsem(cs: CriticalSection) { + rcc::enable_and_reset_with_cs::(cs); + + unsafe { + crate::rcc::REFCOUNT_STOP1 = 0; + crate::rcc::REFCOUNT_STOP2 = 0; + } } struct State { diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 15478eed4..f35eb71e4 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -147,17 +147,17 @@ pub enum StopMode { Stop2, } -#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))] +#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))] use crate::pac::pwr::vals::Lpms; -#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))] +#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))] impl Into for StopMode { fn into(self) -> Lpms { match self { StopMode::Stop1 => Lpms::STOP1, - #[cfg(not(stm32wba))] + #[cfg(not(any(stm32wb, stm32wba)))] StopMode::Stop2 => Lpms::STOP2, - #[cfg(stm32wba)] + #[cfg(any(stm32wb, stm32wba))] StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2? } } @@ -237,13 +237,15 @@ impl Executor { trace!("low power: stop 1"); Some(StopMode::Stop1) } else { - trace!("low power: not ready to stop"); + trace!("low power: not ready to stop (refcount_stop1: {})", unsafe { + REFCOUNT_STOP1 + }); None } } #[cfg(all(stm32wb, feature = "low-power"))] - fn configure_stop_stm32wb(&self, _stop_mode: StopMode) -> Result<(), ()> { + fn configure_stop_stm32wb(&self) -> Result<(), ()> { use core::task::Poll; use embassy_futures::poll_once; @@ -252,14 +254,20 @@ impl Executor { use crate::pac::rcc::vals::{Smps, Sw}; use crate::pac::{PWR, RCC}; + trace!("low power: trying to get sem3"); + let sem3_mutex = match poll_once(HardwareSemaphoreChannel::::new(3).lock(0)) { Poll::Pending => None, Poll::Ready(mutex) => Some(mutex), } .ok_or(())?; + trace!("low power: got sem3"); + let sem4_mutex = HardwareSemaphoreChannel::::new(4).try_lock(0); if let Some(sem4_mutex) = sem4_mutex { + trace!("low power: got sem4"); + if PWR.extscr().read().c2ds() { drop(sem4_mutex); } else { @@ -297,9 +305,9 @@ impl Executor { #[allow(unused_variables)] fn configure_stop(&self, stop_mode: StopMode) -> Result<(), ()> { #[cfg(all(stm32wb, feature = "low-power"))] - self.configure_stop_stm32wb(stop_mode)?; + self.configure_stop_stm32wb()?; - #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))] + #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wlex))] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); #[cfg(stm32h5)] crate::pac::PWR.pmcr().modify(|v| { diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index f5684d4df..8fcb6b2b4 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -31,7 +31,7 @@ stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng", "dual- stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash", "dual-bank"] stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"] stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash -stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng", "hsem"] +stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng", "hsem", "stop"] stm32wba52cg = ["embassy-stm32/stm32wba52cg", "spi-v345", "chrono", "rng", "hash"] stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono", "hsem"] stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] diff --git a/tests/stm32/src/bin/hsem.rs b/tests/stm32/src/bin/hsem.rs index 19648997c..fa69f22b2 100644 --- a/tests/stm32/src/bin/hsem.rs +++ b/tests/stm32/src/bin/hsem.rs @@ -30,6 +30,9 @@ async fn main(_spawner: Spawner) { // // hsem.channel_for(SemaphoreNumber::Channel5).unlock(0); + #[cfg(feature = "stm32wb55rg")] + let [_channel1, _channel2, mut channel5, _channel6] = hsem.split(); + #[cfg(not(feature = "stm32wb55rg"))] let [_channel1, _channel2, _channel3, _channel4, mut channel5, _channel6] = hsem.split(); info!("Locking channel 5"); -- cgit From 331901135c9537e726e08390eacdcd6c965d2406 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 20 Nov 2025 07:49:04 -0600 Subject: low power: don't enter stop without rcc config --- embassy-stm32/src/low_power.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index f35eb71e4..9de49c867 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -50,7 +50,7 @@ use critical_section::CriticalSection; use embassy_executor::*; use crate::interrupt; -use crate::rcc::{REFCOUNT_STOP1, REFCOUNT_STOP2}; +use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2}; use crate::time_driver::get_driver; const THREAD_PENDER: usize = usize::MAX; @@ -201,7 +201,7 @@ impl Executor { { use crate::pac::rcc::vals::Sw; use crate::pac::{PWR, RCC}; - use crate::rcc::{RCC_CONFIG, init as init_rcc}; + use crate::rcc::init as init_rcc; let extscr = PWR.extscr().read(); if extscr.c1stop2f() || extscr.c1stopf() { @@ -245,7 +245,7 @@ impl Executor { } #[cfg(all(stm32wb, feature = "low-power"))] - fn configure_stop_stm32wb(&self) -> Result<(), ()> { + fn configure_stop_stm32wb(&self, _cs: CriticalSection) -> Result<(), ()> { use core::task::Poll; use embassy_futures::poll_once; @@ -303,9 +303,9 @@ impl Executor { } #[allow(unused_variables)] - fn configure_stop(&self, stop_mode: StopMode) -> Result<(), ()> { + fn configure_stop(&self, _cs: CriticalSection, stop_mode: StopMode) -> Result<(), ()> { #[cfg(all(stm32wb, feature = "low-power"))] - self.configure_stop_stm32wb()?; + self.configure_stop_stm32wb(_cs)?; #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wlex))] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); @@ -330,9 +330,10 @@ impl Executor { compiler_fence(Ordering::SeqCst); critical_section::with(|cs| { + let _ = unsafe { RCC_CONFIG }?; let stop_mode = Self::stop_mode(cs)?; - let _ = get_driver().pause_time(cs).ok()?; - self.configure_stop(stop_mode).ok()?; + get_driver().pause_time(cs).ok()?; + self.configure_stop(cs, stop_mode).ok()?; Some(()) }) -- cgit From 8d1b4fde897af2c943b5b1abe1503a49a5b8560a Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 20 Nov 2025 07:49:14 -0600 Subject: adc: fix ringbuf stop --- embassy-stm32/src/adc/ringbuffered.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index a56f8ca0b..5437866d3 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs @@ -49,8 +49,6 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { } pub fn stop(&mut self) { - T::stop(); - self.ring_buf.request_pause(); compiler_fence(Ordering::SeqCst); @@ -161,7 +159,7 @@ impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> { return Ok(len); } Err(_) => { - self.stop(); + self.ring_buf.request_pause(); return Err(OverrunError); } -- cgit From 219de4be85f6e63e73693c934be54687c9ad860c Mon Sep 17 00:00:00 2001 From: Gerzain Mata Date: Wed, 19 Nov 2025 20:45:36 -0700 Subject: stm32: Fixed ADC4 enable() for WBA --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/adc/adc4.rs | 18 +++++++++++++++++- examples/stm32wba6/src/bin/adc.rs | 28 +++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index d2f675dbc..8dc34ff72 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: Fixed ADC4 enable() for WBA - feat: add poll_for methods to exti - feat: implement stop for stm32wb. - change: rework hsem and add HIL test for some chips. diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 499fc2093..472eb46fd 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -113,10 +113,26 @@ foreach_adc!( } fn enable() { + let cr_initial = ADC4::regs().cr().read(); + let isr_initial = ADC4::regs().isr().read(); + + if cr_initial.aden() && isr_initial.adrdy() { + return; + } + + if cr_initial.aden() || cr_initial.adstart() { + if cr_initial.adstart() { + ADC4::regs().cr().modify(|w| w.set_adstp(true)); + while ADC4::regs().cr().read().adstart() {} + } + + ADC4::regs().cr().modify(|w| w.set_addis(true)); + while ADC4::regs().cr().read().aden() {} + } + ADC4::regs().isr().write(|w| w.set_adrdy(true)); ADC4::regs().cr().modify(|w| w.set_aden(true)); while !ADC4::regs().isr().read().adrdy() {} - ADC4::regs().isr().write(|w| w.set_adrdy(true)); } fn start() { diff --git a/examples/stm32wba6/src/bin/adc.rs b/examples/stm32wba6/src/bin/adc.rs index 9d1f39419..14f4a0636 100644 --- a/examples/stm32wba6/src/bin/adc.rs +++ b/examples/stm32wba6/src/bin/adc.rs @@ -3,11 +3,37 @@ use defmt::*; use embassy_stm32::adc::{Adc, AdcChannel, SampleTime, adc4}; +use embassy_stm32::Config; +use embassy_stm32::rcc::{ + AHB5Prescaler, AHBPrescaler, APBPrescaler, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, +}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: embassy_executor::Spawner) { - let config = embassy_stm32::Config::default(); + let mut config = Config::default(); + // Fine-tune PLL1 dividers/multipliers + config.rcc.pll1 = Some(embassy_stm32::rcc::Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz + mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO + divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) + // divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED) + divq: None, + divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG) + frac: Some(0), // Fractional part (enabled) + }); + + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb7_pre = APBPrescaler::DIV1; + config.rcc.ahb5_pre = AHB5Prescaler::DIV4; + + // voltage scale for max performance + config.rcc.voltage_scale = VoltageScale::RANGE1; + // route PLL1_P into the USB‐OTG‐HS block + config.rcc.sys = Sysclk::PLL1_R; let mut p = embassy_stm32::init(config); -- cgit From 3abc2e592f66c16ada6c475e48cde282b79d3c1f Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 20 Nov 2025 14:27:31 -0600 Subject: adc: allow usage of anyadcchannel for adc4 --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/adc/mod.rs | 6 +++--- examples/stm32u5/src/bin/adc.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 597cbb192..c547fa443 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 use of anyadcchannel for adc4 - change: rework hsem and add HIL test for some chips. - change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871)) - feat: allow embassy_executor::main for low power diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 74648cc21..755cb78c2 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -436,9 +436,9 @@ pub struct AnyAdcChannel { is_differential: bool, _phantom: PhantomData, } -impl_peripheral!(AnyAdcChannel); -impl AdcChannel for AnyAdcChannel {} -impl SealedAdcChannel for AnyAdcChannel { +impl_peripheral!(AnyAdcChannel); +impl AdcChannel for AnyAdcChannel {} +impl SealedAdcChannel for AnyAdcChannel { fn channel(&self) -> u8 { self.channel } diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index ad59c0bea..4d2d93aa2 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -31,7 +31,7 @@ async fn main(_spawner: embassy_executor::Spawner) { // **** ADC4 init **** let mut adc4 = Adc::new_adc4(p.ADC4); - let mut adc4_pin1 = p.PC1; // A4 + let mut adc4_pin1 = p.PC1.degrade_adc(); // A4 let mut adc4_pin2 = p.PC0; // A5 adc4.set_resolution_adc4(adc4::Resolution::BITS12); adc4.set_averaging_adc4(adc4::Averaging::Samples256); -- cgit