stm32/dac: dedup pin and DMA traits, demacrofify.
This commit is contained in:
parent
17cce79807
commit
f007b53db3
@ -1151,6 +1151,8 @@ fn main() {
|
||||
(("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)),
|
||||
(("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)),
|
||||
(("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)),
|
||||
(("dac", "OUT1"), quote!(crate::dac::DacPin<Ch1>)),
|
||||
(("dac", "OUT2"), quote!(crate::dac::DacPin<Ch2>)),
|
||||
].into();
|
||||
|
||||
for p in METADATA.peripherals {
|
||||
@ -1250,17 +1252,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
// DAC is special
|
||||
if regs.kind == "dac" {
|
||||
let peri = format_ident!("{}", p.name);
|
||||
let pin_name = format_ident!("{}", pin.pin);
|
||||
let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap();
|
||||
|
||||
g.extend(quote! {
|
||||
impl_dac_pin!( #peri, #pin_name, #ch);
|
||||
})
|
||||
}
|
||||
|
||||
if regs.kind == "spdifrx" {
|
||||
let peri = format_ident!("{}", p.name);
|
||||
let pin_name = format_ident!("{}", pin.pin);
|
||||
@ -1304,8 +1295,8 @@ fn main() {
|
||||
(("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
|
||||
(("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)),
|
||||
(("hspi", "HSPI1"), quote!(crate::hspi::HspiDma)),
|
||||
(("dac", "CH1"), quote!(crate::dac::DacDma1)),
|
||||
(("dac", "CH2"), quote!(crate::dac::DacDma2)),
|
||||
(("dac", "CH1"), quote!(crate::dac::Dma<Ch1>)),
|
||||
(("dac", "CH2"), quote!(crate::dac::Dma<Ch2>)),
|
||||
(("timer", "UP"), quote!(crate::timer::UpDma)),
|
||||
(("hash", "IN"), quote!(crate::hash::Dma)),
|
||||
(("cryp", "IN"), quote!(crate::cryp::DmaIn)),
|
||||
|
||||
@ -100,20 +100,18 @@ pub enum ValueArray<'a> {
|
||||
///
|
||||
/// If you want to use both channels, either together or independently,
|
||||
/// create a [`Dac`] first and use it to access each channel.
|
||||
pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> {
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
pub struct DacChannel<'d, T: Instance, C: Channel, DMA = NoDma> {
|
||||
phantom: PhantomData<&'d mut (T, C)>,
|
||||
#[allow(unused)]
|
||||
dma: PeripheralRef<'d, DMA>,
|
||||
}
|
||||
|
||||
/// DAC channel 1 type alias.
|
||||
pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>;
|
||||
pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch1, DMA>;
|
||||
/// DAC channel 2 type alias.
|
||||
pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>;
|
||||
|
||||
impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
const IDX: usize = (N - 1) as usize;
|
||||
pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch2, DMA>;
|
||||
|
||||
impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> {
|
||||
/// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
|
||||
///
|
||||
/// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
|
||||
@ -127,7 +125,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
pub fn new(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
dma: impl Peripheral<P = DMA> + 'd,
|
||||
pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::Pin> + 'd,
|
||||
pin: impl Peripheral<P = impl DacPin<T, C> + crate::gpio::Pin> + 'd,
|
||||
) -> Self {
|
||||
into_ref!(dma, pin);
|
||||
pin.set_as_analog();
|
||||
@ -173,7 +171,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
pub fn set_enable(&mut self, on: bool) {
|
||||
critical_section::with(|_| {
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_en(Self::IDX, on);
|
||||
reg.set_en(C::IDX, on);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -194,8 +192,8 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
pub fn set_trigger(&mut self, source: TriggerSel) {
|
||||
critical_section::with(|_| {
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_en(Self::IDX, false);
|
||||
reg.set_tsel(Self::IDX, source as u8);
|
||||
reg.set_en(C::IDX, false);
|
||||
reg.set_tsel(C::IDX, source as u8);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -204,7 +202,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
pub fn set_triggering(&mut self, on: bool) {
|
||||
critical_section::with(|_| {
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_ten(Self::IDX, on);
|
||||
reg.set_ten(C::IDX, on);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -212,7 +210,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
/// Software trigger this channel.
|
||||
pub fn trigger(&mut self) {
|
||||
T::regs().swtrigr().write(|reg| {
|
||||
reg.set_swtrig(Self::IDX, true);
|
||||
reg.set_swtrig(C::IDX, true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -223,10 +221,10 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
pub fn set_mode(&mut self, mode: Mode) {
|
||||
critical_section::with(|_| {
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_en(Self::IDX, false);
|
||||
reg.set_en(C::IDX, false);
|
||||
});
|
||||
T::regs().mcr().modify(|reg| {
|
||||
reg.set_mode(Self::IDX, mode.mode());
|
||||
reg.set_mode(C::IDX, mode.mode());
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -237,15 +235,15 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
/// it will be output after the next trigger.
|
||||
pub fn set(&mut self, value: Value) {
|
||||
match value {
|
||||
Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)),
|
||||
Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)),
|
||||
Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)),
|
||||
Value::Bit8(v) => T::regs().dhr8r(C::IDX).write(|reg| reg.set_dhr(v)),
|
||||
Value::Bit12Left(v) => T::regs().dhr12l(C::IDX).write(|reg| reg.set_dhr(v)),
|
||||
Value::Bit12Right(v) => T::regs().dhr12r(C::IDX).write(|reg| reg.set_dhr(v)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the current output value of the DAC.
|
||||
pub fn read(&self) -> u16 {
|
||||
T::regs().dor(Self::IDX).read().dor()
|
||||
T::regs().dor(C::IDX).read().dor()
|
||||
}
|
||||
|
||||
/// Set HFSEL as appropriate for the current peripheral clock frequency.
|
||||
@ -277,14 +275,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_dma_methods {
|
||||
($n:literal, $trait:ident) => {
|
||||
impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA>
|
||||
where
|
||||
DMA: $trait<T>,
|
||||
{
|
||||
/// Write `data` to this channel via DMA.
|
||||
///
|
||||
/// To prevent delays or glitches when outputing a periodic waveform, the `circular`
|
||||
@ -292,11 +283,14 @@ macro_rules! impl_dma_methods {
|
||||
/// `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) {
|
||||
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(Self::IDX, true);
|
||||
w.set_dmaen(Self::IDX, true);
|
||||
w.set_en(C::IDX, true);
|
||||
w.set_dmaen(C::IDX, true);
|
||||
});
|
||||
|
||||
let tx_request = self.dma.request();
|
||||
@ -316,7 +310,7 @@ macro_rules! impl_dma_methods {
|
||||
dma_channel,
|
||||
tx_request,
|
||||
buf,
|
||||
T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8,
|
||||
T::regs().dhr8r(C::IDX).as_ptr() as *mut u8,
|
||||
tx_options,
|
||||
)
|
||||
},
|
||||
@ -325,7 +319,7 @@ macro_rules! impl_dma_methods {
|
||||
dma_channel,
|
||||
tx_request,
|
||||
buf,
|
||||
T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16,
|
||||
T::regs().dhr12l(C::IDX).as_ptr() as *mut u16,
|
||||
tx_options,
|
||||
)
|
||||
},
|
||||
@ -334,7 +328,7 @@ macro_rules! impl_dma_methods {
|
||||
dma_channel,
|
||||
tx_request,
|
||||
buf,
|
||||
T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16,
|
||||
T::regs().dhr12r(C::IDX).as_ptr() as *mut u16,
|
||||
tx_options,
|
||||
)
|
||||
},
|
||||
@ -343,18 +337,13 @@ macro_rules! impl_dma_methods {
|
||||
tx_f.await;
|
||||
|
||||
T::regs().cr().modify(|w| {
|
||||
w.set_en(Self::IDX, false);
|
||||
w.set_dmaen(Self::IDX, false);
|
||||
w.set_en(C::IDX, false);
|
||||
w.set_dmaen(C::IDX, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_dma_methods!(1, DacDma1);
|
||||
impl_dma_methods!(2, DacDma2);
|
||||
|
||||
impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
|
||||
impl<'d, T: Instance, C: Channel, DMA> Drop for DacChannel<'d, T, C, DMA> {
|
||||
fn drop(&mut self) {
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
@ -371,8 +360,8 @@ impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
|
||||
/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split();
|
||||
/// ```
|
||||
pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> {
|
||||
ch1: DacChannel<'d, T, 1, DMACh1>,
|
||||
ch2: DacChannel<'d, T, 2, DMACh2>,
|
||||
ch1: DacChannel<'d, T, Ch1, DMACh1>,
|
||||
ch2: DacChannel<'d, T, Ch2, DMACh2>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
||||
@ -392,8 +381,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
dma_ch1: impl Peripheral<P = DMACh1> + 'd,
|
||||
dma_ch2: impl Peripheral<P = DMACh2> + 'd,
|
||||
pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::Pin> + 'd,
|
||||
pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + 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,
|
||||
) -> Self {
|
||||
into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
|
||||
pin_ch1.set_as_analog();
|
||||
@ -514,11 +503,30 @@ trait SealedInstance {
|
||||
/// DAC instance.
|
||||
#[allow(private_bounds)]
|
||||
pub trait Instance: SealedInstance + RccPeripheral + 'static {}
|
||||
dma_trait!(DacDma1, Instance);
|
||||
dma_trait!(DacDma2, Instance);
|
||||
|
||||
/// Marks a pin that can be used with the DAC
|
||||
pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
||||
/// Channel 1 marker type.
|
||||
pub enum Ch1 {}
|
||||
/// Channel 2 marker type.
|
||||
pub enum Ch2 {}
|
||||
|
||||
trait SealedChannel {
|
||||
const IDX: usize;
|
||||
}
|
||||
/// DAC channel trait.
|
||||
#[allow(private_bounds)]
|
||||
pub trait Channel: SealedChannel {}
|
||||
|
||||
impl SealedChannel for Ch1 {
|
||||
const IDX: usize = 0;
|
||||
}
|
||||
impl SealedChannel for Ch2 {
|
||||
const IDX: usize = 1;
|
||||
}
|
||||
impl Channel for Ch1 {}
|
||||
impl Channel for Ch2 {}
|
||||
|
||||
dma_trait!(Dma, Instance, Channel);
|
||||
pin_trait!(DacPin, Instance, Channel);
|
||||
|
||||
foreach_peripheral!(
|
||||
(dac, $inst:ident) => {
|
||||
@ -531,9 +539,3 @@ foreach_peripheral!(
|
||||
impl crate::dac::Instance for peripherals::$inst {}
|
||||
};
|
||||
);
|
||||
|
||||
macro_rules! impl_dac_pin {
|
||||
($inst:ident, $pin:ident, $ch:expr) => {
|
||||
impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user