stm32f042_hal/
gpio.rs

1//! General Purpose Input / Output
2
3use core::marker::PhantomData;
4
5/// Extension trait to split a GPIO peripheral in independent pins and registers
6pub trait GpioExt {
7    /// The parts to split the GPIO into
8    type Parts;
9
10    /// Splits the GPIO block into independent pins and registers
11    fn split(self) -> Self::Parts;
12}
13
14pub struct AF0;
15pub struct AF1;
16pub struct AF2;
17pub struct AF3;
18pub struct AF4;
19pub struct AF5;
20pub struct AF6;
21pub struct AF7;
22
23pub struct Alternate<MODE> {
24    _mode: PhantomData<MODE>,
25}
26
27/// Input mode (type state)
28pub struct Input<MODE> {
29    _mode: PhantomData<MODE>,
30}
31
32/// Floating input (type state)
33pub struct Floating;
34
35/// Pulled down input (type state)
36pub struct PullDown;
37
38/// Pulled up input (type state)
39pub struct PullUp;
40
41/// Open drain input or output (type state)
42pub struct OpenDrain;
43
44/// Output mode (type state)
45pub struct Output<MODE> {
46    _mode: PhantomData<MODE>,
47}
48
49/// Push pull output (type state)
50pub struct PushPull;
51
52macro_rules! gpio {
53    ($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, [
54        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
55    ]) => {
56        /// GPIO
57        pub mod $gpiox {
58            use core::marker::PhantomData;
59
60            use hal::digital::{InputPin, OutputPin, StatefulOutputPin};
61            use stm32::$GPIOX;
62
63            use stm32::RCC;
64            use super::{
65                Alternate, Floating, GpioExt, Input, OpenDrain, Output,
66                PullDown, PullUp, PushPull, AF0, AF1, AF2, AF3, AF4, AF5, AF6, AF7,
67            };
68
69            /// GPIO parts
70            pub struct Parts {
71                $(
72                    /// Pin
73                    pub $pxi: $PXi<$MODE>,
74                )+
75            }
76
77            impl GpioExt for $GPIOX {
78                type Parts = Parts;
79
80                fn split(self) -> Parts {
81                    // NOTE(unsafe) This executes only during initialisation
82                    let rcc = unsafe { &(*RCC::ptr()) };
83                    rcc.ahbenr.modify(|_, w| w.$iopxenr().set_bit());
84
85                    Parts {
86                        $(
87                            $pxi: $PXi { _mode: PhantomData },
88                        )+
89                    }
90                }
91            }
92
93            /// Partially erased pin
94            pub struct $PXx<MODE> {
95                i: u8,
96                _mode: PhantomData<MODE>,
97            }
98
99            impl<MODE> StatefulOutputPin for $PXx<Output<MODE>> {
100                fn is_set_high(&self) -> bool {
101                    !self.is_set_low()
102                }
103
104                fn is_set_low(&self) -> bool {
105                    // NOTE(unsafe) atomic read with no side effects
106                    unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }
107                }
108            }
109
110            impl<MODE> OutputPin for $PXx<Output<MODE>> {
111                fn set_high(&mut self) {
112                    // NOTE(unsafe) atomic write to a stateless register
113                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
114                }
115
116                fn set_low(&mut self) {
117                    // NOTE(unsafe) atomic write to a stateless register
118                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }
119                }
120            }
121
122            impl<MODE> InputPin for $PXx<Input<MODE>> {
123                fn is_high(&self) -> bool {
124                    !self.is_low()
125                }
126
127                fn is_low(&self) -> bool {
128                    // NOTE(unsafe) atomic read with no side effects
129                    unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
130                }
131            }
132
133            fn _set_alternate_mode (index:usize, mode: u32)
134            {
135                let offset = 2 * index;
136                let offset2 = 4 * index;
137                unsafe {
138                    if offset2 < 32 {
139                        &(*$GPIOX::ptr()).afrl.modify(|r, w| {
140                            w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
141                        });
142                    } else
143                    {
144                        let offset2 = offset2 - 32;
145                        &(*$GPIOX::ptr()).afrh.modify(|r, w| {
146                            w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
147                        });
148                    }
149                    &(*$GPIOX::ptr()).moder.modify(|r, w| {
150                        w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
151                    });
152                }
153            }
154
155            $(
156                /// Pin
157                pub struct $PXi<MODE> {
158                    _mode: PhantomData<MODE>,
159                }
160
161                impl<MODE> $PXi<MODE> {
162                    /// Configures the pin to operate in AF0 mode
163                    pub fn into_alternate_af0(
164                        self,
165                    ) -> $PXi<Alternate<AF0>> {
166                        _set_alternate_mode($i, 0);
167                        $PXi { _mode: PhantomData }
168                    }
169
170                    /// Configures the pin to operate in AF1 mode
171                    pub fn into_alternate_af1(
172                        self,
173                    ) -> $PXi<Alternate<AF1>> {
174                        _set_alternate_mode($i, 1);
175                        $PXi { _mode: PhantomData }
176                    }
177
178                    /// Configures the pin to operate in AF2 mode
179                    pub fn into_alternate_af2(
180                        self,
181                    ) -> $PXi<Alternate<AF2>> {
182                        _set_alternate_mode($i, 2);
183                        $PXi { _mode: PhantomData }
184                    }
185
186                    /// Configures the pin to operate in AF3 mode
187                    pub fn into_alternate_af3(
188                        self,
189                    ) -> $PXi<Alternate<AF3>> {
190                        _set_alternate_mode($i, 3);
191                        $PXi { _mode: PhantomData }
192                    }
193
194                    /// Configures the pin to operate in AF4 mode
195                    pub fn into_alternate_af4(
196                        self,
197                    ) -> $PXi<Alternate<AF4>> {
198                        _set_alternate_mode($i, 4);
199                        $PXi { _mode: PhantomData }
200                    }
201
202                    /// Configures the pin to operate in AF5 mode
203                    pub fn into_alternate_af5(
204                        self,
205                    ) -> $PXi<Alternate<AF5>> {
206                        _set_alternate_mode($i, 5);
207                        $PXi { _mode: PhantomData }
208                    }
209
210                    /// Configures the pin to operate in AF6 mode
211                    pub fn into_alternate_af6(
212                        self,
213                    ) -> $PXi<Alternate<AF6>> {
214                        _set_alternate_mode($i, 6);
215                        $PXi { _mode: PhantomData }
216                    }
217
218                    /// Configures the pin to operate in AF7 mode
219                    pub fn into_alternate_af7(
220                        self,
221                    ) -> $PXi<Alternate<AF7>> {
222                        _set_alternate_mode($i, 7);
223                        $PXi { _mode: PhantomData }
224                    }
225
226                    /// Configures the pin to operate as a floating input pin
227                    pub fn into_floating_input(
228                        self,
229                    ) -> $PXi<Input<Floating>> {
230                        let offset = 2 * $i;
231                        unsafe {
232                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
233                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
234                            });
235                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
236                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
237                            });
238                        }
239                        $PXi { _mode: PhantomData }
240                    }
241
242                    /// Configures the pin to operate as a pulled down input pin
243                    pub fn into_pull_down_input(
244                        self,
245                        ) -> $PXi<Input<PullDown>> {
246                        let offset = 2 * $i;
247                        unsafe {
248                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
249                                w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
250                            });
251                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
252                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
253                            });
254                        }
255                        $PXi { _mode: PhantomData }
256                    }
257
258                    /// Configures the pin to operate as a pulled up input pin
259                    pub fn into_pull_up_input(
260                        self,
261                    ) -> $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                        }
271                        $PXi { _mode: PhantomData }
272                    }
273
274                    /// Configures the pin to operate as an open drain output pin
275                    pub fn into_open_drain_output(
276                        self,
277                    ) -> $PXi<Output<OpenDrain>> {
278                        let offset = 2 * $i;
279                        unsafe {
280                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
281                                w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
282                            });
283                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
284                                w.bits(r.bits() | (0b1 << $i))
285                            });
286                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
287                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
288                            });
289                        }
290                        $PXi { _mode: PhantomData }
291                    }
292
293                    /// Configures the pin to operate as an push pull output pin
294                    pub fn into_push_pull_output(
295                        self,
296                    ) -> $PXi<Output<PushPull>> {
297                        let offset = 2 * $i;
298
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                        }
310                        $PXi { _mode: PhantomData }
311                    }
312
313                    /// Configures the pin to operate as an push pull output pin with quick fall
314                    /// and rise times
315                    pub fn into_push_pull_output_hs(
316                        self,
317                    ) -> $PXi<Output<PushPull>> {
318                        let offset = 2 * $i;
319
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()).ospeedr.modify(|r, w| {
328                                w.bits(r.bits() & !(0b1 << $i))
329                            });
330                            &(*$GPIOX::ptr()).moder.modify(|r, w| {
331                                w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
332                            });
333                        }
334
335                        $PXi { _mode: PhantomData }
336                    }
337                }
338
339                impl $PXi<Output<OpenDrain>> {
340                    /// Enables / disables the internal pull up
341                    pub fn internal_pull_up(&mut self, on: bool) {
342                        let offset = 2 * $i;
343                        let value = if on { 0b01 } else { 0b00 };
344                        unsafe {
345                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
346                                w.bits((r.bits() & !(0b11 << offset)) | (value << offset))
347                         })};
348                    }
349                }
350
351                impl<MODE> $PXi<Alternate<MODE>> {
352                    /// Enables / disables the internal pull up
353                    pub fn internal_pull_up(self, on: bool) -> Self {
354                        let offset = 2 * $i;
355                        let value = if on { 0b01 } else { 0b00 };
356                        unsafe {
357                            &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
358                                w.bits((r.bits() & !(0b11 << offset)) | (value << offset))
359                         })};
360
361                        self
362                    }
363                }
364
365                impl<MODE> $PXi<Alternate<MODE>> {
366                    /// Turns pin alternate configuration pin into open drain
367                    pub fn set_open_drain(self) -> Self {
368                        let offset = $i;
369                        unsafe {
370                            &(*$GPIOX::ptr()).otyper.modify(|r, w| {
371                                w.bits(r.bits() | (1 << offset))
372                         })};
373
374                        self
375                    }
376                }
377
378                impl<MODE> $PXi<Output<MODE>> {
379                    /// Erases the pin number from the type
380                    ///
381                    /// This is useful when you want to collect the pins into an array where you
382                    /// need all the elements to have the same type
383                    pub fn downgrade(self) -> $PXx<Output<MODE>> {
384                        $PXx {
385                            i: $i,
386                            _mode: self._mode,
387                        }
388                    }
389                }
390
391                impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
392                    fn is_set_high(&self) -> bool {
393                        !self.is_set_low()
394                    }
395
396                    fn is_set_low(&self) -> bool {
397                        // NOTE(unsafe) atomic read with no side effects
398                        unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
399                    }
400                }
401
402                impl<MODE> OutputPin for $PXi<Output<MODE>> {
403                    fn set_high(&mut self) {
404                        // NOTE(unsafe) atomic write to a stateless register
405                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
406                    }
407
408                    fn set_low(&mut self) {
409                        // NOTE(unsafe) atomic write to a stateless register
410                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << ($i + 16))) }
411                    }
412                }
413
414                impl<MODE> $PXi<Input<MODE>> {
415                    /// Erases the pin number from the type
416                    ///
417                    /// This is useful when you want to collect the pins into an array where you
418                    /// need all the elements to have the same type
419                    pub fn downgrade(self) -> $PXx<Input<MODE>> {
420                        $PXx {
421                            i: $i,
422                            _mode: self._mode,
423                        }
424                    }
425                }
426
427                impl<MODE> InputPin for $PXi<Input<MODE>> {
428                    fn is_high(&self) -> bool {
429                        !self.is_low()
430                    }
431
432                    fn is_low(&self) -> bool {
433                        // NOTE(unsafe) atomic read with no side effects
434                        unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
435                    }
436                }
437            )+
438
439                impl<TYPE> $PXx<TYPE> {
440                    pub fn get_id (&self) -> u8
441                    {
442                        self.i
443                    }
444                }
445        }
446    }
447}
448
449gpio!(GPIOA, gpioa, iopaen, PA, [
450    PA0: (pa0, 0, Input<Floating>),
451    PA1: (pa1, 1, Input<Floating>),
452    PA2: (pa2, 2, Input<Floating>),
453    PA3: (pa3, 3, Input<Floating>),
454    PA4: (pa4, 4, Input<Floating>),
455    PA5: (pa5, 5, Input<Floating>),
456    PA6: (pa6, 6, Input<Floating>),
457    PA7: (pa7, 7, Input<Floating>),
458    PA8: (pa8, 8, Input<Floating>),
459    PA9: (pa9, 9, Input<Floating>),
460    PA10: (pa10, 10, Input<Floating>),
461    PA11: (pa11, 11, Input<Floating>),
462    PA12: (pa12, 12, Input<Floating>),
463    PA13: (pa13, 13, Input<Floating>),
464    PA14: (pa14, 14, Input<Floating>),
465    PA15: (pa15, 15, Input<Floating>),
466]);
467
468gpio!(GPIOB, gpiob, iopben, PB, [
469    PB0: (pb0, 0, Input<Floating>),
470    PB1: (pb1, 1, Input<Floating>),
471    PB2: (pb2, 2, Input<Floating>),
472    PB3: (pb3, 3, Input<Floating>),
473    PB4: (pb4, 4, Input<Floating>),
474    PB5: (pb5, 5, Input<Floating>),
475    PB6: (pb6, 6, Input<Floating>),
476    PB7: (pb7, 7, Input<Floating>),
477    PB8: (pb8, 8, Input<Floating>),
478    PB9: (pb9, 9, Input<Floating>),
479    PB10: (pb10, 10, Input<Floating>),
480    PB11: (pb11, 11, Input<Floating>),
481    PB12: (pb12, 12, Input<Floating>),
482    PB13: (pb13, 13, Input<Floating>),
483    PB14: (pb14, 14, Input<Floating>),
484    PB15: (pb15, 15, Input<Floating>),
485]);
486
487gpio!(GPIOC, gpioc, iopcen, PC, [
488    PC13: (pc13, 13, Input<Floating>),
489    PC14: (pc14, 14, Input<Floating>),
490    PC15: (pc15, 15, Input<Floating>),
491]);
492
493gpio!(GPIOF, gpiof, iopfen, PF, [
494    PF0: (pf0, 0, Input<Floating>),
495    PF1: (pf1, 1, Input<Floating>),
496    PF11: (pf11, 11, Input<Floating>),
497]);