stm32l4_hal/
gpio.rs

1//! General Purpose Input / Output
2
3// Based on (ripped)
4// https://github.com/japaric/stm32f30x-hal/blob/master/src/gpio.rs
5
6use core::marker::PhantomData;
7
8use crate::rcc::AHB2;
9
10/// Extension trait to split a GPIO peripheral in independent pins and registers
11pub trait GpioExt {
12    /// The to split the GPIO into
13    type Parts;
14
15    /// Splits the GPIO block into independent pins and registers
16    fn split(self, ahb: &mut AHB2) -> Self::Parts;
17}
18
19/// Input mode (type state)
20pub struct Input<MODE> {
21    _mode: PhantomData<MODE>,
22}
23
24/// Floating input (type state)
25pub struct Floating;
26/// Pulled down input (type state)
27pub struct PullDown;
28/// Pulled up input (type state)
29pub struct PullUp;
30
31/// Output mode (type state)
32pub struct Output<MODE> {
33    _mode: PhantomData<MODE>,
34}
35
36/// Push pull output (type state)
37pub struct PushPull;
38/// Open drain output (type state)
39pub struct OpenDrain;
40
41/// Alternate mode (type state)
42pub struct Alternate<AF, MODE>
43{
44    _af: PhantomData<AF>,
45    _mode: PhantomData<MODE>,
46}
47
48/// Alternate function 0 (type state)
49pub struct AF0;
50
51/// Alternate function 1 (type state)
52pub struct AF1;
53
54/// Alternate function 2 (type state)
55pub struct AF2;
56
57/// Alternate function 3 (type state)
58pub struct AF3;
59
60/// Alternate function 4 (type state)
61pub struct AF4;
62
63/// Alternate function 5 (type state)
64pub struct AF5;
65
66/// Alternate function 6 (type state)
67pub struct AF6;
68
69/// Alternate function 7 (type state)
70pub struct AF7;
71
72/// Alternate function 8 (type state)
73pub struct AF8;
74
75/// Alternate function 9 (type state)
76pub struct AF9;
77
78/// Alternate function 10 (type state)
79pub struct AF10;
80
81/// Alternate function 11 (type state)
82pub struct AF11;
83
84/// Alternate function 12 (type state)
85pub struct AF12;
86
87/// Alternate function 13 (type state)
88pub struct AF13;
89
90/// Alternate function 14 (type state)
91pub struct AF14;
92
93/// Alternate function 15 (type state)
94pub struct AF15;
95
96macro_rules! gpio {
97    ($GPIOX:ident, $gpiox:ident, $gpioy:ident, $iopxenr:ident, $iopxrst:ident, $PXx:ident, [
98        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $AFR:ident),)+
99    ]) => {
100        /// GPIO
101        pub mod $gpiox {
102            use core::marker::PhantomData;
103
104            use crate::hal::digital::OutputPin;
105            use crate::stm32::{$gpioy, $GPIOX};
106
107            use crate::rcc::AHB2;
108            use super::{
109                Alternate, AF4, AF5, AF6, AF7, AF8, AF9, Floating, GpioExt, Input, OpenDrain, Output,
110                PullDown, PullUp, PushPull,
111            };
112
113            /// GPIO parts
114            pub struct Parts {
115                /// Opaque AFRH register
116                pub afrh: AFRH,
117                /// Opaque AFRL register
118                pub afrl: AFRL,
119                /// Opaque MODER register
120                pub moder: MODER,
121                /// Opaque OTYPER register
122                pub otyper: OTYPER,
123                /// Opaque PUPDR register
124                pub pupdr: PUPDR,
125                $(
126                    /// Pin
127                    pub $pxi: $PXi<$MODE>,
128                )+
129            }
130
131            impl GpioExt for $GPIOX {
132                type Parts = Parts;
133
134                fn split(self, ahb: &mut AHB2) -> Parts {
135                    ahb.enr().modify(|_, w| w.$iopxenr().set_bit());
136                    ahb.rstr().modify(|_, w| w.$iopxrst().set_bit());
137                    ahb.rstr().modify(|_, w| w.$iopxrst().clear_bit());
138
139                    Parts {
140                        afrh: AFRH { _0: () },
141                        afrl: AFRL { _0: () },
142                        moder: MODER { _0: () },
143                        otyper: OTYPER { _0: () },
144                        pupdr: PUPDR { _0: () },
145                        $(
146                            $pxi: $PXi { _mode: PhantomData },
147                        )+
148                    }
149                }
150            }
151
152            /// Opaque AFRL register
153            pub struct AFRL {
154                _0: (),
155            }
156
157            impl AFRL {
158                pub(crate) fn afr(&mut self) -> &$gpioy::AFRL {
159                    unsafe { &(*$GPIOX::ptr()).afrl }
160                }
161            }
162
163            /// Opaque AFRH register
164            pub struct AFRH {
165                _0: (),
166            }
167
168            impl AFRH {
169                // TODO remove `allow`
170                #[allow(dead_code)]
171                pub(crate) fn afr(&mut self) -> &$gpioy::AFRH {
172                    unsafe { &(*$GPIOX::ptr()).afrh }
173                }
174            }
175
176            /// Opaque MODER register
177            pub struct MODER {
178                _0: (),
179            }
180
181            impl MODER {
182                pub(crate) fn moder(&mut self) -> &$gpioy::MODER {
183                    unsafe { &(*$GPIOX::ptr()).moder }
184                }
185            }
186
187            /// Opaque OTYPER register
188            pub struct OTYPER {
189                _0: (),
190            }
191
192            impl OTYPER {
193                pub(crate) fn otyper(&mut self) -> &$gpioy::OTYPER {
194                    unsafe { &(*$GPIOX::ptr()).otyper }
195                }
196            }
197
198            /// Opaque PUPDR register
199            pub struct PUPDR {
200                _0: (),
201            }
202
203            impl PUPDR {
204                pub(crate) fn pupdr(&mut self) -> &$gpioy::PUPDR {
205                    unsafe { &(*$GPIOX::ptr()).pupdr }
206                }
207            }
208
209            /// Partially erased pin
210            pub struct $PXx<MODE> {
211                i: u8,
212                _mode: PhantomData<MODE>,
213            }
214
215            impl<MODE> OutputPin for $PXx<Output<MODE>> {
216                fn set_high(&mut self) {
217                    // NOTE(unsafe) atomic write to a stateless register
218                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
219                }
220
221                fn set_low(&mut self) {
222                    // NOTE(unsafe) atomic write to a stateless register
223                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + self.i))) }
224                }
225            }
226
227            $(
228                /// Pin
229                pub struct $PXi<MODE> {
230                    _mode: PhantomData<MODE>,
231                }
232
233                impl<MODE> $PXi<MODE> {
234                    /// Configures the pin to serve as alternate function 4 (AF4)
235                    pub fn into_af4(
236                        self,
237                        moder: &mut MODER,
238                        afr: &mut $AFR,
239                    ) -> $PXi<Alternate<AF4, MODE>> {
240                        let offset = 2 * $i;
241
242                        // alternate function mode
243                        let mode = 0b10;
244                        moder.moder().modify(|r, w| unsafe {
245                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
246                        });
247
248                        let af = 4;
249                        let offset = 4 * ($i % 8);
250                        afr.afr().modify(|r, w| unsafe {
251                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
252                        });
253
254                        $PXi { _mode: PhantomData }
255                    }
256
257                    /// Configures the pin to serve as alternate function 5 (AF5)
258                    pub fn into_af5(
259                        self,
260                        moder: &mut MODER,
261                        afr: &mut $AFR,
262                    ) -> $PXi<Alternate<AF5, MODE>> {
263                        let offset = 2 * $i;
264
265                        // alternate function mode
266                        let mode = 0b10;
267                        moder.moder().modify(|r, w| unsafe {
268                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
269                        });
270
271                        let af = 5;
272                        let offset = 4 * ($i % 8);
273                        afr.afr().modify(|r, w| unsafe {
274                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
275                        });
276
277                        $PXi { _mode: PhantomData }
278                    }
279
280                    /// Configures the pin to serve as alternate function 6 (AF6)
281                    pub fn into_af6(
282                        self,
283                        moder: &mut MODER,
284                        afr: &mut $AFR,
285                    ) -> $PXi<Alternate<AF6, MODE>> {
286                        let offset = 2 * $i;
287
288                        // alternate function mode
289                        let mode = 0b10;
290                        moder.moder().modify(|r, w| unsafe {
291                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
292                        });
293
294                        let af = 6;
295                        let offset = 4 * ($i % 8);
296                        afr.afr().modify(|r, w| unsafe {
297                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
298                        });
299
300                        $PXi { _mode: PhantomData }
301                    }
302
303                    /// Configures the pin to serve as alternate function 7 (AF7)
304                    pub fn into_af7(
305                        self,
306                        moder: &mut MODER,
307                        afr: &mut $AFR,
308                    ) -> $PXi<Alternate<AF7, MODE>> {
309                        let offset = 2 * $i;
310
311                        // alternate function mode
312                        let mode = 0b10;
313                        moder.moder().modify(|r, w| unsafe {
314                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
315                        });
316
317                        let af = 7;
318                        let offset = 4 * ($i % 8);
319
320                        afr.afr().modify(|r, w| unsafe {
321                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
322                        });
323
324                        $PXi { _mode: PhantomData }
325                    }
326
327                    /// Configures the pin to serve as alternate function 8 (AF8)
328                    pub fn into_af8(
329                        self,
330                        moder: &mut MODER,
331                        afr: &mut $AFR,
332                    ) -> $PXi<Alternate<AF8, MODE>> {
333                        let offset = 2 * $i;
334
335                        // alternate function mode
336                        let mode = 0b10;
337                        moder.moder().modify(|r, w| unsafe {
338                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
339                        });
340
341                        let af = 8;
342                        let offset = 4 * ($i % 8);
343
344                        afr.afr().modify(|r, w| unsafe {
345                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
346                        });
347
348                        $PXi { _mode: PhantomData }
349                    }
350
351                    /// Configures the pin to serve as alternate function 9 (AF9)
352                    pub fn into_af9(
353                        self,
354                        moder: &mut MODER,
355                        afr: &mut $AFR,
356                    ) -> $PXi<Alternate<AF9, MODE>> {
357                        let offset = 2 * $i;
358
359                        // alternate function mode
360                        let mode = 0b10;
361                        moder.moder().modify(|r, w| unsafe {
362                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
363                        });
364
365                        let af = 9;
366                        let offset = 4 * ($i % 8);
367
368                        afr.afr().modify(|r, w| unsafe {
369                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
370                        });
371
372                        $PXi { _mode: PhantomData }
373                    }
374
375                    /// Configures the pin to operate as a floating input pin
376                    pub fn into_floating_input(
377                        self,
378                        moder: &mut MODER,
379                        pupdr: &mut PUPDR,
380                    ) -> $PXi<Input<Floating>> {
381                        let offset = 2 * $i;
382
383                        // input mode
384                        moder
385                            .moder()
386                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
387
388                        // no pull-up or pull-down
389                        pupdr
390                            .pupdr()
391                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
392
393                        $PXi { _mode: PhantomData }
394                    }
395
396                    /// Configures the pin to operate as a pulled down input pin
397                    pub fn into_pull_down_input(
398                        self,
399                        moder: &mut MODER,
400                        pupdr: &mut PUPDR,
401                    ) -> $PXi<Input<PullDown>> {
402                        let offset = 2 * $i;
403
404                        // input mode
405                        moder
406                            .moder()
407                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
408
409                        // pull-down
410                        pupdr.pupdr().modify(|r, w| unsafe {
411                            w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
412                        });
413
414                        $PXi { _mode: PhantomData }
415                    }
416
417                    /// Configures the pin to operate as a pulled up input pin
418                    pub fn into_pull_up_input(
419                        self,
420                        moder: &mut MODER,
421                        pupdr: &mut PUPDR,
422                    ) -> $PXi<Input<PullUp>> {
423                        let offset = 2 * $i;
424
425                        // input mode
426                        moder
427                            .moder()
428                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
429
430                        // pull-up
431                        pupdr.pupdr().modify(|r, w| unsafe {
432                            w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
433                        });
434
435                        $PXi { _mode: PhantomData }
436                    }
437
438                    /// Configures the pin to operate as an open drain output pin
439                    pub fn into_open_drain_output(
440                        self,
441                        moder: &mut MODER,
442                        otyper: &mut OTYPER,
443                    ) -> $PXi<Output<OpenDrain>> {
444                        let offset = 2 * $i;
445
446                        // general purpose output mode
447                        let mode = 0b01;
448                        moder.moder().modify(|r, w| unsafe {
449                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
450                        });
451
452                        // open drain output
453                        otyper
454                            .otyper()
455                            .modify(|r, w| unsafe { w.bits(r.bits() | (0b1 << $i)) });
456
457                        $PXi { _mode: PhantomData }
458                    }
459
460                    /// Configures the pin to operate as an push pull output pin
461                    pub fn into_push_pull_output(
462                        self,
463                        moder: &mut MODER,
464                        otyper: &mut OTYPER,
465                    ) -> $PXi<Output<PushPull>> {
466                        let offset = 2 * $i;
467
468                        // general purpose output mode
469                        let mode = 0b01;
470                        moder.moder().modify(|r, w| unsafe {
471                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
472                        });
473
474                        // push pull output
475                        otyper
476                            .otyper()
477                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1 << $i)) });
478
479                        $PXi { _mode: PhantomData }
480                    }
481
482                    /// Configures the pin to operate as an touch sample
483                    pub fn into_touch_sample(
484                        self,
485                        moder: &mut MODER,
486                        otyper: &mut OTYPER,
487                        afr: &mut $AFR,
488                    ) -> $PXi<Alternate<AF9, Output<OpenDrain>>> {
489                        let od = self.into_open_drain_output(moder, otyper);
490                        od.into_af9(moder, afr)
491                    }
492
493                    /// Configures the pin to operate as an touch channel
494                    pub fn into_touch_channel(
495                        self,
496                        moder: &mut MODER,
497                        otyper: &mut OTYPER,
498                        afr: &mut $AFR,
499                    ) -> $PXi<Alternate<AF9, Output<PushPull>>> {
500                        let od = self.into_push_pull_output(moder, otyper);
501                        od.into_af9(moder, afr)
502                    }
503                }
504
505                impl $PXi<Output<OpenDrain>> {
506                    /// Enables / disables the internal pull up
507                    pub fn internal_pull_up(&mut self, pupdr: &mut PUPDR, on: bool) {
508                        let offset = 2 * $i;
509
510                        pupdr.pupdr().modify(|r, w| unsafe {
511                            w.bits(
512                                (r.bits() & !(0b11 << offset)) | if on {
513                                    0b01 << offset
514                                } else {
515                                    0
516                                },
517                            )
518                        });
519                    }
520                }
521
522                impl<MODE> $PXi<Output<MODE>> {
523                    /// Erases the pin number from the type
524                    ///
525                    /// This is useful when you want to collect the pins into an array where you
526                    /// need all the elements to have the same type
527                    pub fn downgrade(self) -> $PXx<Output<MODE>> {
528                        $PXx {
529                            i: $i,
530                            _mode: self._mode,
531                        }
532                    }
533                }
534
535                impl<MODE> OutputPin for $PXi<Output<MODE>> {
536                    fn set_high(&mut self) {
537                        // NOTE(unsafe) atomic write to a stateless register
538                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
539                    }
540
541                    fn set_low(&mut self) {
542                        // NOTE(unsafe) atomic write to a stateless register
543                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
544                    }
545                }
546            )+
547        }
548    }
549}
550
551gpio!(GPIOA, gpioa, gpioa, gpioaen, gpioarst, PAx, [
552    PA0: (pa0, 0, Input<Floating>, AFRL),
553    PA1: (pa1, 1, Input<Floating>, AFRL),
554    PA2: (pa2, 2, Input<Floating>, AFRL),
555    PA3: (pa3, 3, Input<Floating>, AFRL),
556    PA4: (pa4, 4, Input<Floating>, AFRL),
557    PA5: (pa5, 5, Input<Floating>, AFRL),
558    PA6: (pa6, 6, Input<Floating>, AFRL),
559    PA7: (pa7, 7, Input<Floating>, AFRL),
560    PA8: (pa8, 8, Input<Floating>, AFRH),
561    PA9: (pa9, 9, Input<Floating>, AFRH),
562    PA10: (pa10, 10, Input<Floating>, AFRH),
563    PA11: (pa11, 11, Input<Floating>, AFRH),
564    PA12: (pa12, 12, Input<Floating>, AFRH),
565]);
566
567gpio!(GPIOB, gpiob, gpiob, gpioben, gpiobrst, PBx, [
568    PB0: (pb0, 0, Input<Floating>, AFRL),
569    PB1: (pb1, 1, Input<Floating>, AFRL),
570    PB2: (pb2, 2, Input<Floating>, AFRL),
571    PB3: (pb3, 3, Input<Floating>, AFRL),
572    PB4: (pb4, 4, Input<Floating>, AFRL),
573    PB5: (pb5, 5, Input<Floating>, AFRL),
574    PB6: (pb6, 6, Input<Floating>, AFRL),
575    PB7: (pb7, 7, Input<Floating>, AFRL),
576]);