diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac.rs similarity index 61% rename from embassy-stm32/src/dac/v2.rs rename to 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 @@ +#![macro_use] + use embassy_hal_common::{into_ref, PeripheralRef}; -use crate::dac::{DacPin, Instance}; use crate::pac::dac; -use crate::Peripheral; +use crate::rcc::RccPeripheral; +use crate::{peripherals, Peripheral}; #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -18,6 +20,15 @@ pub enum Channel { Ch2, } +impl Channel { + fn index(&self) -> usize { + match self { + Channel::Ch1 => 0, + Channel::Ch2 => 1, + } + } +} + #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Ch1Trigger { @@ -91,14 +102,6 @@ pub struct Dac<'d, T: Instance> { _peri: PeripheralRef<'d, T>, } -macro_rules! enable { - ($enable_reg:ident, $enable_field:ident, $reset_reg:ident, $reset_field:ident) => { - crate::pac::RCC.$enable_reg().modify(|w| w.$enable_field(true)); - crate::pac::RCC.$reset_reg().modify(|w| w.$reset_field(true)); - crate::pac::RCC.$reset_reg().modify(|w| w.$reset_field(false)); - }; -} - impl<'d, T: Instance> Dac<'d, T> { pub fn new_1ch(peri: impl Peripheral

+ 'd, _ch1: impl Peripheral

