diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index a54c40833..1acb0a9ae 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -3,27 +3,21 @@ #[cfg_attr(dac_v1, path = "v1.rs")] #[cfg_attr(dac_v2, path = "v2.rs")] mod _version; -use crate::gpio::NoPin; use crate::peripherals; pub use _version::*; pub(crate) mod sealed { - use crate::gpio::OptionalPin; - pub trait Instance { fn regs() -> &'static crate::pac::dac::Dac; } - pub trait DacPin: OptionalPin {} + pub trait DacPin: crate::gpio::Pin {} } pub trait Instance: sealed::Instance + 'static {} pub trait DacPin: sealed::DacPin + 'static {} -impl DacPin for NoPin {} -impl sealed::DacPin for NoPin {} - crate::pac::peripherals!( (dac, $inst:ident) => { impl crate::dac::sealed::Instance for peripherals::$inst { diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac/v2.rs index 49da48e88..751eebf79 100644 --- a/embassy-stm32/src/dac/v2.rs +++ b/embassy-stm32/src/dac/v2.rs @@ -1,33 +1,25 @@ use crate::dac::{DacPin, Instance}; -use crate::gpio::AnyPin; use crate::pac::dac; use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_hal_common::unborrow; -/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock -/// configuration. -unsafe fn enable() { - #[cfg(rcc_h7)] - crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); - #[cfg(rcc_g0)] - crate::pac::RCC.apbenr1().modify(|w| w.set_dac1en(true)); - #[cfg(rcc_l4)] - crate::pac::RCC.apb1enr1().modify(|w| w.set_dac1en(true)); -} - -#[derive(Debug)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { UnconfiguredChannel, InvalidValue, } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Channel { Ch1, Ch2, } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Ch1Trigger { Tim6, Tim3, @@ -52,6 +44,8 @@ impl Ch1Trigger { } } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Ch2Trigger { Tim6, Tim8, @@ -78,46 +72,61 @@ impl Ch2Trigger { } } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Alignment { Left, Right, } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Value { Bit8(u8), Bit12(u16, Alignment), } pub struct Dac<'d, T: Instance> { - ch1: Option, - ch2: Option, + channels: u8, phantom: PhantomData<&'d mut T>, } impl<'d, T: Instance> Dac<'d, T> { - pub fn new( - _peri: impl Unborrow + 'd, - ch1: impl Unborrow>, - ch2: impl Unborrow>, + pub fn new_1ch( + peri: impl Unborrow + 'd, + _ch1: impl Unborrow> + 'd, ) -> Self { - unborrow!(ch1, ch2); + unborrow!(peri); + Self::new_inner(peri, 1) + } + pub fn new_2ch( + peri: impl Unborrow + 'd, + _ch1: impl Unborrow> + 'd, + _ch2: impl Unborrow> + 'd, + ) -> Self { + unborrow!(peri); + Self::new_inner(peri, 2) + } + + fn new_inner(_peri: T, channels: u8) -> Self { unsafe { - enable(); - } + // Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock + // configuration. + #[cfg(rcc_h7)] + crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); + #[cfg(rcc_g0)] + crate::pac::RCC.apbenr1().modify(|w| w.set_dac1en(true)); + #[cfg(rcc_l4)] + crate::pac::RCC.apb1enr1().modify(|w| w.set_dac1en(true)); - let ch1 = ch1.degrade_optional(); - if ch1.is_some() { - unsafe { + if channels >= 1 { T::regs().cr().modify(|reg| { reg.set_en1(true); }); } - } - let ch2 = ch2.degrade_optional(); - if ch2.is_some() { - unsafe { + if channels >= 2 { T::regs().cr().modify(|reg| { reg.set_en2(true); }); @@ -125,41 +134,37 @@ impl<'d, T: Instance> Dac<'d, T> { } Self { - ch1, - ch2, + channels, phantom: PhantomData, } } - fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { - match ch { - Channel::Ch1 => { - if self.ch1.is_none() { - Err(Error::UnconfiguredChannel) - } else { - unsafe { - T::regs().cr().modify(|reg| { - reg.set_en1(on); - }); - } - Ok(()) - } - } - Channel::Ch2 => { - if self.ch2.is_none() { - Err(Error::UnconfiguredChannel) - } else { - unsafe { - T::regs().cr().modify(|reg| { - reg.set_en2(on); - }); - } - Ok(()) - } - } + /// Check the channel is configured + fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> { + if ch == Channel::Ch2 && self.channels < 2 { + Err(Error::UnconfiguredChannel) + } else { + Ok(()) } } + 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); + }); + }, + } + Ok(()) + } + pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> { self.set_channel_enable(ch, true) } @@ -169,9 +174,7 @@ impl<'d, T: Instance> Dac<'d, T> { } pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { - if self.ch1.is_none() { - return Err(Error::UnconfiguredChannel); - } + self.check_channel_exists(Channel::Ch1)?; unwrap!(self.disable_channel(Channel::Ch1)); unsafe { T::regs().cr().modify(|reg| { @@ -182,9 +185,7 @@ impl<'d, T: Instance> Dac<'d, T> { } pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { - if self.ch2.is_none() { - return Err(Error::UnconfiguredChannel); - } + self.check_channel_exists(Channel::Ch2)?; unwrap!(self.disable_channel(Channel::Ch2)); unsafe { T::regs().cr().modify(|reg| { @@ -195,32 +196,20 @@ 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 => { - if self.ch1.is_none() { - Err(Error::UnconfiguredChannel) - } else { - unsafe { - T::regs().swtrigr().write(|reg| { - reg.set_swtrig1(true); - }); - } - Ok(()) - } - } - Channel::Ch2 => { - if self.ch2.is_none() { - Err(Error::UnconfiguredChannel) - } else { - unsafe { - T::regs().swtrigr().write(|reg| { - reg.set_swtrig2(true); - }); - } - Ok(()) - } - } + Channel::Ch1 => unsafe { + T::regs().swtrigr().write(|reg| { + reg.set_swtrig1(true); + }); + }, + Channel::Ch2 => unsafe { + T::regs().swtrigr().write(|reg| { + reg.set_swtrig2(true); + }) + }, } + Ok(()) } pub fn trigger_all(&mut self) { @@ -233,43 +222,31 @@ impl<'d, T: Instance> Dac<'d, T> { } pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { + self.check_channel_exists(Channel::Ch2)?; match ch { - Channel::Ch1 => { - if self.ch1.is_none() { - Err(Error::UnconfiguredChannel) - } else { - 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)); - }, - } - Ok(()) - } - } - Channel::Ch2 => { - if self.ch2.is_none() { - Err(Error::UnconfiguredChannel) - } else { - 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)); - }, - } - Ok(()) - } - } + 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)); + }, + }, + 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)); + }, + }, } + Ok(()) } } diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 315aa363c..cbfa5f098 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -9,6 +9,15 @@ use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unborrow; use futures::future::poll_fn; +#[macro_export] +macro_rules! configure { + ($($name:ident),*) => { + $( + unsafe { $name.unborrow() }.configure(); + )* + } +} + /// The level on the VSync pin when the data is not valid on the parallel interface. #[derive(Clone, Copy, PartialEq)] pub enum VSyncDataInvalidLevel { @@ -50,6 +59,23 @@ pub enum Error { PeripheralError, } +#[non_exhaustive] +pub struct Config { + pub vsync_level: VSyncDataInvalidLevel, + pub hsync_level: HSyncDataInvalidLevel, + pub pixclk_polarity: PixelClockPolarity, +} + +impl Default for Config { + fn default() -> Self { + Self { + vsync_level: VSyncDataInvalidLevel::High, + hsync_level: HSyncDataInvalidLevel::Low, + pixclk_polarity: PixelClockPolarity::RisingEdge, + } + } +} + pub struct Dcmi<'d, T: Instance, Dma: FrameDma> { inner: T, dma: Dma, @@ -61,13 +87,85 @@ where T: Instance, Dma: FrameDma, { - pub fn new( + pub fn new_8bit( + peri: impl Unborrow + 'd, + dma: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + d0: impl Unborrow + 'd, + d1: impl Unborrow + 'd, + d2: impl Unborrow + 'd, + d3: impl Unborrow + 'd, + d4: impl Unborrow + 'd, + d5: impl Unborrow + 'd, + d6: impl Unborrow + 'd, + d7: impl Unborrow + 'd, + v_sync: impl Unborrow + 'd, + h_sync: impl Unborrow + 'd, + pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7); + configure!(v_sync, h_sync, pixclk); + + Self::new_inner(peri, dma, irq, config, false, 0b00) + } + pub fn new_10bit( + peri: impl Unborrow + 'd, + dma: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + d0: impl Unborrow + 'd, + d1: impl Unborrow + 'd, + d2: impl Unborrow + 'd, + d3: impl Unborrow + 'd, + d4: impl Unborrow + 'd, + d5: impl Unborrow + 'd, + d6: impl Unborrow + 'd, + d7: impl Unborrow + 'd, + d8: impl Unborrow + 'd, + d9: impl Unborrow + 'd, + v_sync: impl Unborrow + 'd, + h_sync: impl Unborrow + 'd, + pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); + configure!(v_sync, h_sync, pixclk); + + Self::new_inner(peri, dma, irq, config, false, 0b01) + } + + pub fn new_12bit( + peri: impl Unborrow + 'd, + dma: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + d0: impl Unborrow + 'd, + d1: impl Unborrow + 'd, + d2: impl Unborrow + 'd, + d3: impl Unborrow + 'd, + d4: impl Unborrow + 'd, + d5: impl Unborrow + 'd, + d6: impl Unborrow + 'd, + d7: impl Unborrow + 'd, + d8: impl Unborrow + 'd, + d9: impl Unborrow + 'd, + d10: impl Unborrow + 'd, + d11: impl Unborrow + 'd, + v_sync: impl Unborrow + 'd, + h_sync: impl Unborrow + 'd, + pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); + configure!(v_sync, h_sync, pixclk); + + Self::new_inner(peri, dma, irq, config, false, 0b10) + } + pub fn new_14bit( peri: impl Unborrow + 'd, dma: impl Unborrow + 'd, - vsync_level: VSyncDataInvalidLevel, - hsync_level: HSyncDataInvalidLevel, - pixclk_polarity: PixelClockPolarity, - use_embedded_synchronization: bool, irq: impl Unborrow + 'd, d0: impl Unborrow + 'd, d1: impl Unborrow + 'd, @@ -86,58 +184,132 @@ where v_sync: impl Unborrow + 'd, h_sync: impl Unborrow + 'd, pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); + configure!(v_sync, h_sync, pixclk); + + Self::new_inner(peri, dma, irq, config, false, 0b11) + } + + pub fn new_es_8bit( + peri: impl Unborrow + 'd, + dma: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + d0: impl Unborrow + 'd, + d1: impl Unborrow + 'd, + d2: impl Unborrow + 'd, + d3: impl Unborrow + 'd, + d4: impl Unborrow + 'd, + d5: impl Unborrow + 'd, + d6: impl Unborrow + 'd, + d7: impl Unborrow + 'd, + pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7); + configure!(pixclk); + + Self::new_inner(peri, dma, irq, config, true, 0b00) + } + + pub fn new_es_10bit( + peri: impl Unborrow + 'd, + dma: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + d0: impl Unborrow + 'd, + d1: impl Unborrow + 'd, + d2: impl Unborrow + 'd, + d3: impl Unborrow + 'd, + d4: impl Unborrow + 'd, + d5: impl Unborrow + 'd, + d6: impl Unborrow + 'd, + d7: impl Unborrow + 'd, + d8: impl Unborrow + 'd, + d9: impl Unborrow + 'd, + pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); + configure!(pixclk); + + Self::new_inner(peri, dma, irq, config, true, 0b01) + } + + pub fn new_es_12bit( + peri: impl Unborrow + 'd, + dma: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + d0: impl Unborrow + 'd, + d1: impl Unborrow + 'd, + d2: impl Unborrow + 'd, + d3: impl Unborrow + 'd, + d4: impl Unborrow + 'd, + d5: impl Unborrow + 'd, + d6: impl Unborrow + 'd, + d7: impl Unborrow + 'd, + d8: impl Unborrow + 'd, + d9: impl Unborrow + 'd, + d10: impl Unborrow + 'd, + d11: impl Unborrow + 'd, + pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); + configure!(pixclk); + + Self::new_inner(peri, dma, irq, config, true, 0b10) + } + pub fn new_es_14bit( + peri: impl Unborrow + 'd, + dma: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + d0: impl Unborrow + 'd, + d1: impl Unborrow + 'd, + d2: impl Unborrow + 'd, + d3: impl Unborrow + 'd, + d4: impl Unborrow + 'd, + d5: impl Unborrow + 'd, + d6: impl Unborrow + 'd, + d7: impl Unborrow + 'd, + d8: impl Unborrow + 'd, + d9: impl Unborrow + 'd, + d10: impl Unborrow + 'd, + d11: impl Unborrow + 'd, + d12: impl Unborrow + 'd, + d13: impl Unborrow + 'd, + pixclk: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(peri, dma, irq); + configure!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); + configure!(pixclk); + + Self::new_inner(peri, dma, irq, config, true, 0b11) + } + + fn new_inner( + peri: T, + dma: Dma, + irq: T::Interrupt, + config: Config, + use_embedded_synchronization: bool, + edm: u8, ) -> Self { T::reset(); T::enable(); - unborrow!( - peri, dma, irq, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, v_sync, - h_sync, pixclk - ); - - d0.configure(); - d1.configure(); - d2.configure(); - d3.configure(); - d4.configure(); - d5.configure(); - d6.configure(); - d7.configure(); - d8.configure(); - d9.configure(); - d10.configure(); - d11.configure(); - d12.configure(); - d13.configure(); - - v_sync.configure(); - h_sync.configure(); - pixclk.configure(); - - let edm = match ( - d8.pin().is_some(), - d9.pin().is_some(), - d10.pin().is_some(), - d11.pin().is_some(), - d12.pin().is_some(), - d13.pin().is_some(), - ) { - (true, true, true, true, true, true) => 0b11, // 14 bits - (true, true, true, true, false, false) => 0b10, // 12 bits - (true, true, false, false, false, false) => 0b01, // 10 bits - (false, false, false, false, false, false) => 0b00, // 8 bits - _ => { - panic!("Invalid pin configuration."); - } - }; - unsafe { peri.regs().cr().modify(|r| { r.set_cm(true); // disable continuous mode (snapshot mode) r.set_ess(use_embedded_synchronization); - r.set_pckpol(pixclk_polarity == PixelClockPolarity::RisingEdge); - r.set_vspol(vsync_level == VSyncDataInvalidLevel::High); - r.set_hspol(hsync_level == HSyncDataInvalidLevel::High); + r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge); + r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High); + r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High); r.set_fcrc(0x00); // capture every frame r.set_edm(edm); // extended data mode }); @@ -271,14 +443,6 @@ mod sealed { }; } - macro_rules! optional_pin { - ($name:ident) => { - pub trait $name: crate::gpio::OptionalPin { - fn configure(&mut self); - } - }; - } - pin!(D0Pin); pin!(D1Pin); pin!(D2Pin); @@ -287,15 +451,15 @@ mod sealed { pin!(D5Pin); pin!(D6Pin); pin!(D7Pin); - optional_pin!(D8Pin); - optional_pin!(D9Pin); - optional_pin!(D10Pin); - optional_pin!(D11Pin); - optional_pin!(D12Pin); - optional_pin!(D13Pin); + pin!(D8Pin); + pin!(D9Pin); + pin!(D10Pin); + pin!(D11Pin); + pin!(D12Pin); + pin!(D13Pin); - optional_pin!(HSyncPin); - optional_pin!(VSyncPin); + pin!(HSyncPin); + pin!(VSyncPin); pin!(PixClkPin); } @@ -408,24 +572,6 @@ macro_rules! impl_pin { }; } -macro_rules! impl_no_pin { - ($signal:ident) => { - impl sealed::$signal for crate::gpio::NoPin { - fn configure(&mut self) {} - } - impl $signal for crate::gpio::NoPin {} - }; -} - -impl_no_pin!(D8Pin); -impl_no_pin!(D9Pin); -impl_no_pin!(D10Pin); -impl_no_pin!(D11Pin); -impl_no_pin!(D12Pin); -impl_no_pin!(D13Pin); -impl_no_pin!(HSyncPin); -impl_no_pin!(VSyncPin); - crate::pac::peripheral_pins!( ($inst:ident, dcmi, DCMI, $pin:ident, D0, $af:expr) => { impl_pin!($pin, D0Pin, $af); diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index f154a66c4..175abbd27 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -544,54 +544,6 @@ impl sealed::Pin for AnyPin { // ==================== -pub trait OptionalPin: sealed::OptionalPin + Sized { - type Pin: Pin; - fn pin(&self) -> Option<&Self::Pin>; - fn pin_mut(&mut self) -> Option<&mut Self::Pin>; - - /// Convert from concrete pin type PX_XX to type erased `Option`. - #[inline] - fn degrade_optional(mut self) -> Option { - self.pin_mut() - .map(|pin| unsafe { core::ptr::read(pin) }.degrade()) - } -} - -impl sealed::OptionalPin for T {} -impl OptionalPin for T { - type Pin = T; - - #[inline] - fn pin(&self) -> Option<&T> { - Some(self) - } - - #[inline] - fn pin_mut(&mut self) -> Option<&mut T> { - Some(self) - } -} - -#[derive(Clone, Copy, Debug)] -pub struct NoPin; -unsafe_impl_unborrow!(NoPin); -impl sealed::OptionalPin for NoPin {} -impl OptionalPin for NoPin { - type Pin = AnyPin; - - #[inline] - fn pin(&self) -> Option<&AnyPin> { - None - } - - #[inline] - fn pin_mut(&mut self) -> Option<&mut AnyPin> { - None - } -} - -// ==================== - crate::pac::pins!( ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { impl Pin for peripherals::$pin_name { diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 1cb191a95..17a7cbd0a 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -248,31 +248,6 @@ crate::pac::interrupts! { }; } -#[allow(unused)] -macro_rules! impl_pwm_nopin { - ($inst:ident) => { - impl_no_pin!($inst, Channel1Pin); - impl_no_pin!($inst, Channel1ComplementaryPin); - impl_no_pin!($inst, Channel2Pin); - impl_no_pin!($inst, Channel2ComplementaryPin); - impl_no_pin!($inst, Channel3Pin); - impl_no_pin!($inst, Channel3ComplementaryPin); - impl_no_pin!($inst, Channel4Pin); - impl_no_pin!($inst, Channel4ComplementaryPin); - impl_no_pin!($inst, ExternalTriggerPin); - impl_no_pin!($inst, BreakInputPin); - impl_no_pin!($inst, BreakInputComparator1Pin); - impl_no_pin!($inst, BreakInputComparator2Pin); - impl_no_pin!($inst, BreakInput2Pin); - impl_no_pin!($inst, BreakInput2Comparator1Pin); - impl_no_pin!($inst, BreakInput2Comparator2Pin); - }; -} - -crate::pac::peripherals!( - (timer, $inst:ident) => { impl_pwm_nopin!($inst); }; -); - crate::pac::peripheral_pins!( ($inst:ident, timer, $block:ident, $pin:ident, CH1, $af:expr) => { impl_pin!($inst, Channel1Pin, $pin, $af); diff --git a/embassy-stm32/src/pwm/pins.rs b/embassy-stm32/src/pwm/pins.rs index 77ba1f6d5..059e76231 100644 --- a/embassy-stm32/src/pwm/pins.rs +++ b/embassy-stm32/src/pwm/pins.rs @@ -1,4 +1,4 @@ -use crate::gpio::OptionalPin; +use crate::gpio::Pin; #[cfg(feature = "unstable-pac")] pub mod low_level { @@ -6,118 +6,106 @@ pub mod low_level { } pub(crate) mod sealed { - use crate::gpio::sealed::OptionalPin; + use crate::gpio::sealed::Pin; - pub trait Channel1Pin: OptionalPin { + pub trait Channel1Pin: Pin { unsafe fn configure(&mut self); } - pub trait Channel1ComplementaryPin: OptionalPin { + pub trait Channel1ComplementaryPin: Pin { unsafe fn configure(&mut self); } - pub trait Channel2Pin: OptionalPin { + pub trait Channel2Pin: Pin { unsafe fn configure(&mut self); } - pub trait Channel2ComplementaryPin: OptionalPin { + pub trait Channel2ComplementaryPin: Pin { unsafe fn configure(&mut self); } - pub trait Channel3Pin: OptionalPin { + pub trait Channel3Pin: Pin { unsafe fn configure(&mut self); } - pub trait Channel3ComplementaryPin: OptionalPin { + pub trait Channel3ComplementaryPin: Pin { unsafe fn configure(&mut self); } - pub trait Channel4Pin: OptionalPin { + pub trait Channel4Pin: Pin { unsafe fn configure(&mut self); } - pub trait Channel4ComplementaryPin: OptionalPin { + pub trait Channel4ComplementaryPin: Pin { unsafe fn configure(&mut self); } - pub trait ExternalTriggerPin: OptionalPin { + pub trait ExternalTriggerPin: Pin { unsafe fn configure(&mut self); } - pub trait BreakInputPin: OptionalPin { + pub trait BreakInputPin: Pin { unsafe fn configure(&mut self); } - pub trait BreakInputComparator1Pin: OptionalPin { + pub trait BreakInputComparator1Pin: Pin { unsafe fn configure(&mut self); } - pub trait BreakInputComparator2Pin: OptionalPin { + pub trait BreakInputComparator2Pin: Pin { unsafe fn configure(&mut self); } - pub trait BreakInput2Pin: OptionalPin { + pub trait BreakInput2Pin: Pin { unsafe fn configure(&mut self); } - pub trait BreakInput2Comparator1Pin: OptionalPin { + pub trait BreakInput2Comparator1Pin: Pin { unsafe fn configure(&mut self); } - pub trait BreakInput2Comparator2Pin: OptionalPin { + pub trait BreakInput2Comparator2Pin: Pin { unsafe fn configure(&mut self); } } -pub trait Channel1Pin: sealed::Channel1Pin + OptionalPin + 'static {} +pub trait Channel1Pin: sealed::Channel1Pin + Pin + 'static {} pub trait Channel1ComplementaryPin: - sealed::Channel1ComplementaryPin + OptionalPin + 'static + sealed::Channel1ComplementaryPin + Pin + 'static { } pub trait Channel2Pin: sealed::Channel2Pin + 'static {} pub trait Channel2ComplementaryPin: - sealed::Channel2ComplementaryPin + OptionalPin + 'static + sealed::Channel2ComplementaryPin + Pin + 'static { } pub trait Channel3Pin: sealed::Channel3Pin + 'static {} pub trait Channel3ComplementaryPin: - sealed::Channel3ComplementaryPin + OptionalPin + 'static + sealed::Channel3ComplementaryPin + Pin + 'static { } pub trait Channel4Pin: sealed::Channel4Pin + 'static {} pub trait Channel4ComplementaryPin: - sealed::Channel4ComplementaryPin + OptionalPin + 'static + sealed::Channel4ComplementaryPin + Pin + 'static { } -pub trait ExternalTriggerPin: - sealed::ExternalTriggerPin + OptionalPin + 'static -{ -} +pub trait ExternalTriggerPin: sealed::ExternalTriggerPin + Pin + 'static {} -pub trait BreakInputPin: sealed::BreakInputPin + OptionalPin + 'static {} +pub trait BreakInputPin: sealed::BreakInputPin + Pin + 'static {} pub trait BreakInputComparator1Pin: - sealed::BreakInputComparator1Pin + OptionalPin + 'static + sealed::BreakInputComparator1Pin + Pin + 'static { } pub trait BreakInputComparator2Pin: - sealed::BreakInputComparator2Pin + OptionalPin + 'static + sealed::BreakInputComparator2Pin + Pin + 'static { } -pub trait BreakInput2Pin: sealed::BreakInput2Pin + OptionalPin + 'static {} +pub trait BreakInput2Pin: sealed::BreakInput2Pin + Pin + 'static {} pub trait BreakInput2Comparator1Pin: - sealed::BreakInput2Comparator1Pin + OptionalPin + 'static + sealed::BreakInput2Comparator1Pin + Pin + 'static { } pub trait BreakInput2Comparator2Pin: - sealed::BreakInput2Comparator2Pin + OptionalPin + 'static + sealed::BreakInput2Comparator2Pin + Pin + 'static { } -macro_rules! impl_no_pin { - ($timer:ident, $signal:ident) => { - impl crate::pwm::pins::sealed::$signal for crate::gpio::NoPin { - unsafe fn configure(&mut self) {} - } - impl crate::pwm::pins::$signal for crate::gpio::NoPin {} - }; -} - #[allow(unused)] macro_rules! impl_pin { ($timer:ident, $signal:ident, $pin:ident, $af:expr) => { diff --git a/embassy-stm32/src/pwm/simple_pwm.rs b/embassy-stm32/src/pwm/simple_pwm.rs index 3dc46e6e8..6e1b9ce0d 100644 --- a/embassy-stm32/src/pwm/simple_pwm.rs +++ b/embassy-stm32/src/pwm/simple_pwm.rs @@ -12,7 +12,46 @@ pub struct SimplePwm<'d, T> { } impl<'d, T: CaptureCompareCapable16bitInstance> SimplePwm<'d, T> { - pub fn new>( + pub fn new_1ch>( + tim: impl Unborrow + 'd, + ch1: impl Unborrow> + 'd, + freq: F, + ) -> Self { + unborrow!(ch1); + Self::new_inner(tim, freq, move || unsafe { + ch1.configure(); + }) + } + + pub fn new_2ch>( + tim: impl Unborrow + 'd, + ch1: impl Unborrow> + 'd, + ch2: impl Unborrow> + 'd, + freq: F, + ) -> Self { + unborrow!(ch1, ch2); + Self::new_inner(tim, freq, move || unsafe { + ch1.configure(); + ch2.configure(); + }) + } + + pub fn new_3ch>( + tim: impl Unborrow + 'd, + ch1: impl Unborrow> + 'd, + ch2: impl Unborrow> + 'd, + ch3: impl Unborrow> + 'd, + freq: F, + ) -> Self { + unborrow!(ch1, ch2, ch3); + Self::new_inner(tim, freq, move || unsafe { + ch1.configure(); + ch2.configure(); + ch3.configure(); + }) + } + + pub fn new_4ch>( tim: impl Unborrow + 'd, ch1: impl Unborrow> + 'd, ch2: impl Unborrow> + 'd, @@ -20,17 +59,26 @@ impl<'d, T: CaptureCompareCapable16bitInstance> SimplePwm<'d, T> { ch4: impl Unborrow> + 'd, freq: F, ) -> Self { - unborrow!(tim, ch1, ch2, ch3, ch4); - - T::enable(); - ::reset(); - - unsafe { + unborrow!(ch1, ch2, ch3, ch4); + Self::new_inner(tim, freq, move || unsafe { ch1.configure(); ch2.configure(); ch3.configure(); ch4.configure(); - } + }) + } + + fn new_inner>( + tim: impl Unborrow + 'd, + freq: F, + configure_pins: impl FnOnce(), + ) -> Self { + unborrow!(tim); + + T::enable(); + ::reset(); + + configure_pins(); let mut this = Self { inner: tim, diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 4cf45f6f9..469216236 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -8,8 +8,8 @@ use embassy_hal_common::unborrow; use self::sealed::WordSize; use crate::dma; use crate::dma::NoDma; -use crate::gpio::sealed::{AFType, Pin}; -use crate::gpio::{AnyPin, NoPin, OptionalPin}; +use crate::gpio::sealed::{AFType, Pin as _}; +use crate::gpio::{AnyPin, Pin}; use crate::pac::spi::{regs, vals}; use crate::peripherals; use crate::rcc::RccPeripheral; @@ -92,10 +92,116 @@ pub struct Spi<'d, T: Instance, Tx, Rx> { impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { pub fn new( + peri: impl Unborrow + 'd, + sck: impl Unborrow> + 'd, + mosi: impl Unborrow> + 'd, + miso: impl Unborrow> + 'd, + txdma: impl Unborrow + 'd, + rxdma: impl Unborrow + 'd, + freq: F, + config: Config, + ) -> Self + where + F: Into, + { + unborrow!(sck, mosi, miso); + unsafe { + sck.set_as_af(sck.af_num(), AFType::OutputPushPull); + #[cfg(any(spi_v2, spi_v3))] + sck.set_speed(crate::gpio::Speed::VeryHigh); + mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); + #[cfg(any(spi_v2, spi_v3))] + mosi.set_speed(crate::gpio::Speed::VeryHigh); + miso.set_as_af(miso.af_num(), AFType::Input); + #[cfg(any(spi_v2, spi_v3))] + miso.set_speed(crate::gpio::Speed::VeryHigh); + } + + Self::new_inner( + peri, + Some(sck.degrade()), + Some(mosi.degrade()), + Some(miso.degrade()), + txdma, + rxdma, + freq, + config, + ) + } + + pub fn new_rxonly( + peri: impl Unborrow + 'd, + sck: impl Unborrow> + 'd, + miso: impl Unborrow> + 'd, + txdma: impl Unborrow + 'd, // TODO remove + rxdma: impl Unborrow + 'd, + freq: F, + config: Config, + ) -> Self + where + F: Into, + { + unborrow!(sck, miso); + unsafe { + sck.set_as_af(sck.af_num(), AFType::OutputPushPull); + #[cfg(any(spi_v2, spi_v3))] + sck.set_speed(crate::gpio::Speed::VeryHigh); + miso.set_as_af(miso.af_num(), AFType::Input); + #[cfg(any(spi_v2, spi_v3))] + miso.set_speed(crate::gpio::Speed::VeryHigh); + } + + Self::new_inner( + peri, + Some(sck.degrade()), + None, + Some(miso.degrade()), + txdma, + rxdma, + freq, + config, + ) + } + + pub fn new_txonly( + peri: impl Unborrow + 'd, + sck: impl Unborrow> + 'd, + mosi: impl Unborrow> + 'd, + txdma: impl Unborrow + 'd, + rxdma: impl Unborrow + 'd, // TODO remove + freq: F, + config: Config, + ) -> Self + where + F: Into, + { + unborrow!(sck, mosi); + unsafe { + sck.set_as_af(sck.af_num(), AFType::OutputPushPull); + #[cfg(any(spi_v2, spi_v3))] + sck.set_speed(crate::gpio::Speed::VeryHigh); + mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); + #[cfg(any(spi_v2, spi_v3))] + mosi.set_speed(crate::gpio::Speed::VeryHigh); + } + + Self::new_inner( + peri, + Some(sck.degrade()), + Some(mosi.degrade()), + None, + txdma, + rxdma, + freq, + config, + ) + } + + fn new_inner( _peri: impl Unborrow + 'd, - sck: impl Unborrow>, - mosi: impl Unborrow>, - miso: impl Unborrow>, + sck: Option, + mosi: Option, + miso: Option, txdma: impl Unborrow, rxdma: impl Unborrow, freq: F, @@ -104,32 +210,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { where F: Into, { - unborrow!(sck, mosi, miso, txdma, rxdma); - - let sck_af = sck.af_num(); - let mosi_af = mosi.af_num(); - let miso_af = miso.af_num(); - let sck = sck.degrade_optional(); - let mosi = mosi.degrade_optional(); - let miso = miso.degrade_optional(); - - unsafe { - sck.as_ref().map(|x| { - x.set_as_af(sck_af, AFType::OutputPushPull); - #[cfg(any(spi_v2, spi_v3))] - x.set_speed(crate::gpio::Speed::VeryHigh); - }); - mosi.as_ref().map(|x| { - x.set_as_af(mosi_af, AFType::OutputPushPull); - #[cfg(any(spi_v2, spi_v3))] - x.set_speed(crate::gpio::Speed::VeryHigh); - }); - miso.as_ref().map(|x| { - x.set_as_af(miso_af, AFType::Input); - #[cfg(any(spi_v2, spi_v3))] - x.set_speed(crate::gpio::Speed::VeryHigh); - }); - } + unborrow!(txdma, rxdma); let pclk = T::frequency(); let br = compute_baud_rate(pclk, freq.into()); @@ -719,15 +800,15 @@ pub(crate) mod sealed { fn regs() -> &'static crate::pac::spi::Spi; } - pub trait SckPin: OptionalPin { + pub trait SckPin: Pin { fn af_num(&self) -> u8; } - pub trait MosiPin: OptionalPin { + pub trait MosiPin: Pin { fn af_num(&self) -> u8; } - pub trait MisoPin: OptionalPin { + pub trait MisoPin: Pin { fn af_num(&self) -> u8; } @@ -865,26 +946,6 @@ crate::pac::peripheral_pins!( }; ); -macro_rules! impl_nopin { - ($inst:ident, $signal:ident) => { - impl $signal for NoPin {} - - impl sealed::$signal for NoPin { - fn af_num(&self) -> u8 { - 0 - } - } - }; -} - -crate::pac::peripherals!( - (spi, $inst:ident) => { - impl_nopin!($inst, SckPin); - impl_nopin!($inst, MosiPin); - impl_nopin!($inst, MisoPin); - }; -); - macro_rules! impl_dma { ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { impl sealed::$signal for T diff --git a/embassy-stm32/src/subghz/mod.rs b/embassy-stm32/src/subghz/mod.rs index 87f376c40..9c8b7f7ec 100644 --- a/embassy-stm32/src/subghz/mod.rs +++ b/embassy-stm32/src/subghz/mod.rs @@ -215,11 +215,11 @@ impl<'d, Tx, Rx> SubGhz<'d, Tx, Rx> { /// clock. pub fn new( peri: impl Unborrow + 'd, - sck: impl Unborrow>, - mosi: impl Unborrow>, - miso: impl Unborrow>, - txdma: impl Unborrow, - rxdma: impl Unborrow, + sck: impl Unborrow> + 'd, + mosi: impl Unborrow> + 'd, + miso: impl Unborrow> + 'd, + txdma: impl Unborrow + 'd, + rxdma: impl Unborrow + 'd, ) -> Self { Self::pulse_radio_reset(); diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index 3dd45318d..fb71c8b7d 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -6,7 +6,6 @@ mod example_common; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy_stm32::gpio::NoPin; use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel}; use embassy_stm32::time::U32Ext; use embassy_stm32::Peripherals; @@ -16,7 +15,7 @@ use example_common::*; async fn main(_spawner: Spawner, p: Peripherals) { info!("Hello World!"); - let mut pwm = SimplePwm::new(p.TIM2, p.PA5, NoPin, NoPin, NoPin, 10000.hz()); + let mut pwm = SimplePwm::new_1ch(p.TIM2, p.PA5, 10000.hz()); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 9760d0f74..f87b27f4f 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -4,8 +4,8 @@ use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy_stm32::dcmi::*; -use embassy_stm32::gpio::{Level, NoPin, Output, Speed}; +use embassy_stm32::dcmi::{self, *}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; use embassy_stm32::interrupt; use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; @@ -78,31 +78,10 @@ async fn main(_spawner: Spawner, p: Peripherals) { ); let dcmi_irq = interrupt::take!(DCMI); - let mut dcmi = Dcmi::new( - p.DCMI, - p.DMA1_CH0, - VSyncDataInvalidLevel::High, - HSyncDataInvalidLevel::Low, - PixelClockPolarity::RisingEdge, - false, - dcmi_irq, - p.PC6, - p.PC7, - p.PE0, - p.PE1, - p.PE4, - p.PD3, - p.PE5, - p.PE6, - NoPin, - NoPin, - NoPin, - NoPin, - NoPin, - NoPin, - p.PB7, - p.PA4, - p.PA6, + let config = dcmi::Config::default(); + let mut dcmi = Dcmi::new_8bit( + p.DCMI, p.DMA1_CH0, dcmi_irq, p.PC6, p.PC7, p.PE0, p.PE1, p.PE4, p.PD3, p.PE5, p.PE6, + p.PB7, p.PA4, p.PA6, config, ); defmt::info!("attempting capture"); diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index 4cd2f2cd1..8353405ad 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -5,7 +5,6 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::NoPin; use example_common::*; use cortex_m_rt::entry; @@ -17,7 +16,7 @@ fn main() -> ! { let p = embassy_stm32::init(config()); - let mut dac = Dac::new(p.DAC1, p.PA4, NoPin); + let mut dac = Dac::new_1ch(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 2640f249d..1bf69104d 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -10,7 +10,6 @@ use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; use embassy::util::Unborrow; use embassy_hal_common::unborrow; -use embassy_stm32::gpio::NoPin; use embassy_stm32::pwm::{pins::*, Channel, OutputCompareMode}; use embassy_stm32::time::{Hertz, U32Ext}; use embassy_stm32::timer::GeneralPurpose32bitInstance; @@ -33,7 +32,7 @@ pub fn config() -> Config { async fn main(_spawner: Spawner, p: Peripherals) { info!("Hello World!"); - let mut pwm = SimplePwm32::new(p.TIM5, p.PA0, NoPin, NoPin, NoPin, 10000.hz()); + let mut pwm = SimplePwm32::new(p.TIM5, p.PA0, p.PA1, p.PA2, p.PA3, 10000.hz()); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index 020150a39..b3edbde68 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -6,7 +6,6 @@ mod example_common; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy_stm32::gpio::NoPin; use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel}; use embassy_stm32::time::U32Ext; use embassy_stm32::{Config, Peripherals}; @@ -28,7 +27,7 @@ pub fn config() -> Config { async fn main(_spawner: Spawner, p: Peripherals) { info!("Hello World!"); - let mut pwm = SimplePwm::new(p.TIM3, p.PA6, NoPin, NoPin, NoPin, 10000.hz()); + let mut pwm = SimplePwm::new_1ch(p.TIM3, p.PA6, 10000.hz()); let max = pwm.get_max_duty(); pwm.enable(Channel::Ch1); diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs index 6cdd6d3ff..201ba473b 100644 --- a/examples/stm32l4/src/bin/dac.rs +++ b/examples/stm32l4/src/bin/dac.rs @@ -6,7 +6,6 @@ mod example_common; use embassy_stm32::dac::{Channel, Dac, Value}; -use embassy_stm32::gpio::NoPin; use embassy_stm32::pac; use example_common::*; @@ -22,7 +21,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut dac = Dac::new(p.DAC1, p.PA4, NoPin); + let mut dac = Dac::new_1ch(p.DAC1, p.PA4); loop { for v in 0..=255 {