Skip to content

Commit 6950aad

Browse files
dimpoloburrbull
authored andcommitted
Add second downgrade function that removes both pin and port from the type.
1 parent 1f57503 commit 6950aad

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
106106
- Added support for CAN on additional models: STM32F412, STM32F413, STM32F415,
107107
STM32F417, STM32F423, STM32F427, STM32F429, STM32F437, STM32F439, STM32F469,
108108
and STM32F479 [#262]
109+
- Added `gpio::gpiox::Pxi::downgrade2` method [#272]
109110

110111
[#231]: https://github.com/stm32-rs/stm32f4xx-hal/pull/231
111112
[#262]: https://github.com/stm32-rs/stm32f4xx-hal/pull/262
112113
[#263]: https://github.com/stm32-rs/stm32f4xx-hal/pull/263
113114
[#278]: https://github.com/stm32-rs/stm32f4xx-hal/issues/278
114115
[#273]: https://github.com/stm32-rs/stm32f4xx-hal/pull/273
115116
[#286]: https://github.com/stm32-rs/stm32f4xx-hal/pull/286
117+
[#272]: https://github.com/stm32-rs/stm32f4xx-hal/issues/272
116118

117119
### Fixed
118120

src/gpio.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use core::marker::PhantomData;
44

5+
use embedded_hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin};
6+
57
use crate::pac::EXTI;
68
use crate::syscfg::SysCfg;
79

@@ -745,6 +747,14 @@ macro_rules! gpio {
745747
_mode: self._mode,
746748
}
747749
}
750+
751+
/// Erases the pin number and the port from the type
752+
///
753+
/// This is useful when you want to collect the pins into an array where you
754+
/// need all the elements to have the same type
755+
pub fn downgrade2(self) -> super::Pin<MODE>{
756+
super::Pin::new($port_id, $i)
757+
}
748758
}
749759

750760
impl<MODE> OutputPin for $PXi<Output<MODE>> {
@@ -1037,3 +1047,109 @@ gpio!(GPIOK, gpiok, PK, 10, [
10371047
PK6: (pk6, 6, Input<Floating>),
10381048
PK7: (pk7, 7, Input<Floating>),
10391049
]);
1050+
1051+
/// Fully erased pin
1052+
pub struct Pin<MODE> {
1053+
// Bits 0-3: Pin, Bits 4-7: Port
1054+
pin_port: u8,
1055+
_mode: PhantomData<MODE>,
1056+
}
1057+
1058+
impl<MODE> PinExt for Pin<MODE> {
1059+
type Mode = MODE;
1060+
1061+
#[inline(always)]
1062+
fn pin_id(&self) -> u8 {
1063+
self.pin_port & 0x0f
1064+
}
1065+
#[inline(always)]
1066+
fn port_id(&self) -> u8 {
1067+
self.pin_port >> 4
1068+
}
1069+
}
1070+
1071+
impl<MODE> Pin<MODE> {
1072+
fn new(port: u8, pin: u8) -> Self {
1073+
Self {
1074+
pin_port: port << 4 | pin,
1075+
_mode: PhantomData,
1076+
}
1077+
}
1078+
1079+
#[inline]
1080+
fn block(&self) -> &crate::pac::gpioa::RegisterBlock {
1081+
// This function uses pointer arithmetic instead of branching to be more efficient
1082+
1083+
// The logic relies on the following assumptions:
1084+
// - GPIOA register is available on all chips
1085+
// - all gpio register blocks have the same layout
1086+
// - consecutive gpio register blocks have the same offset between them, namely 0x0400
1087+
// - Pin::new was called with a valid port
1088+
1089+
// FIXME could be calculated after const_raw_ptr_to_usize_cast stabilization #51910
1090+
const GPIO_REGISTER_OFFSET: usize = 0x0400;
1091+
1092+
let offset = GPIO_REGISTER_OFFSET * self.port_id() as usize;
1093+
let block_ptr =
1094+
(crate::pac::GPIOA::ptr() as usize + offset) as *const crate::pac::gpioa::RegisterBlock;
1095+
1096+
unsafe { &*block_ptr }
1097+
}
1098+
}
1099+
1100+
impl<MODE> OutputPin for Pin<Output<MODE>> {
1101+
type Error = core::convert::Infallible;
1102+
1103+
fn set_low(&mut self) -> Result<(), Self::Error> {
1104+
// NOTE(unsafe) atomic write to a stateless register
1105+
unsafe {
1106+
self.block()
1107+
.bsrr
1108+
.write(|w| w.bits(1 << (self.pin_id() + 16)))
1109+
};
1110+
Ok(())
1111+
}
1112+
1113+
fn set_high(&mut self) -> Result<(), Self::Error> {
1114+
// NOTE(unsafe) atomic write to a stateless register
1115+
unsafe { self.block().bsrr.write(|w| w.bits(1 << self.pin_id())) };
1116+
Ok(())
1117+
}
1118+
}
1119+
1120+
impl<MODE> StatefulOutputPin for Pin<Output<MODE>> {
1121+
fn is_set_high(&self) -> Result<bool, Self::Error> {
1122+
self.is_set_low().map(|v| !v)
1123+
}
1124+
1125+
fn is_set_low(&self) -> Result<bool, Self::Error> {
1126+
// NOTE(unsafe) atomic read with no side effects
1127+
Ok(self.block().odr.read().bits() & (1 << self.pin_id()) == 0)
1128+
}
1129+
}
1130+
1131+
impl<MODE> toggleable::Default for Pin<Output<MODE>> {}
1132+
1133+
impl<MODE> InputPin for Pin<Output<MODE>> {
1134+
type Error = core::convert::Infallible;
1135+
1136+
fn is_high(&self) -> Result<bool, Self::Error> {
1137+
self.is_low().map(|v| !v)
1138+
}
1139+
1140+
fn is_low(&self) -> Result<bool, Self::Error> {
1141+
Ok(self.block().idr.read().bits() & (1 << self.pin_id()) == 0)
1142+
}
1143+
}
1144+
1145+
impl<MODE> InputPin for Pin<Input<MODE>> {
1146+
type Error = core::convert::Infallible;
1147+
1148+
fn is_high(&self) -> Result<bool, Self::Error> {
1149+
self.is_low().map(|v| !v)
1150+
}
1151+
1152+
fn is_low(&self) -> Result<bool, Self::Error> {
1153+
Ok(self.block().idr.read().bits() & (1 << self.pin_id()) == 0)
1154+
}
1155+
}

0 commit comments

Comments
 (0)