aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-11-24 23:51:07 +0000
committerGitHub <[email protected]>2023-11-24 23:51:07 +0000
commit8b46343b34f0e6c2486131a0d18de46e9a835d22 (patch)
tree868f23ec36bd02625894eb51358f1050b98ffe58
parentf5c9e3baa6615928f948cf9ae4c03123d2d84cbc (diff)
parenta3ea01473a37451dbd80552ae501e854175055db (diff)
Merge pull request #2199 from adamgreig/stm32-dac
STM32 DAC: update to new PAC, combine ch1/ch2, fix trigger selection
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs29
-rw-r--r--embassy-stm32/src/dac/mod.rs873
-rw-r--r--embassy-stm32/src/dac/tsel.rs282
-rw-r--r--embassy-stm32/src/rcc/f3.rs5
-rw-r--r--examples/stm32f4/src/bin/dac.rs5
-rw-r--r--examples/stm32h7/src/bin/dac.rs5
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs31
-rw-r--r--examples/stm32l4/src/bin/dac.rs5
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs31
-rw-r--r--tests/stm32/src/bin/dac.rs10
11 files changed, 741 insertions, 539 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index d04000a1d..292902ac7 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -58,7 +58,7 @@ rand_core = "0.6.3"
58sdio-host = "0.5.0" 58sdio-host = "0.5.0"
59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
60critical-section = "1.1" 60critical-section = "1.1"
61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949" } 61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd" }
62vcell = "0.1.3" 62vcell = "0.1.3"
63bxcan = "0.7.0" 63bxcan = "0.7.0"
64nb = "1.0.0" 64nb = "1.0.0"
@@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
76[build-dependencies] 76[build-dependencies]
77proc-macro2 = "1.0.36" 77proc-macro2 = "1.0.36"
78quote = "1.0.15" 78quote = "1.0.15"
79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949", default-features = false, features = ["metadata"]} 79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd", default-features = false, features = ["metadata"]}
80 80
81 81
82[features] 82[features]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 4aae58229..7bfd290d2 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -65,7 +65,6 @@ fn main() {
65 match r.kind { 65 match r.kind {
66 // Generate singletons per pin, not per port 66 // Generate singletons per pin, not per port
67 "gpio" => { 67 "gpio" => {
68 println!("{}", p.name);
69 let port_letter = p.name.strip_prefix("GPIO").unwrap(); 68 let port_letter = p.name.strip_prefix("GPIO").unwrap();
70 for pin_num in 0..16 { 69 for pin_num in 0..16 {
71 singletons.push(format!("P{}{}", port_letter, pin_num)); 70 singletons.push(format!("P{}{}", port_letter, pin_num));
@@ -997,8 +996,8 @@ fn main() {
997 // SDMMCv1 uses the same channel for both directions, so just implement for RX 996 // SDMMCv1 uses the same channel for both directions, so just implement for RX
998 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 997 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
999 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), 998 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
1000 (("dac", "CH1"), quote!(crate::dac::DmaCh1)), 999 (("dac", "CH1"), quote!(crate::dac::DacDma1)),
1001 (("dac", "CH2"), quote!(crate::dac::DmaCh2)), 1000 (("dac", "CH2"), quote!(crate::dac::DacDma2)),
1002 ] 1001 ]
1003 .into(); 1002 .into();
1004 1003
@@ -1352,15 +1351,6 @@ fn main() {
1352 1351
1353 if let Some(core) = core_name { 1352 if let Some(core) = core_name {
1354 println!("cargo:rustc-cfg={}_{}", &chip_name[..chip_name.len() - 2], core); 1353 println!("cargo:rustc-cfg={}_{}", &chip_name[..chip_name.len() - 2], core);
1355 } else {
1356 println!("cargo:rustc-cfg={}", &chip_name[..chip_name.len() - 2]);
1357 }
1358
1359 // ========
1360 // stm32f3 wildcard features used in RCC
1361
1362 if chip_name.starts_with("stm32f3") {
1363 println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]);
1364 } 1354 }
1365 1355
1366 // ======= 1356 // =======
@@ -1375,16 +1365,25 @@ fn main() {
1375 if &chip_name[..8] == "stm32wba" { 1365 if &chip_name[..8] == "stm32wba" {
1376 println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba 1366 println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba
1377 println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52 1367 println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52
1368 println!("cargo:rustc-cfg=package_{}", &chip_name[10..11]);
1369 println!("cargo:rustc-cfg=flashsize_{}", &chip_name[11..12]);
1378 } else { 1370 } else {
1379 println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 1371 println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4
1380 println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429 1372 println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429
1381 println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x 1373 println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x
1382 println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9 1374 println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9
1375 println!("cargo:rustc-cfg=package_{}", &chip_name[9..10]);
1376 println!("cargo:rustc-cfg=flashsize_{}", &chip_name[10..11]);
1383 } 1377 }
1384 1378
1385 // Handle time-driver-XXXX features. 1379 // Mark the L4+ chips as they have many differences to regular L4.
1386 if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {} 1380 if &chip_name[..7] == "stm32l4" {
1387 println!("cargo:rustc-cfg={}", &chip_name[..chip_name.len() - 2]); 1381 if "pqrs".contains(&chip_name[7..8]) {
1382 println!("cargo:rustc-cfg=stm32l4_plus");
1383 } else {
1384 println!("cargo:rustc-cfg=stm32l4_nonplus");
1385 }
1386 }
1388 1387
1389 println!("cargo:rerun-if-changed=build.rs"); 1388 println!("cargo:rerun-if-changed=build.rs");
1390} 1389}
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 3d1a820ed..500eac4c1 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -1,136 +1,66 @@
1//! Provide access to the STM32 digital-to-analog converter (DAC).
1#![macro_use] 2#![macro_use]
2 3
3//! Provide access to the STM32 digital-to-analog converter (DAC).
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5 5
6use embassy_hal_internal::{into_ref, PeripheralRef}; 6use embassy_hal_internal::{into_ref, PeripheralRef};
7 7
8use crate::dma::NoDma;
9#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
8use crate::pac::dac; 10use crate::pac::dac;
9use crate::rcc::RccPeripheral; 11use crate::rcc::RccPeripheral;
10use crate::{peripherals, Peripheral}; 12use crate::{peripherals, Peripheral};
11 13
12#[derive(Debug, Copy, Clone, Eq, PartialEq)] 14mod tsel;
13#[cfg_attr(feature = "defmt", derive(defmt::Format))] 15pub use tsel::TriggerSel;
14/// Custom Errors
15pub enum Error {
16 UnconfiguredChannel,
17 InvalidValue,
18}
19
20#[derive(Debug, Copy, Clone, Eq, PartialEq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22/// DAC Channels
23pub enum Channel {
24 Ch1,
25 Ch2,
26}
27
28impl Channel {
29 const fn index(&self) -> usize {
30 match self {
31 Channel::Ch1 => 0,
32 Channel::Ch2 => 1,
33 }
34 }
35}
36
37#[derive(Debug, Copy, Clone, Eq, PartialEq)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39/// Trigger sources for CH1
40pub enum Ch1Trigger {
41 #[cfg(dac_v3)]
42 Tim1,
43 Tim2,
44 #[cfg(not(dac_v3))]
45 Tim3,
46 #[cfg(dac_v3)]
47 Tim4,
48 #[cfg(dac_v3)]
49 Tim5,
50 Tim6,
51 Tim7,
52 #[cfg(dac_v3)]
53 Tim8,
54 Tim15,
55 #[cfg(dac_v3)]
56 Hrtim1Dactrg1,
57 #[cfg(dac_v3)]
58 Hrtim1Dactrg2,
59 #[cfg(dac_v3)]
60 Lptim1,
61 #[cfg(dac_v3)]
62 Lptim2,
63 #[cfg(dac_v3)]
64 Lptim3,
65 Exti9,
66 Software,
67}
68
69impl Ch1Trigger {
70 fn tsel(&self) -> dac::vals::Tsel1 {
71 match self {
72 #[cfg(dac_v3)]
73 Ch1Trigger::Tim1 => dac::vals::Tsel1::TIM1_TRGO,
74 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
75 #[cfg(not(dac_v3))]
76 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
77 #[cfg(dac_v3)]
78 Ch1Trigger::Tim4 => dac::vals::Tsel1::TIM4_TRGO,
79 #[cfg(dac_v3)]
80 Ch1Trigger::Tim5 => dac::vals::Tsel1::TIM5_TRGO,
81 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
82 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
83 #[cfg(dac_v3)]
84 Ch1Trigger::Tim8 => dac::vals::Tsel1::TIM8_TRGO,
85 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
86 #[cfg(dac_v3)]
87 Ch1Trigger::Hrtim1Dactrg1 => dac::vals::Tsel1::HRTIM1_DACTRG1,
88 #[cfg(dac_v3)]
89 Ch1Trigger::Hrtim1Dactrg2 => dac::vals::Tsel1::HRTIM1_DACTRG2,
90 #[cfg(dac_v3)]
91 Ch1Trigger::Lptim1 => dac::vals::Tsel1::LPTIM1_OUT,
92 #[cfg(dac_v3)]
93 Ch1Trigger::Lptim2 => dac::vals::Tsel1::LPTIM2_OUT,
94 #[cfg(dac_v3)]
95 Ch1Trigger::Lptim3 => dac::vals::Tsel1::LPTIM3_OUT,
96 Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
97 Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
98 }
99 }
100}
101 16
17/// Operating mode for DAC channel
18#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
102#[derive(Debug, Copy, Clone, Eq, PartialEq)] 19#[derive(Debug, Copy, Clone, Eq, PartialEq)]
103#[cfg_attr(feature = "defmt", derive(defmt::Format))] 20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
104/// Trigger sources for CH2 21pub enum Mode {
105pub enum Ch2Trigger { 22 /// Normal mode, channel is connected to external pin with buffer enabled.
106 Tim6, 23 NormalExternalBuffered,
107 Tim8, 24 /// Normal mode, channel is connected to external pin and internal peripherals
108 Tim7, 25 /// with buffer enabled.
109 Tim5, 26 NormalBothBuffered,
110 Tim2, 27 /// Normal mode, channel is connected to external pin with buffer disabled.
111 Tim4, 28 NormalExternalUnbuffered,
112 Exti9, 29 /// Normal mode, channel is connected to internal peripherals with buffer disabled.
113 Software, 30 NormalInternalUnbuffered,
31 /// Sample-and-hold mode, channel is connected to external pin with buffer enabled.
32 SampleHoldExternalBuffered,
33 /// Sample-and-hold mode, channel is connected to external pin and internal peripherals
34 /// with buffer enabled.
35 SampleHoldBothBuffered,
36 /// Sample-and-hold mode, channel is connected to external pin and internal peripherals
37 /// with buffer disabled.
38 SampleHoldBothUnbuffered,
39 /// Sample-and-hold mode, channel is connected to internal peripherals with buffer disabled.
40 SampleHoldInternalUnbuffered,
114} 41}
115 42
116impl Ch2Trigger { 43#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
117 fn tsel(&self) -> dac::vals::Tsel2 { 44impl Mode {
45 fn mode(&self) -> dac::vals::Mode {
118 match self { 46 match self {
119 Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO, 47 Mode::NormalExternalBuffered => dac::vals::Mode::NORMAL_EXT_BUFEN,
120 Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO, 48 Mode::NormalBothBuffered => dac::vals::Mode::NORMAL_EXT_INT_BUFEN,
121 Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO, 49 Mode::NormalExternalUnbuffered => dac::vals::Mode::NORMAL_EXT_BUFDIS,
122 Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO, 50 Mode::NormalInternalUnbuffered => dac::vals::Mode::NORMAL_INT_BUFDIS,
123 Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO, 51 Mode::SampleHoldExternalBuffered => dac::vals::Mode::SAMPHOLD_EXT_BUFEN,
124 Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO, 52 Mode::SampleHoldBothBuffered => dac::vals::Mode::SAMPHOLD_EXT_INT_BUFEN,
125 Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9, 53 Mode::SampleHoldBothUnbuffered => dac::vals::Mode::SAMPHOLD_EXT_INT_BUFDIS,
126 Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE, 54 Mode::SampleHoldInternalUnbuffered => dac::vals::Mode::SAMPHOLD_INT_BUFDIS,
127 } 55 }
128 } 56 }
129} 57}
130 58
131#[derive(Debug, Copy, Clone, Eq, PartialEq)] 59#[derive(Debug, Copy, Clone, Eq, PartialEq)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))] 60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133/// Single 8 or 12 bit value that can be output by the DAC 61/// Single 8 or 12 bit value that can be output by the DAC.
62///
63/// 12-bit values outside the permitted range are silently truncated.
134pub enum Value { 64pub enum Value {
135 // 8 bit value 65 // 8 bit value
136 Bit8(u8), 66 Bit8(u8),
@@ -142,7 +72,21 @@ pub enum Value {
142 72
143#[derive(Debug, Copy, Clone, Eq, PartialEq)] 73#[derive(Debug, Copy, Clone, Eq, PartialEq)]
144#[cfg_attr(feature = "defmt", derive(defmt::Format))] 74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
145/// Array variant of [`Value`] 75/// Dual 8 or 12 bit values that can be output by the DAC channels 1 and 2 simultaneously.
76///
77/// 12-bit values outside the permitted range are silently truncated.
78pub enum DualValue {
79 // 8 bit value
80 Bit8(u8, u8),
81 // 12 bit value stored in a u16, left-aligned
82 Bit12Left(u16, u16),
83 // 12 bit value stored in a u16, right-aligned
84 Bit12Right(u16, u16),
85}
86
87#[derive(Debug, Copy, Clone, Eq, PartialEq)]
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89/// Array variant of [`Value`].
146pub enum ValueArray<'a> { 90pub enum ValueArray<'a> {
147 // 8 bit values 91 // 8 bit values
148 Bit8(&'a [u8]), 92 Bit8(&'a [u8]),
@@ -151,400 +95,397 @@ pub enum ValueArray<'a> {
151 // 12 bit values stored in a u16, right-aligned 95 // 12 bit values stored in a u16, right-aligned
152 Bit12Right(&'a [u16]), 96 Bit12Right(&'a [u16]),
153} 97}
154/// Provide common functions for DAC channels
155pub trait DacChannel<T: Instance, Tx> {
156 const CHANNEL: Channel;
157
158 /// Enable trigger of the given channel
159 fn set_trigger_enable(&mut self, on: bool) -> Result<(), Error> {
160 T::regs().cr().modify(|reg| {
161 reg.set_ten(Self::CHANNEL.index(), on);
162 });
163 Ok(())
164 }
165
166 /// Set mode register of the given channel
167 #[cfg(any(dac_v2, dac_v3))]
168 fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> {
169 T::regs().mcr().modify(|reg| {
170 reg.set_mode(Self::CHANNEL.index(), val);
171 });
172 Ok(())
173 }
174
175 /// Set enable register of the given channel
176 fn set_channel_enable(&mut self, on: bool) -> Result<(), Error> {
177 T::regs().cr().modify(|reg| {
178 reg.set_en(Self::CHANNEL.index(), on);
179 });
180 Ok(())
181 }
182
183 /// Enable the DAC channel `ch`
184 fn enable_channel(&mut self) -> Result<(), Error> {
185 self.set_channel_enable(true)
186 }
187
188 /// Disable the DAC channel `ch`
189 fn disable_channel(&mut self) -> Result<(), Error> {
190 self.set_channel_enable(false)
191 }
192
193 /// Perform a software trigger on `ch`
194 fn trigger(&mut self) {
195 T::regs().swtrigr().write(|reg| {
196 reg.set_swtrig(Self::CHANNEL.index(), true);
197 });
198 }
199
200 /// Set a value to be output by the DAC on trigger.
201 ///
202 /// The `value` is written to the corresponding "data holding register".
203 fn set(&mut self, value: Value) -> Result<(), Error> {
204 match value {
205 Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
206 Value::Bit12Left(v) => T::regs().dhr12l(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
207 Value::Bit12Right(v) => T::regs().dhr12r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
208 }
209 Ok(())
210 }
211}
212 98
213/// Hold two DAC channels 99/// Driver for a single DAC channel.
214///
215/// Note: This consumes the DAC `Instance` only once, allowing to get both channels simultaneously.
216/// 100///
217/// # Example for obtaining both DAC channels 101/// If you want to use both channels, either together or independently,
218/// 102/// create a [`Dac`] first and use it to access each channel.
219/// ```ignore 103pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> {
220/// // DMA channels and pins may need to be changed for your controller 104 phantom: PhantomData<&'d mut T>,
221/// let (dac_ch1, dac_ch2) = 105 #[allow(unused)]
222/// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); 106 dma: PeripheralRef<'d, DMA>,
223/// ```
224pub struct Dac<'d, T: Instance, TxCh1, TxCh2> {
225 ch1: DacCh1<'d, T, TxCh1>,
226 ch2: DacCh2<'d, T, TxCh2>,
227} 107}
228 108
229/// DAC CH1 109pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>;
230/// 110pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>;
231/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
232pub struct DacCh1<'d, T: Instance, Tx> {
233 /// To consume T
234 _peri: PeripheralRef<'d, T>,
235 #[allow(unused)] // For chips whose DMA is not (yet) supported
236 dma: PeripheralRef<'d, Tx>,
237}
238 111
239/// DAC CH2 112impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
240/// 113 const IDX: usize = (N - 1) as usize;
241/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
242pub struct DacCh2<'d, T: Instance, Tx> {
243 /// Instead of PeripheralRef to consume T
244 phantom: PhantomData<&'d mut T>,
245 #[allow(unused)] // For chips whose DMA is not (yet) supported
246 dma: PeripheralRef<'d, Tx>,
247}
248 114
249impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { 115 /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
250 /// Obtain DAC CH1 116 ///
117 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
118 ///
119 /// The channel is enabled on creation and begins to drive the output pin.
120 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
121 /// disable the channel; you must re-enable it with `enable()`.
122 ///
123 /// By default, triggering is disabled, but it can be enabled using
124 /// [`DacChannel::set_trigger()`].
251 pub fn new( 125 pub fn new(
252 peri: impl Peripheral<P = T> + 'd, 126 _peri: impl Peripheral<P = T> + 'd,
253 dma: impl Peripheral<P = Tx> + 'd, 127 dma: impl Peripheral<P = DMA> + 'd,
254 pin: impl Peripheral<P = impl DacPin<T, 1>> + crate::gpio::sealed::Pin + 'd, 128 pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::sealed::Pin> + 'd,
255 ) -> Self { 129 ) -> Self {
130 into_ref!(dma, pin);
256 pin.set_as_analog(); 131 pin.set_as_analog();
257 into_ref!(peri, dma);
258 T::enable_and_reset(); 132 T::enable_and_reset();
259 133 let mut dac = Self {
260 let mut dac = Self { _peri: peri, dma }; 134 phantom: PhantomData,
261 135 dma,
262 // Configure each activated channel. All results can be `unwrap`ed since they 136 };
263 // will only error if the channel is not configured (i.e. ch1, ch2 are false) 137 #[cfg(any(dac_v5, dac_v6, dac_v7))]
264 #[cfg(any(dac_v2, dac_v3))] 138 dac.set_hfsel();
265 dac.set_channel_mode(0).unwrap(); 139 dac.enable();
266 dac.enable_channel().unwrap();
267 dac.set_trigger_enable(true).unwrap();
268
269 dac 140 dac
270 } 141 }
271 142
272 /// Select a new trigger for this channel 143 /// Create a new `DacChannel` instance where the external output pin is not used,
144 /// so the DAC can only be used to generate internal signals.
145 /// The GPIO pin is therefore available to be used for other functions.
273 /// 146 ///
274 /// **Important**: This disables the channel! 147 /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
275 pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { 148 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
276 unwrap!(self.disable_channel()); 149 /// channel; you must re-enable it with `enable()`.
277 T::regs().cr().modify(|reg| {
278 reg.set_tsel1(trigger.tsel());
279 });
280 Ok(())
281 }
282
283 /// Write `data` to the DAC CH1 via DMA.
284 /// 150 ///
285 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. 151 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
286 /// This will configure a circular DMA transfer that periodically outputs the `data`.
287 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
288 /// 152 ///
289 /// **Important:** Channel 1 has to be configured for the DAC instance! 153 /// By default, triggering is disabled, but it can be enabled using
290 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> 154 /// [`DacChannel::set_trigger()`].
291 where 155 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
292 Tx: DmaCh1<T>, 156 pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self {
293 { 157 into_ref!(dma);
294 let channel = Channel::Ch1.index(); 158 T::enable_and_reset();
295 debug!("Writing to channel {}", channel); 159 let mut dac = Self {
296 160 phantom: PhantomData,
297 // Enable DAC and DMA 161 dma,
298 T::regs().cr().modify(|w| {
299 w.set_en(channel, true);
300 w.set_dmaen(channel, true);
301 });
302
303 let tx_request = self.dma.request();
304 let dma_channel = &mut self.dma;
305
306 let tx_options = crate::dma::TransferOptions {
307 circular,
308 half_transfer_ir: false,
309 complete_transfer_ir: !circular,
310 ..Default::default()
311 };
312
313 // Initiate the correct type of DMA transfer depending on what data is passed
314 let tx_f = match data {
315 ValueArray::Bit8(buf) => unsafe {
316 crate::dma::Transfer::new_write(
317 dma_channel,
318 tx_request,
319 buf,
320 T::regs().dhr8r(channel).as_ptr() as *mut u8,
321 tx_options,
322 )
323 },
324 ValueArray::Bit12Left(buf) => unsafe {
325 crate::dma::Transfer::new_write(
326 dma_channel,
327 tx_request,
328 buf,
329 T::regs().dhr12l(channel).as_ptr() as *mut u16,
330 tx_options,
331 )
332 },
333 ValueArray::Bit12Right(buf) => unsafe {
334 crate::dma::Transfer::new_write(
335 dma_channel,
336 tx_request,
337 buf,
338 T::regs().dhr12r(channel).as_ptr() as *mut u16,
339 tx_options,
340 )
341 },
342 }; 162 };
163 #[cfg(any(dac_v5, dac_v6, dac_v7))]
164 dac.set_hfsel();
165 dac.set_mode(Mode::NormalInternalUnbuffered);
166 dac.enable();
167 dac
168 }
343 169
344 tx_f.await; 170 /// Enable or disable this channel.
345 171 pub fn set_enable(&mut self, on: bool) {
346 // finish dma 172 critical_section::with(|_| {
347 // TODO: Do we need to check any status registers here? 173 T::regs().cr().modify(|reg| {
348 T::regs().cr().modify(|w| { 174 reg.set_en(Self::IDX, on);
349 // Disable the DAC peripheral 175 });
350 w.set_en(channel, false);
351 // Disable the DMA. TODO: Is this necessary?
352 w.set_dmaen(channel, false);
353 }); 176 });
354
355 Ok(())
356 } 177 }
357}
358 178
359impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { 179 /// Enable this channel.
360 /// Obtain DAC CH2 180 pub fn enable(&mut self) {
361 pub fn new( 181 self.set_enable(true)
362 _peri: impl Peripheral<P = T> + 'd, 182 }
363 dma: impl Peripheral<P = Tx> + 'd,
364 pin: impl Peripheral<P = impl DacPin<T, 2>> + crate::gpio::sealed::Pin + 'd,
365 ) -> Self {
366 pin.set_as_analog();
367 into_ref!(_peri, dma);
368 T::enable_and_reset();
369 183
370 let mut dac = Self { 184 /// Disable this channel.
371 phantom: PhantomData, 185 pub fn disable(&mut self) {
372 dma, 186 self.set_enable(false)
373 }; 187 }
374 188
375 // Configure each activated channel. All results can be `unwrap`ed since they 189 /// Set the trigger source for this channel.
376 // will only error if the channel is not configured (i.e. ch1, ch2 are false) 190 ///
377 #[cfg(any(dac_v2, dac_v3))] 191 /// This method disables the channel, so you may need to re-enable afterwards.
378 dac.set_channel_mode(0).unwrap(); 192 pub fn set_trigger(&mut self, source: TriggerSel) {
379 dac.enable_channel().unwrap(); 193 critical_section::with(|_| {
380 dac.set_trigger_enable(true).unwrap(); 194 T::regs().cr().modify(|reg| {
195 reg.set_en(Self::IDX, false);
196 reg.set_tsel(Self::IDX, source as u8);
197 });
198 });
199 }
381 200
382 dac 201 /// Enable or disable triggering for this channel.
202 pub fn set_triggering(&mut self, on: bool) {
203 critical_section::with(|_| {
204 T::regs().cr().modify(|reg| {
205 reg.set_ten(Self::IDX, on);
206 });
207 });
383 } 208 }
384 209
385 /// Select a new trigger for this channel 210 /// Software trigger this channel.
386 pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { 211 pub fn trigger(&mut self) {
387 unwrap!(self.disable_channel()); 212 T::regs().swtrigr().write(|reg| {
388 T::regs().cr().modify(|reg| { 213 reg.set_swtrig(Self::IDX, true);
389 reg.set_tsel2(trigger.tsel());
390 }); 214 });
391 Ok(())
392 } 215 }
393 216
394 /// Write `data` to the DAC CH2 via DMA. 217 /// Set mode of this channel.
395 ///
396 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
397 /// This will configure a circular DMA transfer that periodically outputs the `data`.
398 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
399 /// 218 ///
400 /// **Important:** Channel 2 has to be configured for the DAC instance! 219 /// This method disables the channel, so you may need to re-enable afterwards.
401 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> 220 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
402 where 221 pub fn set_mode(&mut self, mode: Mode) {
403 Tx: DmaCh2<T>, 222 critical_section::with(|_| {
404 { 223 T::regs().cr().modify(|reg| {
405 let channel = Channel::Ch2.index(); 224 reg.set_en(Self::IDX, false);
406 debug!("Writing to channel {}", channel); 225 });
407 226 T::regs().mcr().modify(|reg| {
408 // Enable DAC and DMA 227 reg.set_mode(Self::IDX, mode.mode());
409 T::regs().cr().modify(|w| { 228 });
410 w.set_en(channel, true);
411 w.set_dmaen(channel, true);
412 }); 229 });
230 }
231
232 /// Write a new value to this channel.
233 ///
234 /// If triggering is not enabled, the new value is immediately output; otherwise,
235 /// it will be output after the next trigger.
236 pub fn set(&mut self, value: Value) {
237 match value {
238 Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)),
239 Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)),
240 Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)),
241 }
242 }
413 243
414 let tx_request = self.dma.request(); 244 /// Read the current output value of the DAC.
415 let dma_channel = &mut self.dma; 245 pub fn read(&self) -> u16 {
246 T::regs().dor(Self::IDX).read().dor()
247 }
416 248
417 let tx_options = crate::dma::TransferOptions { 249 /// Set HFSEL as appropriate for the current peripheral clock frequency.
418 circular, 250 #[cfg(dac_v5)]
419 half_transfer_ir: false, 251 fn set_hfsel(&mut self) {
420 complete_transfer_ir: !circular, 252 if T::frequency() >= crate::time::mhz(80) {
421 ..Default::default() 253 critical_section::with(|_| {
422 }; 254 T::regs().cr().modify(|reg| {
255 reg.set_hfsel(true);
256 });
257 });
258 }
259 }
423 260
424 // Initiate the correct type of DMA transfer depending on what data is passed 261 /// Set HFSEL as appropriate for the current peripheral clock frequency.
425 let tx_f = match data { 262 #[cfg(any(dac_v6, dac_v7))]
426 ValueArray::Bit8(buf) => unsafe { 263 fn set_hfsel(&mut self) {
427 crate::dma::Transfer::new_write( 264 if T::frequency() >= crate::time::mhz(160) {
428 dma_channel, 265 critical_section::with(|_| {
429 tx_request, 266 T::regs().mcr().modify(|reg| {
430 buf, 267 reg.set_hfsel(0b10);
431 T::regs().dhr8r(channel).as_ptr() as *mut u8, 268 });
432 tx_options, 269 });
433 ) 270 } else if T::frequency() >= crate::time::mhz(80) {
434 }, 271 critical_section::with(|_| {
435 ValueArray::Bit12Left(buf) => unsafe { 272 T::regs().mcr().modify(|reg| {
436 crate::dma::Transfer::new_write( 273 reg.set_hfsel(0b01);
437 dma_channel, 274 });
438 tx_request, 275 });
439 buf, 276 }
440 T::regs().dhr12l(channel).as_ptr() as *mut u16, 277 }
441 tx_options, 278}
442 )
443 },
444 ValueArray::Bit12Right(buf) => unsafe {
445 crate::dma::Transfer::new_write(
446 dma_channel,
447 tx_request,
448 buf,
449 T::regs().dhr12r(channel).as_ptr() as *mut u16,
450 tx_options,
451 )
452 },
453 };
454 279
455 tx_f.await; 280macro_rules! impl_dma_methods {
281 ($n:literal, $trait:ident) => {
282 impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA>
283 where
284 DMA: $trait<T>,
285 {
286 /// Write `data` to this channel via DMA.
287 ///
288 /// To prevent delays or glitches when outputing a periodic waveform, the `circular`
289 /// flag can be set. This configures a circular DMA transfer that continually outputs
290 /// `data`. Note that for performance reasons in circular mode the transfer-complete
291 /// interrupt is disabled.
292 #[cfg(not(gpdma))]
293 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) {
294 // Enable DAC and DMA
295 T::regs().cr().modify(|w| {
296 w.set_en(Self::IDX, true);
297 w.set_dmaen(Self::IDX, true);
298 });
299
300 let tx_request = self.dma.request();
301 let dma_channel = &mut self.dma;
302
303 let tx_options = crate::dma::TransferOptions {
304 circular,
305 half_transfer_ir: false,
306 complete_transfer_ir: !circular,
307 ..Default::default()
308 };
309
310 // Initiate the correct type of DMA transfer depending on what data is passed
311 let tx_f = match data {
312 ValueArray::Bit8(buf) => unsafe {
313 crate::dma::Transfer::new_write(
314 dma_channel,
315 tx_request,
316 buf,
317 T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8,
318 tx_options,
319 )
320 },
321 ValueArray::Bit12Left(buf) => unsafe {
322 crate::dma::Transfer::new_write(
323 dma_channel,
324 tx_request,
325 buf,
326 T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16,
327 tx_options,
328 )
329 },
330 ValueArray::Bit12Right(buf) => unsafe {
331 crate::dma::Transfer::new_write(
332 dma_channel,
333 tx_request,
334 buf,
335 T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16,
336 tx_options,
337 )
338 },
339 };
340
341 tx_f.await;
342
343 T::regs().cr().modify(|w| {
344 w.set_en(Self::IDX, false);
345 w.set_dmaen(Self::IDX, false);
346 });
347 }
348 }
349 };
350}
456 351
457 // finish dma 352impl_dma_methods!(1, DacDma1);
458 // TODO: Do we need to check any status registers here? 353impl_dma_methods!(2, DacDma2);
459 T::regs().cr().modify(|w| {
460 // Disable the DAC peripheral
461 w.set_en(channel, false);
462 // Disable the DMA. TODO: Is this necessary?
463 w.set_dmaen(channel, false);
464 });
465 354
466 Ok(()) 355impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
356 fn drop(&mut self) {
357 T::disable();
467 } 358 }
468} 359}
469 360
470impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { 361/// DAC driver.
471 /// Create a new DAC instance with both channels. 362///
363/// Use this struct when you want to use both channels, either together or independently.
364///
365/// # Example
366///
367/// ```ignore
368/// // Pins may need to be changed for your specific device.
369/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC, NoDma, NoDma, p.PA4, p.PA5).split();
370/// ```
371pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> {
372 ch1: DacChannel<'d, T, 1, DMACh1>,
373 ch2: DacChannel<'d, T, 2, DMACh2>,
374}
375
376impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
377 /// Create a new `Dac` instance, consuming the underlying DAC peripheral.
378 ///
379 /// This struct allows you to access both channels of the DAC, where available. You can either
380 /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use
381 /// the two channels together.
382 ///
383 /// The channels are enabled on creation and begins to drive their output pins.
384 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
385 /// disable the channel; you must re-enable them with `enable()`.
472 /// 386 ///
473 /// This is used to obtain two independent channels via `split()` for use e.g. with DMA. 387 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
388 /// method on the underlying channels.
474 pub fn new( 389 pub fn new(
475 peri: impl Peripheral<P = T> + 'd, 390 _peri: impl Peripheral<P = T> + 'd,
476 dma_ch1: impl Peripheral<P = TxCh1> + 'd, 391 dma_ch1: impl Peripheral<P = DMACh1> + 'd,
477 dma_ch2: impl Peripheral<P = TxCh2> + 'd, 392 dma_ch2: impl Peripheral<P = DMACh2> + 'd,
478 pin_ch1: impl Peripheral<P = impl DacPin<T, 1>> + crate::gpio::sealed::Pin + 'd, 393 pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::sealed::Pin> + 'd,
479 pin_ch2: impl Peripheral<P = impl DacPin<T, 2>> + crate::gpio::sealed::Pin + 'd, 394 pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::sealed::Pin> + 'd,
480 ) -> Self { 395 ) -> Self {
396 into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
481 pin_ch1.set_as_analog(); 397 pin_ch1.set_as_analog();
482 pin_ch2.set_as_analog(); 398 pin_ch2.set_as_analog();
483 into_ref!(peri, dma_ch1, dma_ch2); 399 // Enable twice to increment the DAC refcount for each channel.
484 T::enable_and_reset(); 400 T::enable_and_reset();
401 T::enable_and_reset();
402 Self {
403 ch1: DacCh1 {
404 phantom: PhantomData,
405 dma: dma_ch1,
406 },
407 ch2: DacCh2 {
408 phantom: PhantomData,
409 dma: dma_ch2,
410 },
411 }
412 }
485 413
486 let mut dac_ch1 = DacCh1 { 414 /// Create a new `Dac` instance where the external output pins are not used,
487 _peri: peri, 415 /// so the DAC can only be used to generate internal signals but the GPIO
488 dma: dma_ch1, 416 /// pins remain available for other functions.
489 }; 417 ///
490 418 /// This struct allows you to access both channels of the DAC, where available. You can either
491 let mut dac_ch2 = DacCh2 { 419 /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two
492 phantom: PhantomData, 420 /// channels together.
493 dma: dma_ch2, 421 ///
494 }; 422 /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
495 423 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
496 // Configure each activated channel. All results can be `unwrap`ed since they 424 /// channel; you must re-enable them with `enable()`.
497 // will only error if the channel is not configured (i.e. ch1, ch2 are false) 425 ///
498 #[cfg(any(dac_v2, dac_v3))] 426 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
499 dac_ch1.set_channel_mode(0).unwrap(); 427 /// method on the underlying channels.
500 dac_ch1.enable_channel().unwrap(); 428 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
501 dac_ch1.set_trigger_enable(true).unwrap(); 429 pub fn new_internal(
502 430 _peri: impl Peripheral<P = T> + 'd,
503 #[cfg(any(dac_v2, dac_v3))] 431 dma_ch1: impl Peripheral<P = DMACh1> + 'd,
504 dac_ch2.set_channel_mode(0).unwrap(); 432 dma_ch2: impl Peripheral<P = DMACh2> + 'd,
505 dac_ch2.enable_channel().unwrap(); 433 ) -> Self {
506 dac_ch2.set_trigger_enable(true).unwrap(); 434 into_ref!(dma_ch1, dma_ch2);
507 435 // Enable twice to increment the DAC refcount for each channel.
436 T::enable_and_reset();
437 T::enable_and_reset();
508 Self { 438 Self {
509 ch1: dac_ch1, 439 ch1: DacCh1 {
510 ch2: dac_ch2, 440 phantom: PhantomData,
441 dma: dma_ch1,
442 },
443 ch2: DacCh2 {
444 phantom: PhantomData,
445 dma: dma_ch2,
446 },
511 } 447 }
512 } 448 }
513 449
514 /// Split the DAC into CH1 and CH2 for independent use. 450 /// Split this `Dac` into separate channels.
515 pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) { 451 ///
452 /// You can access and move the channels around separately after splitting.
453 pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) {
516 (self.ch1, self.ch2) 454 (self.ch1, self.ch2)
517 } 455 }
518 456
519 /// Get mutable reference to CH1 457 /// Temporarily access channel 1.
520 pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> { 458 pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> {
521 &mut self.ch1 459 &mut self.ch1
522 } 460 }
523 461
524 /// Get mutable reference to CH2 462 /// Temporarily access channel 2.
525 pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> { 463 pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> {
526 &mut self.ch2 464 &mut self.ch2
527 } 465 }
528 466
529 /// Get reference to CH1 467 /// Simultaneously update channels 1 and 2 with a new value.
530 pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> { 468 ///
531 &self.ch1 469 /// If triggering is not enabled, the new values are immediately output;
532 } 470 /// otherwise, they will be output after the next trigger.
533 471 pub fn set(&mut self, values: DualValue) {
534 /// Get reference to CH2 472 match values {
535 pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> { 473 DualValue::Bit8(v1, v2) => T::regs().dhr8rd().write(|reg| {
536 &self.ch2 474 reg.set_dhr(0, v1);
475 reg.set_dhr(1, v2);
476 }),
477 DualValue::Bit12Left(v1, v2) => T::regs().dhr12ld().write(|reg| {
478 reg.set_dhr(0, v1);
479 reg.set_dhr(1, v2);
480 }),
481 DualValue::Bit12Right(v1, v2) => T::regs().dhr12rd().write(|reg| {
482 reg.set_dhr(0, v1);
483 reg.set_dhr(1, v2);
484 }),
485 }
537 } 486 }
538} 487}
539 488
540impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> {
541 const CHANNEL: Channel = Channel::Ch1;
542}
543
544impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> {
545 const CHANNEL: Channel = Channel::Ch2;
546}
547
548pub(crate) mod sealed { 489pub(crate) mod sealed {
549 pub trait Instance { 490 pub trait Instance {
550 fn regs() -> &'static crate::pac::dac::Dac; 491 fn regs() -> &'static crate::pac::dac::Dac;
@@ -552,34 +493,36 @@ pub(crate) mod sealed {
552} 493}
553 494
554pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 495pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
555dma_trait!(DmaCh1, Instance); 496dma_trait!(DacDma1, Instance);
556dma_trait!(DmaCh2, Instance); 497dma_trait!(DacDma2, Instance);
557 498
558/// Marks a pin that can be used with the DAC 499/// Marks a pin that can be used with the DAC
559pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} 500pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
560 501
561foreach_peripheral!( 502foreach_peripheral!(
562 (dac, $inst:ident) => { 503 (dac, $inst:ident) => {
563 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented 504 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
564 #[cfg(any(rcc_h7, rcc_h7rm0433))] 505 #[cfg(any(rcc_h7, rcc_h7rm0433))]
565 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { 506 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
566 fn frequency() -> crate::time::Hertz { 507 fn frequency() -> crate::time::Hertz {
567 critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 }) 508 critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 })
568 } 509 }
569 510
570 fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { 511 fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
571 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); 512 // TODO: Increment refcount?
572 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); 513 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
573 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); 514 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
574 } 515 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
575 516 }
576 fn disable_with_cs(_cs: critical_section::CriticalSection) { 517
577 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)) 518 fn disable_with_cs(_cs: critical_section::CriticalSection) {
578 } 519 // TODO: Decrement refcount?
579 } 520 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
580 521 }
581 #[cfg(any(rcc_h7, rcc_h7rm0433))] 522 }
582 impl crate::rcc::RccPeripheral for peripherals::$inst {} 523
524 #[cfg(any(rcc_h7, rcc_h7rm0433))]
525 impl crate::rcc::RccPeripheral for peripherals::$inst {}
583 526
584 impl crate::dac::sealed::Instance for peripherals::$inst { 527 impl crate::dac::sealed::Instance for peripherals::$inst {
585 fn regs() -> &'static crate::pac::dac::Dac { 528 fn regs() -> &'static crate::pac::dac::Dac {
diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs
new file mode 100644
index 000000000..f38dd8fd7
--- /dev/null
+++ b/embassy-stm32/src/dac/tsel.rs
@@ -0,0 +1,282 @@
1/// Trigger selection for STM32F0.
2#[cfg(stm32f0)]
3#[derive(Debug, Copy, Clone, Eq, PartialEq)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5pub enum TriggerSel {
6 Tim6 = 0,
7 Tim3 = 1,
8 Tim7 = 2,
9 Tim15 = 3,
10 Tim2 = 4,
11 Exti9 = 6,
12 Software = 7,
13}
14
15/// Trigger selection for STM32F1.
16#[cfg(stm32f1)]
17#[derive(Debug, Copy, Clone, Eq, PartialEq)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub enum TriggerSel {
20 Tim6 = 0,
21 #[cfg(any(stm32f100, stm32f105, stm32f107))]
22 Tim3 = 1,
23 #[cfg(any(stm32f101, stm32f103))]
24 Tim8 = 1,
25 Tim7 = 2,
26 #[cfg(any(stm32f101, stm32f103, stm32f105, stm32f107))]
27 Tim5 = 3,
28 #[cfg(all(stm32f100, any(flashsize_4, flashsize_6, flashsize_8, flashsize_b)))]
29 Tim15 = 3,
30 #[cfg(all(stm32f100, any(flashsize_c, flashsize_d, flashsize_e)))]
31 /// Can be remapped to TIM15 with MISC_REMAP in AFIO_MAPR2.
32 Tim5Or15 = 3,
33 Tim2 = 4,
34 Tim4 = 5,
35 Exti9 = 6,
36 Software = 7,
37}
38
39/// Trigger selection for STM32F2/F4/F7/L4, except F410 or L4+.
40#[cfg(all(any(stm32f2, stm32f4, stm32f7, stm32l4_nonplus), not(stm32f410)))]
41#[derive(Debug, Copy, Clone, Eq, PartialEq)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub enum TriggerSel {
44 Tim6 = 0,
45 Tim8 = 1,
46 #[cfg(not(any(stm32l45x, stm32l46x)))]
47 Tim7 = 2,
48 Tim5 = 3,
49 Tim2 = 4,
50 Tim4 = 5,
51 Exti9 = 6,
52 Software = 7,
53}
54
55/// Trigger selection for STM32F410.
56#[cfg(stm32f410)]
57#[derive(Debug, Copy, Clone, Eq, PartialEq)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub enum TriggerSel {
60 Tim5 = 3,
61 Exti9 = 6,
62 Software = 7,
63}
64
65/// Trigger selection for STM32F301/2 and 318.
66#[cfg(any(stm32f301, stm32f302, stm32f318))]
67#[derive(Debug, Copy, Clone, Eq, PartialEq)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69pub enum TriggerSel {
70 Tim6 = 0,
71 #[cfg(stm32f302)]
72 /// Requires DAC_TRIG_RMP set in SYSCFG_CFGR1.
73 Tim3 = 1,
74 Tim15 = 3,
75 Tim2 = 4,
76 #[cfg(all(stm32f302, any(flashsize_6, flashsize_8)))]
77 Tim4 = 5,
78 Exti9 = 6,
79 Software = 7,
80}
81
82/// Trigger selection for STM32F303/3x8 (excluding 318 which is like 301, and 378 which is 37x).
83#[cfg(any(stm32f303, stm32f328, stm32f358, stm32f398))]
84#[derive(Debug, Copy, Clone, Eq, PartialEq)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub enum TriggerSel {
87 Tim6 = 0,
88 /// * DAC1: defaults to TIM8 but can be remapped to TIM3 with DAC_TRIG_RMP in SYSCFG_CFGR1
89 /// * DAC2: always TIM3
90 Tim8Or3 = 1,
91 Tim7 = 2,
92 Tim15 = 3,
93 Tim2 = 4,
94 Tim4 = 5,
95 Exti9 = 6,
96 Software = 7,
97}
98
99/// Trigger selection for STM32F37x.
100#[cfg(any(stm32f373, stm32f378))]
101#[derive(Debug, Copy, Clone, Eq, PartialEq)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103pub enum TriggerSel {
104 Tim6 = 0,
105 Tim3 = 1,
106 Tim7 = 2,
107 /// TIM5 on DAC1, TIM18 on DAC2
108 Dac1Tim5Dac2Tim18 = 3,
109 Tim2 = 4,
110 Tim4 = 5,
111 Exti9 = 6,
112 Software = 7,
113}
114
115/// Trigger selection for STM32F334.
116#[cfg(stm32f334)]
117#[derive(Debug, Copy, Clone, Eq, PartialEq)]
118#[cfg_attr(feature = "defmt", derive(defmt::Format))]
119pub enum TriggerSel {
120 Tim6 = 0,
121 /// Requires DAC_TRIG_RMP set in SYSCFG_CFGR1.
122 Tim3 = 1,
123 Tim7 = 2,
124 /// Can be remapped to HRTIM_DACTRG1 using DAC1_TRIG3_RMP in SYSCFG_CFGR3.
125 Tim15OrHrtimDacTrg1 = 3,
126 Tim2 = 4,
127 /// Requires DAC_TRIG5_RMP set in SYSCFG_CFGR3.
128 HrtimDacTrg2 = 5,
129}
130
131/// Trigger selection for STM32L0.
132#[cfg(stm32l0)]
133#[derive(Debug, Copy, Clone, Eq, PartialEq)]
134#[cfg_attr(feature = "defmt", derive(defmt::Format))]
135pub enum TriggerSel {
136 Tim6 = 0,
137 Tim3 = 1,
138 Tim3Ch3 = 2,
139 Tim21 = 3,
140 Tim2 = 4,
141 Tim7 = 5,
142 Exti9 = 6,
143 Software = 7,
144}
145
146/// Trigger selection for STM32L1.
147#[cfg(stm32l1)]
148#[derive(Debug, Copy, Clone, Eq, PartialEq)]
149#[cfg_attr(feature = "defmt", derive(defmt::Format))]
150pub enum TriggerSel {
151 Tim6 = 0,
152 Tim7 = 2,
153 Tim9 = 3,
154 Tim2 = 4,
155 Tim4 = 5,
156 Exti9 = 6,
157 Software = 7,
158}
159
160/// Trigger selection for L4+, L5, U5, H7.
161#[cfg(any(stm32l4_plus, stm32l5, stm32u5, stm32h7))]
162#[derive(Debug, Copy, Clone, Eq, PartialEq)]
163#[cfg_attr(feature = "defmt", derive(defmt::Format))]
164pub enum TriggerSel {
165 Software = 0,
166 Tim1 = 1,
167 Tim2 = 2,
168 Tim4 = 3,
169 Tim5 = 4,
170 Tim6 = 5,
171 Tim7 = 6,
172 Tim8 = 7,
173 Tim15 = 8,
174 #[cfg(all(stm32h7, hrtim))]
175 Hrtim1DacTrg1 = 9,
176 #[cfg(all(stm32h7, hrtim))]
177 Hrtim1DacTrg2 = 10,
178 Lptim1 = 11,
179 #[cfg(not(stm32u5))]
180 Lptim2 = 12,
181 #[cfg(stm32u5)]
182 Lptim3 = 12,
183 Exti9 = 13,
184 #[cfg(any(stm32h7ax, stm32h7bx))]
185 /// RM0455 suggests this might be LPTIM2 on DAC1 and LPTIM3 on DAC2,
186 /// but it's probably wrong. Please let us know if you find out.
187 Lptim3 = 14,
188 #[cfg(any(stm32h72x, stm32h73x))]
189 Tim23 = 14,
190 #[cfg(any(stm32h72x, stm32h73x))]
191 Tim24 = 15,
192}
193
194/// Trigger selection for H5.
195#[cfg(stm32h5)]
196#[derive(Debug, Copy, Clone, Eq, PartialEq)]
197#[cfg_attr(feature = "defmt", derive(defmt::Format))]
198pub enum TriggerSel {
199 Software = 0,
200 Tim1 = 1,
201 Tim2 = 2,
202 #[cfg(any(stm32h56x, stm32h57x))]
203 Tim4 = 3,
204 #[cfg(stm32h503)]
205 Tim3 = 3,
206 #[cfg(any(stm32h56x, stm32h57x))]
207 Tim5 = 4,
208 Tim6 = 5,
209 Tim7 = 6,
210 #[cfg(any(stm32h56x, stm32h57x))]
211 Tim8 = 7,
212 #[cfg(any(stm32h56x, stm32h57x))]
213 Tim15 = 8,
214 Lptim1 = 11,
215 Lptim2 = 12,
216 Exti9 = 13,
217}
218
219/// Trigger selection for G0.
220#[cfg(stm32g0)]
221#[derive(Debug, Copy, Clone, Eq, PartialEq)]
222#[cfg_attr(feature = "defmt", derive(defmt::Format))]
223pub enum TriggerSel {
224 Software = 0,
225 Tim1 = 1,
226 Tim2 = 2,
227 Tim3 = 3,
228 Tim6 = 5,
229 Tim7 = 6,
230 Tim15 = 8,
231 Lptim1 = 11,
232 Lptim2 = 12,
233 Exti9 = 13,
234}
235
236/// Trigger selection for G4.
237#[cfg(stm32g4)]
238#[derive(Debug, Copy, Clone, Eq, PartialEq)]
239#[cfg_attr(feature = "defmt", derive(defmt::Format))]
240pub enum TriggerSel {
241 Software = 0,
242 /// * DAC1, DAC2, DAC4: TIM8
243 /// * DAC3: TIM1
244 Dac124Tim8Dac3Tim1 = 1,
245 Tim7 = 2,
246 Tim15 = 3,
247 Tim2 = 4,
248 Tim4 = 5,
249 Exti9 = 6,
250 Tim6 = 7,
251 Tim3 = 8,
252 HrtimDacRstTrg1 = 9,
253 HrtimDacRstTrg2 = 10,
254 HrtimDacRstTrg3 = 11,
255 HrtimDacRstTrg4 = 12,
256 HrtimDacRstTrg5 = 13,
257 HrtimDacRstTrg6 = 14,
258 /// * DAC1, DAC4: HRTIM_DAC_TRG1
259 /// * DAC2: HRTIM_DAC_TRG2
260 /// * DAC3: HRTIM_DAC_TRG3
261 HrtimDacTrg123 = 15,
262}
263
264/// Trigger selection for WL.
265#[cfg(stm32wl)]
266#[derive(Debug, Copy, Clone, Eq, PartialEq)]
267#[cfg_attr(feature = "defmt", derive(defmt::Format))]
268pub enum TriggerSel {
269 Software = 0,
270 Tim1 = 1,
271 Tim2 = 2,
272 Lptim1 = 11,
273 Lptim2 = 12,
274 Lptim3 = 13,
275 Exti9 = 14,
276}
277
278impl TriggerSel {
279 pub fn tsel(&self) -> u8 {
280 *self as u8
281 }
282}
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs
index 9dcd50df4..bf035fd25 100644
--- a/embassy-stm32/src/rcc/f3.rs
+++ b/embassy-stm32/src/rcc/f3.rs
@@ -346,10 +346,7 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
346 None => { 346 None => {
347 cfg_if::cfg_if! { 347 cfg_if::cfg_if! {
348 // For some chips PREDIV is always two, and cannot be changed 348 // For some chips PREDIV is always two, and cannot be changed
349 if #[cfg(any( 349 if #[cfg(any(flashsize_d, flashsize_e))] {
350 stm32f302xd, stm32f302xe, stm32f303xd,
351 stm32f303xe, stm32f398xe
352 ))] {
353 let (multiplier, divisor) = get_mul_div(sysclk, HSI_FREQ.0); 350 let (multiplier, divisor) = get_mul_div(sysclk, HSI_FREQ.0);
354 ( 351 (
355 Hertz((HSI_FREQ.0 / divisor) * multiplier), 352 Hertz((HSI_FREQ.0 / divisor) * multiplier),
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index aaedcfecc..8f14d6078 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -4,7 +4,7 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacCh1, DacChannel, Value}; 7use embassy_stm32::dac::{DacCh1, Value};
8use embassy_stm32::dma::NoDma; 8use embassy_stm32::dma::NoDma;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -14,11 +14,10 @@ async fn main(_spawner: Spawner) -> ! {
14 info!("Hello World, dude!"); 14 info!("Hello World, dude!");
15 15
16 let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4); 16 let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4);
17 unwrap!(dac.set_trigger_enable(false));
18 17
19 loop { 18 loop {
20 for v in 0..=255 { 19 for v in 0..=255 {
21 unwrap!(dac.set(Value::Bit8(to_sine_wave(v)))); 20 dac.set(Value::Bit8(to_sine_wave(v)));
22 } 21 }
23 } 22 }
24} 23}
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index 35fd6550f..f66268151 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -4,7 +4,7 @@
4 4
5use cortex_m_rt::entry; 5use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dac::{DacCh1, DacChannel, Value}; 7use embassy_stm32::dac::{DacCh1, Value};
8use embassy_stm32::dma::NoDma; 8use embassy_stm32::dma::NoDma;
9use embassy_stm32::Config; 9use embassy_stm32::Config;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
@@ -46,11 +46,10 @@ fn main() -> ! {
46 let p = embassy_stm32::init(config); 46 let p = embassy_stm32::init(config);
47 47
48 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 48 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
49 unwrap!(dac.set_trigger_enable(false));
50 49
51 loop { 50 loop {
52 for v in 0..=255 { 51 for v in 0..=255 {
53 unwrap!(dac.set(Value::Bit8(to_sine_wave(v)))); 52 dac.set(Value::Bit8(to_sine_wave(v)));
54 } 53 }
55 } 54 }
56} 55}
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index e141fc484..c19fdd623 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -4,21 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacChannel, ValueArray}; 7use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm}; 8use embassy_stm32::pac::timer::vals::{Mms, Opm};
9use embassy_stm32::peripherals::{TIM6, TIM7}; 9use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral; 10use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::timer::low_level::Basic16bitInstance; 12use embassy_stm32::timer::low_level::Basic16bitInstance;
13use micromath::F32Ext; 13use micromath::F32Ext;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
15 15
16pub type Dac1Type =
17 embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
18
19pub type Dac2Type =
20 embassy_stm32::dac::DacCh2<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
21
22#[embassy_executor::main] 16#[embassy_executor::main]
23async fn main(spawner: Spawner) { 17async fn main(spawner: Spawner) {
24 let mut config = embassy_stm32::Config::default(); 18 let mut config = embassy_stm32::Config::default();
@@ -63,7 +57,7 @@ async fn main(spawner: Spawner) {
63} 57}
64 58
65#[embassy_executor::task] 59#[embassy_executor::task]
66async fn dac_task1(mut dac: Dac1Type) { 60async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
67 let data: &[u8; 256] = &calculate_array::<256>(); 61 let data: &[u8; 256] = &calculate_array::<256>();
68 62
69 info!("TIM6 frequency is {}", TIM6::frequency()); 63 info!("TIM6 frequency is {}", TIM6::frequency());
@@ -77,8 +71,9 @@ async fn dac_task1(mut dac: Dac1Type) {
77 error!("Reload value {} below threshold!", reload); 71 error!("Reload value {} below threshold!", reload);
78 } 72 }
79 73
80 dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap(); 74 dac.set_trigger(embassy_stm32::dac::TriggerSel::Tim6);
81 dac.enable_channel().unwrap(); 75 dac.set_triggering(true);
76 dac.enable();
82 77
83 TIM6::enable_and_reset(); 78 TIM6::enable_and_reset();
84 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 79 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
@@ -100,14 +95,12 @@ async fn dac_task1(mut dac: Dac1Type) {
100 // Loop technically not necessary if DMA circular mode is enabled 95 // Loop technically not necessary if DMA circular mode is enabled
101 loop { 96 loop {
102 info!("Loop DAC1"); 97 info!("Loop DAC1");
103 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await { 98 dac.write(ValueArray::Bit8(data), true).await;
104 error!("Could not write to dac: {}", e);
105 }
106 } 99 }
107} 100}
108 101
109#[embassy_executor::task] 102#[embassy_executor::task]
110async fn dac_task2(mut dac: Dac2Type) { 103async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
111 let data: &[u8; 256] = &calculate_array::<256>(); 104 let data: &[u8; 256] = &calculate_array::<256>();
112 105
113 info!("TIM7 frequency is {}", TIM7::frequency()); 106 info!("TIM7 frequency is {}", TIM7::frequency());
@@ -127,7 +120,9 @@ async fn dac_task2(mut dac: Dac2Type) {
127 w.set_cen(true); 120 w.set_cen(true);
128 }); 121 });
129 122
130 dac.select_trigger(embassy_stm32::dac::Ch2Trigger::Tim7).unwrap(); 123 dac.set_trigger(embassy_stm32::dac::TriggerSel::Tim7);
124 dac.set_triggering(true);
125 dac.enable();
131 126
132 debug!( 127 debug!(
133 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", 128 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
@@ -138,9 +133,7 @@ async fn dac_task2(mut dac: Dac2Type) {
138 data.len() 133 data.len()
139 ); 134 );
140 135
141 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await { 136 dac.write(ValueArray::Bit8(data), true).await;
142 error!("Could not write to dac: {}", e);
143 }
144} 137}
145 138
146fn to_sine_wave(v: u8) -> u8 { 139fn to_sine_wave(v: u8) -> u8 {
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index 0193a248e..d6a7ff624 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -3,7 +3,7 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dac::{DacCh1, DacChannel, Value}; 6use embassy_stm32::dac::{DacCh1, Value};
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -13,11 +13,10 @@ fn main() -> ! {
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); 15 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
16 unwrap!(dac.set_trigger_enable(false));
17 16
18 loop { 17 loop {
19 for v in 0..=255 { 18 for v in 0..=255 {
20 unwrap!(dac.set(Value::Bit8(to_sine_wave(v)))); 19 dac.set(Value::Bit8(to_sine_wave(v)));
21 } 20 }
22 } 21 }
23} 22}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index 98f37f906..dc86dbf43 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -4,21 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacChannel, ValueArray}; 7use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm}; 8use embassy_stm32::pac::timer::vals::{Mms, Opm};
9use embassy_stm32::peripherals::{TIM6, TIM7}; 9use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral; 10use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::timer::low_level::Basic16bitInstance; 12use embassy_stm32::timer::low_level::Basic16bitInstance;
13use micromath::F32Ext; 13use micromath::F32Ext;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
15 15
16pub type Dac1Type =
17 embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
18
19pub type Dac2Type =
20 embassy_stm32::dac::DacCh2<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
21
22#[embassy_executor::main] 16#[embassy_executor::main]
23async fn main(spawner: Spawner) { 17async fn main(spawner: Spawner) {
24 let config = embassy_stm32::Config::default(); 18 let config = embassy_stm32::Config::default();
@@ -34,7 +28,7 @@ async fn main(spawner: Spawner) {
34} 28}
35 29
36#[embassy_executor::task] 30#[embassy_executor::task]
37async fn dac_task1(mut dac: Dac1Type) { 31async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
38 let data: &[u8; 256] = &calculate_array::<256>(); 32 let data: &[u8; 256] = &calculate_array::<256>();
39 33
40 info!("TIM6 frequency is {}", TIM6::frequency()); 34 info!("TIM6 frequency is {}", TIM6::frequency());
@@ -48,8 +42,9 @@ async fn dac_task1(mut dac: Dac1Type) {
48 error!("Reload value {} below threshold!", reload); 42 error!("Reload value {} below threshold!", reload);
49 } 43 }
50 44
51 dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap(); 45 dac.set_trigger(embassy_stm32::dac::TriggerSel::Tim6);
52 dac.enable_channel().unwrap(); 46 dac.set_triggering(true);
47 dac.enable();
53 48
54 TIM6::enable_and_reset(); 49 TIM6::enable_and_reset();
55 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 50 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
@@ -71,14 +66,12 @@ async fn dac_task1(mut dac: Dac1Type) {
71 // Loop technically not necessary if DMA circular mode is enabled 66 // Loop technically not necessary if DMA circular mode is enabled
72 loop { 67 loop {
73 info!("Loop DAC1"); 68 info!("Loop DAC1");
74 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await { 69 dac.write(ValueArray::Bit8(data), true).await;
75 error!("Could not write to dac: {}", e);
76 }
77 } 70 }
78} 71}
79 72
80#[embassy_executor::task] 73#[embassy_executor::task]
81async fn dac_task2(mut dac: Dac2Type) { 74async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
82 let data: &[u8; 256] = &calculate_array::<256>(); 75 let data: &[u8; 256] = &calculate_array::<256>();
83 76
84 info!("TIM7 frequency is {}", TIM7::frequency()); 77 info!("TIM7 frequency is {}", TIM7::frequency());
@@ -98,7 +91,9 @@ async fn dac_task2(mut dac: Dac2Type) {
98 w.set_cen(true); 91 w.set_cen(true);
99 }); 92 });
100 93
101 dac.select_trigger(embassy_stm32::dac::Ch2Trigger::Tim7).unwrap(); 94 dac.set_trigger(embassy_stm32::dac::TriggerSel::Tim7);
95 dac.set_triggering(true);
96 dac.enable();
102 97
103 debug!( 98 debug!(
104 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", 99 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
@@ -109,9 +104,7 @@ async fn dac_task2(mut dac: Dac2Type) {
109 data.len() 104 data.len()
110 ); 105 );
111 106
112 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await { 107 dac.write(ValueArray::Bit8(data), true).await;
113 error!("Could not write to dac: {}", e);
114 }
115} 108}
116 109
117fn to_sine_wave(v: u8) -> u8 { 110fn to_sine_wave(v: u8) -> u8 {
diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs
index 10e3c3e81..824eb8803 100644
--- a/tests/stm32/src/bin/dac.rs
+++ b/tests/stm32/src/bin/dac.rs
@@ -10,7 +10,7 @@ use common::*;
10use defmt::assert; 10use defmt::assert;
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_stm32::adc::Adc; 12use embassy_stm32::adc::Adc;
13use embassy_stm32::dac::{DacCh1, DacChannel, Value}; 13use embassy_stm32::dac::{DacCh1, Value};
14use embassy_stm32::dma::NoDma; 14use embassy_stm32::dma::NoDma;
15use embassy_time::{Delay, Timer}; 15use embassy_time::{Delay, Timer};
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
@@ -26,9 +26,7 @@ async fn main(_spawner: Spawner) {
26 #[cfg(any(feature = "stm32h755zi", feature = "stm32g071rb"))] 26 #[cfg(any(feature = "stm32h755zi", feature = "stm32g071rb"))]
27 let dac_peripheral = p.DAC1; 27 let dac_peripheral = p.DAC1;
28 28
29 let mut dac: DacCh1<'_, _, NoDma> = DacCh1::new(dac_peripheral, NoDma, p.PA4); 29 let mut dac = DacCh1::new(dac_peripheral, NoDma, p.PA4);
30 unwrap!(dac.set_trigger_enable(false));
31
32 let mut adc = Adc::new(p.ADC1, &mut Delay); 30 let mut adc = Adc::new(p.ADC1, &mut Delay);
33 31
34 #[cfg(feature = "stm32h755zi")] 32 #[cfg(feature = "stm32h755zi")]
@@ -36,7 +34,7 @@ async fn main(_spawner: Spawner) {
36 #[cfg(any(feature = "stm32f429zi", feature = "stm32g071rb"))] 34 #[cfg(any(feature = "stm32f429zi", feature = "stm32g071rb"))]
37 let normalization_factor: i32 = 16; 35 let normalization_factor: i32 = 16;
38 36
39 unwrap!(dac.set(Value::Bit8(0))); 37 dac.set(Value::Bit8(0));
40 // Now wait a little to obtain a stable value 38 // Now wait a little to obtain a stable value
41 Timer::after_millis(30).await; 39 Timer::after_millis(30).await;
42 let offset = adc.read(&mut unsafe { embassy_stm32::Peripherals::steal() }.PA4); 40 let offset = adc.read(&mut unsafe { embassy_stm32::Peripherals::steal() }.PA4);
@@ -44,7 +42,7 @@ async fn main(_spawner: Spawner) {
44 for v in 0..=255 { 42 for v in 0..=255 {
45 // First set the DAC output value 43 // First set the DAC output value
46 let dac_output_val = to_sine_wave(v); 44 let dac_output_val = to_sine_wave(v);
47 unwrap!(dac.set(Value::Bit8(dac_output_val))); 45 dac.set(Value::Bit8(dac_output_val));
48 46
49 // Now wait a little to obtain a stable value 47 // Now wait a little to obtain a stable value
50 Timer::after_millis(30).await; 48 Timer::after_millis(30).await;