mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 12:20:37 +00:00
stm32/dac: remove DMA generic params.
This commit is contained in:
parent
f007b53db3
commit
73ec3a7506
@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::into_ref;
|
||||||
|
|
||||||
use crate::dma::NoDma;
|
use crate::dma::ChannelAndRequest;
|
||||||
|
use crate::mode::{Async, Blocking, Mode as PeriMode};
|
||||||
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
use crate::pac::dac;
|
use crate::pac::dac;
|
||||||
use crate::rcc::{self, RccPeripheral};
|
use crate::rcc::{self, RccPeripheral};
|
||||||
@ -100,22 +101,20 @@ pub enum ValueArray<'a> {
|
|||||||
///
|
///
|
||||||
/// If you want to use both channels, either together or independently,
|
/// If you want to use both channels, either together or independently,
|
||||||
/// create a [`Dac`] first and use it to access each channel.
|
/// create a [`Dac`] first and use it to access each channel.
|
||||||
pub struct DacChannel<'d, T: Instance, C: Channel, DMA = NoDma> {
|
pub struct DacChannel<'d, T: Instance, C: Channel, M: PeriMode> {
|
||||||
phantom: PhantomData<&'d mut (T, C)>,
|
phantom: PhantomData<&'d mut (T, C, M)>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
dma: PeripheralRef<'d, DMA>,
|
dma: Option<ChannelAndRequest<'d>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DAC channel 1 type alias.
|
/// DAC channel 1 type alias.
|
||||||
pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch1, DMA>;
|
pub type DacCh1<'d, T, M> = DacChannel<'d, T, Ch1, M>;
|
||||||
/// DAC channel 2 type alias.
|
/// DAC channel 2 type alias.
|
||||||
pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch2, DMA>;
|
pub type DacCh2<'d, T, M> = DacChannel<'d, T, Ch2, M>;
|
||||||
|
|
||||||
impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> {
|
impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Async> {
|
||||||
/// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
|
/// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
|
||||||
///
|
///
|
||||||
/// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
|
|
||||||
///
|
|
||||||
/// The channel is enabled on creation and begin to drive the output pin.
|
/// The channel is enabled on creation and begin to drive the output pin.
|
||||||
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will
|
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will
|
||||||
/// disable the channel; you must re-enable it with `enable()`.
|
/// disable the channel; you must re-enable it with `enable()`.
|
||||||
@ -123,21 +122,18 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> {
|
|||||||
/// By default, triggering is disabled, but it can be enabled using
|
/// By default, triggering is disabled, but it can be enabled using
|
||||||
/// [`DacChannel::set_trigger()`].
|
/// [`DacChannel::set_trigger()`].
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
dma: impl Peripheral<P = DMA> + 'd,
|
dma: impl Peripheral<P = impl Dma<T, C>> + 'd,
|
||||||
pin: impl Peripheral<P = impl DacPin<T, C> + crate::gpio::Pin> + 'd,
|
pin: impl Peripheral<P = impl DacPin<T, C>> + 'd,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(dma, pin);
|
into_ref!(dma, pin);
|
||||||
pin.set_as_analog();
|
pin.set_as_analog();
|
||||||
rcc::enable_and_reset::<T>();
|
Self::new_inner(
|
||||||
let mut dac = Self {
|
peri,
|
||||||
phantom: PhantomData,
|
new_dma!(dma),
|
||||||
dma,
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
};
|
Mode::NormalExternalBuffered,
|
||||||
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
)
|
||||||
dac.set_hfsel();
|
|
||||||
dac.enable();
|
|
||||||
dac
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `DacChannel` instance where the external output pin is not used,
|
/// Create a new `DacChannel` instance where the external output pin is not used,
|
||||||
@ -148,13 +144,99 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> {
|
|||||||
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
|
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
|
||||||
/// channel; you must re-enable it with `enable()`.
|
/// channel; you must re-enable it with `enable()`.
|
||||||
///
|
///
|
||||||
/// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
|
/// By default, triggering is disabled, but it can be enabled using
|
||||||
|
/// [`DacChannel::set_trigger()`].
|
||||||
|
#[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
|
||||||
|
pub fn new_internal(peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = impl Dma<T, C>> + 'd) -> Self {
|
||||||
|
into_ref!(dma);
|
||||||
|
Self::new_inner(peri, new_dma!(dma), Mode::NormalInternalUnbuffered)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write `data` to this channel via DMA.
|
||||||
|
///
|
||||||
|
/// To prevent delays or glitches when outputing a periodic waveform, the `circular`
|
||||||
|
/// flag can be set. This configures a circular DMA transfer that continually outputs
|
||||||
|
/// `data`. Note that for performance reasons in circular mode the transfer-complete
|
||||||
|
/// interrupt is disabled.
|
||||||
|
#[cfg(not(gpdma))]
|
||||||
|
pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) {
|
||||||
|
// Enable DAC and DMA
|
||||||
|
T::regs().cr().modify(|w| {
|
||||||
|
w.set_en(C::IDX, true);
|
||||||
|
w.set_dmaen(C::IDX, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
let dma = self.dma.as_mut().unwrap();
|
||||||
|
|
||||||
|
let tx_options = crate::dma::TransferOptions {
|
||||||
|
circular,
|
||||||
|
half_transfer_ir: false,
|
||||||
|
complete_transfer_ir: !circular,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initiate the correct type of DMA transfer depending on what data is passed
|
||||||
|
let tx_f = match data {
|
||||||
|
ValueArray::Bit8(buf) => unsafe { dma.write(buf, T::regs().dhr8r(C::IDX).as_ptr() as *mut u8, tx_options) },
|
||||||
|
ValueArray::Bit12Left(buf) => unsafe {
|
||||||
|
dma.write(buf, T::regs().dhr12l(C::IDX).as_ptr() as *mut u16, tx_options)
|
||||||
|
},
|
||||||
|
ValueArray::Bit12Right(buf) => unsafe {
|
||||||
|
dma.write(buf, T::regs().dhr12r(C::IDX).as_ptr() as *mut u16, tx_options)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
tx_f.await;
|
||||||
|
|
||||||
|
T::regs().cr().modify(|w| {
|
||||||
|
w.set_en(C::IDX, false);
|
||||||
|
w.set_dmaen(C::IDX, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Blocking> {
|
||||||
|
/// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
|
||||||
|
///
|
||||||
|
/// The channel is enabled on creation and begin to drive the output pin.
|
||||||
|
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will
|
||||||
|
/// disable the channel; you must re-enable it with `enable()`.
|
||||||
|
///
|
||||||
|
/// By default, triggering is disabled, but it can be enabled using
|
||||||
|
/// [`DacChannel::set_trigger()`].
|
||||||
|
pub fn new_blocking(peri: impl Peripheral<P = T> + 'd, pin: impl Peripheral<P = impl DacPin<T, C>> + 'd) -> Self {
|
||||||
|
into_ref!(pin);
|
||||||
|
pin.set_as_analog();
|
||||||
|
Self::new_inner(
|
||||||
|
peri,
|
||||||
|
None,
|
||||||
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
|
Mode::NormalExternalBuffered,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `DacChannel` instance where the external output pin is not used,
|
||||||
|
/// so the DAC can only be used to generate internal signals.
|
||||||
|
/// The GPIO pin is therefore available to be used for other functions.
|
||||||
|
///
|
||||||
|
/// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
|
||||||
|
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
|
||||||
|
/// channel; you must re-enable it with `enable()`.
|
||||||
///
|
///
|
||||||
/// By default, triggering is disabled, but it can be enabled using
|
/// By default, triggering is disabled, but it can be enabled using
|
||||||
/// [`DacChannel::set_trigger()`].
|
/// [`DacChannel::set_trigger()`].
|
||||||
#[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
|
#[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
|
||||||
pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self {
|
pub fn new_internal_blocking(peri: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
into_ref!(dma);
|
Self::new_inner(peri, None, Mode::NormalInternalUnbuffered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> {
|
||||||
|
fn new_inner(
|
||||||
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
|
dma: Option<ChannelAndRequest<'d>>,
|
||||||
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode,
|
||||||
|
) -> Self {
|
||||||
rcc::enable_and_reset::<T>();
|
rcc::enable_and_reset::<T>();
|
||||||
let mut dac = Self {
|
let mut dac = Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -162,7 +244,8 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> {
|
|||||||
};
|
};
|
||||||
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
||||||
dac.set_hfsel();
|
dac.set_hfsel();
|
||||||
dac.set_mode(Mode::NormalInternalUnbuffered);
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
|
dac.set_mode(mode);
|
||||||
dac.enable();
|
dac.enable();
|
||||||
dac
|
dac
|
||||||
}
|
}
|
||||||
@ -275,75 +358,9 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write `data` to this channel via DMA.
|
|
||||||
///
|
|
||||||
/// To prevent delays or glitches when outputing a periodic waveform, the `circular`
|
|
||||||
/// flag can be set. This configures a circular DMA transfer that continually outputs
|
|
||||||
/// `data`. Note that for performance reasons in circular mode the transfer-complete
|
|
||||||
/// interrupt is disabled.
|
|
||||||
#[cfg(not(gpdma))]
|
|
||||||
pub async fn write(&mut self, data: ValueArray<'_>, circular: bool)
|
|
||||||
where
|
|
||||||
DMA: Dma<T, C>,
|
|
||||||
{
|
|
||||||
// Enable DAC and DMA
|
|
||||||
T::regs().cr().modify(|w| {
|
|
||||||
w.set_en(C::IDX, true);
|
|
||||||
w.set_dmaen(C::IDX, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
let tx_request = self.dma.request();
|
|
||||||
let dma_channel = &mut self.dma;
|
|
||||||
|
|
||||||
let tx_options = crate::dma::TransferOptions {
|
|
||||||
circular,
|
|
||||||
half_transfer_ir: false,
|
|
||||||
complete_transfer_ir: !circular,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initiate the correct type of DMA transfer depending on what data is passed
|
|
||||||
let tx_f = match data {
|
|
||||||
ValueArray::Bit8(buf) => unsafe {
|
|
||||||
crate::dma::Transfer::new_write(
|
|
||||||
dma_channel,
|
|
||||||
tx_request,
|
|
||||||
buf,
|
|
||||||
T::regs().dhr8r(C::IDX).as_ptr() as *mut u8,
|
|
||||||
tx_options,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
ValueArray::Bit12Left(buf) => unsafe {
|
|
||||||
crate::dma::Transfer::new_write(
|
|
||||||
dma_channel,
|
|
||||||
tx_request,
|
|
||||||
buf,
|
|
||||||
T::regs().dhr12l(C::IDX).as_ptr() as *mut u16,
|
|
||||||
tx_options,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
ValueArray::Bit12Right(buf) => unsafe {
|
|
||||||
crate::dma::Transfer::new_write(
|
|
||||||
dma_channel,
|
|
||||||
tx_request,
|
|
||||||
buf,
|
|
||||||
T::regs().dhr12r(C::IDX).as_ptr() as *mut u16,
|
|
||||||
tx_options,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
tx_f.await;
|
|
||||||
|
|
||||||
T::regs().cr().modify(|w| {
|
|
||||||
w.set_en(C::IDX, false);
|
|
||||||
w.set_dmaen(C::IDX, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, C: Channel, DMA> Drop for DacChannel<'d, T, C, DMA> {
|
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>();
|
rcc::disable::<T>();
|
||||||
}
|
}
|
||||||
@ -357,14 +374,14 @@ impl<'d, T: Instance, C: Channel, DMA> Drop for DacChannel<'d, T, C, DMA> {
|
|||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// // Pins may need to be changed for your specific device.
|
/// // Pins may need to be changed for your specific device.
|
||||||
/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split();
|
/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new_blocking(p.DAC1, p.PA4, p.PA5).split();
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> {
|
pub struct Dac<'d, T: Instance, M: PeriMode> {
|
||||||
ch1: DacChannel<'d, T, Ch1, DMACh1>,
|
ch1: DacChannel<'d, T, Ch1, M>,
|
||||||
ch2: DacChannel<'d, T, Ch2, DMACh2>,
|
ch2: DacChannel<'d, T, Ch2, M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
impl<'d, T: Instance> Dac<'d, T, Async> {
|
||||||
/// Create a new `Dac` instance, consuming the underlying DAC peripheral.
|
/// Create a new `Dac` instance, consuming the underlying DAC peripheral.
|
||||||
///
|
///
|
||||||
/// This struct allows you to access both channels of the DAC, where available. You can either
|
/// This struct allows you to access both channels of the DAC, where available. You can either
|
||||||
@ -378,37 +395,22 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
|||||||
/// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
|
/// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
|
||||||
/// method on the underlying channels.
|
/// method on the underlying channels.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
dma_ch1: impl Peripheral<P = DMACh1> + 'd,
|
dma_ch1: impl Peripheral<P = impl Dma<T, Ch1>> + 'd,
|
||||||
dma_ch2: impl Peripheral<P = DMACh2> + 'd,
|
dma_ch2: impl Peripheral<P = impl Dma<T, Ch2>> + 'd,
|
||||||
pin_ch1: impl Peripheral<P = impl DacPin<T, Ch1> + crate::gpio::Pin> + 'd,
|
pin_ch1: impl Peripheral<P = impl DacPin<T, Ch1> + crate::gpio::Pin> + 'd,
|
||||||
pin_ch2: impl Peripheral<P = impl DacPin<T, Ch2> + crate::gpio::Pin> + 'd,
|
pin_ch2: impl Peripheral<P = impl DacPin<T, Ch2> + crate::gpio::Pin> + 'd,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
|
into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
|
||||||
pin_ch1.set_as_analog();
|
pin_ch1.set_as_analog();
|
||||||
pin_ch2.set_as_analog();
|
pin_ch2.set_as_analog();
|
||||||
|
Self::new_inner(
|
||||||
// Enable twice to increment the DAC refcount for each channel.
|
peri,
|
||||||
rcc::enable_and_reset::<T>();
|
new_dma!(dma_ch1),
|
||||||
rcc::enable_and_reset::<T>();
|
new_dma!(dma_ch2),
|
||||||
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
let mut ch1 = DacCh1 {
|
Mode::NormalExternalBuffered,
|
||||||
phantom: PhantomData,
|
)
|
||||||
dma: dma_ch1,
|
|
||||||
};
|
|
||||||
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
|
||||||
ch1.set_hfsel();
|
|
||||||
ch1.enable();
|
|
||||||
|
|
||||||
let mut ch2 = DacCh2 {
|
|
||||||
phantom: PhantomData,
|
|
||||||
dma: dma_ch2,
|
|
||||||
};
|
|
||||||
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
|
||||||
ch2.set_hfsel();
|
|
||||||
ch2.enable();
|
|
||||||
|
|
||||||
Self { ch1, ch2 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `Dac` instance where the external output pins are not used,
|
/// Create a new `Dac` instance where the external output pins are not used,
|
||||||
@ -427,11 +429,77 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
|||||||
/// method on the underlying channels.
|
/// method on the underlying channels.
|
||||||
#[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
|
#[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
|
||||||
pub fn new_internal(
|
pub fn new_internal(
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
dma_ch1: impl Peripheral<P = DMACh1> + 'd,
|
dma_ch1: impl Peripheral<P = impl Dma<T, Ch1>> + 'd,
|
||||||
dma_ch2: impl Peripheral<P = DMACh2> + 'd,
|
dma_ch2: impl Peripheral<P = impl Dma<T, Ch2>> + 'd,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(dma_ch1, dma_ch2);
|
into_ref!(dma_ch1, dma_ch2);
|
||||||
|
Self::new_inner(
|
||||||
|
peri,
|
||||||
|
new_dma!(dma_ch1),
|
||||||
|
new_dma!(dma_ch2),
|
||||||
|
Mode::NormalInternalUnbuffered,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> Dac<'d, T, Blocking> {
|
||||||
|
/// Create a new `Dac` instance, consuming the underlying DAC peripheral.
|
||||||
|
///
|
||||||
|
/// This struct allows you to access both channels of the DAC, where available. You can either
|
||||||
|
/// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use
|
||||||
|
/// the two channels together.
|
||||||
|
///
|
||||||
|
/// The channels are enabled on creation and begin to drive their output pins.
|
||||||
|
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will
|
||||||
|
/// disable the channel; you must re-enable them with `enable()`.
|
||||||
|
///
|
||||||
|
/// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
|
||||||
|
/// method on the underlying channels.
|
||||||
|
pub fn new_blocking(
|
||||||
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
|
pin_ch1: impl Peripheral<P = impl DacPin<T, Ch1> + crate::gpio::Pin> + 'd,
|
||||||
|
pin_ch2: impl Peripheral<P = impl DacPin<T, Ch2> + crate::gpio::Pin> + 'd,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(pin_ch1, pin_ch2);
|
||||||
|
pin_ch1.set_as_analog();
|
||||||
|
pin_ch2.set_as_analog();
|
||||||
|
Self::new_inner(
|
||||||
|
peri,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
|
Mode::NormalExternalBuffered,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `Dac` instance where the external output pins are not used,
|
||||||
|
/// so the DAC can only be used to generate internal signals but the GPIO
|
||||||
|
/// pins remain available for other functions.
|
||||||
|
///
|
||||||
|
/// This struct allows you to access both channels of the DAC, where available. You can either
|
||||||
|
/// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two
|
||||||
|
/// channels together.
|
||||||
|
///
|
||||||
|
/// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
|
||||||
|
/// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
|
||||||
|
/// channel; you must re-enable them with `enable()`.
|
||||||
|
///
|
||||||
|
/// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
|
||||||
|
/// method on the underlying channels.
|
||||||
|
#[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
|
||||||
|
pub fn new_internal(peri: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
|
Self::new_inner(peri, None, None, Mode::NormalInternalUnbuffered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> {
|
||||||
|
fn new_inner(
|
||||||
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
|
dma_ch1: Option<ChannelAndRequest<'d>>,
|
||||||
|
dma_ch2: Option<ChannelAndRequest<'d>>,
|
||||||
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode,
|
||||||
|
) -> Self {
|
||||||
// Enable twice to increment the DAC refcount for each channel.
|
// Enable twice to increment the DAC refcount for each channel.
|
||||||
rcc::enable_and_reset::<T>();
|
rcc::enable_and_reset::<T>();
|
||||||
rcc::enable_and_reset::<T>();
|
rcc::enable_and_reset::<T>();
|
||||||
@ -442,7 +510,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
|||||||
};
|
};
|
||||||
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
||||||
ch1.set_hfsel();
|
ch1.set_hfsel();
|
||||||
ch1.set_mode(Mode::NormalInternalUnbuffered);
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
|
ch1.set_mode(mode);
|
||||||
ch1.enable();
|
ch1.enable();
|
||||||
|
|
||||||
let mut ch2 = DacCh2 {
|
let mut ch2 = DacCh2 {
|
||||||
@ -451,7 +520,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
|||||||
};
|
};
|
||||||
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
#[cfg(any(dac_v5, dac_v6, dac_v7))]
|
||||||
ch2.set_hfsel();
|
ch2.set_hfsel();
|
||||||
ch2.set_mode(Mode::NormalInternalUnbuffered);
|
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||||
|
ch2.set_mode(mode);
|
||||||
ch2.enable();
|
ch2.enable();
|
||||||
|
|
||||||
Self { ch1, ch2 }
|
Self { ch1, ch2 }
|
||||||
@ -460,17 +530,17 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
|||||||
/// Split this `Dac` into separate channels.
|
/// Split this `Dac` into separate channels.
|
||||||
///
|
///
|
||||||
/// You can access and move the channels around separately after splitting.
|
/// You can access and move the channels around separately after splitting.
|
||||||
pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) {
|
pub fn split(self) -> (DacCh1<'d, T, M>, DacCh2<'d, T, M>) {
|
||||||
(self.ch1, self.ch2)
|
(self.ch1, self.ch2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Temporarily access channel 1.
|
/// Temporarily access channel 1.
|
||||||
pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> {
|
pub fn ch1(&mut self) -> &mut DacCh1<'d, T, M> {
|
||||||
&mut self.ch1
|
&mut self.ch1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Temporarily access channel 2.
|
/// Temporarily access channel 2.
|
||||||
pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> {
|
pub fn ch2(&mut self) -> &mut DacCh2<'d, T, M> {
|
||||||
&mut self.ch2
|
&mut self.ch2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dac::{DacCh1, Value};
|
use embassy_stm32::dac::{DacCh1, Value};
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
@ -12,7 +11,7 @@ async fn main(_spawner: Spawner) -> ! {
|
|||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
info!("Hello World, dude!");
|
info!("Hello World, dude!");
|
||||||
|
|
||||||
let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
|
let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
for v in 0..=255 {
|
for v in 0..=255 {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::dac::{DacCh1, Value};
|
use embassy_stm32::dac::{DacCh1, Value};
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::Config;
|
use embassy_stm32::Config;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
let p = embassy_stm32::init(config);
|
let p = embassy_stm32::init(config);
|
||||||
|
|
||||||
let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
|
let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
for v in 0..=255 {
|
for v in 0..=255 {
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
|
use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
|
||||||
|
use embassy_stm32::mode::Async;
|
||||||
use embassy_stm32::pac::timer::vals::Mms;
|
use embassy_stm32::pac::timer::vals::Mms;
|
||||||
use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
|
use embassy_stm32::peripherals::{DAC1, TIM6, TIM7};
|
||||||
use embassy_stm32::rcc::frequency;
|
use embassy_stm32::rcc::frequency;
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
use embassy_stm32::timer::low_level::Timer;
|
use embassy_stm32::timer::low_level::Timer;
|
||||||
@ -56,7 +57,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
|
async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) {
|
||||||
let data: &[u8; 256] = &calculate_array::<256>();
|
let data: &[u8; 256] = &calculate_array::<256>();
|
||||||
|
|
||||||
info!("TIM6 frequency is {}", frequency::<TIM6>());
|
info!("TIM6 frequency is {}", frequency::<TIM6>());
|
||||||
@ -99,7 +100,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
|
async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) {
|
||||||
let data: &[u8; 256] = &calculate_array::<256>();
|
let data: &[u8; 256] = &calculate_array::<256>();
|
||||||
|
|
||||||
info!("TIM7 frequency is {}", frequency::<TIM6>());
|
info!("TIM7 frequency is {}", frequency::<TIM6>());
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::dac::{DacCh1, Value};
|
use embassy_stm32::dac::{DacCh1, Value};
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[cortex_m_rt::entry]
|
#[cortex_m_rt::entry]
|
||||||
@ -11,7 +10,7 @@ fn main() -> ! {
|
|||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
|
let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
for v in 0..=255 {
|
for v in 0..=255 {
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
|
use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
|
||||||
|
use embassy_stm32::mode::Async;
|
||||||
use embassy_stm32::pac::timer::vals::Mms;
|
use embassy_stm32::pac::timer::vals::Mms;
|
||||||
use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
|
use embassy_stm32::peripherals::{DAC1, TIM6, TIM7};
|
||||||
use embassy_stm32::rcc::frequency;
|
use embassy_stm32::rcc::frequency;
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
use embassy_stm32::timer::low_level::Timer;
|
use embassy_stm32::timer::low_level::Timer;
|
||||||
@ -27,7 +28,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
|
async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) {
|
||||||
let data: &[u8; 256] = &calculate_array::<256>();
|
let data: &[u8; 256] = &calculate_array::<256>();
|
||||||
|
|
||||||
info!("TIM6 frequency is {}", frequency::<TIM6>());
|
info!("TIM6 frequency is {}", frequency::<TIM6>());
|
||||||
@ -70,7 +71,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
|
async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) {
|
||||||
let data: &[u8; 256] = &calculate_array::<256>();
|
let data: &[u8; 256] = &calculate_array::<256>();
|
||||||
|
|
||||||
info!("TIM7 frequency is {}", frequency::<TIM7>());
|
info!("TIM7 frequency is {}", frequency::<TIM7>());
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::dac::{DacCh1, Value};
|
use embassy_stm32::dac::{DacCh1, Value};
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[cortex_m_rt::entry]
|
#[cortex_m_rt::entry]
|
||||||
@ -11,7 +10,7 @@ fn main() -> ! {
|
|||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
|
let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
for v in 0..=255 {
|
for v in 0..=255 {
|
||||||
|
@ -12,7 +12,6 @@ use defmt::assert;
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::adc::Adc;
|
use embassy_stm32::adc::Adc;
|
||||||
use embassy_stm32::dac::{DacCh1, Value};
|
use embassy_stm32::dac::{DacCh1, Value};
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
use micromath::F32Ext;
|
use micromath::F32Ext;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
@ -27,7 +26,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let dac_pin = peri!(p, DAC_PIN);
|
let dac_pin = peri!(p, DAC_PIN);
|
||||||
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
||||||
|
|
||||||
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
|
let mut dac = DacCh1::new_blocking(dac, dac_pin);
|
||||||
let mut adc = Adc::new(adc);
|
let mut adc = Adc::new(adc);
|
||||||
|
|
||||||
#[cfg(feature = "stm32h755zi")]
|
#[cfg(feature = "stm32h755zi")]
|
||||||
|
@ -12,7 +12,6 @@ use defmt::assert;
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::adc::Adc;
|
use embassy_stm32::adc::Adc;
|
||||||
use embassy_stm32::dac::{DacCh1, Value};
|
use embassy_stm32::dac::{DacCh1, Value};
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::{bind_interrupts, peripherals};
|
use embassy_stm32::{bind_interrupts, peripherals};
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
use micromath::F32Ext;
|
use micromath::F32Ext;
|
||||||
@ -32,7 +31,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let dac_pin = peri!(p, DAC_PIN);
|
let dac_pin = peri!(p, DAC_PIN);
|
||||||
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
||||||
|
|
||||||
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
|
let mut dac = DacCh1::new_blocking(dac, dac_pin);
|
||||||
let mut adc = Adc::new(adc, Irqs);
|
let mut adc = Adc::new(adc, Irqs);
|
||||||
|
|
||||||
#[cfg(feature = "stm32h755zi")]
|
#[cfg(feature = "stm32h755zi")]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user