Skip to content

Commit f11894e

Browse files
committed
Add erased pin variant
1 parent 7905ce9 commit f11894e

File tree

1 file changed

+288
-6
lines changed

1 file changed

+288
-6
lines changed

src/gpio.rs

Lines changed: 288 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ pub trait ExtiPin {
145145
macro_rules! gpio {
146146
($GPIOX:ident, $gpiox:ident, $gpio_doc:expr,
147147
$Rec:ident, $PXx:ident, $extigpionr:expr, [
148-
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $exticri:ident),)+
149-
]) => {
148+
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $exticri:ident),)+
149+
]) => {
150150
#[doc=$gpio_doc]
151151
pub mod $gpiox {
152152
use core::marker::PhantomData;
@@ -161,7 +161,7 @@ macro_rules! gpio {
161161
Alternate, Floating, GpioExt, Input, OpenDrain,
162162
Output, Speed, PullDown, PullUp, PushPull, AF0, AF1,
163163
AF2, AF3, AF4, AF5, AF6, AF7, AF8, AF9, AF10, AF11,
164-
AF12, AF13, AF14, AF15, Analog, Edge, ExtiPin, };
164+
AF12, AF13, AF14, AF15, Analog, Edge, ExtiPin, erased::ErasedPin, };
165165

166166
use crate::Never;
167167

@@ -542,7 +542,7 @@ macro_rules! gpio {
542542
(*$GPIOX::ptr()).moder.modify(|r, w| {
543543
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
544544
}
545-
)};
545+
)};
546546

547547
$PXi { _mode: PhantomData }
548548
}
@@ -598,7 +598,7 @@ macro_rules! gpio {
598598
(*$GPIOX::ptr()).moder.modify(|r, w| {
599599
w.bits((r.bits() & !(0b11 << offset)) | (0b11 << offset))
600600
}
601-
)};
601+
)};
602602

603603
$PXi { _mode: PhantomData }
604604
}
@@ -676,6 +676,19 @@ macro_rules! gpio {
676676
}
677677

