@@ -41,6 +41,63 @@ pub struct Output<MODE> {
4141/// Push pull output (type state)
4242pub struct PushPull ;
4343
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+
44101/// GPIO Pin speed selection
45102#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
46103pub enum Speed {
@@ -85,7 +142,8 @@ macro_rules! gpio {
85142 use crate :: rcc:: Rcc ;
86143 use super :: {
87144 Floating , GpioExt , Input , OpenDrain , Output , Speed ,
88- PullDown , PullUp , PushPull , AltMode , Analog , Port
145+ PullDown , PullUp , PushPull , AltMode , Analog , Port ,
146+ PinMode ,
89147 } ;
90148
91149 /// GPIO parts
@@ -218,122 +276,188 @@ macro_rules! gpio {
218276 }
219277 }
220278
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 ) {
226285 let offset = 2 * $i;
227286 unsafe {
228287 & ( * $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) )
230289 } ) ;
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+
231297 & ( * $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
234329 } ;
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 >>( ) ;
235339 $PXi {
236340 _mode: PhantomData
237341 }
238342 }
239343
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.
241356 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 >>( ) ;
253360 $PXi {
254361 _mode: PhantomData
255362 }
256363 }
257364
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.
259377 pub fn into_pull_up_input(
260- self ,
378+ mut self ,
261379 ) -> $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 >>( ) ;
271381 $PXi {
272382 _mode: PhantomData
273383 }
274384 }
275385
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.
277398 pub fn into_analog(
278- self ,
399+ mut self ,
279400 ) -> $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 >( ) ;
289402 $PXi {
290403 _mode: PhantomData
291404 }
292405 }
293406
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.
295419 pub fn into_open_drain_output(
296- self ,
420+ mut self ,
297421 ) -> $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 >>( ) ;
310423 $PXi {
311424 _mode: PhantomData
312425 }
313426 }
314427
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.
316440 pub fn into_push_pull_output(
317- self ,
441+ mut self ,
318442 ) -> $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 >>( ) ;
331444 $PXi {
332445 _mode: PhantomData
333446 }
334447 }
335448
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.
337461 pub fn set_speed( self , speed: Speed ) -> Self {
338462 let offset = 2 * $i;
339463 unsafe {
0 commit comments