From efb3b3a0a8577059896100336f430c4eb45c544f Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Wed, 23 Jun 2021 19:22:53 -0300 Subject: [PATCH 1/4] stm32: Allow for open drain configuration for output pin --- embassy-stm32/src/gpio.rs | 57 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 873c73b4e..e562dcab7 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 {} From a3f0aa02a4cf12df9ce7b7bda02a56b74bf028ab Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Fri, 25 Jun 2021 17:22:51 -0300 Subject: [PATCH 2/4] Separate OpenDrain pin to a new type --- embassy-stm32/src/gpio.rs | 114 +++++++++++++++++++++++++++++--------- 1 file changed, 88 insertions(+), 26 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index e562dcab7..5c2b0f6fc 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -18,7 +18,19 @@ pub enum Pull { Down, } -/// Pull setting for an input. +impl From for vals::Pupdr { + fn from(pull: Pull) -> Self { + use Pull::*; + + match pull { + None => vals::Pupdr::FLOATING, + Up => vals::Pupdr::PULLUP, + Down => vals::Pupdr::PULLDOWN, + } + } +} + +/// Speed settings #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Speed { @@ -56,12 +68,7 @@ impl<'d, T: Pin> Input<'d, T> { cortex_m::interrupt::free(|_| unsafe { let r = pin.block(); let n = pin.pin() as usize; - let val = match pull { - Pull::None => vals::Pupdr::FLOATING, - Pull::Up => vals::Pupdr::PULLUP, - Pull::Down => vals::Pupdr::PULLDOWN, - }; - r.pupdr().modify(|w| w.set_pupdr(n, val)); + r.pupdr().modify(|w| w.set_pupdr(n, pull.into())); r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); }); @@ -111,12 +118,7 @@ pub struct Output<'d, T: Pin> { } impl<'d, T: Pin> Output<'d, T> { - pub fn new( - pin: impl Unborrow + 'd, - initial_output: Level, - speed: Speed, - open_drain: bool, - ) -> Self { + pub fn new(pin: impl Unborrow + 'd, initial_output: Level, speed: Speed) -> Self { unborrow!(pin); match initial_output { @@ -129,9 +131,6 @@ 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); }); @@ -149,8 +148,6 @@ 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); }); } } @@ -184,19 +181,84 @@ impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> { } } -impl<'d, T: Pin> InputPin for Output<'d, T> { - type Error = Infallible; +impl<'d, T: Pin> toggleable::Default for Output<'d, T> {} - fn is_high(&self) -> Result { - self.is_set_high() - } +/// GPIO output open-drain driver. +pub struct OutputOpenDrain<'d, T: Pin> { + pub(crate) pin: T, + phantom: PhantomData<&'d mut T>, +} - fn is_low(&self) -> Result { - self.is_set_low() +impl<'d, T: Pin> OutputOpenDrain<'d, T> { + pub fn new( + pin: impl Unborrow + 'd, + initial_output: Level, + speed: Speed, + pull: Pull, + ) -> Self { + unborrow!(pin); + + match initial_output { + Level::High => pin.set_high(), + Level::Low => pin.set_low(), + } + + cortex_m::interrupt::free(|_| unsafe { + let r = pin.block(); + let n = pin.pin() as usize; + r.pupdr().modify(|w| w.set_pupdr(n, pull.into())); + r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN)); + pin.set_speed(speed); + }); + + Self { + pin, + phantom: PhantomData, + } } } -impl<'d, T: Pin> toggleable::Default for Output<'d, T> {} +impl<'d, T: Pin> Drop for OutputOpenDrain<'d, T> { + fn drop(&mut self) { + cortex_m::interrupt::free(|_| unsafe { + let r = self.pin.block(); + 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)); + }); + } +} + +impl<'d, T: Pin> OutputPin for OutputOpenDrain<'d, T> { + type Error = Infallible; + + /// Set the output as high. + fn set_high(&mut self) -> Result<(), Self::Error> { + self.pin.set_high(); + Ok(()) + } + + /// Set the output as low. + fn set_low(&mut self) -> Result<(), Self::Error> { + self.pin.set_low(); + Ok(()) + } +} + +impl<'d, T: Pin> InputPin for Input<'d, T> { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.is_low().map(|v| !v) + } + + fn is_low(&self) -> Result { + // NOTE(safety) Atomic read + let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as usize) }; + Ok(state == vals::Idr::LOW) + } +} pub(crate) mod sealed { use super::*; From 0eaadfc1253285c04340e32f14efa1133cb30dbe Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Fri, 25 Jun 2021 17:32:24 -0300 Subject: [PATCH 3/4] stm32: Update gpio examples --- embassy-stm32/src/gpio.rs | 18 +++++++++--------- examples/stm32f4/src/bin/blinky.rs | 4 ++-- examples/stm32f4/src/bin/button.rs | 8 ++++---- examples/stm32f4/src/bin/spi.rs | 4 ++-- examples/stm32h7/src/bin/blinky.rs | 10 ++++------ examples/stm32l0/src/bin/blinky.rs | 4 ++-- examples/stm32l0/src/bin/button.rs | 6 +++--- examples/stm32l0/src/bin/spi.rs | 4 ++-- examples/stm32l4/src/bin/blinky.rs | 4 ++-- examples/stm32l4/src/bin/button.rs | 6 +++--- examples/stm32l4/src/bin/spi.rs | 4 ++-- examples/stm32wb55/src/bin/blinky.rs | 4 ++-- 12 files changed, 37 insertions(+), 39 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 5c2b0f6fc..1bc5553a2 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -34,11 +34,11 @@ impl From for vals::Pupdr { #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Speed { - LowSpeed, - MediumSpeed, + Low, + Medium, #[cfg(not(syscfg_f0))] - HighSpeed, - VeryHighSpeed, + High, + VeryHigh, } impl From for vals::Ospeedr { @@ -46,11 +46,11 @@ impl From for vals::Ospeedr { use Speed::*; match speed { - LowSpeed => vals::Ospeedr::LOWSPEED, - MediumSpeed => vals::Ospeedr::MEDIUMSPEED, + Low => vals::Ospeedr::LOWSPEED, + Medium => vals::Ospeedr::MEDIUMSPEED, #[cfg(not(syscfg_f0))] - HighSpeed => vals::Ospeedr::HIGHSPEED, - VeryHighSpeed => vals::Ospeedr::VERYHIGHSPEED, + High => vals::Ospeedr::HIGHSPEED, + VeryHigh => vals::Ospeedr::VERYHIGHSPEED, } } } @@ -246,7 +246,7 @@ impl<'d, T: Pin> OutputPin for OutputOpenDrain<'d, T> { } } -impl<'d, T: Pin> InputPin for Input<'d, T> { +impl<'d, T: Pin> InputPin for OutputOpenDrain<'d, T> { type Error = Infallible; fn is_high(&self) -> Result { diff --git a/examples/stm32f4/src/bin/blinky.rs b/examples/stm32f4/src/bin/blinky.rs index 7590764d8..d2b607c2c 100644 --- a/examples/stm32f4/src/bin/blinky.rs +++ b/examples/stm32f4/src/bin/blinky.rs @@ -8,7 +8,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Level, Output}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embedded_hal::digital::v2::OutputPin; use example_common::*; @@ -40,7 +40,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut led = Output::new(p.PB7, Level::High); + let mut led = Output::new(p.PB7, Level::High, Speed::Low); loop { info!("high"); diff --git a/examples/stm32f4/src/bin/button.rs b/examples/stm32f4/src/bin/button.rs index 1ee99f527..c7160d219 100644 --- a/examples/stm32f4/src/bin/button.rs +++ b/examples/stm32f4/src/bin/button.rs @@ -8,7 +8,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Input, Level, Output, Pull}; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embedded_hal::digital::v2::{InputPin, OutputPin}; use example_common::*; @@ -41,9 +41,9 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let button = Input::new(p.PC13, Pull::Down); - let mut led1 = Output::new(p.PB0, Level::High); - let _led2 = Output::new(p.PB7, Level::High); - let mut led3 = Output::new(p.PB14, Level::High); + let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); + let _led2 = Output::new(p.PB7, Level::High, Speed::Low); + let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); loop { if button.is_high().unwrap() { diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index 610bb64e9..dda0ee4ed 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs @@ -9,7 +9,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Level, Output}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embedded_hal::digital::v2::OutputPin; use example_common::*; @@ -58,7 +58,7 @@ fn main() -> ! { Config::default(), ); - let mut cs = Output::new(p.PE0, Level::High); + let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); loop { let mut buf = [0x0A; 4]; diff --git a/examples/stm32h7/src/bin/blinky.rs b/examples/stm32h7/src/bin/blinky.rs index c425b7f8e..d9f891e49 100644 --- a/examples/stm32h7/src/bin/blinky.rs +++ b/examples/stm32h7/src/bin/blinky.rs @@ -8,15 +8,15 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Level, Output}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embedded_hal::digital::v2::OutputPin; use example_common::*; use cortex_m_rt::entry; use stm32h7::stm32h743 as pac; -use stm32h7xx_hal as hal; use hal::prelude::*; +use stm32h7xx_hal as hal; #[entry] fn main() -> ! { @@ -24,8 +24,7 @@ fn main() -> ! { let pp = pac::Peripherals::take().unwrap(); - let pwrcfg = pp.PWR.constrain() - .freeze(); + let pwrcfg = pp.PWR.constrain().freeze(); let rcc = pp.RCC.constrain(); @@ -60,7 +59,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut led = Output::new(p.PB14, Level::High); + let mut led = Output::new(p.PB14, Level::High, Speed::Low); loop { info!("high"); @@ -71,5 +70,4 @@ fn main() -> ! { led.set_low().unwrap(); cortex_m::asm::delay(10_000_000); } - } diff --git a/examples/stm32l0/src/bin/blinky.rs b/examples/stm32l0/src/bin/blinky.rs index ab0a2bdb2..833c14fbf 100644 --- a/examples/stm32l0/src/bin/blinky.rs +++ b/examples/stm32l0/src/bin/blinky.rs @@ -9,7 +9,7 @@ #[path = "../example_common.rs"] mod example_common; use embassy_stm32::{ - gpio::{Level, Output}, + gpio::{Level, Output, Speed}, rcc::*, }; use embedded_hal::digital::v2::OutputPin; @@ -25,7 +25,7 @@ fn main() -> ! { Rcc::new(p.RCC).enable_debug_wfe(&mut p.DBGMCU, true); - let mut led = Output::new(p.PB5, Level::High); + let mut led = Output::new(p.PB5, Level::High, Speed::Low); loop { info!("high"); diff --git a/examples/stm32l0/src/bin/button.rs b/examples/stm32l0/src/bin/button.rs index 04c48112a..5f46ec794 100644 --- a/examples/stm32l0/src/bin/button.rs +++ b/examples/stm32l0/src/bin/button.rs @@ -9,7 +9,7 @@ #[path = "../example_common.rs"] mod example_common; use embassy_stm32::{ - gpio::{Input, Level, Output, Pull}, + gpio::{Input, Level, Output, Pull, Speed}, rcc::*, }; use embedded_hal::digital::v2::{InputPin, OutputPin}; @@ -25,8 +25,8 @@ fn main() -> ! { Rcc::new(p.RCC).enable_debug_wfe(&mut p.DBGMCU, true); let button = Input::new(p.PB2, Pull::Up); - let mut led1 = Output::new(p.PA5, Level::High); - let mut led2 = Output::new(p.PB5, Level::High); + let mut led1 = Output::new(p.PA5, Level::High, Speed::Low); + let mut led2 = Output::new(p.PB5, Level::High, Speed::Low); loop { if button.is_high().unwrap() { diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs index 0e828c436..9bb9b741e 100644 --- a/examples/stm32l0/src/bin/spi.rs +++ b/examples/stm32l0/src/bin/spi.rs @@ -9,7 +9,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Level, Output}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embedded_hal::digital::v2::OutputPin; use example_common::*; @@ -36,7 +36,7 @@ fn main() -> ! { Config::default(), ); - let mut cs = Output::new(p.PA15, Level::High); + let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); loop { let mut buf = [0x0A; 4]; diff --git a/examples/stm32l4/src/bin/blinky.rs b/examples/stm32l4/src/bin/blinky.rs index 42c9333f4..ae4b3d1d1 100644 --- a/examples/stm32l4/src/bin/blinky.rs +++ b/examples/stm32l4/src/bin/blinky.rs @@ -8,7 +8,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Level, Output}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embedded_hal::digital::v2::OutputPin; use example_common::*; @@ -39,7 +39,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut led = Output::new(p.PB14, Level::High); + let mut led = Output::new(p.PB14, Level::High, Speed::Low); loop { info!("high"); diff --git a/examples/stm32l4/src/bin/button.rs b/examples/stm32l4/src/bin/button.rs index 962d5aa75..3efeee20f 100644 --- a/examples/stm32l4/src/bin/button.rs +++ b/examples/stm32l4/src/bin/button.rs @@ -8,7 +8,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Input, Level, Output, Pull}; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embedded_hal::digital::v2::{InputPin, OutputPin}; use example_common::*; @@ -40,8 +40,8 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let button = Input::new(p.PC13, Pull::Up); - let mut led1 = Output::new(p.PA5, Level::High); - let mut led2 = Output::new(p.PB14, Level::High); + let mut led1 = Output::new(p.PA5, Level::High, Speed::Low); + let mut led2 = Output::new(p.PB14, Level::High, Speed::Low); loop { if button.is_high().unwrap() { diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 7c672b70d..28c563c19 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs @@ -9,7 +9,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Level, Output}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embedded_hal::digital::v2::OutputPin; use example_common::*; @@ -52,7 +52,7 @@ fn main() -> ! { Config::default(), ); - let mut cs = Output::new(p.PE0, Level::High); + let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); loop { let mut buf = [0x0A; 4]; diff --git a/examples/stm32wb55/src/bin/blinky.rs b/examples/stm32wb55/src/bin/blinky.rs index 8ce78a3c3..d53ad611a 100644 --- a/examples/stm32wb55/src/bin/blinky.rs +++ b/examples/stm32wb55/src/bin/blinky.rs @@ -8,7 +8,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_stm32::gpio::{Level, Output}; +use embassy_stm32::gpio::{Level, Output, Speed}; use embedded_hal::digital::v2::OutputPin; use example_common::*; @@ -28,7 +28,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); - let mut led = Output::new(p.PB0, Level::High); + let mut led = Output::new(p.PB0, Level::High, Speed::Low); loop { info!("high"); From c5022b1196e45fb772d902fd0f4dbced2ef120eb Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sun, 27 Jun 2021 13:25:35 -0300 Subject: [PATCH 4/4] stm32: Make sure Output gpio driver is pushpull --- embassy-stm32/src/gpio.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 1bc5553a2..bf8400ca9 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -131,6 +131,7 @@ 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)); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); pin.set_speed(speed); });