diff --git a/Cargo.toml b/Cargo.toml index 279e89d9..3afb3034 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ stm32g4 = { version = "0.16.0", features = ["atomics"] } paste = "1.0" fugit = "0.3.7" stm32-usbd = { version = "0.7.0", optional = true } -fixed = { version = "1.28.0", optional = true } +fixed = { version = "1.28.0" } embedded-io = "0.6" [dependencies.cortex-m] @@ -106,7 +106,7 @@ defmt = [ "embedded-io/defmt-03", "embedded-test/defmt", ] -cordic = ["dep:fixed"] +cordic = [] adc3 = [] adc4 = [] adc5 = [] diff --git a/examples/dual-dac.rs b/examples/dual-dac.rs new file mode 100644 index 00000000..4ce7e8d2 --- /dev/null +++ b/examples/dual-dac.rs @@ -0,0 +1,62 @@ +//! Simple Dual DAC example for STM32G4 microcontrollers. +//! +//! This simple example configures DAC1 in DualDac mode and outputs a wrapping +//! ramp on PA4, and its inverse on PA5. +//! +//! This example highlights using the [`hal::dac::format::SampleQ15`] format for +//! native Q1.15 fixed point conversion by the DAC hardware when moving from holding register +//! to output register. +//! +//! Setting a channel to 0.0 will output a DC voltage of Vref/2, negative +//! values will be in the range [0.0..Vref/2], and positive values will be [Vref/2..Vref]. +//! + +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +use fixed::types::I1F15; +use hal::dac::dual::DualDacExt; +use hal::delay::SYSTDelayExt; +use hal::gpio::GpioExt; +use hal::rcc::RccExt; +use stm32g4xx_hal as hal; +mod utils; +extern crate cortex_m_rt as rt; + +use hal::stm32; +use rt::entry; + +#[entry] +fn main() -> ! { + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); + + let mut rcc = dp.RCC.constrain(); + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + + // Get a DualDac instance from DAC1 with channel outputs on PA4 and PA5 + let dac = dp.DAC1.into_dual::( + (gpioa.pa4, gpioa.pa5), + &mut rcc, + &mut delay, + ); + + // Enable the DAC + let mut dac = dac.enable(); + + // Create an initial value that we'll sweep using the minimum fixed point value (-1.0) + let mut value = I1F15::MIN; + + loop { + // Output value on channel 1, and inverted value on channel 2 + // This uses the DAC's dual channel hold register, and native signed format mode + // to write both channels simultaneously with a single register write operation. + dac.set_channels(value, -value); + + // Increment and wrap the value by the minimum fixed point type increment delta + value = value.wrapping_add(I1F15::DELTA); + } +} diff --git a/src/dac.rs b/src/dac.rs index 874bf688..b90ff97d 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -9,12 +9,27 @@ use core::marker::PhantomData; use core::mem::MaybeUninit; use core::ops::Deref; +use crate::dac::trigger::DacTriggerSource; +use crate::dma::mux::DmaMuxResources; +use crate::dma::traits::TargetAddress; +use crate::dma::MemoryToPeripheral; use crate::gpio::{Analog, PA4, PA5, PA6}; use crate::pac; use crate::rcc::{self, *}; use crate::stm32::dac1::mcr::HFSEL; use embedded_hal::delay::DelayNs; +pub mod dual; +pub mod format; +pub mod trigger; + +/// DAC Channel identifier +#[repr(u8)] +pub enum DacChannel { + Ch1 = 0, + Ch2 = 1, +} + pub trait DacOut { fn get_value(&mut self) -> V; fn set_value(&mut self, val: V); @@ -137,6 +152,7 @@ impl SawtoothConfig { /// Enabled DAC (type state) pub struct Enabled; +pub struct EnabledDma; // / Enabled DAC without output buffer (type state) //pub struct EnabledUnbuffered; /// Enabled DAC wave generator for triangle or noise wave form (type state) @@ -282,6 +298,43 @@ impl DacCh(&mut self) + where + Source: DacTriggerSource, + { + // Set the TSELx bits to the trigger signal identifier from the DacTriggerSource impl + let dac = unsafe { &(*DAC::ptr()) }; + if CH == DacChannel::Ch1 as u8 { + unsafe { dac.cr().modify(|_, w| w.tsel1().bits(Source::SIGNAL)) }; + } + if CH == DacChannel::Ch2 as u8 { + unsafe { dac.cr().modify(|_, w| w.tsel2().bits(Source::SIGNAL)) }; + } + + // Enable the TENx flag in DAC CR + dac.cr().modify(|_, w| w.ten(CH).set_bit()); + } + + pub fn enable_dma(self, rcc: &mut Rcc) -> DacCh { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.mcr() + .modify(|_, w| unsafe { w.hfsel().variant(hfsel(rcc)).mode(CH).bits(MODE_BITS) }); + + dac.cr() + .modify(|_, w| w.dmaen(CH).set_bit().en(CH).set_bit()); + + dac.dhr12r(CH as usize).write(|w| unsafe { w.bits(0) }); + + DacCh::new() + } + pub fn enable_generator( self, config: GeneratorConfig, @@ -450,7 +503,16 @@ impl } } -pub trait DacExt: Sized { +/// DMA state implementation +impl DacCh { + pub fn start(&mut self, val: u16) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.dhr12r(CH as usize) + .write(|w| unsafe { w.bits(val as u32) }); + } +} + +pub trait DacExt: Instance + Sized { fn constrain(self, pins: PINS, rcc: &mut Rcc) -> PINS::Output where PINS: Pins; @@ -478,3 +540,28 @@ macro_rules! impl_dac_ext { } impl_dac_ext!(pac::DAC1, pac::DAC2, pac::DAC3, pac::DAC4,); + +macro_rules! impl_dac_dma { + ($($DAC:ty, $channel:expr, $dmamux:ident)+) => {$( + unsafe impl TargetAddress + for DacCh<$DAC, $channel, MODE_BITS, ED> + where $DAC: Instance + { + type MemSize = u32; + const REQUEST_LINE: Option = Some(DmaMuxResources::$dmamux as u8); + + fn address(&self) -> u32 { + let dac = unsafe { &(*<$DAC>::ptr()) }; + dac.dhr12r($channel as usize) as *const _ as u32 + } + } + )+}; +} + +impl_dac_dma!(pac::DAC1, 0, DAC1_CH1); +impl_dac_dma!(pac::DAC1, 1, DAC1_CH2); +impl_dac_dma!(pac::DAC2, 0, DAC2_CH1); +impl_dac_dma!(pac::DAC3, 0, DAC3_CH1); +impl_dac_dma!(pac::DAC3, 1, DAC3_CH2); +impl_dac_dma!(pac::DAC4, 0, DAC4_CH1); +impl_dac_dma!(pac::DAC4, 1, DAC4_CH2); diff --git a/src/dac/dual.rs b/src/dac/dual.rs new file mode 100644 index 00000000..6cf7df85 --- /dev/null +++ b/src/dac/dual.rs @@ -0,0 +1,192 @@ +#![deny(missing_docs)] + +//! Dual DAC +//! +//! This module provides access to the dual DAC channels of the STM32G4 series microcontrollers. +//! It allows for simultaneous access to both DAC channels and supports DMA transfers. +//! + +use core::marker::PhantomData; + +use embedded_hal::delay::DelayNs; + +use crate::dac::{ + format::SampleFormat, trigger::DacTriggerSource, DacCh, DacChannel, Disabled, Enabled, + Instance, M_EXT_PIN, +}; +use crate::dac::{hfsel, DacExt as _, Pins}; + +use crate::dac::format::{self, ToDac as _}; +use crate::dma::mux::DmaMuxResources; +use crate::dma::traits::TargetAddress; +use crate::dma::MemoryToPeripheral; +use crate::rcc::Rcc; + +/// Extension trait for [`Instance`] to create a [`DualDac`] from the given pins and RCC. +pub trait DualDacExt: Instance + Sized { + /// Create a dual DAC instance from the given pins and RCC. + /// + /// DAC calibration is performed before enabling the DAC, so + /// a DelayNs implementation is required. + /// + /// This uses the dual hold registers (DHR12xD, DHR8RD) and + /// can write to both DAC channels simultaneously with DMA support. + fn into_dual( + self, + pins: PINS, + rcc: &mut Rcc, + delay: &mut impl DelayNs, + ) -> DualDac + where + PINS: Pins< + Self, + Output = ( + DacCh, + DacCh, + ), + >; +} + +/// Dual DAC handle +pub struct DualDac { + _ch1: DacCh, + _ch2: DacCh, + _phantom: PhantomData, +} + +impl DualDac { + /// Enable DMA double mode for the specified channel. + /// This creates a single DMA request for every + /// two external hardware triggers (excluding software triggers). + #[inline(always)] + pub fn enable_dma_double(&mut self, channel: DacChannel, enable: bool) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.mcr() + .modify(|_, w| w.dmadouble(channel as u8).bit(enable)); + } + + /// Enable DMA for the specified channel + #[inline(always)] + pub fn enable_dma(&mut self, channel: DacChannel, enable: bool) { + let dac = unsafe { &(*DAC::ptr()) }; + dac.cr().modify(|_, w| w.dmaen(channel as u8).bit(enable)); + } + + /// Enable trigger for the specified channel and the [`DacTriggerSource`] + /// provided as a generic type parameter. + /// + /// This will cause the DAC to copy the hold register to the output register + /// when the trigger is raised by a timer signal or external interrupt, + /// and issue a new DMA request if DMA is enabled. + #[inline(always)] + pub fn enable_trigger(&mut self, channel: DacChannel) + where + Source: DacTriggerSource, + { + // Set the TSELx bits to the trigger signal identifier from the DacTriggerSource impl + let dac = unsafe { &(*DAC::ptr()) }; + match channel { + DacChannel::Ch1 => { + unsafe { dac.cr().modify(|_, w| w.tsel1().bits(Source::SIGNAL)) }; + } + DacChannel::Ch2 => { + unsafe { dac.cr().modify(|_, w| w.tsel2().bits(Source::SIGNAL)) }; + } + } + + // Enable the TENx flag in DAC CR + dac.cr().modify(|_, w| w.ten(channel as u8).set_bit()); + } + + /// Enable both DAC channels + #[inline(always)] + pub fn enable(self) -> DualDac { + let dac = unsafe { &(*DAC::ptr()) }; + + dac.cr().modify(|_, w| w.en(0).set_bit().en(1).set_bit()); + DualDac { + _ch1: DacCh::new(), + _ch2: DacCh::new(), + _phantom: PhantomData, + } + } +} + +impl DualDac { + /// Write to both DAC channels simultaneously. + #[inline(always)] + pub fn set_channels(&mut self, ch1: F::Scalar, ch2: F::Scalar) { + let dac = unsafe { &(*DAC::ptr()) }; + + let bits = (ch2.to_dac() as u32) << F::CH2_SHIFT | (ch1.to_dac() as u32) & F::CH1_MASK; + + match F::DEPTH { + format::SampleDepth::Bits12(alignment) => match alignment { + format::Alignment::Left => { + dac.dhr12ld().write(|w| unsafe { w.bits(bits) }); + } + format::Alignment::Right => { + dac.dhr12rd().write(|w| unsafe { w.bits(bits) }); + } + }, + format::SampleDepth::Bits8 => { + // NOTE: 8-bit is always right aligned + dac.dhr8rd().write(|w| unsafe { w.bits(bits) }); + } + } + } +} + +impl DualDacExt for DAC { + fn into_dual( + self, + pins: PINS, + rcc: &mut Rcc, + delay: &mut impl DelayNs, + ) -> DualDac + where + PINS: Pins< + Self, + Output = ( + DacCh, + DacCh, + ), + >, + { + let (ch1, ch2) = self.constrain(pins, rcc); + + let ch1 = ch1.calibrate_buffer(delay); + let ch2 = ch2.calibrate_buffer(delay); + + // Configure HFSEL + let dac = unsafe { &(*DAC::ptr()) }; + let hfsel = hfsel(rcc); + dac.mcr().modify(|_, w| w.hfsel().variant(hfsel)); + + // Apply the format configuration to both channels + for channel in 0..2 { + dac.mcr().modify(|_, w| w.sinformat(channel).bit(F::SIGNED)); + } + + DualDac { + _ch1: ch1, + _ch2: ch2, + _phantom: PhantomData, + } + } +} + +unsafe impl TargetAddress + for DualDac +{ + type MemSize = u32; + const REQUEST_LINE: Option = Some(DmaMuxResources::DAC1_CH1 as u8); + + fn address(&self) -> u32 { + let dac = unsafe { &(*DAC::ptr()) }; + match F::SIGNED { + true => dac.dhr12ld() as *const _ as u32, + false => dac.dhr12rd() as *const _ as u32, + } + } +} diff --git a/src/dac/format.rs b/src/dac/format.rs new file mode 100644 index 00000000..0c8cac5b --- /dev/null +++ b/src/dac/format.rs @@ -0,0 +1,113 @@ +//! STM32G4 DAC Data Sample Formats + +use fixed::types::{I1F15, I1F7}; + +/// Alignment of the samples in the DAC hold register. +/// Left alignment is used for signed 2's complement data +pub enum Alignment { + Left, + Right, +} + +/// Sample bit depth and alignment +pub enum SampleDepth { + Bits12(Alignment), + Bits8, +} + +pub trait SampleFormat { + /// Bit depth of the sample format (8 or 12 bits) + const DEPTH: SampleDepth; + /// Signedness of the sample format + const SIGNED: bool; + /// Shift amount for Channel 2 samples into the 32 bit hold register + const CH2_SHIFT: u8; + /// Mask for Channel 1 samples in the 32 bit hold register + const CH1_MASK: u32; + + /// Scalar type for this sample format + /// Q1.7, Q1.11, Q1.15 use fixed types, unsigned are u8 or u16 + type Scalar: ToDac; +} + +/// Conversion trait for DAC data. Used to support conversion from +/// fixed point types to their bit representation as u16. +pub trait ToDac { + fn to_dac(&self) -> u16; +} + +impl ToDac for I1F7 { + fn to_dac(&self) -> u16 { + self.to_bits() as u16 + } +} + +impl ToDac for I1F15 { + fn to_dac(&self) -> u16 { + self.to_bits() as u16 + } +} + +impl ToDac for u16 { + #[inline(always)] + fn to_dac(&self) -> u16 { + *self + } +} + +impl ToDac for u8 { + #[inline(always)] + fn to_dac(&self) -> u16 { + *self as u16 + } +} + +/// Unsigned 8-bit samples +pub struct SampleU8; +impl SampleFormat for SampleU8 { + const DEPTH: SampleDepth = SampleDepth::Bits8; + const SIGNED: bool = false; + const CH2_SHIFT: u8 = 8; + const CH1_MASK: u32 = 0xFF; + type Scalar = u8; +} + +/// Unsigned 12-bit samples +pub struct SampleU12; +impl SampleFormat for SampleU12 { + const DEPTH: SampleDepth = SampleDepth::Bits12(Alignment::Right); + const SIGNED: bool = false; + const CH2_SHIFT: u8 = 16; + const CH1_MASK: u32 = 0xFFFF; + type Scalar = u16; +} + +/// Fixed point signed Q1.7 samples +pub struct SampleQ7; +impl SampleFormat for SampleQ7 { + const DEPTH: SampleDepth = SampleDepth::Bits8; + const SIGNED: bool = true; + const CH2_SHIFT: u8 = 8; + const CH1_MASK: u32 = 0xFF; + type Scalar = I1F7; +} + +/// Fixed point signed Q1.11 samples +pub struct SampleQ11; +impl SampleFormat for SampleQ11 { + const DEPTH: SampleDepth = SampleDepth::Bits12(Alignment::Left); + const SIGNED: bool = true; + const CH2_SHIFT: u8 = 16; + const CH1_MASK: u32 = 0xFFFF; + type Scalar = I1F15; +} + +/// Fixed point signed Q1.15 samples +pub struct SampleQ15; +impl SampleFormat for SampleQ15 { + const DEPTH: SampleDepth = SampleDepth::Bits12(Alignment::Left); + const SIGNED: bool = true; + const CH2_SHIFT: u8 = 16; + const CH1_MASK: u32 = 0xFFFF; + type Scalar = I1F15; +} diff --git a/src/dac/trigger.rs b/src/dac/trigger.rs new file mode 100644 index 00000000..bb1869b4 --- /dev/null +++ b/src/dac/trigger.rs @@ -0,0 +1,212 @@ +use crate::dac::Instance; +use crate::stm32::{DAC1, DAC2, DAC3, DAC4}; + +pub trait DacTriggerSource { + const SIGNAL: u8; + + #[inline(always)] + fn signal(&self) -> u8 { + Self::SIGNAL + } +} + +pub trait DacIncrementSource { + const SIGNAL: u8; + + #[inline(always)] + fn signal(&self) -> u8 { + Self::SIGNAL + } +} + +/// Implements the struct representing a DAC trigger source. +/// Sources which are valid for a DAC instance will have a [`DacTriggerSource`] +/// trait implemented on them with the const SIGNAL set to the signal +/// interconnection from RM0440 Table 187 +macro_rules! impl_dac_trigger { + ($($source:ident)+) => {$( + pub struct $source; + )+}; +} + +impl_dac_trigger!(Software); +impl_dac_trigger!(Timer1); +impl_dac_trigger!(Timer2); +impl_dac_trigger!(Timer3); +impl_dac_trigger!(Timer4); +impl_dac_trigger!(Timer5); +impl_dac_trigger!(Timer6); +impl_dac_trigger!(Timer7); +impl_dac_trigger!(Timer8); +impl_dac_trigger!(Timer15); + +impl_dac_trigger!(HrtimDacReset1); +impl_dac_trigger!(HrtimDacReset2); +impl_dac_trigger!(HrtimDacReset3); +impl_dac_trigger!(HrtimDacReset4); +impl_dac_trigger!(HrtimDacReset5); +impl_dac_trigger!(HrtimDacReset6); +impl_dac_trigger!(HrtimDacTrigger1); +impl_dac_trigger!(HrtimDacTrigger2); +impl_dac_trigger!(HrtimDacTrigger3); +impl_dac_trigger!(HrtimDacStep1); +impl_dac_trigger!(HrtimDacStep2); +impl_dac_trigger!(HrtimDacStep3); +impl_dac_trigger!(HrtimDacStep4); +impl_dac_trigger!(HrtimDacStep5); +impl_dac_trigger!(HrtimDacStep6); + +impl_dac_trigger!(Exti9); +impl_dac_trigger!(Exti10); + +/// Macro to implement the DacTriggerSource trait for each supported trigger source +/// specific to each DAC peripheral instance. +macro_rules! impl_dac_channel_trigger { + ($($DAC:ty, $source:ident, $signal:expr)+) => {$( + impl DacTriggerSource<$DAC> for $source { + const SIGNAL: u8 = $signal; + } + )+}; +} + +/// Macro to implement the DacIncrementSource trait for each supported +/// increment trigger source specific to each DAC peripheral instance. +macro_rules! impl_dac_increment_trigger { + ($($DAC:ty, $source:ident, $signal:expr)+) => {$( + impl DacIncrementSource<$DAC> for $source { + const SIGNAL: u8 = $signal; + } + )+}; +} + +impl_dac_channel_trigger!(DAC1, Software, 0); +impl_dac_channel_trigger!(DAC1, Timer8, 1); +impl_dac_channel_trigger!(DAC1, Timer7, 2); +impl_dac_channel_trigger!(DAC1, Timer15, 3); +impl_dac_channel_trigger!(DAC1, Timer2, 4); +impl_dac_channel_trigger!(DAC1, Timer4, 5); +impl_dac_channel_trigger!(DAC1, Exti9, 6); +impl_dac_channel_trigger!(DAC1, Timer6, 7); +impl_dac_channel_trigger!(DAC1, Timer3, 8); +impl_dac_channel_trigger!(DAC1, HrtimDacReset1, 9); +impl_dac_channel_trigger!(DAC1, HrtimDacReset2, 10); +impl_dac_channel_trigger!(DAC1, HrtimDacReset3, 11); +impl_dac_channel_trigger!(DAC1, HrtimDacReset4, 12); +impl_dac_channel_trigger!(DAC1, HrtimDacReset5, 13); +impl_dac_channel_trigger!(DAC1, HrtimDacReset6, 14); +impl_dac_channel_trigger!(DAC1, HrtimDacTrigger1, 15); + +impl_dac_increment_trigger!(DAC1, Software, 0); +impl_dac_increment_trigger!(DAC1, Timer8, 1); +impl_dac_increment_trigger!(DAC1, Timer7, 2); +impl_dac_increment_trigger!(DAC1, Timer15, 3); +impl_dac_increment_trigger!(DAC1, Timer2, 4); +impl_dac_increment_trigger!(DAC1, Timer4, 5); +impl_dac_increment_trigger!(DAC1, Exti10, 6); +impl_dac_increment_trigger!(DAC1, Timer6, 7); +impl_dac_increment_trigger!(DAC1, Timer3, 8); +impl_dac_increment_trigger!(DAC1, HrtimDacStep1, 9); +impl_dac_increment_trigger!(DAC1, HrtimDacStep2, 10); +impl_dac_increment_trigger!(DAC1, HrtimDacStep3, 11); +impl_dac_increment_trigger!(DAC1, HrtimDacStep4, 12); +impl_dac_increment_trigger!(DAC1, HrtimDacStep5, 13); +impl_dac_increment_trigger!(DAC1, HrtimDacStep6, 14); + +impl_dac_channel_trigger!(DAC2, Software, 0); +impl_dac_channel_trigger!(DAC2, Timer8, 1); +impl_dac_channel_trigger!(DAC2, Timer7, 2); +impl_dac_channel_trigger!(DAC2, Timer15, 3); +impl_dac_channel_trigger!(DAC2, Timer2, 4); +impl_dac_channel_trigger!(DAC2, Timer4, 5); +impl_dac_channel_trigger!(DAC2, Exti9, 6); +impl_dac_channel_trigger!(DAC2, Timer6, 7); +impl_dac_channel_trigger!(DAC2, Timer3, 8); +impl_dac_channel_trigger!(DAC2, HrtimDacReset1, 9); +impl_dac_channel_trigger!(DAC2, HrtimDacReset2, 10); +impl_dac_channel_trigger!(DAC2, HrtimDacReset3, 11); +impl_dac_channel_trigger!(DAC2, HrtimDacReset4, 12); +impl_dac_channel_trigger!(DAC2, HrtimDacReset5, 13); +impl_dac_channel_trigger!(DAC2, HrtimDacReset6, 14); +impl_dac_channel_trigger!(DAC2, HrtimDacTrigger2, 15); + +impl_dac_increment_trigger!(DAC2, Software, 0); +impl_dac_increment_trigger!(DAC2, Timer8, 1); +impl_dac_increment_trigger!(DAC2, Timer7, 2); +impl_dac_increment_trigger!(DAC2, Timer15, 3); +impl_dac_increment_trigger!(DAC2, Timer2, 4); +impl_dac_increment_trigger!(DAC2, Timer4, 5); +impl_dac_increment_trigger!(DAC2, Exti10, 6); +impl_dac_increment_trigger!(DAC2, Timer6, 7); +impl_dac_increment_trigger!(DAC2, Timer3, 8); +impl_dac_increment_trigger!(DAC2, HrtimDacStep1, 9); +impl_dac_increment_trigger!(DAC2, HrtimDacStep2, 10); +impl_dac_increment_trigger!(DAC2, HrtimDacStep3, 11); +impl_dac_increment_trigger!(DAC2, HrtimDacStep4, 12); +impl_dac_increment_trigger!(DAC2, HrtimDacStep5, 13); +impl_dac_increment_trigger!(DAC2, HrtimDacStep6, 14); + +impl_dac_channel_trigger!(DAC3, Software, 1); +impl_dac_channel_trigger!(DAC3, Timer1, 1); +impl_dac_channel_trigger!(DAC3, Timer7, 2); +impl_dac_channel_trigger!(DAC3, Timer15, 3); +impl_dac_channel_trigger!(DAC3, Timer2, 4); +impl_dac_channel_trigger!(DAC3, Timer4, 5); +impl_dac_channel_trigger!(DAC3, Exti9, 6); +impl_dac_channel_trigger!(DAC3, Timer6, 7); +impl_dac_channel_trigger!(DAC3, Timer3, 8); +impl_dac_channel_trigger!(DAC3, HrtimDacReset1, 9); +impl_dac_channel_trigger!(DAC3, HrtimDacReset2, 10); +impl_dac_channel_trigger!(DAC3, HrtimDacReset3, 11); +impl_dac_channel_trigger!(DAC3, HrtimDacReset4, 12); +impl_dac_channel_trigger!(DAC3, HrtimDacReset5, 13); +impl_dac_channel_trigger!(DAC3, HrtimDacReset6, 14); +impl_dac_channel_trigger!(DAC3, HrtimDacTrigger3, 15); + +impl_dac_increment_trigger!(DAC3, Software, 0); +impl_dac_increment_trigger!(DAC3, Timer1, 1); +impl_dac_increment_trigger!(DAC3, Timer7, 2); +impl_dac_increment_trigger!(DAC3, Timer15, 3); +impl_dac_increment_trigger!(DAC3, Timer2, 4); +impl_dac_increment_trigger!(DAC3, Timer4, 5); +impl_dac_increment_trigger!(DAC3, Exti10, 6); +impl_dac_increment_trigger!(DAC3, Timer6, 7); +impl_dac_increment_trigger!(DAC3, Timer3, 8); +impl_dac_increment_trigger!(DAC3, HrtimDacStep1, 9); +impl_dac_increment_trigger!(DAC3, HrtimDacStep2, 10); +impl_dac_increment_trigger!(DAC3, HrtimDacStep3, 11); +impl_dac_increment_trigger!(DAC3, HrtimDacStep4, 12); +impl_dac_increment_trigger!(DAC3, HrtimDacStep5, 13); +impl_dac_increment_trigger!(DAC3, HrtimDacStep6, 14); + +impl_dac_channel_trigger!(DAC4, Software, 1); +impl_dac_channel_trigger!(DAC4, Timer8, 1); +impl_dac_channel_trigger!(DAC4, Timer7, 2); +impl_dac_channel_trigger!(DAC4, Timer15, 3); +impl_dac_channel_trigger!(DAC4, Timer2, 4); +impl_dac_channel_trigger!(DAC4, Timer4, 5); +impl_dac_channel_trigger!(DAC4, Exti9, 6); +impl_dac_channel_trigger!(DAC4, Timer6, 7); +impl_dac_channel_trigger!(DAC4, Timer3, 8); +impl_dac_channel_trigger!(DAC4, HrtimDacReset1, 9); +impl_dac_channel_trigger!(DAC4, HrtimDacReset2, 10); +impl_dac_channel_trigger!(DAC4, HrtimDacReset3, 11); +impl_dac_channel_trigger!(DAC4, HrtimDacReset4, 12); +impl_dac_channel_trigger!(DAC4, HrtimDacReset5, 13); +impl_dac_channel_trigger!(DAC4, HrtimDacReset6, 14); +impl_dac_channel_trigger!(DAC4, HrtimDacTrigger1, 15); + +impl_dac_increment_trigger!(DAC4, Software, 0); +impl_dac_increment_trigger!(DAC4, Timer8, 1); +impl_dac_increment_trigger!(DAC4, Timer7, 2); +impl_dac_increment_trigger!(DAC4, Timer15, 3); +impl_dac_increment_trigger!(DAC4, Timer2, 4); +impl_dac_increment_trigger!(DAC4, Timer4, 5); +impl_dac_increment_trigger!(DAC4, Exti10, 6); +impl_dac_increment_trigger!(DAC4, Timer6, 7); +impl_dac_increment_trigger!(DAC4, Timer3, 8); +impl_dac_increment_trigger!(DAC4, HrtimDacStep1, 9); +impl_dac_increment_trigger!(DAC4, HrtimDacStep2, 10); +impl_dac_increment_trigger!(DAC4, HrtimDacStep3, 11); +impl_dac_increment_trigger!(DAC4, HrtimDacStep4, 12); +impl_dac_increment_trigger!(DAC4, HrtimDacStep5, 13); +impl_dac_increment_trigger!(DAC4, HrtimDacStep6, 14); diff --git a/src/dma/traits.rs b/src/dma/traits.rs index c72d6287..62b0544e 100644 --- a/src/dma/traits.rs +++ b/src/dma/traits.rs @@ -176,7 +176,7 @@ pub trait Direction { /// and for the DMA. pub unsafe trait TargetAddress { /// Memory size of the target address - type MemSize; + type MemSize: 'static; /// The address to be used by the DMA channel fn address(&self) -> u32;