diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-11-24 23:51:07 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-24 23:51:07 +0000 |
| commit | 8b46343b34f0e6c2486131a0d18de46e9a835d22 (patch) | |
| tree | 868f23ec36bd02625894eb51358f1050b98ffe58 | |
| parent | f5c9e3baa6615928f948cf9ae4c03123d2d84cbc (diff) | |
| parent | a3ea01473a37451dbd80552ae501e854175055db (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.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 29 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/mod.rs | 873 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/tsel.rs | 282 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f3.rs | 5 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/dac.rs | 5 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/dac.rs | 5 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/dac_dma.rs | 31 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/dac.rs | 5 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/dac_dma.rs | 31 | ||||
| -rw-r--r-- | tests/stm32/src/bin/dac.rs | 10 |
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" | |||
| 58 | sdio-host = "0.5.0" | 58 | sdio-host = "0.5.0" |
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 60 | critical-section = "1.1" |
| 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd" } |
| 62 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 76 | [build-dependencies] | 76 | [build-dependencies] |
| 77 | proc-macro2 = "1.0.36" | 77 | proc-macro2 = "1.0.36" |
| 78 | quote = "1.0.15" | 78 | quote = "1.0.15" |
| 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949", default-features = false, features = ["metadata"]} | 79 | stm32-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). | ||
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | 5 | ||
| 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 7 | 7 | ||
| 8 | use crate::dma::NoDma; | ||
| 9 | #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] | ||
| 8 | use crate::pac::dac; | 10 | use crate::pac::dac; |
| 9 | use crate::rcc::RccPeripheral; | 11 | use crate::rcc::RccPeripheral; |
| 10 | use crate::{peripherals, Peripheral}; | 12 | use crate::{peripherals, Peripheral}; |
| 11 | 13 | ||
| 12 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 14 | mod tsel; |
| 13 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 15 | pub use tsel::TriggerSel; |
| 14 | /// Custom Errors | ||
| 15 | pub 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 | ||
| 23 | pub enum Channel { | ||
| 24 | Ch1, | ||
| 25 | Ch2, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl 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 | ||
| 40 | pub 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 | |||
| 69 | impl 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 | 21 | pub enum Mode { |
| 105 | pub 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 | ||
| 116 | impl Ch2Trigger { | 43 | #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] |
| 117 | fn tsel(&self) -> dac::vals::Tsel2 { | 44 | impl 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. | ||
| 134 | pub enum Value { | 64 | pub 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. | ||
| 78 | pub 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`]. | ||
| 146 | pub enum ValueArray<'a> { | 90 | pub 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 | ||
| 155 | pub 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 | 103 | pub 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 | /// ``` | ||
| 224 | pub 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 | 109 | pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; |
| 230 | /// | 110 | pub 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. | ||
| 232 | pub 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 | 112 | impl<'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. | ||
| 242 | pub 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 | ||
| 249 | impl<'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 | ||
| 359 | impl<'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; | 280 | macro_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 | 352 | impl_dma_methods!(1, DacDma1); |
| 458 | // TODO: Do we need to check any status registers here? | 353 | impl_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(()) | 355 | impl<'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 | ||
| 470 | impl<'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 | /// ``` | ||
| 371 | pub 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 | |||
| 376 | impl<'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 | ||
| 540 | impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> { | ||
| 541 | const CHANNEL: Channel = Channel::Ch1; | ||
| 542 | } | ||
| 543 | |||
| 544 | impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> { | ||
| 545 | const CHANNEL: Channel = Channel::Ch2; | ||
| 546 | } | ||
| 547 | |||
| 548 | pub(crate) mod sealed { | 489 | pub(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 | ||
| 554 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | 495 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} |
| 555 | dma_trait!(DmaCh1, Instance); | 496 | dma_trait!(DacDma1, Instance); |
| 556 | dma_trait!(DmaCh2, Instance); | 497 | dma_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 |
| 559 | pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} | 500 | pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} |
| 560 | 501 | ||
| 561 | foreach_peripheral!( | 502 | foreach_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))] | ||
| 5 | pub 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))] | ||
| 19 | pub 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))] | ||
| 43 | pub 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))] | ||
| 59 | pub 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))] | ||
| 69 | pub 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))] | ||
| 86 | pub 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))] | ||
| 103 | pub 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))] | ||
| 119 | pub 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))] | ||
| 135 | pub 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))] | ||
| 150 | pub 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))] | ||
| 164 | pub 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))] | ||
| 198 | pub 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))] | ||
| 223 | pub 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))] | ||
| 240 | pub 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))] | ||
| 268 | pub 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 | |||
| 278 | impl 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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dac::{DacCh1, DacChannel, Value}; | 7 | use embassy_stm32::dac::{DacCh1, Value}; |
| 8 | use embassy_stm32::dma::NoDma; | 8 | use embassy_stm32::dma::NoDma; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {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 | ||
| 5 | use cortex_m_rt::entry; | 5 | use cortex_m_rt::entry; |
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_stm32::dac::{DacCh1, DacChannel, Value}; | 7 | use embassy_stm32::dac::{DacCh1, Value}; |
| 8 | use embassy_stm32::dma::NoDma; | 8 | use embassy_stm32::dma::NoDma; |
| 9 | use embassy_stm32::Config; | 9 | use embassy_stm32::Config; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dac::{DacChannel, ValueArray}; | 7 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; |
| 8 | use embassy_stm32::pac::timer::vals::{Mms, Opm}; | 8 | use embassy_stm32::pac::timer::vals::{Mms, Opm}; |
| 9 | use embassy_stm32::peripherals::{TIM6, TIM7}; | 9 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 10 | use embassy_stm32::rcc::low_level::RccPeripheral; | 10 | use embassy_stm32::rcc::low_level::RccPeripheral; |
| 11 | use embassy_stm32::time::Hertz; | 11 | use embassy_stm32::time::Hertz; |
| 12 | use embassy_stm32::timer::low_level::Basic16bitInstance; | 12 | use embassy_stm32::timer::low_level::Basic16bitInstance; |
| 13 | use micromath::F32Ext; | 13 | use micromath::F32Ext; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 15 | ||
| 16 | pub type Dac1Type = | ||
| 17 | embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>; | ||
| 18 | |||
| 19 | pub 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] |
| 23 | async fn main(spawner: Spawner) { | 17 | async 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] |
| 66 | async fn dac_task1(mut dac: Dac1Type) { | 60 | async 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] |
| 110 | async fn dac_task2(mut dac: Dac2Type) { | 103 | async 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 | ||
| 146 | fn to_sine_wave(v: u8) -> u8 { | 139 | fn 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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_stm32::dac::{DacCh1, DacChannel, Value}; | 6 | use embassy_stm32::dac::{DacCh1, Value}; |
| 7 | use embassy_stm32::dma::NoDma; | 7 | use embassy_stm32::dma::NoDma; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dac::{DacChannel, ValueArray}; | 7 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; |
| 8 | use embassy_stm32::pac::timer::vals::{Mms, Opm}; | 8 | use embassy_stm32::pac::timer::vals::{Mms, Opm}; |
| 9 | use embassy_stm32::peripherals::{TIM6, TIM7}; | 9 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 10 | use embassy_stm32::rcc::low_level::RccPeripheral; | 10 | use embassy_stm32::rcc::low_level::RccPeripheral; |
| 11 | use embassy_stm32::time::Hertz; | 11 | use embassy_stm32::time::Hertz; |
| 12 | use embassy_stm32::timer::low_level::Basic16bitInstance; | 12 | use embassy_stm32::timer::low_level::Basic16bitInstance; |
| 13 | use micromath::F32Ext; | 13 | use micromath::F32Ext; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 15 | ||
| 16 | pub type Dac1Type = | ||
| 17 | embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>; | ||
| 18 | |||
| 19 | pub 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] |
| 23 | async fn main(spawner: Spawner) { | 17 | async 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] |
| 37 | async fn dac_task1(mut dac: Dac1Type) { | 31 | async 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] |
| 81 | async fn dac_task2(mut dac: Dac2Type) { | 74 | async 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 | ||
| 117 | fn to_sine_wave(v: u8) -> u8 { | 110 | fn 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::*; | |||
| 10 | use defmt::assert; | 10 | use defmt::assert; |
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | use embassy_stm32::adc::Adc; | 12 | use embassy_stm32::adc::Adc; |
| 13 | use embassy_stm32::dac::{DacCh1, DacChannel, Value}; | 13 | use embassy_stm32::dac::{DacCh1, Value}; |
| 14 | use embassy_stm32::dma::NoDma; | 14 | use embassy_stm32::dma::NoDma; |
| 15 | use embassy_time::{Delay, Timer}; | 15 | use embassy_time::{Delay, Timer}; |
| 16 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {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; |
