diff options
| -rw-r--r-- | embassy-stm32/src/dac.rs (renamed from embassy-stm32/src/dac/v2.rs) | 176 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/mod.rs | 36 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/v1.rs | 1 | ||||
| -rw-r--r-- | examples/stm32f4/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/dac.rs | 37 | ||||
| m--------- | stm32-data | 0 |
6 files changed, 136 insertions, 115 deletions
diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac.rs index 6b7f41c63..60e856c78 100644 --- a/embassy-stm32/src/dac/v2.rs +++ b/embassy-stm32/src/dac.rs | |||
| @@ -1,8 +1,10 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 1 | use embassy_hal_common::{into_ref, PeripheralRef}; | 3 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 2 | 4 | ||
| 3 | use crate::dac::{DacPin, Instance}; | ||
| 4 | use crate::pac::dac; | 5 | use crate::pac::dac; |
| 5 | use crate::Peripheral; | 6 | use crate::rcc::RccPeripheral; |
| 7 | use crate::{peripherals, Peripheral}; | ||
| 6 | 8 | ||
| 7 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 9 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 8 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -18,6 +20,15 @@ pub enum Channel { | |||
| 18 | Ch2, | 20 | Ch2, |
| 19 | } | 21 | } |
| 20 | 22 | ||
| 23 | impl Channel { | ||
| 24 | fn index(&self) -> usize { | ||
| 25 | match self { | ||
| 26 | Channel::Ch1 => 0, | ||
| 27 | Channel::Ch2 => 1, | ||
| 28 | } | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 21 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 32 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 22 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 33 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 23 | pub enum Ch1Trigger { | 34 | pub enum Ch1Trigger { |
| @@ -91,14 +102,6 @@ pub struct Dac<'d, T: Instance> { | |||
| 91 | _peri: PeripheralRef<'d, T>, | 102 | _peri: PeripheralRef<'d, T>, |
| 92 | } | 103 | } |
| 93 | 104 | ||
| 94 | macro_rules! enable { | ||
| 95 | ($enable_reg:ident, $enable_field:ident, $reset_reg:ident, $reset_field:ident) => { | ||
| 96 | crate::pac::RCC.$enable_reg().modify(|w| w.$enable_field(true)); | ||
| 97 | crate::pac::RCC.$reset_reg().modify(|w| w.$reset_field(true)); | ||
| 98 | crate::pac::RCC.$reset_reg().modify(|w| w.$reset_field(false)); | ||
| 99 | }; | ||
| 100 | } | ||
| 101 | |||
| 102 | impl<'d, T: Instance> Dac<'d, T> { | 105 | impl<'d, T: Instance> Dac<'d, T> { |
| 103 | pub fn new_1ch(peri: impl Peripheral<P = T> + 'd, _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd) -> Self { | 106 | pub fn new_1ch(peri: impl Peripheral<P = T> + 'd, _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd) -> Self { |
| 104 | into_ref!(peri); | 107 | into_ref!(peri); |
| @@ -115,31 +118,15 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 115 | } | 118 | } |
| 116 | 119 | ||
| 117 | fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self { | 120 | fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self { |
| 121 | T::enable(); | ||
| 122 | T::reset(); | ||
| 123 | |||
| 118 | unsafe { | 124 | unsafe { |
| 119 | // Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock | 125 | T::regs().cr().modify(|reg| { |
| 120 | // configuration. | 126 | for ch in 0..channels { |
| 121 | critical_section::with(|_| { | 127 | reg.set_en(ch as usize, true); |
| 122 | #[cfg(rcc_h7)] | 128 | } |
| 123 | enable!(apb1lenr, set_dac12en, apb1lrstr, set_dac12rst); | ||
| 124 | #[cfg(rcc_h7ab)] | ||
| 125 | enable!(apb1lenr, set_dac1en, apb1lrstr, set_dac1rst); | ||
| 126 | #[cfg(stm32g0)] | ||
| 127 | enable!(apbenr1, set_dac1en, apbrstr1, set_dac1rst); | ||
| 128 | #[cfg(any(stm32l4, stm32l5))] | ||
| 129 | enable!(apb1enr1, set_dac1en, apb1rstr1, set_dac1rst); | ||
| 130 | }); | 129 | }); |
| 131 | |||
| 132 | if channels >= 1 { | ||
| 133 | T::regs().cr().modify(|reg| { | ||
| 134 | reg.set_en1(true); | ||
| 135 | }); | ||
| 136 | } | ||
| 137 | |||
| 138 | if channels >= 2 { | ||
| 139 | T::regs().cr().modify(|reg| { | ||
| 140 | reg.set_en2(true); | ||
| 141 | }); | ||
| 142 | } | ||
| 143 | } | 130 | } |
| 144 | 131 | ||
| 145 | Self { channels, _peri: peri } | 132 | Self { channels, _peri: peri } |
| @@ -156,17 +143,10 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 156 | 143 | ||
| 157 | fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { | 144 | fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { |
| 158 | self.check_channel_exists(ch)?; | 145 | self.check_channel_exists(ch)?; |
| 159 | match ch { | 146 | unsafe { |
| 160 | Channel::Ch1 => unsafe { | 147 | T::regs().cr().modify(|reg| { |
| 161 | T::regs().cr().modify(|reg| { | 148 | reg.set_en(ch.index(), on); |
| 162 | reg.set_en1(on); | 149 | }) |
| 163 | }) | ||
| 164 | }, | ||
| 165 | Channel::Ch2 => unsafe { | ||
| 166 | T::regs().cr().modify(|reg| { | ||
| 167 | reg.set_en2(on); | ||
| 168 | }); | ||
| 169 | }, | ||
| 170 | } | 150 | } |
| 171 | Ok(()) | 151 | Ok(()) |
| 172 | } | 152 | } |
| @@ -203,17 +183,10 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 203 | 183 | ||
| 204 | pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { | 184 | pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { |
| 205 | self.check_channel_exists(ch)?; | 185 | self.check_channel_exists(ch)?; |
| 206 | match ch { | 186 | unsafe { |
| 207 | Channel::Ch1 => unsafe { | 187 | T::regs().swtrigr().write(|reg| { |
| 208 | T::regs().swtrigr().write(|reg| { | 188 | reg.set_swtrig(ch.index(), true); |
| 209 | reg.set_swtrig1(true); | 189 | }); |
| 210 | }); | ||
| 211 | }, | ||
| 212 | Channel::Ch2 => unsafe { | ||
| 213 | T::regs().swtrigr().write(|reg| { | ||
| 214 | reg.set_swtrig2(true); | ||
| 215 | }) | ||
| 216 | }, | ||
| 217 | } | 190 | } |
| 218 | Ok(()) | 191 | Ok(()) |
| 219 | } | 192 | } |
| @@ -221,38 +194,85 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 221 | pub fn trigger_all(&mut self) { | 194 | pub fn trigger_all(&mut self) { |
| 222 | unsafe { | 195 | unsafe { |
| 223 | T::regs().swtrigr().write(|reg| { | 196 | T::regs().swtrigr().write(|reg| { |
| 224 | reg.set_swtrig1(true); | 197 | reg.set_swtrig(Channel::Ch1.index(), true); |
| 225 | reg.set_swtrig2(true); | 198 | reg.set_swtrig(Channel::Ch2.index(), true); |
| 226 | }) | 199 | }) |
| 227 | } | 200 | } |
| 228 | } | 201 | } |
| 229 | 202 | ||
| 230 | pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { | 203 | pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { |
| 231 | self.check_channel_exists(ch)?; | 204 | self.check_channel_exists(ch)?; |
| 232 | match ch { | 205 | match value { |
| 233 | Channel::Ch1 => match value { | 206 | Value::Bit8(v) => unsafe { |
| 234 | Value::Bit8(v) => unsafe { | 207 | T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)); |
| 235 | T::regs().dhr8r1().write(|reg| reg.set_dacc1dhr(v)); | 208 | }, |
| 236 | }, | 209 | Value::Bit12(v, Alignment::Left) => unsafe { |
| 237 | Value::Bit12(v, Alignment::Left) => unsafe { | 210 | T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)); |
| 238 | T::regs().dhr12l1().write(|reg| reg.set_dacc1dhr(v)); | ||
| 239 | }, | ||
| 240 | Value::Bit12(v, Alignment::Right) => unsafe { | ||
| 241 | T::regs().dhr12r1().write(|reg| reg.set_dacc1dhr(v)); | ||
| 242 | }, | ||
| 243 | }, | 211 | }, |
| 244 | Channel::Ch2 => match value { | 212 | Value::Bit12(v, Alignment::Right) => unsafe { |
| 245 | Value::Bit8(v) => unsafe { | 213 | T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)); |
| 246 | T::regs().dhr8r2().write(|reg| reg.set_dacc2dhr(v)); | ||
| 247 | }, | ||
| 248 | Value::Bit12(v, Alignment::Left) => unsafe { | ||
| 249 | T::regs().dhr12l2().write(|reg| reg.set_dacc2dhr(v)); | ||
| 250 | }, | ||
| 251 | Value::Bit12(v, Alignment::Right) => unsafe { | ||
| 252 | T::regs().dhr12r2().write(|reg| reg.set_dacc2dhr(v)); | ||
| 253 | }, | ||
| 254 | }, | 214 | }, |
| 255 | } | 215 | } |
| 256 | Ok(()) | 216 | Ok(()) |
| 257 | } | 217 | } |
| 258 | } | 218 | } |
| 219 | |||
| 220 | pub(crate) mod sealed { | ||
| 221 | pub trait Instance { | ||
| 222 | fn regs() -> &'static crate::pac::dac::Dac; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | ||
| 227 | |||
| 228 | pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} | ||
| 229 | |||
| 230 | foreach_peripheral!( | ||
| 231 | (dac, $inst:ident) => { | ||
| 232 | // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented | ||
| 233 | #[cfg(rcc_h7)] | ||
| 234 | impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { | ||
| 235 | fn frequency() -> crate::time::Hertz { | ||
| 236 | critical_section::with(|_| unsafe { | ||
| 237 | crate::rcc::get_freqs().apb1 | ||
| 238 | }) | ||
| 239 | } | ||
| 240 | |||
| 241 | fn reset() { | ||
| 242 | critical_section::with(|_| unsafe { | ||
| 243 | crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); | ||
| 244 | crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); | ||
| 245 | }) | ||
| 246 | } | ||
| 247 | |||
| 248 | fn enable() { | ||
| 249 | critical_section::with(|_| unsafe { | ||
| 250 | crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); | ||
| 251 | }) | ||
| 252 | } | ||
| 253 | |||
| 254 | fn disable() { | ||
| 255 | critical_section::with(|_| unsafe { | ||
| 256 | crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)); | ||
| 257 | }) | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | #[cfg(rcc_h7)] | ||
| 262 | impl crate::rcc::RccPeripheral for peripherals::$inst {} | ||
| 263 | |||
| 264 | impl crate::dac::sealed::Instance for peripherals::$inst { | ||
| 265 | fn regs() -> &'static crate::pac::dac::Dac { | ||
| 266 | &crate::pac::$inst | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | impl crate::dac::Instance for peripherals::$inst {} | ||
| 271 | }; | ||
| 272 | ); | ||
| 273 | |||
| 274 | macro_rules! impl_dac_pin { | ||
| 275 | ($inst:ident, $pin:ident, $ch:expr) => { | ||
| 276 | impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {} | ||
| 277 | }; | ||
| 278 | } | ||
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs deleted file mode 100644 index f1cb452c7..000000000 --- a/embassy-stm32/src/dac/mod.rs +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | #[cfg_attr(dac_v1, path = "v1.rs")] | ||
| 4 | #[cfg_attr(dac_v2, path = "v2.rs")] | ||
| 5 | mod _version; | ||
| 6 | pub use _version::*; | ||
| 7 | |||
| 8 | use crate::peripherals; | ||
| 9 | |||
| 10 | pub(crate) mod sealed { | ||
| 11 | pub trait Instance { | ||
| 12 | fn regs() -> &'static crate::pac::dac::Dac; | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | pub trait Instance: sealed::Instance + 'static {} | ||
| 17 | |||
| 18 | pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} | ||
| 19 | |||
| 20 | foreach_peripheral!( | ||
| 21 | (dac, $inst:ident) => { | ||
| 22 | impl crate::dac::sealed::Instance for peripherals::$inst { | ||
| 23 | fn regs() -> &'static crate::pac::dac::Dac { | ||
| 24 | &crate::pac::$inst | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | impl crate::dac::Instance for peripherals::$inst {} | ||
| 29 | }; | ||
| 30 | ); | ||
| 31 | |||
| 32 | macro_rules! impl_dac_pin { | ||
| 33 | ($inst:ident, $pin:ident, $ch:expr) => { | ||
| 34 | impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {} | ||
| 35 | }; | ||
| 36 | } | ||
diff --git a/embassy-stm32/src/dac/v1.rs b/embassy-stm32/src/dac/v1.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/dac/v1.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 37464b1e0..3c58320dd 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml | |||
| @@ -21,6 +21,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa | |||
| 21 | heapless = { version = "0.7.5", default-features = false } | 21 | heapless = { version = "0.7.5", default-features = false } |
| 22 | nb = "1.0.0" | 22 | nb = "1.0.0" |
| 23 | embedded-storage = "0.3.0" | 23 | embedded-storage = "0.3.0" |
| 24 | micromath = "2.0.0" | ||
| 24 | 25 | ||
| 25 | usb-device = "0.2" | 26 | usb-device = "0.2" |
| 26 | usbd-serial = "0.1.1" | 27 | usbd-serial = "0.1.1" |
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs new file mode 100644 index 000000000..392f5bf4d --- /dev/null +++ b/examples/stm32f4/src/bin/dac.rs | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::executor::Spawner; | ||
| 7 | use embassy_stm32::dac::{Channel, Dac, Value}; | ||
| 8 | use embassy_stm32::Peripherals; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner, p: Peripherals) -> ! { | ||
| 13 | info!("Hello World, dude!"); | ||
| 14 | |||
| 15 | let mut dac = Dac::new_1ch(p.DAC, p.PA4); | ||
| 16 | |||
| 17 | loop { | ||
| 18 | for v in 0..=255 { | ||
| 19 | unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); | ||
| 20 | unwrap!(dac.trigger(Channel::Ch1)); | ||
| 21 | } | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | use micromath::F32Ext; | ||
| 26 | |||
| 27 | fn to_sine_wave(v: u8) -> u8 { | ||
| 28 | if v >= 128 { | ||
| 29 | // top half | ||
| 30 | let r = 3.14 * ((v - 128) as f32 / 128.0); | ||
| 31 | (r.sin() * 128.0 + 127.0) as u8 | ||
| 32 | } else { | ||
| 33 | // bottom half | ||
| 34 | let r = 3.14 + 3.14 * (v as f32 / 128.0); | ||
| 35 | (r.sin() * 128.0 + 127.0) as u8 | ||
| 36 | } | ||
| 37 | } | ||
diff --git a/stm32-data b/stm32-data | |||
| Subproject b13ba26f6f9b7049097e39ccc7e5e246ac023d1 | Subproject 758c9e74625c68bc23d66ced8bfeb5643c63cec | ||
