diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-08-08 11:37:41 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-08-08 11:37:41 +0000 |
| commit | b7b4c84067e0e85fa641a540458438297176f2e4 (patch) | |
| tree | 73a659ae11498729a252cddc4e48b57e4ed6176a | |
| parent | b400e6aa75f8b629a948c891447e2aab49f57a42 (diff) | |
| parent | ed74bcb8d8b3414dc041ee0cbdf544a6604a5f25 (diff) | |
Merge #892
892: Merge v1, v2 DAC and update register definitions r=Dirbaio a=chemicstry
This merges v1 (unimplemented) and v2 DAC implementations, because they share most of the code except for some exotic stuff, which is not yet implemented for neither of the versions. This should allow using DAC on all chips that have v1 peripheral.
~Currently blocked on https://github.com/embassy-rs/stm32-data/pull/153~
Co-authored-by: chemicstry <[email protected]>
| -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 | ||