> + 'd) -> Self { into_ref!(peri); @@ -115,31 +118,15 @@ impl<'d, T: Instance> Dac<'d, T> { } fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self { + T::enable(); + T::reset(); + unsafe { - // Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock - // configuration. - critical_section::with(|_| { - #[cfg(rcc_h7)] - enable!(apb1lenr, set_dac12en, apb1lrstr, set_dac12rst); - #[cfg(rcc_h7ab)] - enable!(apb1lenr, set_dac1en, apb1lrstr, set_dac1rst); - #[cfg(stm32g0)] - enable!(apbenr1, set_dac1en, apbrstr1, set_dac1rst); - #[cfg(any(stm32l4, stm32l5))] - enable!(apb1enr1, set_dac1en, apb1rstr1, set_dac1rst); + T::regs().cr().modify(|reg| { + for ch in 0..channels { + reg.set_en(ch as usize, true); + } }); - - if channels >= 1 { - T::regs().cr().modify(|reg| { - reg.set_en1(true); - }); - } - - if channels >= 2 { - T::regs().cr().modify(|reg| { - reg.set_en2(true); - }); - } } Self { channels, _peri: peri } @@ -156,17 +143,10 @@ impl<'d, T: Instance> Dac<'d, T> { fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { self.check_channel_exists(ch)?; - match ch { - Channel::Ch1 => unsafe { - T::regs().cr().modify(|reg| { - reg.set_en1(on); - }) - }, - Channel::Ch2 => unsafe { - T::regs().cr().modify(|reg| { - reg.set_en2(on); - }); - }, + unsafe { + T::regs().cr().modify(|reg| { + reg.set_en(ch.index(), on); + }) } Ok(()) } @@ -203,17 +183,10 @@ impl<'d, T: Instance> Dac<'d, T> { pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { self.check_channel_exists(ch)?; - match ch { - Channel::Ch1 => unsafe { - T::regs().swtrigr().write(|reg| { - reg.set_swtrig1(true); - }); - }, - Channel::Ch2 => unsafe { - T::regs().swtrigr().write(|reg| { - reg.set_swtrig2(true); - }) - }, + unsafe { + T::regs().swtrigr().write(|reg| { + reg.set_swtrig(ch.index(), true); + }); } Ok(()) } @@ -221,38 +194,85 @@ impl<'d, T: Instance> Dac<'d, T> { pub fn trigger_all(&mut self) { unsafe { T::regs().swtrigr().write(|reg| { - reg.set_swtrig1(true); - reg.set_swtrig2(true); + reg.set_swtrig(Channel::Ch1.index(), true); + reg.set_swtrig(Channel::Ch2.index(), true); }) } } pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { self.check_channel_exists(ch)?; - match ch { - Channel::Ch1 => match value { - Value::Bit8(v) => unsafe { - T::regs().dhr8r1().write(|reg| reg.set_dacc1dhr(v)); - }, - Value::Bit12(v, Alignment::Left) => unsafe { - T::regs().dhr12l1().write(|reg| reg.set_dacc1dhr(v)); - }, - Value::Bit12(v, Alignment::Right) => unsafe { - T::regs().dhr12r1().write(|reg| reg.set_dacc1dhr(v)); - }, + match value { + Value::Bit8(v) => unsafe { + T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)); }, - Channel::Ch2 => match value { - Value::Bit8(v) => unsafe { - T::regs().dhr8r2().write(|reg| reg.set_dacc2dhr(v)); - }, - Value::Bit12(v, Alignment::Left) => unsafe { - T::regs().dhr12l2().write(|reg| reg.set_dacc2dhr(v)); - }, - Value::Bit12(v, Alignment::Right) => unsafe { - T::regs().dhr12r2().write(|reg| reg.set_dacc2dhr(v)); - }, + Value::Bit12(v, Alignment::Left) => unsafe { + T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)); + }, + Value::Bit12(v, Alignment::Right) => unsafe { + T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)); }, } Ok(()) } } + +pub(crate) mod sealed { + pub trait Instance { + fn regs() -> &'static crate::pac::dac::Dac; + } +} + +pub trait Instance: sealed::Instance + RccPeripheral + 'static {} + +pub trait DacPin: crate::gpio::Pin + 'static {} + +foreach_peripheral!( + (dac, $inst:ident) => { + // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented + #[cfg(rcc_h7)] + impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { + fn frequency() -> crate::time::Hertz { + critical_section::with(|_| unsafe { + crate::rcc::get_freqs().apb1 + }) + } + + fn reset() { + critical_section::with(|_| unsafe { + crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); + crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); + }) + } + + fn enable() { + critical_section::with(|_| unsafe { + crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); + }) + } + + fn disable() { + critical_section::with(|_| unsafe { + crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)); + }) + } + } + + #[cfg(rcc_h7)] + impl crate::rcc::RccPeripheral for peripherals::$inst {} + + impl crate::dac::sealed::Instance for peripherals::$inst { + fn regs() -> &'static crate::pac::dac::Dac { + &crate::pac::$inst + } + } + + impl crate::dac::Instance for peripherals::$inst {} + }; +); + +macro_rules! impl_dac_pin { + ($inst:ident, $pin:ident, $ch:expr) => { + impl crate::dac::DacPin for crate::peripherals::$pin {} + }; +} 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 @@ -#![macro_use] - -#[cfg_attr(dac_v1, path = "v1.rs")] -#[cfg_attr(dac_v2, path = "v2.rs")] -mod _version; -pub use _version::*; - -use crate::peripherals; - -pub(crate) mod sealed { - pub trait Instance { - fn regs() -> &'static crate::pac::dac::Dac; - } -} - -pub trait Instance: sealed::Instance + 'static {} - -pub trait DacPin: crate::gpio::Pin + 'static {} - -foreach_peripheral!( - (dac, $inst:ident) => { - impl crate::dac::sealed::Instance for peripherals::$inst { - fn regs() -> &'static crate::pac::dac::Dac { - &crate::pac::$inst - } - } - - impl crate::dac::Instance for peripherals::$inst {} - }; -); - -macro_rules! impl_dac_pin { - ($inst:ident, $pin:ident, $ch:expr) => { - impl crate::dac::DacPin for crate::peripherals::$pin {} - }; -} 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 @@ - 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 heapless = { version = "0.7.5", default-features = false } nb = "1.0.0" embedded-storage = "0.3.0" +micromath = "2.0.0" usb-device = "0.2" 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 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::executor::Spawner; +use embassy_stm32::dac::{Channel, Dac, Value}; +use embassy_stm32::Peripherals; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner, p: Peripherals) -> ! { + info!("Hello World, dude!"); + + let mut dac = Dac::new_1ch(p.DAC, p.PA4); + + loop { + for v in 0..=255 { + unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); + unwrap!(dac.trigger(Channel::Ch1)); + } + } +} + +use micromath::F32Ext; + +fn to_sine_wave(v: u8) -> u8 { + if v >= 128 { + // top half + let r = 3.14 * ((v - 128) as f32 / 128.0); + (r.sin() * 128.0 + 127.0) as u8 + } else { + // bottom half + let r = 3.14 + 3.14 * (v as f32 / 128.0); + (r.sin() * 128.0 + 127.0) as u8 + } +} diff --git a/stm32-data b/stm32-data index b13ba26f6..758c9e746 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit b13ba26f6f9b7049097e39ccc7e5e246ac023d15 +Subproject commit 758c9e74625c68bc23d66ced8bfeb5643c63cec9