stm32f30x_hal/
gpio.rs

1//! General Purpose Input / Output
2
3// TODO the pins here currently correspond to the LQFP-100 package. There should be Cargo features
4// that let you select different microcontroller packages
5
6use core::marker::PhantomData;
7
8use rcc::AHB;
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 AHB) -> 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 function 0 (type state)
42pub struct AF0;
43
44/// Alternate function 1 (type state)
45pub struct AF1;
46
47/// Alternate function 2 (type state)
48pub struct AF2;
49
50/// Alternate function 3 (type state)
51pub struct AF3;
52
53/// Alternate function 4 (type state)
54pub struct AF4;
55
56/// Alternate function 5 (type state)
57pub struct AF5;
58
59/// Alternate function 6 (type state)
60pub struct AF6;
61
62/// Alternate function 7 (type state)
63pub struct AF7;
64
65/// Alternate function 8 (type state)
66pub struct AF8;
67
68/// Alternate function 9 (type state)
69pub struct AF9;
70
71/// Alternate function 10 (type state)
72pub struct AF10;
73
74/// Alternate function 11 (type state)
75pub struct AF11;
76
77/// Alternate function 12 (type state)
78pub struct AF12;
79
80/// Alternate function 13 (type state)
81pub struct AF13;
82
83/// Alternate function 14 (type state)
84pub struct AF14;
85
86/// Alternate function 15 (type state)
87pub struct AF15;
88
89macro_rules! gpio {
90    ($GPIOX:ident, $gpiox:ident, $gpioy:ident, $iopxenr:ident, $iopxrst:ident, $PXx:ident, [
91        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $AFR:ident),)+
92    ]) => {
93        /// GPIO
94        pub mod $gpiox {
95            use core::marker::PhantomData;
96
97            use hal::digital::OutputPin;
98            use stm32f30x::{$gpioy, $GPIOX};
99
100            use rcc::AHB;
101            use super::{
102                AF4, AF5, AF6, AF7, Floating, GpioExt, Input, OpenDrain, Output,
103                PullDown, PullUp, PushPull,
104            };
105
106            /// GPIO parts
107            pub struct Parts {
108                /// Opaque AFRH register
109                pub afrh: AFRH,
110                /// Opaque AFRL register
111                pub afrl: AFRL,
112                /// Opaque MODER register
113                pub moder: MODER,
114                /// Opaque OTYPER register
115                pub otyper: OTYPER,
116                /// Opaque PUPDR register
117                pub pupdr: PUPDR,
118                $(
119                    /// Pin
120                    pub $pxi: $PXi<$MODE>,
121                )+
122            }
123
124            impl GpioExt for $GPIOX {
125                type Parts = Parts;
126
127                fn split(self, ahb: &mut AHB) -> Parts {
128                    ahb.enr().modify(|_, w| w.$iopxenr().enabled());
129                    ahb.rstr().modify(|_, w| w.$iopxrst().set_bit());
130                    ahb.rstr().modify(|_, w| w.$iopxrst().clear_bit());
131
132                    Parts {
133                        afrh: AFRH { _0: () },
134                        afrl: AFRL { _0: () },
135                        moder: MODER { _0: () },
136                        otyper: OTYPER { _0: () },
137                        pupdr: PUPDR { _0: () },
138                        $(
139                            $pxi: $PXi { _mode: PhantomData },
140                        )+
141                    }
142                }
143            }
144
145            /// Opaque AFRL register
146            pub struct AFRL {
147                _0: (),
148            }
149
150            impl AFRL {
151                pub(crate) fn afr(&mut self) -> &$gpioy::AFRL {
152                    unsafe { &(*$GPIOX::ptr()).afrl }
153                }
154            }
155
156            /// Opaque AFRH register
157            pub struct AFRH {
158                _0: (),
159            }
160
161            impl AFRH {
162                pub(crate) fn afr(&mut self) -> &$gpioy::AFRH {
163                    unsafe { &(*$GPIOX::ptr()).afrh }
164                }
165            }
166
167            /// Opaque MODER register
168            pub struct MODER {
169                _0: (),
170            }
171
172            impl MODER {
173                pub(crate) fn moder(&mut self) -> &$gpioy::MODER {
174                    unsafe { &(*$GPIOX::ptr()).moder }
175                }
176            }
177
178            /// Opaque OTYPER register
179            pub struct OTYPER {
180                _0: (),
181            }
182
183            impl OTYPER {
184                pub(crate) fn otyper(&mut self) -> &$gpioy::OTYPER {
185                    unsafe { &(*$GPIOX::ptr()).otyper }
186                }
187            }
188
189            /// Opaque PUPDR register
190            pub struct PUPDR {
191                _0: (),
192            }
193
194            impl PUPDR {
195                pub(crate) fn pupdr(&mut self) -> &$gpioy::PUPDR {
196                    unsafe { &(*$GPIOX::ptr()).pupdr }
197                }
198            }
199
200            /// Partially erased pin
201            pub struct $PXx<MODE> {
202                i: u8,
203                _mode: PhantomData<MODE>,
204            }
205
206            impl<MODE> OutputPin for $PXx<Output<MODE>> {
207                fn set_high(&mut self) {
208                    // NOTE(unsafe) atomic write to a stateless register
209                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
210                }
211
212                fn set_low(&mut self) {
213                    // NOTE(unsafe) atomic write to a stateless register
214                    unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + self.i))) }
215                }
216            }
217
218            $(
219                /// Pin
220                pub struct $PXi<MODE> {
221                    _mode: PhantomData<MODE>,
222                }
223
224                impl<MODE> $PXi<MODE> {
225                    /// Configures the pin to serve as alternate function 4 (AF4)
226                    pub fn into_af4(
227                        self,
228                        moder: &mut MODER,
229                        afr: &mut $AFR,
230                    ) -> $PXi<AF4> {
231                        let offset = 2 * $i;
232
233                        // alternate function mode
234                        let mode = 0b10;
235                        moder.moder().modify(|r, w| unsafe {
236                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
237                        });
238
239                        let af = 4;
240                        let offset = 4 * ($i % 8);
241                        afr.afr().modify(|r, w| unsafe {
242                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
243                        });
244
245                        $PXi { _mode: PhantomData }
246                    }
247
248                    /// Configures the pin to serve as alternate function 5 (AF5)
249                    pub fn into_af5(
250                        self,
251                        moder: &mut MODER,
252                        afr: &mut $AFR,
253                    ) -> $PXi<AF5> {
254                        let offset = 2 * $i;
255
256                        // alternate function mode
257                        let mode = 0b10;
258                        moder.moder().modify(|r, w| unsafe {
259                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
260                        });
261
262                        let af = 5;
263                        let offset = 4 * ($i % 8);
264                        afr.afr().modify(|r, w| unsafe {
265                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
266                        });
267
268                        $PXi { _mode: PhantomData }
269                    }
270
271                    /// Configures the pin to serve as alternate function 6 (AF6)
272                    pub fn into_af6(
273                        self,
274                        moder: &mut MODER,
275                        afr: &mut $AFR,
276                    ) -> $PXi<AF6> {
277                        let offset = 2 * $i;
278
279                        // alternate function mode
280                        let mode = 0b10;
281                        moder.moder().modify(|r, w| unsafe {
282                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
283                        });
284
285                        let af = 6;
286                        let offset = 4 * ($i % 8);
287                        afr.afr().modify(|r, w| unsafe {
288                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
289                        });
290
291                        $PXi { _mode: PhantomData }
292                    }
293
294                    /// Configures the pin to serve as alternate function 7 (AF7)
295                    pub fn into_af7(
296                        self,
297                        moder: &mut MODER,
298                        afr: &mut $AFR,
299                    ) -> $PXi<AF7> {
300                        let offset = 2 * $i;
301
302                        // alternate function mode
303                        let mode = 0b10;
304                        moder.moder().modify(|r, w| unsafe {
305                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
306                        });
307
308                        let af = 7;
309                        let offset = 4 * ($i % 8);
310
311                        afr.afr().modify(|r, w| unsafe {
312                            w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
313                        });
314
315                        $PXi { _mode: PhantomData }
316                    }
317
318                    /// Configures the pin to operate as a floating input pin
319                    pub fn into_floating_input(
320                        self,
321                        moder: &mut MODER,
322                        pupdr: &mut PUPDR,
323                    ) -> $PXi<Input<Floating>> {
324                        let offset = 2 * $i;
325
326                        // input mode
327                        moder
328                            .moder()
329                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
330
331                        // no pull-up or pull-down
332                        pupdr
333                            .pupdr()
334                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
335
336                        $PXi { _mode: PhantomData }
337                    }
338
339                    /// Configures the pin to operate as a pulled down input pin
340                    pub fn into_pull_down_input(
341                        self,
342                        moder: &mut MODER,
343                        pupdr: &mut PUPDR,
344                    ) -> $PXi<Input<PullDown>> {
345                        let offset = 2 * $i;
346
347                        // input mode
348                        moder
349                            .moder()
350                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
351
352                        // pull-down
353                        pupdr.pupdr().modify(|r, w| unsafe {
354                            w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
355                        });
356
357                        $PXi { _mode: PhantomData }
358                    }
359
360                    /// Configures the pin to operate as a pulled up input pin
361                    pub fn into_pull_up_input(
362                        self,
363                        moder: &mut MODER,
364                        pupdr: &mut PUPDR,
365                    ) -> $PXi<Input<PullUp>> {
366                        let offset = 2 * $i;
367
368                        // input mode
369                        moder
370                            .moder()
371                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
372
373                        // pull-up
374                        pupdr.pupdr().modify(|r, w| unsafe {
375                            w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
376                        });
377
378                        $PXi { _mode: PhantomData }
379                    }
380
381                    /// Configures the pin to operate as an open drain output pin
382                    pub fn into_open_drain_output(
383                        self,
384                        moder: &mut MODER,
385                        otyper: &mut OTYPER,
386                    ) -> $PXi<Output<OpenDrain>> {
387                        let offset = 2 * $i;
388
389                        // general purpose output mode
390                        let mode = 0b01;
391                        moder.moder().modify(|r, w| unsafe {
392                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
393                        });
394
395                        // open drain output
396                        otyper
397                            .otyper()
398                            .modify(|r, w| unsafe { w.bits(r.bits() | (0b1 << $i)) });
399
400                        $PXi { _mode: PhantomData }
401                    }
402
403                    /// Configures the pin to operate as an push pull output pin
404                    pub fn into_push_pull_output(
405                        self,
406                        moder: &mut MODER,
407                        otyper: &mut OTYPER,
408                    ) -> $PXi<Output<PushPull>> {
409                        let offset = 2 * $i;
410
411                        // general purpose output mode
412                        let mode = 0b01;
413                        moder.moder().modify(|r, w| unsafe {
414                            w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
415                        });
416
417                        // push pull output
418                        otyper
419                            .otyper()
420                            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1 << $i)) });
421
422                        $PXi { _mode: PhantomData }
423                    }
424                }
425
426                impl $PXi<Output<OpenDrain>> {
427                    /// Enables / disables the internal pull up
428                    pub fn internal_pull_up(&mut self, pupdr: &mut PUPDR, on: bool) {
429                        let offset = 2 * $i;
430
431                        pupdr.pupdr().modify(|r, w| unsafe {
432                            w.bits(
433                                (r.bits() & !(0b11 << offset)) | if on {
434                                    0b01 << offset
435                                } else {
436                                    0
437                                },
438                            )
439                        });
440                    }
441                }
442
443                impl<MODE> $PXi<Output<MODE>> {
444                    /// Erases the pin number from the type
445                    ///
446                    /// This is useful when you want to collect the pins into an array where you
447                    /// need all the elements to have the same type
448                    pub fn downgrade(self) -> $PXx<Output<MODE>> {
449                        $PXx {
450                            i: $i,
451                            _mode: self._mode,
452                        }
453                    }
454                }
455
456                impl<MODE> OutputPin for $PXi<Output<MODE>> {
457                    fn set_high(&mut self) {
458                        // NOTE(unsafe) atomic write to a stateless register
459                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
460                    }
461
462                    fn set_low(&mut self) {
463                        // NOTE(unsafe) atomic write to a stateless register
464                        unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
465                    }
466                }
467            )+
468        }
469    }
470}
471
472gpio!(GPIOA, gpioa, gpioa, iopaen, ioparst, PAx, [
473    PA0: (pa0, 0, Input<Floating>, AFRL),
474    PA1: (pa1, 1, Input<Floating>, AFRL),
475    PA2: (pa2, 2, Input<Floating>, AFRL),
476    PA3: (pa3, 3, Input<Floating>, AFRL),
477    PA4: (pa4, 4, Input<Floating>, AFRL),
478    PA5: (pa5, 5, Input<Floating>, AFRL),
479    PA6: (pa6, 6, Input<Floating>, AFRL),
480    PA7: (pa7, 7, Input<Floating>, AFRL),
481    PA8: (pa8, 8, Input<Floating>, AFRH),
482    PA9: (pa9, 9, Input<Floating>, AFRH),
483    PA10: (pa10, 10, Input<Floating>, AFRH),
484    PA11: (pa11, 11, Input<Floating>, AFRH),
485    PA12: (pa12, 12, Input<Floating>, AFRH),
486    // TODO these are configured as JTAG pins
487    // PA13: (13, Input<Floating>),
488    // PA14: (14, Input<Floating>),
489    // PA15: (15, Input<Floating>),
490]);
491
492gpio!(GPIOB, gpiob, gpiob, iopben, iopbrst, PBx, [
493    PB0: (pb0, 0, Input<Floating>, AFRL),
494    PB1: (pb1, 1, Input<Floating>, AFRL),
495    PB2: (pb2, 2, Input<Floating>, AFRL),
496    // TODO these are configured as JTAG pins
497    // PB3: (3, Input<Floating>),
498    // PB4: (4, Input<Floating>),
499    PB5: (pb5, 5, Input<Floating>, AFRL),
500    PB6: (pb6, 6, Input<Floating>, AFRL),
501    PB7: (pb7, 7, Input<Floating>, AFRL),
502    PB8: (pb8, 8, Input<Floating>, AFRH),
503    PB9: (pb9, 9, Input<Floating>, AFRH),
504    PB10: (pb10, 10, Input<Floating>, AFRH),
505    PB11: (pb11, 11, Input<Floating>, AFRH),
506    PB12: (pb12, 12, Input<Floating>, AFRH),
507    PB13: (pb13, 13, Input<Floating>, AFRH),
508    PB14: (pb14, 14, Input<Floating>, AFRH),
509    PB15: (pb15, 15, Input<Floating>, AFRH),
510]);
511
512gpio!(GPIOC, gpioc, gpioc, iopcen, iopcrst, PCx, [
513    PC0: (pc0, 0, Input<Floating>, AFRL),
514    PC1: (pc1, 1, Input<Floating>, AFRL),
515    PC2: (pc2, 2, Input<Floating>, AFRL),
516    PC3: (pc3, 3, Input<Floating>, AFRL),
517    PC4: (pc4, 4, Input<Floating>, AFRL),
518    PC5: (pc5, 5, Input<Floating>, AFRL),
519    PC6: (pc6, 6, Input<Floating>, AFRL),
520    PC7: (pc7, 7, Input<Floating>, AFRL),
521    PC8: (pc8, 8, Input<Floating>, AFRH),
522    PC9: (pc9, 9, Input<Floating>, AFRH),
523    PC10: (pc10, 10, Input<Floating>, AFRH),
524    PC11: (pc11, 11, Input<Floating>, AFRH),
525    PC12: (pc12, 12, Input<Floating>, AFRH),
526    PC13: (pc13, 13, Input<Floating>, AFRH),
527    PC14: (pc14, 14, Input<Floating>, AFRH),
528    PC15: (pc15, 15, Input<Floating>, AFRH),
529]);
530
531gpio!(GPIOD, gpiod, gpioc, iopden, iopdrst, PDx, [
532    PD0: (pd0, 0, Input<Floating>, AFRL),
533    PD1: (pd1, 1, Input<Floating>, AFRL),
534    PD2: (pd2, 2, Input<Floating>, AFRL),
535    PD3: (pd3, 3, Input<Floating>, AFRL),
536    PD4: (pd4, 4, Input<Floating>, AFRL),
537    PD5: (pd5, 5, Input<Floating>, AFRL),
538    PD6: (pd6, 6, Input<Floating>, AFRL),
539    PD7: (pd7, 7, Input<Floating>, AFRL),
540    PD8: (pd8, 8, Input<Floating>, AFRH),
541    PD9: (pd9, 9, Input<Floating>, AFRH),
542    PD10: (pd10, 10, Input<Floating>, AFRH),
543    PD11: (pd11, 11, Input<Floating>, AFRH),
544    PD12: (pd12, 12, Input<Floating>, AFRH),
545    PD13: (pd13, 13, Input<Floating>, AFRH),
546    PD14: (pd14, 14, Input<Floating>, AFRH),
547    PD15: (pd15, 15, Input<Floating>, AFRH),
548]);
549
550gpio!(GPIOE, gpioe, gpioc, iopeen, ioperst, PEx, [
551    PE0: (pe0, 0, Input<Floating>, AFRL),
552    PE1: (pe1, 1, Input<Floating>, AFRL),
553    PE2: (pe2, 2, Input<Floating>, AFRL),
554    PE3: (pe3, 3, Input<Floating>, AFRL),
555    PE4: (pe4, 4, Input<Floating>, AFRL),
556    PE5: (pe5, 5, Input<Floating>, AFRL),
557    PE6: (pe6, 6, Input<Floating>, AFRL),
558    PE7: (pe7, 7, Input<Floating>, AFRL),
559    PE8: (pe8, 8, Input<Floating>, AFRH),
560    PE9: (pe9, 9, Input<Floating>, AFRH),
561    PE10: (pe10, 10, Input<Floating>, AFRH),
562    PE11: (pe11, 11, Input<Floating>, AFRH),
563    PE12: (pe12, 12, Input<Floating>, AFRH),
564    PE13: (pe13, 13, Input<Floating>, AFRH),
565    PE14: (pe14, 14, Input<Floating>, AFRH),
566    PE15: (pe15, 15, Input<Floating>, AFRH),
567]);
568
569gpio!(GPIOF, gpiof, gpioc, iopfen, iopfrst, PFx, [
570    PF0: (pf0, 0, Input<Floating>, AFRL),
571    PF1: (pf1, 1, Input<Floating>, AFRL),
572    PF2: (pf2, 2, Input<Floating>, AFRL),
573    PF4: (pf3, 4, Input<Floating>, AFRL),
574    PF6: (pf6, 6, Input<Floating>, AFRL),
575    PF9: (pf9, 9, Input<Floating>, AFRH),
576    PF10: (pf10, 10, Input<Floating>, AFRH),
577]);