@@ -41,6 +41,63 @@ pub struct Output<MODE> {
41
41
/// Push pull output (type state)
42
42
pub struct PushPull ;
43
43
44
+ mod sealed {
45
+ pub trait Sealed { }
46
+ }
47
+
48
+ /// Marker trait for valid pin modes (type state).
49
+ ///
50
+ /// It can not be implemented by outside types.
51
+ pub trait PinMode : sealed:: Sealed {
52
+ // These constants are used to implement the pin configuration code.
53
+ // They are not part of public API.
54
+
55
+ #[ doc( hidden) ]
56
+ const PUPDR : u8 ;
57
+ #[ doc( hidden) ]
58
+ const MODER : u8 ;
59
+ #[ doc( hidden) ]
60
+ const OTYPER : Option < u8 > = None ;
61
+ }
62
+
63
+ impl sealed:: Sealed for Input < Floating > { }
64
+ impl PinMode for Input < Floating > {
65
+ const PUPDR : u8 = 0b00 ;
66
+ const MODER : u8 = 0b00 ;
67
+ }
68
+
69
+ impl sealed:: Sealed for Input < PullDown > { }
70
+ impl PinMode for Input < PullDown > {
71
+ const PUPDR : u8 = 0b10 ;
72
+ const MODER : u8 = 0b00 ;
73
+ }
74
+
75
+ impl sealed:: Sealed for Input < PullUp > { }
76
+ impl PinMode for Input < PullUp > {
77
+ const PUPDR : u8 = 0b01 ;
78
+ const MODER : u8 = 0b00 ;
79
+ }
80
+
81
+ impl sealed:: Sealed for Analog { }
82
+ impl PinMode for Analog {
83
+ const PUPDR : u8 = 0b00 ;
84
+ const MODER : u8 = 0b11 ;
85
+ }
86
+
87
+ impl sealed:: Sealed for Output < OpenDrain > { }
88
+ impl PinMode for Output < OpenDrain > {
89
+ const PUPDR : u8 = 0b00 ;
90
+ const MODER : u8 = 0b01 ;
91
+ const OTYPER : Option < u8 > = Some ( 0b1 ) ;
92
+ }
93
+
94
+ impl sealed:: Sealed for Output < PushPull > { }
95
+ impl PinMode for Output < PushPull > {
96
+ const PUPDR : u8 = 0b00 ;
97
+ const MODER : u8 = 0b01 ;
98
+ const OTYPER : Option < u8 > = Some ( 0b0 ) ;
99
+ }
100
+
44
101
/// GPIO Pin speed selection
45
102
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
46
103
pub enum Speed {
@@ -85,7 +142,8 @@ macro_rules! gpio {
85
142
use crate :: rcc:: Rcc ;
86
143
use super :: {
87
144
Floating , GpioExt , Input , OpenDrain , Output , Speed ,
88
- PullDown , PullUp , PushPull , AltMode , Analog , Port
145
+ PullDown , PullUp , PushPull , AltMode , Analog , Port ,
146
+ PinMode ,
89
147
} ;
90
148
91
149
/// GPIO parts
@@ -218,122 +276,188 @@ macro_rules! gpio {
218
276
}
219
277
}
220
278
221
- impl <MODE > $PXi<MODE > {
222
- /// Configures the pin to operate as a floating input pin
223
- pub fn into_floating_input(
224
- self ,
225
- ) -> $PXi<Input <Floating >> {
279
+ impl <MODE : PinMode > $PXi<MODE > {
280
+ /// Puts `self` into mode `M`.
281
+ ///
282
+ /// This violates the type state constraints from `MODE`, so callers must
283
+ /// ensure they use this properly.
284
+ fn mode<M : PinMode >( & mut self ) {
226
285
let offset = 2 * $i;
227
286
unsafe {
228
287
& ( * $GPIOX:: ptr( ) ) . pupdr. modify( |r, w| {
229
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
288
+ w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( u32 :: from ( M :: PUPDR ) << offset) )
230
289
} ) ;
290
+
291
+ if let Some ( otyper) = M :: OTYPER {
292
+ & ( * $GPIOX:: ptr( ) ) . otyper. modify( |r, w| {
293
+ w. bits( r. bits( ) & !( 0b1 << $i) | ( u32 :: from( otyper) << $i) )
294
+ } ) ;
295
+ }
296
+
231
297
& ( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
232
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
233
- } )
298
+ w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( u32 :: from( M :: MODER ) << offset) )
299
+ } ) ;
300
+ }
301
+ }
302
+
303
+ fn with_mode<M , F , R >(
304
+ & mut self ,
305
+ f: F
306
+ ) -> R
307
+ where
308
+ M : PinMode ,
309
+ F : FnOnce ( & mut $PXi<M >) -> R ,
310
+ {
311
+ struct ResetMode <' a, ORIG : PinMode > {
312
+ pin: & ' a mut $PXi<ORIG >,
313
+ }
314
+
315
+ impl <' a, ORIG : PinMode > Drop for ResetMode <' a, ORIG > {
316
+ fn drop( & mut self ) {
317
+ self . pin. mode:: <ORIG >( ) ;
318
+ }
319
+ }
320
+
321
+ self . mode:: <M >( ) ;
322
+
323
+ // This will reset the pin back to the original mode when dropped.
324
+ // (so either when `with_mode` returns or when `f` unwinds)
325
+ let _resetti = ResetMode { pin: self } ;
326
+
327
+ let mut witness = $PXi {
328
+ _mode: PhantomData
234
329
} ;
330
+
331
+ f( & mut witness)
332
+ }
333
+
334
+ /// Configures the pin to operate as a floating input pin.
335
+ pub fn into_floating_input(
336
+ mut self ,
337
+ ) -> $PXi<Input <Floating >> {
338
+ self . mode:: <Input <Floating >>( ) ;
235
339
$PXi {
236
340
_mode: PhantomData
237
341
}
238
342
}
239
343
240
- /// Configures the pin to operate as a pulled down input pin
344
+ /// Temporarily configures this pin as a floating input.
345
+ ///
346
+ /// The closure `f` is called with the reconfigured pin. After it returns,
347
+ /// the pin will be configured back.
348
+ pub fn with_floating_input<R >(
349
+ & mut self ,
350
+ f: impl FnOnce ( & mut $PXi<Input <Floating >>) -> R ,
351
+ ) -> R {
352
+ self . with_mode( f)
353
+ }
354
+
355
+ /// Configures the pin to operate as a pulled-down input pin.
241
356
pub fn into_pull_down_input(
242
- self ,
243
- ) -> $PXi<Input <PullDown >> {
244
- let offset = 2 * $i;
245
- unsafe {
246
- & ( * $GPIOX:: ptr( ) ) . pupdr. modify( |r, w| {
247
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b10 << offset) )
248
- } ) ;
249
- & ( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
250
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
251
- } )
252
- } ;
357
+ mut self ,
358
+ ) -> $PXi<Input <PullDown >> {
359
+ self . mode:: <Input <Floating >>( ) ;
253
360
$PXi {
254
361
_mode: PhantomData
255
362
}
256
363
}
257
364
258
- /// Configures the pin to operate as a pulled up input pin
365
+ /// Temporarily configures this pin as a pulled-down input.
366
+ ///
367
+ /// The closure `f` is called with the reconfigured pin. After it returns,
368
+ /// the pin will be configured back.
369
+ pub fn with_pull_down_input<R >(
370
+ & mut self ,
371
+ f: impl FnOnce ( & mut $PXi<Input <PullDown >>) -> R ,
372
+ ) -> R {
373
+ self . with_mode( f)
374
+ }
375
+
376
+ /// Configures the pin to operate as a pulled-up input pin.
259
377
pub fn into_pull_up_input(
260
- self ,
378
+ mut self ,
261
379
) -> $PXi<Input <PullUp >> {
262
- let offset = 2 * $i;
263
- unsafe {
264
- & ( * $GPIOX:: ptr( ) ) . pupdr. modify( |r, w| {
265
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b01 << offset) )
266
- } ) ;
267
- & ( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
268
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
269
- } )
270
- } ;
380
+ self . mode:: <Input <PullUp >>( ) ;
271
381
$PXi {
272
382
_mode: PhantomData
273
383
}
274
384
}
275
385
276
- /// Configures the pin to operate as an analog pin
386
+ /// Temporarily configures this pin as a pulled-up input.
387
+ ///
388
+ /// The closure `f` is called with the reconfigured pin. After it returns,
389
+ /// the pin will be configured back.
390
+ pub fn with_pull_up_input<R >(
391
+ & mut self ,
392
+ f: impl FnOnce ( & mut $PXi<Input <PullUp >>) -> R ,
393
+ ) -> R {
394
+ self . with_mode( f)
395
+ }
396
+
397
+ /// Configures the pin to operate as an analog pin.
277
398
pub fn into_analog(
278
- self ,
399
+ mut self ,
279
400
) -> $PXi<Analog > {
280
- let offset = 2 * $i;
281
- unsafe {
282
- & ( * $GPIOX:: ptr( ) ) . pupdr. modify( |r, w| {
283
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
284
- } ) ;
285
- & ( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
286
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b11 << offset) )
287
- } ) ;
288
- }
401
+ self . mode:: <Analog >( ) ;
289
402
$PXi {
290
403
_mode: PhantomData
291
404
}
292
405
}
293
406
294
- /// Configures the pin to operate as an open drain output pin
407
+ /// Temporarily configures this pin as an analog pin.
408
+ ///
409
+ /// The closure `f` is called with the reconfigured pin. After it returns,
410
+ /// the pin will be configured back.
411
+ pub fn with_analog<R >(
412
+ & mut self ,
413
+ f: impl FnOnce ( & mut $PXi<Analog >) -> R ,
414
+ ) -> R {
415
+ self . with_mode( f)
416
+ }
417
+
418
+ /// Configures the pin to operate as an open drain output pin.
295
419
pub fn into_open_drain_output(
296
- self ,
420
+ mut self ,
297
421
) -> $PXi<Output <OpenDrain >> {
298
- let offset = 2 * $i;
299
- unsafe {
300
- & ( * $GPIOX:: ptr( ) ) . pupdr. modify( |r, w| {
301
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
302
- } ) ;
303
- & ( * $GPIOX:: ptr( ) ) . otyper. modify( |r, w| {
304
- w. bits( r. bits( ) | ( 0b1 << $i) )
305
- } ) ;
306
- & ( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
307
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b01 << offset) )
308
- } )
309
- } ;
422
+ self . mode:: <Output <OpenDrain >>( ) ;
310
423
$PXi {
311
424
_mode: PhantomData
312
425
}
313
426
}
314
427
315
- /// Configures the pin to operate as an push pull output pin
428
+ /// Temporarily configures this pin as an open drain output.
429
+ ///
430
+ /// The closure `f` is called with the reconfigured pin. After it returns,
431
+ /// the pin will be configured back.
432
+ pub fn with_open_drain_output<R >(
433
+ & mut self ,
434
+ f: impl FnOnce ( & mut $PXi<Output <OpenDrain >>) -> R ,
435
+ ) -> R {
436
+ self . with_mode( f)
437
+ }
438
+
439
+ /// Configures the pin to operate as an push-pull output pin.
316
440
pub fn into_push_pull_output(
317
- self ,
441
+ mut self ,
318
442
) -> $PXi<Output <PushPull >> {
319
- let offset = 2 * $i;
320
- unsafe {
321
- & ( * $GPIOX:: ptr( ) ) . pupdr. modify( |r, w| {
322
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b00 << offset) )
323
- } ) ;
324
- & ( * $GPIOX:: ptr( ) ) . otyper. modify( |r, w| {
325
- w. bits( r. bits( ) & !( 0b1 << $i) )
326
- } ) ;
327
- & ( * $GPIOX:: ptr( ) ) . moder. modify( |r, w| {
328
- w. bits( ( r. bits( ) & !( 0b11 << offset) ) | ( 0b01 << offset) )
329
- } )
330
- } ;
443
+ self . mode:: <Output <PushPull >>( ) ;
331
444
$PXi {
332
445
_mode: PhantomData
333
446
}
334
447
}
335
448
336
- /// Set pin speed
449
+ /// Temporarily configures this pin as a push-pull output.
450
+ ///
451
+ /// The closure `f` is called with the reconfigured pin. After it returns,
452
+ /// the pin will be configured back.
453
+ pub fn with_push_pull_output<R >(
454
+ & mut self ,
455
+ f: impl FnOnce ( & mut $PXi<Output <PushPull >>) -> R ,
456
+ ) -> R {
457
+ self . with_mode( f)
458
+ }
459
+
460
+ /// Set pin speed.
337
461
pub fn set_speed( self , speed: Speed ) -> Self {
338
462
let offset = 2 * $i;
339
463
unsafe {
0 commit comments