-
Notifications
You must be signed in to change notification settings - Fork 182
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
Const generic GPIOs #343
Conversation
d0956bb
to
95ebb02
Compare
@TheZoq2 This is similar to the change landed in the |
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.
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
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)) }); | ||
} |
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.
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?
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.
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) |
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.
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?
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.
Maybe
|
||
impl<MODE> Mode<MODE> for Generic<MODE> {} | ||
/// Pin | ||
pub struct Pin<MODE, CR, const P: char, const N: u8> { |
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.
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
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.
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 |
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.
Where does this 0x41 come from?
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.
This is A
to 0
conversion.
} | ||
#[inline(always)] | ||
fn _is_set_low(&self) -> bool { | ||
unsafe { (*Gpio::<P>::ptr()).odr.read().bits() & (1 << N) == 0 } |
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.
Missing //NOTE(unsafe)
comment
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.
Ok
src/gpio.rs
Outdated
$PXi::<Output<PushPull>>::set_mode(cr) | ||
} | ||
} | ||
// embedded_hal impls |
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.
This comment looks wrong, we are not impl
ing embedded_hal
in this block, right?
} | ||
} | ||
// embedded_hal impls | ||
impl<MODE, CR, const P: char, const N: u8> Pin<Output<MODE>, CR, P, N> { |
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.
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.
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.
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 { |
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.
Maybe I'm misunderstanding things, but should this really be gpioa
, seems like this is more generic?
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.
Sorry. Didn't notice.
src/gpio.rs
Outdated
{ | ||
/// 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()) | ||
} |
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.
Why can these not use the set_mode
functions?
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.
Ok
Talking about erased pin we have alternative implementation for it: |
65b6fd2
to
0a376b5
Compare
@TheZoq2 Can we merge this now? |
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.
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" |
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.
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?
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.
Ok. I've removed last commit.
Is there an alternative for downgrade function?
|
No description provided.