2
2
use core:: marker:: PhantomData ;
3
3
4
4
use crate :: rcc:: Rcc ;
5
+ use core:: convert:: Infallible ;
5
6
use embedded_hal:: digital:: v2:: PinState ;
7
+ use hal:: digital:: v2:: { toggleable, InputPin , OutputPin , StatefulOutputPin } ;
6
8
7
9
/// Default pin mode
8
10
pub type DefaultMode = Analog ;
@@ -16,6 +18,13 @@ pub trait GpioExt {
16
18
fn split ( self , rcc : & mut Rcc ) -> Self :: Parts ;
17
19
}
18
20
21
+ trait GpioRegExt {
22
+ fn is_low ( & self , pos : u8 ) -> bool ;
23
+ fn is_set_low ( & self , pos : u8 ) -> bool ;
24
+ fn set_high ( & self , pos : u8 ) ;
25
+ fn set_low ( & self , pos : u8 ) ;
26
+ }
27
+
19
28
/// Input mode (type state)
20
29
pub struct Input < MODE > {
21
30
_mode : PhantomData < MODE > ,
@@ -44,6 +53,106 @@ pub struct Output<MODE> {
44
53
/// Push pull output (type state)
45
54
pub struct PushPull ;
46
55
56
+ /// Fully erased pin
57
+ pub struct Pin < MODE > {
58
+ i : u8 ,
59
+ port : * const dyn GpioRegExt ,
60
+ _mode : PhantomData < MODE > ,
61
+ }
62
+
63
+ macro_rules! gpio_trait {
64
+ ( $gpiox: ident) => {
65
+ impl GpioRegExt for crate :: stm32:: $gpiox:: RegisterBlock {
66
+ fn is_low( & self , pos: u8 ) -> bool {
67
+ // NOTE(unsafe) atomic read with no side effects
68
+ self . idr. read( ) . bits( ) & ( 1 << pos) == 0
69
+ }
70
+
71
+ fn is_set_low( & self , pos: u8 ) -> bool {
72
+ // NOTE(unsafe) atomic read with no side effects
73
+ self . odr. read( ) . bits( ) & ( 1 << pos) == 0
74
+ }
75
+
76
+ fn set_high( & self , pos: u8 ) {
77
+ // NOTE(unsafe) atomic write to a stateless register
78
+ unsafe { self . bsrr. write( |w| w. bits( 1 << pos) ) }
79
+ }
80
+
81
+ fn set_low( & self , pos: u8 ) {
82
+ // NOTE(unsafe) atomic write to a stateless register
83
+ unsafe { self . bsrr. write( |w| w. bits( 1 << ( pos + 16 ) ) ) }
84
+ }
85
+ }
86
+ } ;
87
+ }
88
+
89
+ gpio_trait ! ( gpioa) ;
90
+ gpio_trait ! ( gpiob) ;
91
+
92
+ // NOTE(unsafe) The only write acess is to BSRR, which is thread safe
93
+ unsafe impl < MODE > Sync for Pin < MODE > { }
94
+ // NOTE(unsafe) this only enables read access to the same pin from multiple
95
+ // threads
96
+ unsafe impl < MODE > Send for Pin < MODE > { }
97
+
98
+ impl < MODE > StatefulOutputPin for Pin < Output < MODE > > {
99
+ #[ inline( always) ]
100
+ fn is_set_high ( & self ) -> Result < bool , Self :: Error > {
101
+ self . is_set_low ( ) . map ( |v| !v)
102
+ }
103
+
104
+ #[ inline( always) ]
105
+ fn is_set_low ( & self ) -> Result < bool , Self :: Error > {
106
+ Ok ( unsafe { ( * self . port ) . is_set_low ( self . i ) } )
107
+ }
108
+ }
109
+
110
+ impl < MODE > OutputPin for Pin < Output < MODE > > {
111
+ type Error = Infallible ;
112
+
113
+ #[ inline( always) ]
114
+ fn set_high ( & mut self ) -> Result < ( ) , Self :: Error > {
115
+ unsafe { ( * self . port ) . set_high ( self . i ) } ;
116
+ Ok ( ( ) )
117
+ }
118
+
119
+ #[ inline( always) ]
120
+ fn set_low ( & mut self ) -> Result < ( ) , Self :: Error > {
121
+ unsafe { ( * self . port ) . set_low ( self . i ) }
122
+ Ok ( ( ) )
123
+ }
124
+ }
125
+
126
+ impl < MODE > toggleable:: Default for Pin < Output < MODE > > { }
127
+
128
+ impl InputPin for Pin < Output < OpenDrain > > {
129
+ type Error = Infallible ;
130
+
131
+ #[ inline( always) ]
132
+ fn is_high ( & self ) -> Result < bool , Self :: Error > {
133
+ self . is_low ( ) . map ( |v| !v)
134
+ }
135
+
136
+ #[ inline( always) ]
137
+ fn is_low ( & self ) -> Result < bool , Self :: Error > {
138
+ Ok ( unsafe { ( * self . port ) . is_low ( self . i ) } )
139
+ }
140
+ }
141
+
142
+ impl < MODE > InputPin for Pin < Input < MODE > > {
143
+ type Error = Infallible ;
144
+
145
+ #[ inline( always) ]
146
+ fn is_high ( & self ) -> Result < bool , Self :: Error > {
147
+ self . is_low ( ) . map ( |v| !v)
148
+ }
149
+
150
+ #[ inline( always) ]
151
+ fn is_low ( & self ) -> Result < bool , Self :: Error > {
152
+ Ok ( unsafe { ( * self . port ) . is_low ( self . i ) } )
153
+ }
154
+ }
155
+
47
156
/// GPIO Pin speed selection
48
157
pub enum Speed {
49
158
Low = 0 ,
@@ -494,6 +603,35 @@ macro_rules! gpio {
494
603
self . i
495
604
}
496
605
}
606
+
607
+ impl <MODE > $PXx<Output <MODE >> {
608
+ /// Erases the port number from the type
609
+ ///
610
+ /// This is useful when you want to collect the pins into an array where you
611
+ /// need all the elements to have the same type
612
+ pub fn downgrade( self ) -> Pin <Output <MODE >> {
613
+ Pin {
614
+ i: self . get_id( ) ,
615
+ port: $GPIOX:: ptr( ) as * const dyn GpioRegExt ,
616
+ _mode: self . _mode,
617
+ }
618
+ }
619
+ }
620
+
621
+ impl <MODE > $PXx<Input <MODE >> {
622
+ /// Erases the port number from the type
623
+ ///
624
+ /// This is useful when you want to collect the pins into an array where you
625
+ /// need all the elements to have the same type
626
+ pub fn downgrade( self ) -> Pin <Input <MODE >> {
627
+ Pin {
628
+ i: self . get_id( ) ,
629
+ port: $GPIOX:: ptr( ) as * const dyn GpioRegExt ,
630
+ _mode: self . _mode,
631
+ }
632
+ }
633
+ }
634
+
497
635
}
498
636
}
499
637
}
0 commit comments