@@ -145,8 +145,8 @@ pub trait ExtiPin {
145
145
macro_rules! gpio {
146
146
( $GPIOX: ident, $gpiox: ident, $gpio_doc: expr,
147
147
$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
+ ] ) => {
150
150
#[ doc=$gpio_doc]
151
151
pub mod $gpiox {
152
152
use core:: marker:: PhantomData ;
@@ -161,7 +161,7 @@ macro_rules! gpio {
161
161
Alternate , Floating , GpioExt , Input , OpenDrain ,
162
162
Output , Speed , PullDown , PullUp , PushPull , AF0 , AF1 ,
163
163
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 , } ;
165
165
166
166
use crate :: Never ;
167
167
@@ -542,7 +542,7 @@ macro_rules! gpio {
542
542
( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
543
543
w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
544
544
}
545
- ) } ;
545
+ ) } ;
546
546
547
547
$PXi { _mode: PhantomData }
548
548
}
@@ -598,7 +598,7 @@ macro_rules! gpio {
598
598
( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
599
599
w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b11 << offset) )
600
600
}
601
- ) } ;
601
+ ) } ;
602
602
603
603
$PXi { _mode: PhantomData }
604
604
}
@@ -676,6 +676,19 @@ macro_rules! gpio {
676
676
}
677
677
678
678
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
+
679
692
/// Erases the pin number from the type
680
693
///
681
694
/// This is useful when you want to collect the
@@ -768,7 +781,7 @@ macro_rules! gpio {
768
781
}
769
782
770
783
impl IoPin <Self , Self >
771
- for $PXi<Output <OpenDrain >>
784
+ for $PXi<Output <OpenDrain >>
772
785
{
773
786
type Error = Never ;
774
787
fn into_input_pin( self ) -> Result <Self , Never > {
@@ -1090,3 +1103,272 @@ gpio!(GPIOK, gpiok, "Port K", Gpiok, PK, 10, [
1090
1103
PK14 : ( pk14, 14 , Analog , exticr4) ,
1091
1104
PK15 : ( pk15, 15 , Analog , exticr4) ,
1092
1105
] ) ;
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