From c8461709e39621a04edcb9c12a5652aa6181d6da Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 13 May 2022 15:19:03 +0200 Subject: [PATCH 1/2] Add open-drain support for embassy-rp This commit adds open-drain support for embassy-rp by adding a new type named embassy_rp::gpio::OutputOpenDrain. --- embassy-rp/src/gpio.rs | 84 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 5fdb2b0c6..79f3a600e 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -86,7 +86,6 @@ pub struct Output<'d, T: Pin> { } impl<'d, T: Pin> Output<'d, T> { - // TODO opendrain pub fn new(pin: impl Unborrow + 'd, initial_output: Level) -> Self { unborrow!(pin); @@ -155,6 +154,89 @@ impl<'d, T: Pin> Drop for Output<'d, T> { } } +/// GPIO output open-drain. +pub struct OutputOpenDrain<'d, T: Pin> { + pin: T, + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: Pin> OutputOpenDrain<'d, T> { + #[inline] + pub fn new(pin: impl Unborrow + 'd, initial_output: Level) -> Self { + unborrow!(pin); + + unsafe { + let val = 1 << pin.pin(); + pin.io().ctrl().write(|w| { + w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::SIO_0.0); + }); + pin.sio_out().value_clr().write_value(val); + + match initial_output { + Level::High => { + // For Open Drain High, disable the output pin. + pin.sio_oe().value_clr().write_value(val); + } + Level::Low => { + // For Open Drain Low, enable the output pin. + pin.sio_oe().value_set().write_value(val); + } + } + } + + Self { + pin, + phantom: PhantomData, + } + } + + /// Set the output as high. + #[inline] + pub fn set_high(&mut self) { + // For Open Drain High, disable the output pin. + unsafe { + self.pin + .sio_oe() + .value_clr() + .write_value(1 << self.pin.pin()); + } + } + + /// Set the output as low. + #[inline] + pub fn set_low(&mut self) { + // For Open Drain Low, enable the output pin. + unsafe { + self.pin + .sio_oe() + .value_set() + .write_value(1 << self.pin.pin()); + } + } + + /// Is the output level high? + #[inline] + pub fn is_set_high(&self) -> bool { + let val = 1 << self.pin.pin(); + unsafe { (self.pin.sio_oe().value().read() & val) == 0 } + } + + /// Is the output level low? + #[inline] + pub fn is_set_low(&self) -> bool { + !self.is_set_high() + } + + /// Toggle pin output + #[inline] + pub fn toggle(&mut self) { + let val = 1 << self.pin.pin(); + unsafe { + self.pin.sio_out().value_xor().write_value(val); + } + } +} + pub(crate) mod sealed { use super::*; From 027ab3371ea85d68c7fc02da69e29924b53aa087 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 19 May 2022 05:43:18 +0200 Subject: [PATCH 2/2] Impl OutputPin/StatefulOutputPin/ToggleableOutputPin This commit implements embedded_hal_02::digital::v2 OutputPin, StatefulOutputPin, and ToggleableOutputPin for embassy-rp. --- embassy-rp/src/gpio.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 79f3a600e..12b9f6aca 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -404,6 +404,38 @@ mod eh02 { Ok(self.toggle()) } } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, T> { + type Error = Infallible; + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } + + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d, T> { + type Error = Infallible; + #[inline] + fn toggle(&mut self) -> Result<(), Self::Error> { + Ok(self.toggle()) + } + } } #[cfg(feature = "unstable-traits")]