diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 50bdc1072..69f15013d 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received - feat: stm32/timer: add set_polarity functions for main and complementary outputs in complementary_pwm - Add I2S support for STM32F1, STM32C0, STM32F0, STM32F3, STM32F7, STM32G0, STM32WL, STM32H5, STM32H7RS +### Fixed + +- STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577)) ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index d8f1f96f2..bc6c3cd34 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -12,6 +12,7 @@ use crate::{peripherals, Peri}; mod tsel; use embassy_hal_internal::PeripheralType; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; pub use tsel::TriggerSel; /// Operating mode for DAC channel @@ -96,6 +97,41 @@ pub enum ValueArray<'a> { Bit12Right(&'a [u16]), } +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +enum ChannelEvent { + Enable, + Disable, +} + +struct InnerState { + channel_count: usize, +} + +type SharedState = embassy_sync::blocking_mutex::Mutex>; +struct State { + state: SharedState, +} + +impl State { + /// Adjusts the channel count in response to a `ChannelEvent`, returning the updated value. + pub fn adjust_channel_count(&self, event: ChannelEvent) -> usize { + self.state.lock(|state| { + { + let mut mut_state = state.borrow_mut(); + match event { + ChannelEvent::Enable => { + mut_state.channel_count += 1; + } + ChannelEvent::Disable => { + mut_state.channel_count -= 1; + } + }; + } + state.borrow().channel_count + }) + } +} /// Driver for a single DAC channel. /// /// If you want to use both channels, either together or independently, @@ -249,6 +285,16 @@ impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> { reg.set_en(C::IDX, on); }); }); + let event = if on { + ChannelEvent::Enable + } else { + ChannelEvent::Disable + }; + let channel_count = T::state().adjust_channel_count(event); + // Disable the DAC only if no more channels are using it. + if channel_count == 0 { + rcc::disable::(); + } } /// Enable this channel. @@ -354,7 +400,7 @@ impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> { impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> { fn drop(&mut self) { - rcc::disable::(); + self.disable(); } } @@ -597,6 +643,13 @@ impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> { trait SealedInstance { fn regs() -> crate::pac::dac::Dac; + + fn state() -> &'static State { + static STATE: State = State { + state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(InnerState { channel_count: 0 })), + }; + &STATE + } } /// DAC instance.