From 388d3e273d3d003e6a058b4bad9e2517dd33d626 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sat, 24 Jun 2023 13:10:59 +0200 Subject: [PATCH] first attempt at fixing the 2nd channel problem --- embassy-stm32/src/dac/mod.rs | 386 +++++++++++++++++++++-------------- 1 file changed, 234 insertions(+), 152 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 5b39758bf..e87292b86 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -1,5 +1,7 @@ #![macro_use] +use core::marker::PhantomData; + use embassy_hal_common::{into_ref, PeripheralRef}; use crate::dma::{Transfer, TransferOptions}; @@ -108,166 +110,108 @@ pub enum ValueArray<'a> { Bit12Right(&'a [u16]), } -pub struct Dac<'d, T: Instance, Tx> { - ch1: bool, - ch2: bool, - txdma: PeripheralRef<'d, Tx>, - _peri: PeripheralRef<'d, T>, -} - -impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { - pub fn new_ch1( - peri: impl Peripheral
+ 'd, - txdma: impl Peripheral
+ 'd, - _ch1: impl Peripheral
> + 'd, - ) -> Self { - into_ref!(peri); - Self::new_inner(peri, true, false, txdma) - } - - pub fn new_ch2( - peri: impl Peripheral
+ 'd, - txdma: impl Peripheral
+ 'd, - _ch2: impl Peripheral
> + 'd, - ) -> Self { - into_ref!(peri); - Self::new_inner(peri, false, true, txdma) - } - - pub fn new_ch1_and_ch2( - peri: impl Peripheral
+ 'd, - txdma: impl Peripheral
+ 'd, - _ch1: impl Peripheral
> + 'd, - _ch2: impl Peripheral
> + 'd, - ) -> Self { - into_ref!(peri); - Self::new_inner(peri, true, true, txdma) - } - - /// Perform initialisation steps for the DAC - fn new_inner(peri: PeripheralRef<'d, T>, ch1: bool, ch2: bool, txdma: impl Peripheral
+ 'd) -> Self {
- into_ref!(txdma);
- T::enable();
- T::reset();
-
- let mut dac = Self {
- ch1,
- ch2,
- txdma,
- _peri: peri,
- };
-
- // Configure each activated channel. All results can be `unwrap`ed since they
- // will only error if the channel is not configured (i.e. ch1, ch2 are false)
- if ch1 {
- dac.set_channel_mode(Channel::Ch1, 0).unwrap();
- dac.enable_channel(Channel::Ch1).unwrap();
- dac.set_trigger_enable(Channel::Ch1, true).unwrap();
- }
- if ch2 {
- dac.set_channel_mode(Channel::Ch2, 0).unwrap();
- dac.enable_channel(Channel::Ch2).unwrap();
- dac.set_trigger_enable(Channel::Ch2, true).unwrap();
- }
-
- dac
- }
-
- /// Check the channel is configured
- fn check_channel_configured(&self, ch: Channel) -> Result<(), Error> {
- if (ch == Channel::Ch1 && !self.ch1) || (ch == Channel::Ch2 && !self.ch2) {
- Err(Error::UnconfiguredChannel)
- } else {
- Ok(())
- }
- }
+pub trait DacChannel + 'd,
+ dma: impl Peripheral + 'd,
+ _pin: impl Peripheral > + 'd,
+ ) -> Self {
+ into_ref!(peri, dma);
+ T::enable();
+ T::reset();
+
+ let mut dac = Self { _peri: peri, dma };
+
+ // Configure each activated channel. All results can be `unwrap`ed since they
+ // will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ dac.set_channel_mode(0).unwrap();
+ dac.enable_channel().unwrap();
+ dac.set_trigger_enable(true).unwrap();
+
+ dac
+ }
+ /// Select a new trigger for CH1 (disables the channel)
+ pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
+ unwrap!(self.disable_channel());
+ T::regs().cr().modify(|reg| {
+ reg.set_tsel1(trigger.tsel());
+ });
+ Ok(())
+ }
/// Write `data` to the DAC CH1 via DMA.
///
@@ -276,36 +220,12 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 1 has to be configured for the DAC instance!
- pub async fn write_ch1(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: Dma + 'd,
+ dma: impl Peripheral + 'd,
+ _pin: impl Peripheral > + 'd,
+ ) -> Self {
+ into_ref!(peri, dma);
+ T::enable();
+ T::reset();
+
+ let mut dac = Self {
+ phantom: PhantomData,
+ dma,
+ };
+
+ // Configure each activated channel. All results can be `unwrap`ed since they
+ // will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ dac.set_channel_mode(0).unwrap();
+ dac.enable_channel().unwrap();
+ dac.set_trigger_enable(true).unwrap();
+
+ dac
+ }
+
+ /// Select a new trigger for CH1 (disables the channel)
+ pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
+ unwrap!(self.disable_channel());
+ T::regs().cr().modify(|reg| {
+ reg.set_tsel2(trigger.tsel());
+ });
+ Ok(())
+ }
+
+ /// Write `data` to the DAC CH1 via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
+ ///
+ /// **Important:** Channel 1 has to be configured for the DAC instance!
+ async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma + 'd,
+ dma_ch1: impl Peripheral + 'd,
+ dma_ch2: impl Peripheral + 'd,
+ _pin_ch1: impl Peripheral > + 'd,
+ _pin_ch2: impl Peripheral > + 'd,
+ ) -> Self {
+ into_ref!(peri, dma_ch1, dma_ch2);
+ T::enable();
+ T::reset();
+
+ let mut dac_ch1 = DacCh1 {
+ _peri: peri,
+ dma: dma_ch1,
+ };
+
+ let mut dac_ch2 = DacCh2 {
+ phantom: PhantomData,
+ dma: dma_ch2,
+ };
+
+ // Configure each activated channel. All results can be `unwrap`ed since they
+ // will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ dac_ch1.set_channel_mode(0).unwrap();
+ dac_ch1.enable_channel().unwrap();
+ dac_ch1.set_trigger_enable(true).unwrap();
+
+ dac_ch1.set_channel_mode(0).unwrap();
+ dac_ch1.enable_channel().unwrap();
+ dac_ch1.set_trigger_enable(true).unwrap();
+
+ Self {
+ ch1: dac_ch1,
+ ch2: dac_ch2,
+ }
+ }
+}
+
+impl<'d, T: Instance, Tx> DacChannel