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

Const generic GPIOs #343

Merged
merged 12 commits into from
Jul 26, 2021
Merged

Const generic GPIOs #343

merged 12 commits into from
Jul 26, 2021

Conversation

burrbull
Copy link
Member

@burrbull burrbull commented Jul 9, 2021

No description provided.

@burrbull burrbull mentioned this pull request Jul 9, 2021
@burrbull burrbull force-pushed the cg-gpio2 branch 8 times, most recently from d0956bb to 95ebb02 Compare July 10, 2021 13:42
@burrbull burrbull mentioned this pull request Jul 10, 2021
@therealprof
Copy link
Member

@TheZoq2 This is similar to the change landed in the stm32f4xx-hal and to me it marks a huge improvement. What's your opinion?

Copy link
Member

@TheZoq2 TheZoq2 left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, as you can probably tell I've been distracted by other things.

Looks like a nice change overall, I left some review comments for the main gpio.rs file. I don't really have the energy to review the erased and partially erased files right now since it's 10:30 pm, I'll see if I can get that done tomorrow

src/gpio.rs Outdated
Comment on lines 242 to 263
let i = self.pin_id();
match edge {
Edge::RISING => {
exti.rtsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
exti.ftsr
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
}
Edge::FALLING => {
exti.ftsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
exti.rtsr
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
}
Edge::RISING_FALLING => {
exti.rtsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
exti.ftsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
}
Copy link
Member

Choose a reason for hiding this comment

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

Looks like we now use a runtime value determine the constant to write, is that constant folded away? I.e. is the compiler smart enough to figure out that self.pin_id is constant?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, compiler optimize out this match to same code as before in release mode.

src/gpio.rs Outdated
Ok(unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 })
impl<MODE> PEPin<MODE, $port_id> {
pub fn erase(self) -> EPin<MODE> {
EPin::$PXx(self)
Copy link
Member

Choose a reason for hiding this comment

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

I don't really like calling this EPin, to me, it's not obvious that that stands for erased pin, should we just call it ErasedPin instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe


impl<MODE> Mode<MODE> for Generic<MODE> {}
/// Pin
pub struct Pin<MODE, CR, const P: char, const N: u8> {
Copy link
Member

Choose a reason for hiding this comment

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

Another naming question: Should we stick with P and N here, or just write out Port and Number. The latter is clearly more verbose, but also makes it less ambiguous

Copy link
Member Author

Choose a reason for hiding this comment

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

It will be too long to use it everywhere. I will add it to docs better.

src/gpio.rs Outdated
}
#[inline(always)]
fn port_id(&self) -> u8 {
P as u8 - 0x41
Copy link
Member

Choose a reason for hiding this comment

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

Where does this 0x41 come from?

Copy link
Member Author

@burrbull burrbull Jul 13, 2021

Choose a reason for hiding this comment

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

This is A to 0 conversion.

}
#[inline(always)]
fn _is_set_low(&self) -> bool {
unsafe { (*Gpio::<P>::ptr()).odr.read().bits() & (1 << N) == 0 }
Copy link
Member

Choose a reason for hiding this comment

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

Missing //NOTE(unsafe) comment

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok

src/gpio.rs Outdated
$PXi::<Output<PushPull>>::set_mode(cr)
}
}
// embedded_hal impls
Copy link
Member

Choose a reason for hiding this comment

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

This comment looks wrong, we are not impling embedded_hal in this block, right?

}
}
// embedded_hal impls
impl<MODE, CR, const P: char, const N: u8> Pin<Output<MODE>, CR, P, N> {
Copy link
Member

Choose a reason for hiding this comment

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

I haven't tested this, but what happens if you use embedded_hal::digital::v2::OutputPin, will the compiler not throw an "ambiguous function call error" since we have both the local set_high and the OutputPin set_high in scope.

Is this a problem? Not having to unwrap certainly has its advantages, but at the same time, it would make code like

use embedded_hal::digital::v2::OutputPin;

fn generic_fn(pin: impl OutputPin) {
    // ...
}

fn main() {
    let pin = // get a pin
    pin.set_high(); // Now ambiguous?
}

break, which might be confusing if the generic stuff is added later in a project.

Ok, I tested it in the playground and it seems like this is a non-issue. I guess I'm not entirely sure how method resolution works in rust.. I'll leave this comment here in case it is an issue in this case, but feel free to ignore it.

Copy link
Member Author

Choose a reason for hiding this comment

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

The inherent methods on type are always preferred than that from traits.
This trick was discussed on matrix where we were decided to use only fallible traits in embedded-hal.

impl<const P: char> Cr<$CR, P> {
// NOTE(allow) we get a warning on GPIOC because it only has 3 high pins
#[allow(dead_code)]
pub(crate) fn cr(&mut self) -> &pac::gpioa::$CR {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe I'm misunderstanding things, but should this really be gpioa, seems like this is more generic?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry. Didn't notice.

src/gpio.rs Outdated
Comment on lines 686 to 711
{
/// Configures the pin to operate as an alternate function push-pull output
/// pin.
#[inline]
pub fn into_alternate_push_pull(
self,
cr: &mut Cr<$CR, P>,
) -> Pin<Alternate<PushPull>, $CR, P, N> {
// Alternate function output push pull
const CNF: u32 = 0b10;
// Output mode, max speed 50 MHz
const MODE: u32 = 0b11;
const BITS: u32 = (CNF << 2) | MODE;

// input mode
cr.cr().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET))
});

Pin::new(Alternate::_new())
}

cr.cr().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b11 << OFFSET)) | ((speed as u32) << OFFSET))
});
}
}
/// Configures the pin to operate as an alternate function open-drain output
/// pin.
#[inline]
pub fn into_alternate_open_drain(
self,
cr: &mut Cr<$CR, P>,
) -> Pin<Alternate<OpenDrain>, $CR, P, N> {
// Alternate function output open drain
const CNF: u32 = 0b11;
// Output mode, max speed 50 MHz
const MODE: u32 = 0b11;
const BITS: u32 = (CNF << 2) | MODE;

// input mode
cr.cr().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET))
});

Pin::new(Alternate::_new())
}
Copy link
Member

Choose a reason for hiding this comment

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

Why can these not use the set_mode functions?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok

@burrbull
Copy link
Member Author

Talking about erased pin we have alternative implementation for it:
https://github.com/stm32-rs/stm32f4xx-hal/blob/master/src/gpio/erased.rs
It is not same beautiful but should be more optimized.

@burrbull burrbull force-pushed the cg-gpio2 branch 2 times, most recently from 65b6fd2 to 0a376b5 Compare July 14, 2021 08:31
@burrbull burrbull mentioned this pull request Jul 14, 2021
@burrbull
Copy link
Member Author

@TheZoq2 Can we merge this now?

Copy link
Member

@TheZoq2 TheZoq2 left a comment

Choose a reason for hiding this comment

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

I don't think we should add external crates for dependencies, apart from that I think this looks good

Cargo.toml Outdated
@@ -52,6 +52,7 @@ mfrc522 = "0.2.0"
serde_derive = "1.0.90"
usb-device = "0.2.3"
usbd-serial = "0.1.0"
hd44780-driver = "0.4.0"
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should depend on crates just for examples, compile times etc. get way worse that way

I think we have had some discussions on this before, perhaps a stm32f1xx_examples repo would be in order?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok. I've removed last commit.

@TheZoq2 TheZoq2 merged commit afe280c into stm32-rs:master Jul 26, 2021
@talhaHavadar
Copy link

talhaHavadar commented Sep 26, 2021

Is there an alternative for downgrade function?

  • Found it already 👍 (ErasedPin)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants