diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-09-05 16:28:53 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-09-05 16:28:53 +0200 |
| commit | 4ac4452c16e1b75bcf70814a9530b7724cc16e7d (patch) | |
| tree | bf7114837ad77c185e98055a3f0c6bfc469a2872 | |
| parent | b8577a31338358d10b1fdb7dd374b0c7eafe86b5 (diff) | |
| parent | 46ce5ab6973f62c48a4de0e69a0a6c5d57d9dbb5 (diff) | |
Merge pull request #4599 from universalhandle/4577-dropped-channel-disables-dac
fix(embassy-stm32): Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/mod.rs | 55 |
2 files changed, 57 insertions, 1 deletions
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 | |||
| 13 | - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received | 13 | - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received |
| 14 | - feat: stm32/timer: add set_polarity functions for main and complementary outputs in complementary_pwm | 14 | - feat: stm32/timer: add set_polarity functions for main and complementary outputs in complementary_pwm |
| 15 | - Add I2S support for STM32F1, STM32C0, STM32F0, STM32F3, STM32F7, STM32G0, STM32WL, STM32H5, STM32H7RS | 15 | - Add I2S support for STM32F1, STM32C0, STM32F0, STM32F3, STM32F7, STM32G0, STM32WL, STM32H5, STM32H7RS |
| 16 | ### Fixed | ||
| 17 | |||
| 18 | - STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577)) | ||
| 16 | 19 | ||
| 17 | ## 0.4.0 - 2025-08-26 | 20 | ## 0.4.0 - 2025-08-26 |
| 18 | 21 | ||
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}; | |||
| 12 | 12 | ||
| 13 | mod tsel; | 13 | mod tsel; |
| 14 | use embassy_hal_internal::PeripheralType; | 14 | use embassy_hal_internal::PeripheralType; |
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 15 | pub use tsel::TriggerSel; | 16 | pub use tsel::TriggerSel; |
| 16 | 17 | ||
| 17 | /// Operating mode for DAC channel | 18 | /// Operating mode for DAC channel |
| @@ -96,6 +97,41 @@ pub enum ValueArray<'a> { | |||
| 96 | Bit12Right(&'a [u16]), | 97 | Bit12Right(&'a [u16]), |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 100 | #[derive(Debug)] | ||
| 101 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 102 | enum ChannelEvent { | ||
| 103 | Enable, | ||
| 104 | Disable, | ||
| 105 | } | ||
| 106 | |||
| 107 | struct InnerState { | ||
| 108 | channel_count: usize, | ||
| 109 | } | ||
| 110 | |||
| 111 | type SharedState = embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, core::cell::RefCell<InnerState>>; | ||
| 112 | struct State { | ||
| 113 | state: SharedState, | ||
| 114 | } | ||
| 115 | |||
| 116 | impl State { | ||
| 117 | /// Adjusts the channel count in response to a `ChannelEvent`, returning the updated value. | ||
| 118 | pub fn adjust_channel_count(&self, event: ChannelEvent) -> usize { | ||
| 119 | self.state.lock(|state| { | ||
| 120 | { | ||
| 121 | let mut mut_state = state.borrow_mut(); | ||
| 122 | match event { | ||
| 123 | ChannelEvent::Enable => { | ||
| 124 | mut_state.channel_count += 1; | ||
| 125 | } | ||
| 126 | ChannelEvent::Disable => { | ||
| 127 | mut_state.channel_count -= 1; | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | } | ||
| 131 | state.borrow().channel_count | ||
| 132 | }) | ||
| 133 | } | ||
| 134 | } | ||
| 99 | /// Driver for a single DAC channel. | 135 | /// Driver for a single DAC channel. |
| 100 | /// | 136 | /// |
| 101 | /// If you want to use both channels, either together or independently, | 137 | /// 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> { | |||
| 249 | reg.set_en(C::IDX, on); | 285 | reg.set_en(C::IDX, on); |
| 250 | }); | 286 | }); |
| 251 | }); | 287 | }); |
| 288 | let event = if on { | ||
| 289 | ChannelEvent::Enable | ||
| 290 | } else { | ||
| 291 | ChannelEvent::Disable | ||
| 292 | }; | ||
| 293 | let channel_count = T::state().adjust_channel_count(event); | ||
| 294 | // Disable the DAC only if no more channels are using it. | ||
| 295 | if channel_count == 0 { | ||
| 296 | rcc::disable::<T>(); | ||
| 297 | } | ||
| 252 | } | 298 | } |
| 253 | 299 | ||
| 254 | /// Enable this channel. | 300 | /// Enable this channel. |
| @@ -354,7 +400,7 @@ impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> { | |||
| 354 | 400 | ||
| 355 | impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> { | 401 | impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> { |
| 356 | fn drop(&mut self) { | 402 | fn drop(&mut self) { |
| 357 | rcc::disable::<T>(); | 403 | self.disable(); |
| 358 | } | 404 | } |
| 359 | } | 405 | } |
| 360 | 406 | ||
| @@ -597,6 +643,13 @@ impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> { | |||
| 597 | 643 | ||
| 598 | trait SealedInstance { | 644 | trait SealedInstance { |
| 599 | fn regs() -> crate::pac::dac::Dac; | 645 | fn regs() -> crate::pac::dac::Dac; |
| 646 | |||
| 647 | fn state() -> &'static State { | ||
| 648 | static STATE: State = State { | ||
| 649 | state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(InnerState { channel_count: 0 })), | ||
| 650 | }; | ||
| 651 | &STATE | ||
| 652 | } | ||
| 600 | } | 653 | } |
| 601 | 654 | ||
| 602 | /// DAC instance. | 655 | /// DAC instance. |
