-
Notifications
You must be signed in to change notification settings - Fork 226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open Drain Output #217
Open Drain Output #217
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,7 +3,7 @@ | |||||||||||||
//! Please take a look at the documentation for [`Pin`] for a detailed explanation. | ||||||||||||||
|
||||||||||||||
use core::marker::PhantomData; | ||||||||||||||
use embedded_hal::digital::v2::{OutputPin, InputPin}; | ||||||||||||||
use embedded_hal::digital::v2::{InputPin, OutputPin}; | ||||||||||||||
|
||||||||||||||
pub trait PinMode: crate::Sealed {} | ||||||||||||||
/// GPIO pin modes | ||||||||||||||
|
@@ -18,6 +18,12 @@ pub mod mode { | |||||||||||||
impl Io for Output {} | ||||||||||||||
impl crate::Sealed for Output {} | ||||||||||||||
|
||||||||||||||
// Pin is configures as a digital output with open drain behaviour | ||||||||||||||
pub struct OpenDrain; | ||||||||||||||
impl super::PinMode for OpenDrain {} | ||||||||||||||
impl Io for OpenDrain {} | ||||||||||||||
impl crate::Sealed for OpenDrain {} | ||||||||||||||
|
||||||||||||||
pub trait InputMode: crate::Sealed {} | ||||||||||||||
|
||||||||||||||
/// Pin is configured as digital input (floating or pulled-up). | ||||||||||||||
|
@@ -137,6 +143,28 @@ impl<PIN: PinOps, MODE: mode::Io> Pin<MODE, PIN> { | |||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Convert this pin into an output pin with open drain, setting the state to low | ||||||||||||||
/// See [Digital Output Open Drain](#digital-output-open-drain) | ||||||||||||||
pub fn into_opendrain(mut self) -> Pin<mode::OpenDrain, PIN> { | ||||||||||||||
unsafe { self.pin.out_clear() }; | ||||||||||||||
unsafe { self.pin.make_output() }; | ||||||||||||||
Pin { | ||||||||||||||
pin: self.pin, | ||||||||||||||
_mode: PhantomData, | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Convert this pin into an output pin with open drain, setting the state to tristate | ||||||||||||||
/// See [Digital Output Open Drain](#digital-output-open-drain) | ||||||||||||||
pub fn into_opendrain_tristate(mut self) -> Pin<mode::OpenDrain, PIN> { | ||||||||||||||
unsafe { self.pin.out_clear() }; | ||||||||||||||
unsafe { self.pin.make_input(false) }; | ||||||||||||||
Pin { | ||||||||||||||
pin: self.pin, | ||||||||||||||
_mode: PhantomData, | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Convert this pin into a floating input pin. See [Digital Input](#digital-input). | ||||||||||||||
/// | ||||||||||||||
/// *Note*: To read deterministic values from the pin, it must be externally pulled to a | ||||||||||||||
|
@@ -300,6 +328,65 @@ impl<PIN: PinOps> OutputPin for Pin<mode::Output, PIN> { | |||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// # Digital Output Open Drain | ||||||||||||||
impl<PIN: PinOps> Pin<mode::OpenDrain, PIN> { | ||||||||||||||
/// Set the pin to tristate mode (Input without PullUp) | ||||||||||||||
#[inline] | ||||||||||||||
pub fn set_tristate(&mut self) { | ||||||||||||||
unsafe { self.pin.make_input(false) } | ||||||||||||||
} | ||||||||||||||
Comment on lines
+333
to
+337
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To rephrase my previous comment: I think for the "open drain" mode, this method should be called
|
||||||||||||||
|
||||||||||||||
/// Set pin low (pull it to GND, Output to low). | ||||||||||||||
#[inline] | ||||||||||||||
pub fn set_low(&mut self) { | ||||||||||||||
unsafe { self.pin.make_output() } | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Check whether the pin is set high. | ||||||||||||||
/// | ||||||||||||||
/// *Note*: The electrical state of the pin might differ due to external circuitry. | ||||||||||||||
#[inline] | ||||||||||||||
pub fn is_set_high(&self) -> bool { | ||||||||||||||
unsafe { self.pin.in_get() } | ||||||||||||||
} | ||||||||||||||
Comment on lines
+345
to
+351
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The The correct implementation would be one checking the bit in the Unfortunately, |
||||||||||||||
|
||||||||||||||
/// Check whether the pin is set low. | ||||||||||||||
/// | ||||||||||||||
/// *Note*: The electrical state of the pin might differ due to external circuitry. | ||||||||||||||
#[inline] | ||||||||||||||
pub fn is_set_low(&self) -> bool { | ||||||||||||||
!unsafe { self.pin.in_get() } | ||||||||||||||
} | ||||||||||||||
Comment on lines
+357
to
+359
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following the above,
Suggested change
The compiler will optimize it to be equivalent to a handrolled implementation.
Comment on lines
+345
to
+359
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think what you actually wanted to do here is implement |
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Implements OutputPin from embedded-hal to make sure external libraries work | ||||||||||||||
impl<PIN: PinOps> OutputPin for Pin<mode::OpenDrain, PIN> { | ||||||||||||||
type Error = core::convert::Infallible; | ||||||||||||||
|
||||||||||||||
fn set_high(&mut self) -> Result<(), Self::Error> { | ||||||||||||||
self.set_tristate(); | ||||||||||||||
Ok(()) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
fn set_low(&mut self) -> Result<(), Self::Error> { | ||||||||||||||
self.set_low(); | ||||||||||||||
Ok(()) | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Implements InputPin from embedded-hal to make sure external libraries work | ||||||||||||||
impl<PIN: PinOps> InputPin for Pin<mode::OpenDrain, PIN> { | ||||||||||||||
type Error = core::convert::Infallible; | ||||||||||||||
|
||||||||||||||
fn is_high(&self) -> Result<bool, Self::Error> { | ||||||||||||||
Ok(self.is_set_high()) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
fn is_low(&self) -> Result<bool, Self::Error> { | ||||||||||||||
Ok(self.is_set_low()) | ||||||||||||||
} | ||||||||||||||
Comment on lines
+381
to
+387
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And these should then call |
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Implements InputPin from embedded-hal to make sure external libraries work | ||||||||||||||
impl<PIN: PinOps, IMODE: mode::InputMode> InputPin for Pin<mode::Input<IMODE>, PIN> { | ||||||||||||||
type Error = core::convert::Infallible; | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, this should then be
into_opendrain_high()
.