678678
impl<MODE> $PXi<MODE> {
679+
/// Erases both the pin number and port from the type
680+
///
681+
/// This is useful when you want to collect the
682+
/// pins into an array where you need all the
683+
/// elements to have the same type
684+
pub fn erase(&self) -> ErasedPin<MODE> {
685+
ErasedPin::new($extigpionr, $i)
686+
// ErasedPin {
687+
// pin_port: $extigpionr << 4 | $i,
688+
// _mode: self._mode,
689+
// }
690+
}
691+
679692
/// Erases the pin number from the type
680693
///
681694
/// This is useful when you want to collect the
@@ -768,7 +781,7 @@ macro_rules! gpio {
768781
}
769782

770783
impl IoPin<Self, Self>
771-
for $PXi<Output<OpenDrain>>
784+
for $PXi<Output<OpenDrain>>
772785
{
773786
type Error = Never;
774787
fn into_input_pin(self) -> Result<Self, Never> {
@@ -1090,3 +1103,272 @@ gpio!(GPIOK, gpiok, "Port K", Gpiok, PK, 10, [
10901103
PK14: (pk14, 14, Analog, exticr4),
10911104
PK15: (pk15, 15, Analog, exticr4),
10921105
]);
1106+
1107+
pub mod erased {
1108+
use super::{
1109+
Alternate, Analog, Floating, Input, OpenDrain, Output, PullDown,
1110+
PullUp, PushPull,
1111+
};
1112+
use crate::Never;
1113+
use core::marker::PhantomData;
1114+
use embedded_hal::digital::v2::{
1115+
toggleable, InputPin, OutputPin, StatefulOutputPin,
1116+
};
1117+
pub type EPin<MODE> = ErasedPin<MODE>;
1118+
1119+
/// Fully erased pin
1120+
///
1121+
/// `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section).
1122+
pub struct ErasedPin<MODE> {
1123+
// Bits 0-3: Pin, Bits 4-7: Port
1124+
pin_port: u8,
1125+
_mode: PhantomData<MODE>,
1126+
}
1127+
1128+
impl<MODE> ErasedPin<MODE> {
1129+
pub(crate) fn new(port: u8, pin: u8) -> Self {
1130+
Self {
1131+
pin_port: port << 4 | pin,
1132+
_mode: PhantomData,
1133+
}
1134+
}
1135+
1136+
#[inline(always)]
1137+
fn pin_id(&self) -> u8 {
1138+
self.pin_port & 0x0f
1139+
}
1140+
#[inline(always)]
1141+
fn port_id(&self) -> u8 {
1142+
self.pin_port >> 4
1143+
}
1144+
1145+
#[inline]
1146+
fn block(&self) -> &crate::pac::gpioa::RegisterBlock {
1147+
// This function uses pointer arithmetic instead of branching to be more efficient
1148+
1149+
// The logic relies on the following assumptions:
1150+
// - GPIOA register is available on all chips
1151+
// - all gpio register blocks have the same layout
1152+
// - consecutive gpio register blocks have the same offset between them, namely 0x0400
1153+
// - ErasedPin::new was called with a valid port
1154+
1155+
// FIXME could be calculated after const_raw_ptr_to_usize_cast stabilization #51910
1156+
const GPIO_REGISTER_OFFSET: usize = 0x0400;
1157+
1158+
let offset = GPIO_REGISTER_OFFSET * self.port_id() as usize;
1159+
let block_ptr = (crate::pac::GPIOA::ptr() as usize + offset)
1160+
as *const crate::pac::gpioa::RegisterBlock;
1161+
1162+
unsafe { &*block_ptr }
1163+
}
1164+
1165+
/// Configures the pin to operate as a floating
1166+
/// input pin
1167+
pub fn into_floating_input(self) -> EPin<Input<Floating>> {
1168+
let offset = 2 * self.pin_id();
1169+
let block = self.block();
1170+
1171+
unsafe {
1172+
block.pupdr.modify(|r, w| {
1173+
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
1174+
});
1175+
block.moder.modify(|r, w| {
1176+
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
1177+
})
1178+
};
1179+
1180+
EPin {
1181+
pin_port: self.pin_port,
1182+
_mode: PhantomData,
1183+
}
1184+
}
1185+
1186+
/// Configures the pin to operate as a pulled down
1187+
/// input pin
1188+
pub fn into_pull_down_input(self) -> EPin<Input<PullDown>> {
1189+
let offset = 2 * self.pin_id();
1190+
let block = self.block();
1191+
1192+
unsafe {
1193+
block.pupdr.modify(|r, w| {
1194+
w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
1195+
});
1196+
block.moder.modify(|r, w| {
1197+
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
1198+
})
1199+
};
1200+
1201+
EPin {
1202+
pin_port: self.pin_port,
1203+
_mode: PhantomData,
1204+
}
1205+
}
1206+
1207+
/// Configures the pin to operate as a pulled up
1208+
/// input pin
1209+
pub fn into_pull_up_input(self) -> EPin<Input<PullUp>> {
1210+
let offset = 2 * self.pin_id();
1211+
let block = self.block();
1212+
1213+
unsafe {
1214+
block.pupdr.modify(|r, w| {
1215+
w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
1216+
});
1217+
block.moder.modify(|r, w| {
1218+
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
1219+
})
1220+
};
1221+
1222+
EPin {
1223+
pin_port: self.pin_port,
1224+
_mode: PhantomData,
1225+
}
1226+
}
1227+
1228+
/// Configures the pin to operate as an open drain
1229+
/// output pin
1230+
pub fn into_open_drain_output(self) -> EPin<Output<OpenDrain>> {
1231+
let offset = 2 * self.pin_id();
1232+
let block = self.block();
1233+
1234+
unsafe {
1235+
block.pupdr.modify(|r, w| {
1236+
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
1237+
});
1238+
block
1239+
.otyper
1240+
.modify(|r, w| w.bits(r.bits() | (0b1 << self.pin_id())));
1241+
block.moder.modify(|r, w| {
1242+
w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
1243+
})
1244+
};
1245+
1246+
EPin {
1247+
pin_port: self.pin_port,
1248+
_mode: PhantomData,
1249+
}
1250+
}
1251+
1252+
/// Configures the pin to operate as an push pull
1253+
/// output pin
1254+
pub fn into_push_pull_output(self) -> EPin<Output<PushPull>> {
1255+
let offset = 2 * self.pin_id();
1256+
let block = self.block();
1257+
1258+
unsafe {
1259+
block.pupdr.modify(|r, w| {
1260+
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
1261+
});
1262+
block
1263+
.otyper
1264+
.modify(|r, w| w.bits(r.bits() & !(0b1 << self.pin_id())));
1265+
block.moder.modify(|r, w| {
1266+
w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
1267+
})
1268+
};
1269+
1270+
EPin {
1271+
pin_port: self.pin_port,
1272+
_mode: PhantomData,
1273+
}
1274+
}
1275+
1276+
/// Configures the pin to operate as an analog
1277+
/// input pin
1278+
pub fn into_analog(self) -> EPin<Analog> {
1279+
let offset = 2 * self.pin_id();
1280+
let block = self.block();
1281+
1282+
unsafe {
1283+
block.pupdr.modify(|r, w| {
1284+
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
1285+
});
1286+
block.moder.modify(|r, w| {
1287+
w.bits((r.bits() & !(0b11 << offset)) | (0b11 << offset))
1288+
})
1289+
};
1290+
1291+
EPin {
1292+
pin_port: self.pin_port,
1293+
_mode: PhantomData,
1294+
}
1295+
}
1296+
}
1297+
1298+
impl<MODE> OutputPin for ErasedPin<Output<MODE>> {
1299+
type Error = Never;
1300+
1301+
#[inline(always)]
1302+
fn set_high(&mut self) -> Result<(), Never> {
1303+
// NOTE(unsafe) atomic write to a stateless register
1304+
unsafe { self.block().bsrr.write(|w| w.bits(1 << self.pin_id())) };
1305+
Ok(())
1306+
}
1307+
1308+
#[inline(always)]
1309+
fn set_low(&mut self) -> Result<(), Never> {
1310+
// NOTE(unsafe) atomic write to a stateless register
1311+
unsafe {
1312+
self.block()
1313+
.bsrr
1314+
.write(|w| w.bits(1 << (self.pin_id() + 16)))
1315+
};
1316+
Ok(())
1317+
}
1318+
}
1319+
1320+
impl<MODE> StatefulOutputPin for ErasedPin<Output<MODE>> {
1321+
#[inline(always)]
1322+
fn is_set_high(&self) -> Result<bool, Never> {
1323+
self.is_set_low().map(|x| !x)
1324+
}
1325+
1326+
#[inline(always)]
1327+
fn is_set_low(&self) -> Result<bool, Never> {
1328+
Ok(self.block().odr.read().bits() & (1 << self.pin_id()) == 0)
1329+
}
1330+
}
1331+
1332+
impl<MODE> toggleable::Default for ErasedPin<Output<MODE>> {}
1333+
impl<MODE> InputPin for ErasedPin<Output<MODE>> {
1334+
type Error = Never;
1335+
1336+
#[inline(always)]
1337+
fn is_high(&self) -> Result<bool, Never> {
1338+
self.is_low().map(|x| !x)
1339+
}
1340+
1341+
#[inline(always)]
1342+
fn is_low(&self) -> Result<bool, Never> {
1343+
Ok(self.block().idr.read().bits() & (1 << self.pin_id()) == 0)
1344+
}
1345+
}
1346+
1347+
impl<MODE> InputPin for ErasedPin<Input<MODE>> {
1348+
type Error = Never;
1349+
1350+
#[inline(always)]
1351+
fn is_high(&self) -> Result<bool, Never> {
1352+
self.is_low().map(|x| !x)
1353+
}
1354+
1355+
#[inline(always)]
1356+
fn is_low(&self) -> Result<bool, Never> {
1357+
Ok(self.block().idr.read().bits() & (1 << self.pin_id()) == 0)
1358+
}
1359+
}
1360+
1361+
impl<MODE> InputPin for ErasedPin<Alternate<MODE>> {
1362+
type Error = Never;
1363+
1364+
#[inline(always)]
1365+
fn is_high(&self) -> Result<bool, Never> {
1366+
self.is_low().map(|x| !x)
1367+
}
1368+
1369+
#[inline(always)]
1370+
fn is_low(&self) -> Result<bool, Never> {
1371+
Ok(self.block().idr.read().bits() & (1 << self.pin_id()) == 0)
1372+
}
1373+
}
1374+
}

0 commit comments

Comments
 (0)