diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 873c73b4..e562dcab 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -18,6 +18,31 @@ pub enum Pull { Down, } +/// Pull setting for an input. +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Speed { + LowSpeed, + MediumSpeed, + #[cfg(not(syscfg_f0))] + HighSpeed, + VeryHighSpeed, +} + +impl From for vals::Ospeedr { + fn from(speed: Speed) -> Self { + use Speed::*; + + match speed { + LowSpeed => vals::Ospeedr::LOWSPEED, + MediumSpeed => vals::Ospeedr::MEDIUMSPEED, + #[cfg(not(syscfg_f0))] + HighSpeed => vals::Ospeedr::HIGHSPEED, + VeryHighSpeed => vals::Ospeedr::VERYHIGHSPEED, + } + } +} + /// GPIO input driver. pub struct Input<'d, T: Pin> { pub(crate) pin: T, @@ -86,7 +111,12 @@ pub struct Output<'d, T: Pin> { } impl<'d, T: Pin> Output<'d, T> { - pub fn new(pin: impl Unborrow + 'd, initial_output: Level) -> Self { + pub fn new( + pin: impl Unborrow + 'd, + initial_output: Level, + speed: Speed, + open_drain: bool, + ) -> Self { unborrow!(pin); match initial_output { @@ -99,6 +129,10 @@ impl<'d, T: Pin> Output<'d, T> { let n = pin.pin() as usize; r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); + if open_drain { + r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN)); + } + pin.set_speed(speed); }); Self { @@ -115,6 +149,8 @@ impl<'d, T: Pin> Drop for Output<'d, T> { let n = self.pin.pin() as usize; r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); + self.pin.set_speed(Speed::LowSpeed); }); } } @@ -148,6 +184,18 @@ impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> { } } +impl<'d, T: Pin> InputPin for Output<'d, T> { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.is_set_high() + } + + fn is_low(&self) -> Result { + self.is_set_low() + } +} + impl<'d, T: Pin> toggleable::Default for Output<'d, T> {} pub(crate) mod sealed { @@ -206,6 +254,13 @@ pub(crate) mod sealed { .moder() .modify(|w| w.set_moder(pin, vals::Moder::ANALOG)); } + + unsafe fn set_speed(&self, speed: Speed) { + let pin = self._pin() as usize; + self.block() + .ospeedr() + .modify(|w| w.set_ospeedr(pin, speed.into())); + } } pub trait OptionalPin {}