Skip to content
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

WIP: add InputPin trait to output pins #88

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 27 additions & 18 deletions src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,26 +546,22 @@ macro_rules! gpio {
}

/// Configures the pin to operate as an open drain output pin
pub fn into_open_drain_output(
self,
moder: &mut MODER,
otyper: &mut OTYPER,
) -> $PXi<Output<OpenDrain>> {
let offset = 2 * $i;

// general purpose output mode
let mode = 0b01;
moder.moder().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
pub fn into_open_drain_output(self) -> $PXi<Output<OpenDrain>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking changes in itself are fine. But changing only this, would mean other parts which take the moder and otyper register must be changed as well, to make it coherent.

We had a discussion about this a while ago in #37. I've no opinion on this, but I'd rather tackle that as whole in another PR :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, we should do this in a separate PR.

But also this implementation here is not safe. The reason we pass &mut references for the relevant GPIO registers in is that this way we can ensure (at compile time) that we have exclusive access to them. We need this, because otherwise race conditions can happen, as explained in #37. To make this safe we'd need something else that ensures exclusive access, like a critical section.

let offset = 2 * $i;
unsafe {
&(*$GPIOX::ptr()).pupdr.modify(|r, w| {
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
});
&(*$GPIOX::ptr()).otyper.modify(|r, w| {
w.bits(r.bits() | (0b1 << $i))
});
&(*$GPIOX::ptr()).moder.modify(|r, w| {
w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
})
};

// open drain output
otyper
.otyper()
.modify(|r, w| unsafe { w.bits(r.bits() | (0b1 << $i)) });

$PXi { _mode: PhantomData }
}
$PXi { _mode: PhantomData }
}

/// Configures the pin to operate as an push pull output pin
pub fn into_push_pull_output(
Expand Down Expand Up @@ -699,6 +695,19 @@ macro_rules! gpio {

#[cfg(feature = "unproven")]
impl<MODE> toggleable::Default for $PXi<Output<MODE>> {}

impl<MODE> InputPin for $PXi<Output<MODE>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost done, this also has to be implemented at line 231 for PXx which is a "fully reased pin", line 425 $PXx, which is a partially erase pin. :) The implementation is almost the same. The compiler will scream the difference to you, or you could look at the other implementations 😉

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nitpick: I think I would move this below

                    impl<MODE> OutputPin for $PXi<Output<MODE>> {

at line 668, because this is another implementation for Output, so this position would make more sense.

type Error = ();

fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}

fn is_low(&self) -> Result<bool, Self::Error> {
// NOTE(unsafe) atomic read with no side effects
Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 })
}
}
)+
Comment on lines +700 to 711
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type Error = ();
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&self) -> Result<bool, Self::Error> {
// NOTE(unsafe) atomic read with no side effects
Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 })
}
}
)+
type Error = ();
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&self) -> Result<bool, Self::Error> {
// NOTE(unsafe) atomic read with no side effects
Ok(unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 })
}
}
)+

Indentation is wrong. I wonder why rustfmt did not complaint 🤔

}
)+
Expand Down