aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorFrancisco José Gómez <[email protected]>2025-08-28 10:36:07 -0400
committerDario Nieuwenhuis <[email protected]>2025-09-05 16:28:40 +0200
commitd264c8ab31d6361a3fb76443ae80630d123d68fb (patch)
tree6db146e7383b2558c2684e9b78e7d598e5a889f0 /embassy-stm32
parentb8577a31338358d10b1fdb7dd374b0c7eafe86b5 (diff)
fix(embassy-stm32): Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope
Fix #4577 by counting references to DacChannel. Modeled after similar code in the `can` module.
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/src/dac/mod.rs55
1 files changed, 54 insertions, 1 deletions
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
13mod tsel; 13mod tsel;
14use embassy_hal_internal::PeripheralType; 14use embassy_hal_internal::PeripheralType;
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15pub use tsel::TriggerSel; 16pub 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))]
102enum ChannelEvent {
103 Enable,
104 Disable,
105}
106
107struct InnerState {
108 channel_count: usize,
109}
110
111type SharedState = embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, core::cell::RefCell<InnerState>>;
112struct State {
113 state: SharedState,
114}
115
116impl 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
355impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> { 401impl<'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
598trait SealedInstance { 644trait 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.