mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-30 05:40:55 +00:00
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.
This commit is contained in:
parent
b8577a3133
commit
d264c8ab31
@ -12,6 +12,7 @@ use crate::{peripherals, Peri};
|
|||||||
|
|
||||||
mod tsel;
|
mod tsel;
|
||||||
use embassy_hal_internal::PeripheralType;
|
use embassy_hal_internal::PeripheralType;
|
||||||
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
pub use tsel::TriggerSel;
|
pub use tsel::TriggerSel;
|
||||||
|
|
||||||
/// Operating mode for DAC channel
|
/// Operating mode for DAC channel
|
||||||
@ -96,6 +97,41 @@ pub enum ValueArray<'a> {
|
|||||||
Bit12Right(&'a [u16]),
|
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<CriticalSectionRawMutex, core::cell::RefCell<InnerState>>;
|
||||||
|
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.
|
/// Driver for a single DAC channel.
|
||||||
///
|
///
|
||||||
/// If you want to use both channels, either together or independently,
|
/// 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);
|
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::<T>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable this channel.
|
/// 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> {
|
impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
rcc::disable::<T>();
|
self.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,6 +643,13 @@ impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> {
|
|||||||
|
|
||||||
trait SealedInstance {
|
trait SealedInstance {
|
||||||
fn regs() -> crate::pac::dac::Dac;
|
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.
|
/// DAC instance.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user