mk20d7_hal/
gpio.rs

1use core::marker::PhantomData;
2use mk20d7::sim::SCGC5;
3
4/// Extension trait to split a GPIO peripheral in independent pins and registers
5pub trait GpioExt {
6    /// The to split the GPIO into
7    type Parts;
8
9    /// Splits the GPIO block into independent pins and registers
10    fn split(self, scgc5: &SCGC5) -> Self::Parts;
11}
12
13/// Input mode (type state)
14pub struct Input<MODE> {
15    _mode: PhantomData<MODE>,
16}
17
18/// Floating input (type state)
19pub struct Floating;
20
21/// Pulled down input (type state)
22pub struct PullDown;
23
24/// Pulled up input (type state)
25pub struct PullUp;
26
27/// Output mode (type state)
28pub struct Output<MODE> {
29    _mode: PhantomData<MODE>,
30}
31
32/// Push pull output (type state)
33pub struct PushPull;
34
35/// Open drain output (type state)
36pub struct OpenDrain;
37
38pub struct Alternate<MODE> {
39    _mode: PhantomData<MODE>,
40}
41
42/// Alternate function 0 (type state, Analog)
43pub struct ALT0;
44
45/// Alternate function 1 (type state, GPIO)
46pub struct ALT1;
47
48/// Alternate function 2 (type state, chip specific)
49pub struct ALT2;
50
51/// Alternate function 3 (type state, chip specific)
52pub struct ALT3;
53
54/// Alternate function 4 (type state, chip specific)
55pub struct ALT4;
56
57/// Alternate function 5 (type state, chip specific)
58pub struct ALT5;
59
60/// Alternate function 6 (type state, chip specific)
61pub struct ALT6;
62
63/// Alternate function 7 (type state, chip specific / JTAG / NMI)
64pub struct ALT7;
65
66// Pin mux controller mode
67enum PinMux {
68    ALT0,
69    ALT1,
70    ALT2,
71    ALT3,
72    ALT4,
73    ALT5,
74    ALT6,
75    ALT7,
76}
77
78// Pin mode (when pin is in ALT1 gpio mode)
79enum PinMode {
80    Output,
81
82    #[allow(dead_code)]
83    Input,
84}
85
86macro_rules! gpio {
87    ($PORTX:ident, $portx:ident, $PTX:ident, $ptx:ident, $gpiox:ident, $docport:expr, [ $($PTXi:ident: ($ptxi:ident, $i:expr, $MODE:ty, $docpin:expr),)+]) =>
88    {
89        #[doc = "General Purpose Input/Output Port "]
90        #[doc = $docport]
91        pub mod $gpiox {
92            use core::marker::PhantomData;
93
94            use hal::digital::{
95                OutputPin, StatefulOutputPin, InputPin,
96                toggleable,
97            };
98
99            use mk20d7::{sim::SCGC5, $PORTX, $PTX, $portx, $ptx};
100
101            use super::{
102                Floating, GpioExt, Input, Output,
103                PushPull,
104                Alternate, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5, ALT6, ALT7,
105                PinMux, PinMode,
106            };
107
108            /// General Purpose Input/Output and Pin Control and Interrupts parts
109            pub struct Parts {
110                // Pin Control and Interrupts parts
111                /// Digital Filter Clock Register
112                pub dfcr: DFCR,
113
114                /// Digital Filter Enable Register
115                pub dfer: DFER,
116
117                /// Digital Filter Width Register
118                pub dfwr: DFWR,
119
120                /// Global Pin Control High Register
121                pub gpchr: GPCHR,
122
123                /// Global Pin Control Low Register
124                pub gpclr: GPCLR,
125
126                /// Interrupt Status Flag Register
127                pub isfr: ISFR,
128
129                /// Pin Control Register n
130                pub pcr: PCR,
131
132                // General Purpose Input/Output parts
133                /// Port Clear Output Register
134                pub pcor: PCOR,
135
136                /// Port Data Direction Register
137                pub pddr: PDDR,
138
139                /// Port Data Input Register
140                pub pdir: PDIR,
141
142                /// Port Data Output Register
143                pub pdor: PDOR,
144
145                /// Port Set Output Register
146                pub psor: PSOR,
147
148                /// Port Toggle Output Register
149                pub ptor: PTOR,
150
151                $(
152                    #[doc = "General Purpose Input/Output Port "]
153                    #[doc = $docport]
154                    #[doc = " Pin "]
155                    #[doc = $docpin]
156                    pub $ptxi: $PTXi<$MODE>,
157                )+
158            }
159
160            impl GpioExt for ($PTX, $PORTX) {
161                type Parts = Parts;
162
163                fn split(self, scgc5: &SCGC5) -> Self::Parts {
164                    // Enable the GPIO module
165                    // Reference: 10.2.3 Clock gating
166                    scgc5.write(|w| w.$portx().set_bit());
167
168                    Parts {
169                        dfcr: DFCR { _0: () },
170                        dfer: DFER { _0: () },
171                        dfwr: DFWR { _0: () },
172                        gpchr: GPCHR { _0: () },
173                        gpclr: GPCLR { _0: () },
174                        isfr: ISFR { _0: () },
175                        pcr: PCR { _0: () },
176                        pcor: PCOR { _0: () },
177                        pddr: PDDR { _0: () },
178                        pdir: PDIR { _0: () },
179                        pdor: PDOR { _0: () },
180                        psor: PSOR { _0: () },
181                        ptor: PTOR { _0: () },
182                        $(
183                            $ptxi: $PTXi {_mode: PhantomData},
184                        )+
185                    }
186                }
187            }
188
189            /// Digital Filter Clock Register
190            pub struct DFCR {
191                _0: (),
192            }
193
194            impl DFCR {
195                #[allow(dead_code)]
196                pub(crate) fn dfcr(&mut self) -> &$portx::DFCR {
197                    unsafe { &(*$PORTX::ptr()).dfcr }
198                }
199            }
200
201            /// Digital Filter Enable Register
202            pub struct DFER {
203                _0: (),
204            }
205
206            impl DFER {
207                #[allow(dead_code)]
208                pub(crate) fn dfer(&mut self) -> &$portx::DFER {
209                    unsafe { &(*$PORTX::ptr()).dfer }
210                }
211            }
212
213            /// Digital Filter Width Register
214            pub struct DFWR {
215                _0: (),
216            }
217
218            impl DFWR {
219                #[allow(dead_code)]
220                pub(crate) fn dfwr(&mut self) -> &$portx::DFWR {
221                    unsafe { &(*$PORTX::ptr()).dfwr }
222                }
223            }
224
225            /// Global Pin Control High Register
226            pub struct GPCHR {
227                _0: (),
228            }
229
230            /// Global Pin Control Low Register
231            pub struct GPCLR {
232                _0: (),
233            }
234
235            /// Interrupt Status Flag Register
236            pub struct ISFR {
237                _0: (),
238            }
239
240            impl ISFR {
241                #[allow(dead_code)]
242                pub(crate) fn isfr(&mut self) -> &$portx::ISFR {
243                    unsafe { &(*$PORTX::ptr()).isfr }
244                }
245            }
246
247            /// Pin Control Register n
248            pub struct PCR {
249                _0: (),
250            }
251
252            impl PCR {
253                pub(crate) fn pcr(&mut self) -> &[$portx::PCR; 32] {
254                    unsafe { &(*$PORTX::ptr()).pcr }
255                }
256            }
257
258            /// Port Clear Output Register
259            pub struct PCOR {
260                _0: (),
261            }
262
263            impl PCOR {
264                pub(crate) fn pcor(&mut self) -> &$ptx::PCOR {
265                    unsafe { &(*$PTX::ptr()).pcor }
266                }
267            }
268
269            /// Port Data Direction Register
270            pub struct PDDR {
271                _0: (),
272            }
273
274            impl PDDR {
275                pub(crate) fn pddr(&mut self) -> &$ptx::PDDR {
276                    unsafe { &(*$PTX::ptr()).pddr }
277                }
278            }
279
280            /// Port Data Input Register
281            pub struct PDIR {
282                _0: (),
283            }
284
285            impl PDIR {
286                pub(crate) fn pdir(&mut self) -> &$ptx::PDIR {
287                    unsafe { &(*$PTX::ptr()).pdir }
288                }
289            }
290
291            /// Port Data Output Register
292            pub struct PDOR {
293                _0: (),
294            }
295
296            impl PDOR {
297                pub(crate) fn pdor(&mut self) -> &$ptx::PDOR {
298                    unsafe { &(*$PTX::ptr()).pdor }
299                }
300            }
301
302            /// Port Set Output Register
303            pub struct PSOR {
304                _0: (),
305            }
306
307            impl PSOR {
308                pub(crate) fn psor(&mut self) -> &$ptx::PSOR {
309                    unsafe { &(*$PTX::ptr()).psor }
310                }
311            }
312
313            /// Port Toggle Output Register
314            pub struct PTOR {
315                _0: (),
316            }
317
318            impl PTOR {
319                #[allow(dead_code)]
320                pub(crate) fn ptor(&mut self) -> &$ptx::PTOR {
321                    unsafe { &(*$PTX::ptr()).ptor }
322                }
323            }
324
325            fn set_pin_mux(pin: usize, pcr: &mut PCR, pin_mux: PinMux) {
326                let alt = match pin_mux {
327                    PinMux::ALT0 => $portx::pcr::MUXW::_000,
328                    PinMux::ALT1 => $portx::pcr::MUXW::_001,
329                    PinMux::ALT2 => $portx::pcr::MUXW::_010,
330                    PinMux::ALT3 => $portx::pcr::MUXW::_011,
331                    PinMux::ALT4 => $portx::pcr::MUXW::_100,
332                    PinMux::ALT5 => $portx::pcr::MUXW::_101,
333                    PinMux::ALT6 => $portx::pcr::MUXW::_110,
334                    PinMux::ALT7 => $portx::pcr::MUXW::_111,
335                };
336
337                pcr.pcr()[pin].write(|w| w.mux().variant(alt));
338            }
339
340            fn set_pin_mode(pin: u32, pddr: &mut PDDR, pin_mode: PinMode) {
341                let bit = match pin_mode {
342                    PinMode::Output => 1 << pin,
343                    PinMode::Input => !(1 << pin),
344                };
345                pddr.pddr().modify(|r, w| unsafe { w.bits(r.bits() | bit) });
346            }
347
348            // This pin owns its section of the PDOR, PSOR, PCOR, PTOR, and PDIR registers, as well
349            // as its PCR register
350            // Reference: 11.14.1 Pin Control Register n (PORTx_PCRn)
351            $(
352                #[doc = "General Purpose Input/Output Port "]
353                #[doc = $docport]
354                #[doc = " Pin "]
355                #[doc = $docpin]
356                pub struct $PTXi<MODE> {
357                    _mode: PhantomData<MODE>,
358                }
359
360                impl<MODE> $PTXi<MODE> {
361                    pub fn into_alternate_alt0(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT0>> {
362                        set_pin_mux($i, pcr, PinMux::ALT0);
363                        $PTXi { _mode: PhantomData }
364                    }
365
366                    pub fn into_alternate_alt1(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT1>> {
367                        set_pin_mux($i, pcr, PinMux::ALT1);
368                        $PTXi { _mode: PhantomData }
369                    }
370
371                    pub fn into_alternate_alt2(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT2>> {
372                        set_pin_mux($i, pcr, PinMux::ALT2);
373                        $PTXi { _mode: PhantomData }
374                    }
375
376                    pub fn into_alternate_alt3(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT3>> {
377                        set_pin_mux($i, pcr, PinMux::ALT3);
378                        $PTXi { _mode: PhantomData }
379                    }
380
381                    pub fn into_alternate_alt4(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT4>> {
382                        set_pin_mux($i, pcr, PinMux::ALT4);
383                        $PTXi { _mode: PhantomData }
384                    }
385
386                    pub fn into_alternate_alt5(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT5>> {
387                        set_pin_mux($i, pcr, PinMux::ALT5);
388                        $PTXi { _mode: PhantomData }
389                    }
390
391                    pub fn into_alternate_alt6(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT6>> {
392                        set_pin_mux($i, pcr, PinMux::ALT6);
393                        $PTXi { _mode: PhantomData }
394                    }
395
396                    pub fn into_alternate_alt7(self, pcr: &mut PCR) -> $PTXi<Alternate<ALT7>> {
397                        set_pin_mux($i, pcr, PinMux::ALT7);
398                        $PTXi { _mode: PhantomData }
399                    }
400
401                    pub fn into_push_pull_output(self, pcr: &mut PCR, pddr: &mut PDDR) -> $PTXi<Output<PushPull>> {
402                        set_pin_mux($i, pcr, PinMux::ALT1);
403                        set_pin_mode($i, pddr, PinMode::Output);
404                        $PTXi { _mode: PhantomData }
405                    }
406                }
407
408                impl<MODE> StatefulOutputPin for $PTXi<Output<MODE>> {
409                    fn is_set_high(&self) -> bool {
410                        !self.is_set_low()
411                    }
412
413                    fn is_set_low(&self) -> bool {
414                        (PDOR { _0: () }).pdor().read().bits() & (1 << $i) == 0
415                    }
416                }
417
418                impl<MODE> OutputPin for $PTXi<Output<MODE>> {
419                    fn set_high(&mut self) {
420                        (PSOR { _0: () }).psor().write(|w| unsafe { w.bits(1 << $i) })
421                    }
422
423                    fn set_low(&mut self) {
424                        (PCOR { _0: () }).pcor().write(|w| unsafe { w.bits(1 << $i) })
425                    }
426                }
427
428                impl<MODE> toggleable::Default for $PTXi<Output<MODE>> {}
429
430                impl<MODE> InputPin for $PTXi<Input<MODE>> {
431                    fn is_high(&self) -> bool {
432                        !self.is_low()
433                    }
434
435                    fn is_low(&self) -> bool {
436                        (PDIR { _0: () }).pdir().read().bits() & (1 << $i) == 0
437                    }
438                }
439            )+
440        }
441    }
442}
443
444// Reference: 10.3.1 K20 Signal Multiplexing and Pin Assignments
445gpio!(PORTA, porta, PTA, pta, gpioa, "A", [
446      PTA0: (pta0, 0, Input<Floating>, "0"),
447      PTA1: (pta1, 1, Input<Floating>, "1"),
448      PTA2: (pta2, 2, Input<Floating>, "2"),
449      PTA3: (pta3, 3, Input<Floating>, "3"),
450      PTA4: (pta4, 4, Input<Floating>, "4"),
451      PTA5: (pta5, 5, Input<Floating>, "5"),
452      PTA12: (pta12, 12, Input<Floating>, "12"),
453      PTA13: (pta13, 13, Input<Floating>, "13"),
454      PTA18: (pta18, 18, Input<Floating>, "18"),
455      PTA19: (pta19, 19, Input<Floating>, "19"),
456]);
457
458gpio!(PORTB, portb, PTB, ptb, gpiob, "B", [
459      PTB0: (ptb0, 0, Input<Floating>, "0"),
460      PTB1: (ptb1, 1, Input<Floating>, "1"),
461      PTB2: (ptb2, 2, Input<Floating>, "2"),
462      PTB3: (ptb3, 3, Input<Floating>, "3"),
463      PTB16: (ptb16, 16, Input<Floating>, "16"),
464      PTB17: (ptb17, 17, Input<Floating>, "17"),
465      PTB18: (ptb18, 18, Input<Floating>, "18"),
466      PTB19: (ptb19, 19, Input<Floating>, "19"),
467]);
468
469gpio!(PORTC, portc, PTC, ptc, gpioc, "C", [
470      PTC0: (ptc0, 0, Input<Floating>, "0"),
471      PTC1: (ptc1, 1, Input<Floating>, "1"),
472      PTC2: (ptc2, 2, Input<Floating>, "2"),
473      PTC3: (ptc3, 3, Input<Floating>, "3"),
474      PTC4: (ptc4, 4, Input<Floating>, "4"),
475      PTC5: (ptc5, 5, Input<Floating>, "5"),
476      PTC6: (ptc6, 6, Input<Floating>, "6"),
477      PTC7: (ptc7, 7, Input<Floating>, "7"),
478      PTC8: (ptc8, 8, Input<Floating>, "8"),
479      PTC9: (ptc9, 9, Input<Floating>, "9"),
480      PTC10: (ptc10, 10, Input<Floating>, "10"),
481      PTC11: (ptc11, 11, Input<Floating>, "11"),
482]);
483
484gpio!(PORTD, portd, PTD, ptd, gpiod, "D", [
485      PTD0: (ptd0, 0, Input<Floating>, "0"),
486      PTD1: (ptd1, 1, Input<Floating>, "1"),
487      PTD2: (ptd2, 2, Input<Floating>, "2"),
488      PTD3: (ptd3, 3, Input<Floating>, "3"),
489      PTD4: (ptd4, 4, Input<Floating>, "4"),
490      PTD5: (ptd5, 5, Input<Floating>, "5"),
491      PTD6: (ptd6, 6, Input<Floating>, "6"),
492      PTD7: (ptd7, 7, Input<Floating>, "7"),
493]);
494
495gpio!(PORTE, porte, PTE, pte, gpioe, "E", [
496      PTE0: (pte0, 0, Input<Floating>, "0"),
497      PTE1: (pte1, 1, Input<Floating>, "1"),
498]);