stm32: Remove OptionalPin

The idea behind OptionalPin has a few problems:

- you need to impl the signal traits for NoPin which is a bit weird https://github.com/embassy-rs/embassy/blob/master/embassy-stm32/src/dcmi.rs#L413-L416
- you can pass any combination of set/unset pins, which needs checking at runtime  https://github.com/embassy-rs/embassy/blob/master/embassy-stm32/src/dcmi.rs#L130

The replacement is to do multiple `new` constructors for each combination of pins you want to take.
This commit is contained in:
Dario Nieuwenhuis 2022-02-10 02:34:59 +01:00
parent 1d265b73b2
commit 550da471be
15 changed files with 546 additions and 431 deletions

View File

@ -3,27 +3,21 @@
#[cfg_attr(dac_v1, path = "v1.rs")] #[cfg_attr(dac_v1, path = "v1.rs")]
#[cfg_attr(dac_v2, path = "v2.rs")] #[cfg_attr(dac_v2, path = "v2.rs")]
mod _version; mod _version;
use crate::gpio::NoPin;
use crate::peripherals; use crate::peripherals;
pub use _version::*; pub use _version::*;
pub(crate) mod sealed { pub(crate) mod sealed {
use crate::gpio::OptionalPin;
pub trait Instance { pub trait Instance {
fn regs() -> &'static crate::pac::dac::Dac; fn regs() -> &'static crate::pac::dac::Dac;
} }
pub trait DacPin<T: Instance, const C: u8>: OptionalPin {} pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin {}
} }
pub trait Instance: sealed::Instance + 'static {} pub trait Instance: sealed::Instance + 'static {}
pub trait DacPin<T: Instance, const C: u8>: sealed::DacPin<T, C> + 'static {} pub trait DacPin<T: Instance, const C: u8>: sealed::DacPin<T, C> + 'static {}
impl<T: Instance, const C: u8> DacPin<T, C> for NoPin {}
impl<T: Instance, const C: u8> sealed::DacPin<T, C> for NoPin {}
crate::pac::peripherals!( crate::pac::peripherals!(
(dac, $inst:ident) => { (dac, $inst:ident) => {
impl crate::dac::sealed::Instance for peripherals::$inst { impl crate::dac::sealed::Instance for peripherals::$inst {

View File

@ -1,33 +1,25 @@
use crate::dac::{DacPin, Instance}; use crate::dac::{DacPin, Instance};
use crate::gpio::AnyPin;
use crate::pac::dac; use crate::pac::dac;
use core::marker::PhantomData; use core::marker::PhantomData;
use embassy::util::Unborrow; use embassy::util::Unborrow;
use embassy_hal_common::unborrow; use embassy_hal_common::unborrow;
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock #[derive(Debug, Copy, Clone, Eq, PartialEq)]
/// 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)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
UnconfiguredChannel, UnconfiguredChannel,
InvalidValue, InvalidValue,
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Channel { pub enum Channel {
Ch1, Ch1,
Ch2, Ch2,
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Ch1Trigger { pub enum Ch1Trigger {
Tim6, Tim6,
Tim3, Tim3,
@ -52,6 +44,8 @@ impl Ch1Trigger {
} }
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Ch2Trigger { pub enum Ch2Trigger {
Tim6, Tim6,
Tim8, Tim8,
@ -78,46 +72,61 @@ impl Ch2Trigger {
} }
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Alignment { pub enum Alignment {
Left, Left,
Right, Right,
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Value { pub enum Value {
Bit8(u8), Bit8(u8),
Bit12(u16, Alignment), Bit12(u16, Alignment),
} }
pub struct Dac<'d, T: Instance> { pub struct Dac<'d, T: Instance> {
ch1: Option<AnyPin>, channels: u8,
ch2: Option<AnyPin>,
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
} }
impl<'d, T: Instance> Dac<'d, T> { impl<'d, T: Instance> Dac<'d, T> {
pub fn new( pub fn new_1ch(
_peri: impl Unborrow<Target = T> + 'd, peri: impl Unborrow<Target = T> + 'd,
ch1: impl Unborrow<Target = impl DacPin<T, 1>>, _ch1: impl Unborrow<Target = impl DacPin<T, 1>> + 'd,
ch2: impl Unborrow<Target = impl DacPin<T, 2>>,
) -> Self { ) -> Self {
unborrow!(ch1, ch2); unborrow!(peri);
Self::new_inner(peri, 1)
}
pub fn new_2ch(
peri: impl Unborrow<Target = T> + 'd,
_ch1: impl Unborrow<Target = impl DacPin<T, 1>> + 'd,
_ch2: impl Unborrow<Target = impl DacPin<T, 2>> + 'd,
) -> Self {
unborrow!(peri);
Self::new_inner(peri, 2)
}
fn new_inner(_peri: T, channels: u8) -> Self {
unsafe { 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 channels >= 1 {
if ch1.is_some() {
unsafe {
T::regs().cr().modify(|reg| { T::regs().cr().modify(|reg| {
reg.set_en1(true); reg.set_en1(true);
}); });
} }
}
let ch2 = ch2.degrade_optional(); if channels >= 2 {
if ch2.is_some() {
unsafe {
T::regs().cr().modify(|reg| { T::regs().cr().modify(|reg| {
reg.set_en2(true); reg.set_en2(true);
}); });
@ -125,41 +134,37 @@ impl<'d, T: Instance> Dac<'d, T> {
} }
Self { Self {
ch1, channels,
ch2,
phantom: PhantomData, phantom: PhantomData,
} }
} }
fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { /// Check the channel is configured
match ch { fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> {
Channel::Ch1 => { if ch == Channel::Ch2 && self.channels < 2 {
if self.ch1.is_none() { Err(Error::UnconfiguredChannel)
Err(Error::UnconfiguredChannel) } else {
} else { Ok(())
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(())
}
}
} }
} }
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> { pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
self.set_channel_enable(ch, true) 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> { pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
if self.ch1.is_none() { self.check_channel_exists(Channel::Ch1)?;
return Err(Error::UnconfiguredChannel);
}
unwrap!(self.disable_channel(Channel::Ch1)); unwrap!(self.disable_channel(Channel::Ch1));
unsafe { unsafe {
T::regs().cr().modify(|reg| { 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> { pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
if self.ch2.is_none() { self.check_channel_exists(Channel::Ch2)?;
return Err(Error::UnconfiguredChannel);
}
unwrap!(self.disable_channel(Channel::Ch2)); unwrap!(self.disable_channel(Channel::Ch2));
unsafe { unsafe {
T::regs().cr().modify(|reg| { 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> { pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
self.check_channel_exists(ch)?;
match ch { match ch {
Channel::Ch1 => { Channel::Ch1 => unsafe {
if self.ch1.is_none() { T::regs().swtrigr().write(|reg| {
Err(Error::UnconfiguredChannel) reg.set_swtrig1(true);
} else { });
unsafe { },
T::regs().swtrigr().write(|reg| { Channel::Ch2 => unsafe {
reg.set_swtrig1(true); T::regs().swtrigr().write(|reg| {
}); reg.set_swtrig2(true);
} })
Ok(()) },
}
}
Channel::Ch2 => {
if self.ch2.is_none() {
Err(Error::UnconfiguredChannel)
} else {
unsafe {
T::regs().swtrigr().write(|reg| {
reg.set_swtrig2(true);
});
}
Ok(())
}
}
} }
Ok(())
} }
pub fn trigger_all(&mut self) { 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> { pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch2)?;
match ch { match ch {
Channel::Ch1 => { Channel::Ch1 => match value {
if self.ch1.is_none() { Value::Bit8(v) => unsafe {
Err(Error::UnconfiguredChannel) T::regs().dhr8r1().write(|reg| reg.set_dacc1dhr(v));
} else { },
match value { Value::Bit12(v, Alignment::Left) => unsafe {
Value::Bit8(v) => unsafe { T::regs().dhr12l1().write(|reg| reg.set_dacc1dhr(v));
T::regs().dhr8r1().write(|reg| reg.set_dacc1dhr(v)); },
}, Value::Bit12(v, Alignment::Right) => unsafe {
Value::Bit12(v, Alignment::Left) => unsafe { T::regs().dhr12r1().write(|reg| reg.set_dacc1dhr(v));
T::regs().dhr12l1().write(|reg| reg.set_dacc1dhr(v)); },
}, },
Value::Bit12(v, Alignment::Right) => unsafe { Channel::Ch2 => match value {
T::regs().dhr12r1().write(|reg| reg.set_dacc1dhr(v)); Value::Bit8(v) => unsafe {
}, T::regs().dhr8r2().write(|reg| reg.set_dacc2dhr(v));
} },
Ok(()) Value::Bit12(v, Alignment::Left) => unsafe {
} T::regs().dhr12l2().write(|reg| reg.set_dacc2dhr(v));
} },
Channel::Ch2 => { Value::Bit12(v, Alignment::Right) => unsafe {
if self.ch2.is_none() { T::regs().dhr12r2().write(|reg| reg.set_dacc2dhr(v));
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(())
}
}
} }
Ok(())
} }
} }

View File

@ -9,6 +9,15 @@ use embassy::waitqueue::AtomicWaker;
use embassy_hal_common::unborrow; use embassy_hal_common::unborrow;
use futures::future::poll_fn; 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. /// The level on the VSync pin when the data is not valid on the parallel interface.
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum VSyncDataInvalidLevel { pub enum VSyncDataInvalidLevel {
@ -50,6 +59,23 @@ pub enum Error {
PeripheralError, 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> { pub struct Dcmi<'d, T: Instance, Dma: FrameDma> {
inner: T, inner: T,
dma: Dma, dma: Dma,
@ -61,13 +87,85 @@ where
T: Instance, T: Instance,
Dma: FrameDma, Dma: FrameDma,
{ {
pub fn new( pub fn new_8bit(
peri: impl Unborrow<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd,
d2: impl Unborrow<Target = impl D2Pin> + 'd,
d3: impl Unborrow<Target = impl D3Pin> + 'd,
d4: impl Unborrow<Target = impl D4Pin> + 'd,
d5: impl Unborrow<Target = impl D5Pin> + 'd,
d6: impl Unborrow<Target = impl D6Pin> + 'd,
d7: impl Unborrow<Target = impl D7Pin> + 'd,
v_sync: impl Unborrow<Target = impl VSyncPin> + 'd,
h_sync: impl Unborrow<Target = impl HSyncPin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + '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<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd,
d2: impl Unborrow<Target = impl D2Pin> + 'd,
d3: impl Unborrow<Target = impl D3Pin> + 'd,
d4: impl Unborrow<Target = impl D4Pin> + 'd,
d5: impl Unborrow<Target = impl D5Pin> + 'd,
d6: impl Unborrow<Target = impl D6Pin> + 'd,
d7: impl Unborrow<Target = impl D7Pin> + 'd,
d8: impl Unborrow<Target = impl D8Pin> + 'd,
d9: impl Unborrow<Target = impl D9Pin> + 'd,
v_sync: impl Unborrow<Target = impl VSyncPin> + 'd,
h_sync: impl Unborrow<Target = impl HSyncPin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + '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<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd,
d2: impl Unborrow<Target = impl D2Pin> + 'd,
d3: impl Unborrow<Target = impl D3Pin> + 'd,
d4: impl Unborrow<Target = impl D4Pin> + 'd,
d5: impl Unborrow<Target = impl D5Pin> + 'd,
d6: impl Unborrow<Target = impl D6Pin> + 'd,
d7: impl Unborrow<Target = impl D7Pin> + 'd,
d8: impl Unborrow<Target = impl D8Pin> + 'd,
d9: impl Unborrow<Target = impl D9Pin> + 'd,
d10: impl Unborrow<Target = impl D10Pin> + 'd,
d11: impl Unborrow<Target = impl D11Pin> + 'd,
v_sync: impl Unborrow<Target = impl VSyncPin> + 'd,
h_sync: impl Unborrow<Target = impl HSyncPin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + '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<Target = T> + 'd, peri: impl Unborrow<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd, dma: impl Unborrow<Target = Dma> + 'd,
vsync_level: VSyncDataInvalidLevel,
hsync_level: HSyncDataInvalidLevel,
pixclk_polarity: PixelClockPolarity,
use_embedded_synchronization: bool,
irq: impl Unborrow<Target = T::Interrupt> + 'd, irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd, d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd, d1: impl Unborrow<Target = impl D1Pin> + 'd,
@ -86,58 +184,132 @@ where
v_sync: impl Unborrow<Target = impl VSyncPin> + 'd, v_sync: impl Unborrow<Target = impl VSyncPin> + 'd,
h_sync: impl Unborrow<Target = impl HSyncPin> + 'd, h_sync: impl Unborrow<Target = impl HSyncPin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + 'd, pixclk: impl Unborrow<Target = impl PixClkPin> + '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<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd,
d2: impl Unborrow<Target = impl D2Pin> + 'd,
d3: impl Unborrow<Target = impl D3Pin> + 'd,
d4: impl Unborrow<Target = impl D4Pin> + 'd,
d5: impl Unborrow<Target = impl D5Pin> + 'd,
d6: impl Unborrow<Target = impl D6Pin> + 'd,
d7: impl Unborrow<Target = impl D7Pin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + '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<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd,
d2: impl Unborrow<Target = impl D2Pin> + 'd,
d3: impl Unborrow<Target = impl D3Pin> + 'd,
d4: impl Unborrow<Target = impl D4Pin> + 'd,
d5: impl Unborrow<Target = impl D5Pin> + 'd,
d6: impl Unborrow<Target = impl D6Pin> + 'd,
d7: impl Unborrow<Target = impl D7Pin> + 'd,
d8: impl Unborrow<Target = impl D8Pin> + 'd,
d9: impl Unborrow<Target = impl D9Pin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + '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<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd,
d2: impl Unborrow<Target = impl D2Pin> + 'd,
d3: impl Unborrow<Target = impl D3Pin> + 'd,
d4: impl Unborrow<Target = impl D4Pin> + 'd,
d5: impl Unborrow<Target = impl D5Pin> + 'd,
d6: impl Unborrow<Target = impl D6Pin> + 'd,
d7: impl Unborrow<Target = impl D7Pin> + 'd,
d8: impl Unborrow<Target = impl D8Pin> + 'd,
d9: impl Unborrow<Target = impl D9Pin> + 'd,
d10: impl Unborrow<Target = impl D10Pin> + 'd,
d11: impl Unborrow<Target = impl D11Pin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + '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<Target = T> + 'd,
dma: impl Unborrow<Target = Dma> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
d0: impl Unborrow<Target = impl D0Pin> + 'd,
d1: impl Unborrow<Target = impl D1Pin> + 'd,
d2: impl Unborrow<Target = impl D2Pin> + 'd,
d3: impl Unborrow<Target = impl D3Pin> + 'd,
d4: impl Unborrow<Target = impl D4Pin> + 'd,
d5: impl Unborrow<Target = impl D5Pin> + 'd,
d6: impl Unborrow<Target = impl D6Pin> + 'd,
d7: impl Unborrow<Target = impl D7Pin> + 'd,
d8: impl Unborrow<Target = impl D8Pin> + 'd,
d9: impl Unborrow<Target = impl D9Pin> + 'd,
d10: impl Unborrow<Target = impl D10Pin> + 'd,
d11: impl Unborrow<Target = impl D11Pin> + 'd,
d12: impl Unborrow<Target = impl D12Pin> + 'd,
d13: impl Unborrow<Target = impl D13Pin> + 'd,
pixclk: impl Unborrow<Target = impl PixClkPin> + '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 { ) -> Self {
T::reset(); T::reset();
T::enable(); 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 { unsafe {
peri.regs().cr().modify(|r| { peri.regs().cr().modify(|r| {
r.set_cm(true); // disable continuous mode (snapshot mode) r.set_cm(true); // disable continuous mode (snapshot mode)
r.set_ess(use_embedded_synchronization); r.set_ess(use_embedded_synchronization);
r.set_pckpol(pixclk_polarity == PixelClockPolarity::RisingEdge); r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge);
r.set_vspol(vsync_level == VSyncDataInvalidLevel::High); r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High);
r.set_hspol(hsync_level == HSyncDataInvalidLevel::High); r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High);
r.set_fcrc(0x00); // capture every frame r.set_fcrc(0x00); // capture every frame
r.set_edm(edm); // extended data mode 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!(D0Pin);
pin!(D1Pin); pin!(D1Pin);
pin!(D2Pin); pin!(D2Pin);
@ -287,15 +451,15 @@ mod sealed {
pin!(D5Pin); pin!(D5Pin);
pin!(D6Pin); pin!(D6Pin);
pin!(D7Pin); pin!(D7Pin);
optional_pin!(D8Pin); pin!(D8Pin);
optional_pin!(D9Pin); pin!(D9Pin);
optional_pin!(D10Pin); pin!(D10Pin);
optional_pin!(D11Pin); pin!(D11Pin);
optional_pin!(D12Pin); pin!(D12Pin);
optional_pin!(D13Pin); pin!(D13Pin);
optional_pin!(HSyncPin); pin!(HSyncPin);
optional_pin!(VSyncPin); pin!(VSyncPin);
pin!(PixClkPin); 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!( crate::pac::peripheral_pins!(
($inst:ident, dcmi, DCMI, $pin:ident, D0, $af:expr) => { ($inst:ident, dcmi, DCMI, $pin:ident, D0, $af:expr) => {
impl_pin!($pin, D0Pin, $af); impl_pin!($pin, D0Pin, $af);

View File

@ -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<AnyPin>`.
#[inline]
fn degrade_optional(mut self) -> Option<AnyPin> {
self.pin_mut()
.map(|pin| unsafe { core::ptr::read(pin) }.degrade())
}
}
impl<T: Pin> sealed::OptionalPin for T {}
impl<T: Pin> 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!( crate::pac::pins!(
($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => {
impl Pin for peripherals::$pin_name { impl Pin for peripherals::$pin_name {

View File

@ -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!( crate::pac::peripheral_pins!(
($inst:ident, timer, $block:ident, $pin:ident, CH1, $af:expr) => { ($inst:ident, timer, $block:ident, $pin:ident, CH1, $af:expr) => {
impl_pin!($inst, Channel1Pin, $pin, $af); impl_pin!($inst, Channel1Pin, $pin, $af);

View File

@ -1,4 +1,4 @@
use crate::gpio::OptionalPin; use crate::gpio::Pin;
#[cfg(feature = "unstable-pac")] #[cfg(feature = "unstable-pac")]
pub mod low_level { pub mod low_level {
@ -6,118 +6,106 @@ pub mod low_level {
} }
pub(crate) mod sealed { pub(crate) mod sealed {
use crate::gpio::sealed::OptionalPin; use crate::gpio::sealed::Pin;
pub trait Channel1Pin<Timer>: OptionalPin { pub trait Channel1Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait Channel1ComplementaryPin<Timer>: OptionalPin { pub trait Channel1ComplementaryPin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait Channel2Pin<Timer>: OptionalPin { pub trait Channel2Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait Channel2ComplementaryPin<Timer>: OptionalPin { pub trait Channel2ComplementaryPin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait Channel3Pin<Timer>: OptionalPin { pub trait Channel3Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait Channel3ComplementaryPin<Timer>: OptionalPin { pub trait Channel3ComplementaryPin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait Channel4Pin<Timer>: OptionalPin { pub trait Channel4Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait Channel4ComplementaryPin<Timer>: OptionalPin { pub trait Channel4ComplementaryPin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait ExternalTriggerPin<Timer>: OptionalPin { pub trait ExternalTriggerPin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait BreakInputPin<Timer>: OptionalPin { pub trait BreakInputPin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait BreakInputComparator1Pin<Timer>: OptionalPin { pub trait BreakInputComparator1Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait BreakInputComparator2Pin<Timer>: OptionalPin { pub trait BreakInputComparator2Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait BreakInput2Pin<Timer>: OptionalPin { pub trait BreakInput2Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait BreakInput2Comparator1Pin<Timer>: OptionalPin { pub trait BreakInput2Comparator1Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
pub trait BreakInput2Comparator2Pin<Timer>: OptionalPin { pub trait BreakInput2Comparator2Pin<Timer>: Pin {
unsafe fn configure(&mut self); unsafe fn configure(&mut self);
} }
} }
pub trait Channel1Pin<Timer>: sealed::Channel1Pin<Timer> + OptionalPin + 'static {} pub trait Channel1Pin<Timer>: sealed::Channel1Pin<Timer> + Pin + 'static {}
pub trait Channel1ComplementaryPin<Timer>: pub trait Channel1ComplementaryPin<Timer>:
sealed::Channel1ComplementaryPin<Timer> + OptionalPin + 'static sealed::Channel1ComplementaryPin<Timer> + Pin + 'static
{ {
} }
pub trait Channel2Pin<Timer>: sealed::Channel2Pin<Timer> + 'static {} pub trait Channel2Pin<Timer>: sealed::Channel2Pin<Timer> + 'static {}
pub trait Channel2ComplementaryPin<Timer>: pub trait Channel2ComplementaryPin<Timer>:
sealed::Channel2ComplementaryPin<Timer> + OptionalPin + 'static sealed::Channel2ComplementaryPin<Timer> + Pin + 'static
{ {
} }
pub trait Channel3Pin<Timer>: sealed::Channel3Pin<Timer> + 'static {} pub trait Channel3Pin<Timer>: sealed::Channel3Pin<Timer> + 'static {}
pub trait Channel3ComplementaryPin<Timer>: pub trait Channel3ComplementaryPin<Timer>:
sealed::Channel3ComplementaryPin<Timer> + OptionalPin + 'static sealed::Channel3ComplementaryPin<Timer> + Pin + 'static
{ {
} }
pub trait Channel4Pin<Timer>: sealed::Channel4Pin<Timer> + 'static {} pub trait Channel4Pin<Timer>: sealed::Channel4Pin<Timer> + 'static {}
pub trait Channel4ComplementaryPin<Timer>: pub trait Channel4ComplementaryPin<Timer>:
sealed::Channel4ComplementaryPin<Timer> + OptionalPin + 'static sealed::Channel4ComplementaryPin<Timer> + Pin + 'static
{ {
} }
pub trait ExternalTriggerPin<Timer>: pub trait ExternalTriggerPin<Timer>: sealed::ExternalTriggerPin<Timer> + Pin + 'static {}
sealed::ExternalTriggerPin<Timer> + OptionalPin + 'static
{
}
pub trait BreakInputPin<Timer>: sealed::BreakInputPin<Timer> + OptionalPin + 'static {} pub trait BreakInputPin<Timer>: sealed::BreakInputPin<Timer> + Pin + 'static {}
pub trait BreakInputComparator1Pin<Timer>: pub trait BreakInputComparator1Pin<Timer>:
sealed::BreakInputComparator1Pin<Timer> + OptionalPin + 'static sealed::BreakInputComparator1Pin<Timer> + Pin + 'static
{ {
} }
pub trait BreakInputComparator2Pin<Timer>: pub trait BreakInputComparator2Pin<Timer>:
sealed::BreakInputComparator2Pin<Timer> + OptionalPin + 'static sealed::BreakInputComparator2Pin<Timer> + Pin + 'static
{ {
} }
pub trait BreakInput2Pin<Timer>: sealed::BreakInput2Pin<Timer> + OptionalPin + 'static {} pub trait BreakInput2Pin<Timer>: sealed::BreakInput2Pin<Timer> + Pin + 'static {}
pub trait BreakInput2Comparator1Pin<Timer>: pub trait BreakInput2Comparator1Pin<Timer>:
sealed::BreakInput2Comparator1Pin<Timer> + OptionalPin + 'static sealed::BreakInput2Comparator1Pin<Timer> + Pin + 'static
{ {
} }
pub trait BreakInput2Comparator2Pin<Timer>: pub trait BreakInput2Comparator2Pin<Timer>:
sealed::BreakInput2Comparator2Pin<Timer> + OptionalPin + 'static sealed::BreakInput2Comparator2Pin<Timer> + Pin + 'static
{ {
} }
macro_rules! impl_no_pin {
($timer:ident, $signal:ident) => {
impl crate::pwm::pins::sealed::$signal<crate::peripherals::$timer> for crate::gpio::NoPin {
unsafe fn configure(&mut self) {}
}
impl crate::pwm::pins::$signal<crate::peripherals::$timer> for crate::gpio::NoPin {}
};
}
#[allow(unused)] #[allow(unused)]
macro_rules! impl_pin { macro_rules! impl_pin {
($timer:ident, $signal:ident, $pin:ident, $af:expr) => { ($timer:ident, $signal:ident, $pin:ident, $af:expr) => {

View File

@ -12,7 +12,46 @@ pub struct SimplePwm<'d, T> {
} }
impl<'d, T: CaptureCompareCapable16bitInstance> SimplePwm<'d, T> { impl<'d, T: CaptureCompareCapable16bitInstance> SimplePwm<'d, T> {
pub fn new<F: Into<Hertz>>( pub fn new_1ch<F: Into<Hertz>>(
tim: impl Unborrow<Target = T> + 'd,
ch1: impl Unborrow<Target = impl Channel1Pin<T>> + 'd,
freq: F,
) -> Self {
unborrow!(ch1);
Self::new_inner(tim, freq, move || unsafe {
ch1.configure();
})
}
pub fn new_2ch<F: Into<Hertz>>(
tim: impl Unborrow<Target = T> + 'd,
ch1: impl Unborrow<Target = impl Channel1Pin<T>> + 'd,
ch2: impl Unborrow<Target = impl Channel2Pin<T>> + 'd,
freq: F,
) -> Self {
unborrow!(ch1, ch2);
Self::new_inner(tim, freq, move || unsafe {
ch1.configure();
ch2.configure();
})
}
pub fn new_3ch<F: Into<Hertz>>(
tim: impl Unborrow<Target = T> + 'd,
ch1: impl Unborrow<Target = impl Channel1Pin<T>> + 'd,
ch2: impl Unborrow<Target = impl Channel2Pin<T>> + 'd,
ch3: impl Unborrow<Target = impl Channel3Pin<T>> + '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<F: Into<Hertz>>(
tim: impl Unborrow<Target = T> + 'd, tim: impl Unborrow<Target = T> + 'd,
ch1: impl Unborrow<Target = impl Channel1Pin<T>> + 'd, ch1: impl Unborrow<Target = impl Channel1Pin<T>> + 'd,
ch2: impl Unborrow<Target = impl Channel2Pin<T>> + 'd, ch2: impl Unborrow<Target = impl Channel2Pin<T>> + 'd,
@ -20,17 +59,26 @@ impl<'d, T: CaptureCompareCapable16bitInstance> SimplePwm<'d, T> {
ch4: impl Unborrow<Target = impl Channel4Pin<T>> + 'd, ch4: impl Unborrow<Target = impl Channel4Pin<T>> + 'd,
freq: F, freq: F,
) -> Self { ) -> Self {
unborrow!(tim, ch1, ch2, ch3, ch4); unborrow!(ch1, ch2, ch3, ch4);
Self::new_inner(tim, freq, move || unsafe {
T::enable();
<T as crate::rcc::sealed::RccPeripheral>::reset();
unsafe {
ch1.configure(); ch1.configure();
ch2.configure(); ch2.configure();
ch3.configure(); ch3.configure();
ch4.configure(); ch4.configure();
} })
}
fn new_inner<F: Into<Hertz>>(
tim: impl Unborrow<Target = T> + 'd,
freq: F,
configure_pins: impl FnOnce(),
) -> Self {
unborrow!(tim);
T::enable();
<T as crate::rcc::sealed::RccPeripheral>::reset();
configure_pins();
let mut this = Self { let mut this = Self {
inner: tim, inner: tim,

View File

@ -8,8 +8,8 @@ use embassy_hal_common::unborrow;
use self::sealed::WordSize; use self::sealed::WordSize;
use crate::dma; use crate::dma;
use crate::dma::NoDma; use crate::dma::NoDma;
use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::sealed::{AFType, Pin as _};
use crate::gpio::{AnyPin, NoPin, OptionalPin}; use crate::gpio::{AnyPin, Pin};
use crate::pac::spi::{regs, vals}; use crate::pac::spi::{regs, vals};
use crate::peripherals; use crate::peripherals;
use crate::rcc::RccPeripheral; 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> { impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub fn new<F>( pub fn new<F>(
peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>> + 'd,
mosi: impl Unborrow<Target = impl MosiPin<T>> + 'd,
miso: impl Unborrow<Target = impl MisoPin<T>> + 'd,
txdma: impl Unborrow<Target = Tx> + 'd,
rxdma: impl Unborrow<Target = Rx> + 'd,
freq: F,
config: Config,
) -> Self
where
F: Into<Hertz>,
{
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<F>(
peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>> + 'd,
miso: impl Unborrow<Target = impl MisoPin<T>> + 'd,
txdma: impl Unborrow<Target = Tx> + 'd, // TODO remove
rxdma: impl Unborrow<Target = Rx> + 'd,
freq: F,
config: Config,
) -> Self
where
F: Into<Hertz>,
{
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<F>(
peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>> + 'd,
mosi: impl Unborrow<Target = impl MosiPin<T>> + 'd,
txdma: impl Unborrow<Target = Tx> + 'd,
rxdma: impl Unborrow<Target = Rx> + 'd, // TODO remove
freq: F,
config: Config,
) -> Self
where
F: Into<Hertz>,
{
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<F>(
_peri: impl Unborrow<Target = T> + 'd, _peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>>, sck: Option<AnyPin>,
mosi: impl Unborrow<Target = impl MosiPin<T>>, mosi: Option<AnyPin>,
miso: impl Unborrow<Target = impl MisoPin<T>>, miso: Option<AnyPin>,
txdma: impl Unborrow<Target = Tx>, txdma: impl Unborrow<Target = Tx>,
rxdma: impl Unborrow<Target = Rx>, rxdma: impl Unborrow<Target = Rx>,
freq: F, freq: F,
@ -104,32 +210,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
where where
F: Into<Hertz>, F: Into<Hertz>,
{ {
unborrow!(sck, mosi, miso, txdma, rxdma); unborrow!(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);
});
}
let pclk = T::frequency(); let pclk = T::frequency();
let br = compute_baud_rate(pclk, freq.into()); let br = compute_baud_rate(pclk, freq.into());
@ -719,15 +800,15 @@ pub(crate) mod sealed {
fn regs() -> &'static crate::pac::spi::Spi; fn regs() -> &'static crate::pac::spi::Spi;
} }
pub trait SckPin<T: Instance>: OptionalPin { pub trait SckPin<T: Instance>: Pin {
fn af_num(&self) -> u8; fn af_num(&self) -> u8;
} }
pub trait MosiPin<T: Instance>: OptionalPin { pub trait MosiPin<T: Instance>: Pin {
fn af_num(&self) -> u8; fn af_num(&self) -> u8;
} }
pub trait MisoPin<T: Instance>: OptionalPin { pub trait MisoPin<T: Instance>: Pin {
fn af_num(&self) -> u8; fn af_num(&self) -> u8;
} }
@ -865,26 +946,6 @@ crate::pac::peripheral_pins!(
}; };
); );
macro_rules! impl_nopin {
($inst:ident, $signal:ident) => {
impl $signal<peripherals::$inst> for NoPin {}
impl sealed::$signal<peripherals::$inst> 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 { macro_rules! impl_dma {
($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => {
impl<T> sealed::$signal<peripherals::$inst> for T impl<T> sealed::$signal<peripherals::$inst> for T

View File

@ -215,11 +215,11 @@ impl<'d, Tx, Rx> SubGhz<'d, Tx, Rx> {
/// clock. /// clock.
pub fn new( pub fn new(
peri: impl Unborrow<Target = SUBGHZSPI> + 'd, peri: impl Unborrow<Target = SUBGHZSPI> + 'd,
sck: impl Unborrow<Target = impl SckPin<SUBGHZSPI>>, sck: impl Unborrow<Target = impl SckPin<SUBGHZSPI>> + 'd,
mosi: impl Unborrow<Target = impl MosiPin<SUBGHZSPI>>, mosi: impl Unborrow<Target = impl MosiPin<SUBGHZSPI>> + 'd,
miso: impl Unborrow<Target = impl MisoPin<SUBGHZSPI>>, miso: impl Unborrow<Target = impl MisoPin<SUBGHZSPI>> + 'd,
txdma: impl Unborrow<Target = Tx>, txdma: impl Unborrow<Target = Tx> + 'd,
rxdma: impl Unborrow<Target = Rx>, rxdma: impl Unborrow<Target = Rx> + 'd,
) -> Self { ) -> Self {
Self::pulse_radio_reset(); Self::pulse_radio_reset();

View File

@ -6,7 +6,6 @@
mod example_common; mod example_common;
use embassy::executor::Spawner; use embassy::executor::Spawner;
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy_stm32::gpio::NoPin;
use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel}; use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel};
use embassy_stm32::time::U32Ext; use embassy_stm32::time::U32Ext;
use embassy_stm32::Peripherals; use embassy_stm32::Peripherals;
@ -16,7 +15,7 @@ use example_common::*;
async fn main(_spawner: Spawner, p: Peripherals) { async fn main(_spawner: Spawner, p: Peripherals) {
info!("Hello World!"); 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(); let max = pwm.get_max_duty();
pwm.enable(Channel::Ch1); pwm.enable(Channel::Ch1);

View File

@ -4,8 +4,8 @@
use embassy::executor::Spawner; use embassy::executor::Spawner;
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy_stm32::dcmi::*; use embassy_stm32::dcmi::{self, *};
use embassy_stm32::gpio::{Level, NoPin, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::i2c::I2c; use embassy_stm32::i2c::I2c;
use embassy_stm32::interrupt; use embassy_stm32::interrupt;
use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; 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 dcmi_irq = interrupt::take!(DCMI);
let mut dcmi = Dcmi::new( let config = dcmi::Config::default();
p.DCMI, let mut dcmi = Dcmi::new_8bit(
p.DMA1_CH0, p.DCMI, p.DMA1_CH0, dcmi_irq, p.PC6, p.PC7, p.PE0, p.PE1, p.PE4, p.PD3, p.PE5, p.PE6,
VSyncDataInvalidLevel::High, p.PB7, p.PA4, p.PA6, config,
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,
); );
defmt::info!("attempting capture"); defmt::info!("attempting capture");

View File

@ -5,7 +5,6 @@
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use embassy_stm32::gpio::NoPin;
use example_common::*; use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
@ -17,7 +16,7 @@ fn main() -> ! {
let p = embassy_stm32::init(config()); 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 { loop {
for v in 0..=255 { for v in 0..=255 {

View File

@ -10,7 +10,6 @@ use embassy::executor::Spawner;
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy::util::Unborrow; use embassy::util::Unborrow;
use embassy_hal_common::unborrow; use embassy_hal_common::unborrow;
use embassy_stm32::gpio::NoPin;
use embassy_stm32::pwm::{pins::*, Channel, OutputCompareMode}; use embassy_stm32::pwm::{pins::*, Channel, OutputCompareMode};
use embassy_stm32::time::{Hertz, U32Ext}; use embassy_stm32::time::{Hertz, U32Ext};
use embassy_stm32::timer::GeneralPurpose32bitInstance; use embassy_stm32::timer::GeneralPurpose32bitInstance;
@ -33,7 +32,7 @@ pub fn config() -> Config {
async fn main(_spawner: Spawner, p: Peripherals) { async fn main(_spawner: Spawner, p: Peripherals) {
info!("Hello World!"); 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(); let max = pwm.get_max_duty();
pwm.enable(Channel::Ch1); pwm.enable(Channel::Ch1);

View File

@ -6,7 +6,6 @@
mod example_common; mod example_common;
use embassy::executor::Spawner; use embassy::executor::Spawner;
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy_stm32::gpio::NoPin;
use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel}; use embassy_stm32::pwm::{simple_pwm::SimplePwm, Channel};
use embassy_stm32::time::U32Ext; use embassy_stm32::time::U32Ext;
use embassy_stm32::{Config, Peripherals}; use embassy_stm32::{Config, Peripherals};
@ -28,7 +27,7 @@ pub fn config() -> Config {
async fn main(_spawner: Spawner, p: Peripherals) { async fn main(_spawner: Spawner, p: Peripherals) {
info!("Hello World!"); 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(); let max = pwm.get_max_duty();
pwm.enable(Channel::Ch1); pwm.enable(Channel::Ch1);

View File

@ -6,7 +6,6 @@
mod example_common; mod example_common;
use embassy_stm32::dac::{Channel, Dac, Value}; use embassy_stm32::dac::{Channel, Dac, Value};
use embassy_stm32::gpio::NoPin;
use embassy_stm32::pac; use embassy_stm32::pac;
use example_common::*; use example_common::*;
@ -22,7 +21,7 @@ fn main() -> ! {
let p = embassy_stm32::init(Default::default()); 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 { loop {
for v in 0..=255 { for v in 0..=255 {