kea_hal/
gpio.rs

1//! GPIO Pheripheral
2//!
3//! Note that per 11.1 of KEA64 Ref Man, if the pin is switch to alternate
4//! peripheral function, the IO functions are disabled. Peripherals have
5//! priority over IO.
6
7use core::marker::PhantomData;
8
9/// Default mode for GPIO pins
10///
11/// at reset, per 11.1 of KEA64 sub-family reference manual (pg. 133)
12/// PTA4:5, PTB4, and PTC4 default to SWD_DIO, SWD_CLK, NMI, & RESET function.
13pub type DefaultMode = HighImpedence;
14
15/// Trait to split the pin register into independent pins and regs
16pub trait GPIOExt {
17    /// holds the pins
18    type Parts;
19
20    /// splits the peripheral into pins
21    fn split(self) -> Self::Parts;
22}
23
24/// High Impedence type state
25///
26/// This is a type state AND and a pin state. It's not technically an input
27/// since the port cannot (successfully) be written to or read from.
28/// The Input probably not readable in this state.
29/// @TODO Verify if functional in state
30pub struct HighImpedence;
31
32/// Input Mode type state
33pub struct Input<MODE> {
34    _mode: PhantomData<MODE>,
35}
36
37/// Output Mode type state
38pub struct Output<MODE> {
39    _mode: PhantomData<MODE>,
40}
41
42/// Floating input type state
43pub struct Floating;
44
45/// PullUp input type state
46pub struct PullUp;
47
48/// PushPull output type state
49pub struct PushPull;
50
51/// High Current Drive output state
52///
53/// For KEA, this is called High Current Drive output type state and is only
54/// available on a few ports.
55pub struct HighDrive;
56
57macro_rules! gpio {
58    ($GPIOx:ident, $gpiox:ident, $puex: ident,
59     [ $($PTX:ident: $PTXn:expr,)+ ],
60     [ $($PTXi:ident: ($ptxi:ident, $i:expr, $FLTOffset:expr),)+ ],
61     [ $($HighDrivePin:ident: ($i2:expr, $HighDriveIndex:expr),)+
62     ]) => {
63
64        /// GPIO Port Module
65        pub mod $gpiox {
66            use super::{PushPull, PullUp, HighDrive, HighImpedence,
67            Floating, Input, Output, GPIOExt, DefaultMode
68            };
69            use crate::hal::digital::v2::{ToggleableOutputPin, InputPin, OutputPin, StatefulOutputPin};
70            use crate::pac::{$GPIOx, PORT};
71            use core::marker::PhantomData;
72            use core::convert::Infallible;
73
74            /// Port Collection
75            pub struct Parts {
76                $(
77                    /// A pin in the port
78                    pub $ptxi: $PTXi<DefaultMode>,
79                )+
80            }
81
82            impl GPIOExt for $GPIOx {
83                type Parts = Parts;
84
85                fn split(self) -> Parts {
86                    Parts {
87                        $(
88                            $ptxi: $PTXi { _mode: PhantomData },
89                        )+
90                    }
91                }
92            }
93
94            $(
95                /// Partially erased pin?
96                pub struct $PTX<MODE> {
97                    i: u8,
98                    _mode: PhantomData<MODE>,
99                }
100
101
102                impl<MODE> OutputPin for $PTX<Output<MODE>> {
103                    type Error = Infallible;
104
105                    fn set_high(&mut self) -> Result<(), Self::Error> {
106                        // Atomically set high via stateless register
107                        unsafe {
108                            (*$GPIOx::ptr()).psor.write(|w| {
109                                w.bits(1 << self.i)
110                            });
111                        }
112                        Ok(())
113                    }
114
115                    fn set_low(&mut self) -> Result<(), Self::Error> {
116                        // Atomically set low via statelss register
117                        unsafe {
118                            (*$GPIOx::ptr()).pcor.write(|w| {
119                                w.bits(1 << self.i)
120                            });
121                        }
122                        Ok(())
123                    }
124                }
125
126                impl<MODE> StatefulOutputPin for $PTX<Output<MODE>> {
127                    fn is_set_high(&self) -> Result<bool, Self::Error> {
128                        Ok(!self.is_set_low()?)
129                    }
130                    fn is_set_low(&self) -> Result<bool, Self::Error> {
131                        // Atomically check truthiness of bit in port
132                        Ok(unsafe {
133                            (*$GPIOx::ptr()).pdor.read().bits() & (1 << self.i)
134                        } == 0)
135                    }
136                }
137
138                impl<MODE> ToggleableOutputPin for $PTX<Output<MODE>> {
139                    type Error = Infallible;
140
141                    fn toggle(&mut self) -> Result<(), Self::Error>{
142                        Ok(unsafe {
143                            (*$GPIOx::ptr()).ptor.write(|w| {
144                                w.bits(1 << self.i)
145                            })
146                        })
147                    }
148                }
149
150                impl<MODE> InputPin for $PTX<Output<MODE>> {
151                    type Error = Infallible;
152
153                    fn is_high(&self) -> Result<bool, Self::Error> {
154                        Ok(!self.is_low()?)
155                    }
156
157                    fn is_low(&self) -> Result<bool, Self::Error> {
158                        Ok(unsafe{
159                            (*$GPIOx::ptr()).pdir.read().bits() & (1 << self.i)
160                        } == 0)
161                    }
162                }
163            )+
164
165            $(
166                /// a GPIO Port Pin
167                pub struct $PTXi<MODE> {
168                    _mode: PhantomData<MODE>,
169                }
170
171                // What is this Into business? I don't remember!
172                // What is the interface like? Where did I see this?
173
174                impl From<$PTXi<DefaultMode>> for $PTXi<Input<PullUp>> {
175                    fn from(pin: $PTXi<DefaultMode>) -> $PTXi<Input<PullUp>> {
176                        pin.into_pull_up_input()
177                    }
178                }
179
180                impl From<$PTXi<DefaultMode>> for $PTXi<Input<Floating>> {
181                    fn from(pin: $PTXi<DefaultMode>) -> $PTXi<Input<Floating>> {
182                        pin.into_floating_input()
183                    }
184                }
185
186                impl From<$PTXi<DefaultMode>> for $PTXi<Output<PushPull>> {
187                    fn from(pin: $PTXi<DefaultMode>) -> $PTXi<Output<PushPull>> {
188                        pin.into_push_pull_output()
189                    }
190                }
191
192                /// Implements the I/O type conversion methods
193                impl<MODE> $PTXi<MODE> {
194                    /// Configure as floating
195                    pub fn into_floating_input(self) -> $PTXi<Input<Floating>> {
196                        //whatever it needs to grab the right bits
197                        // from pull up reg and mode reg
198                        unsafe {
199                            let gpio = &(*$GPIOx::ptr());
200                            let port = &(*PORT::ptr());
201
202                            // Turn off Pull Up (1 = pullup)
203                            port.$puex.modify(|r, w| {
204                                w.bits(r.bits() & !(1 << $i))
205                            });
206
207                            // Set to Input (0 = input)
208                            gpio.pddr.modify(|r, w| {
209                                w.bits(r.bits() & !(1 << $i))
210                            });
211                            // 0 = input
212                            gpio.pidr.modify(|r, w| {
213                                w.bits(r.bits() & !(1 << $i))
214                            });
215                        }
216                        $PTXi {_mode: PhantomData}
217                    }
218
219                    /// Configure as pull up input
220                    pub fn into_pull_up_input(self) -> $PTXi<Input<PullUp>> {
221                        unsafe {
222                            let gpio = &(*$GPIOx::ptr());
223                            let port = &(*PORT::ptr());
224
225                            // Set to Input
226                            // 0 = input, 1 = output
227                            gpio.pddr.modify(|r, w| {
228                                w.bits(r.bits() & !(1 << $i))
229                            });
230                            // 0 = input, 1 = output
231                            gpio.pidr.modify(|r, w| {
232                                w.bits(r.bits() & !(1 << $i))
233                            });
234
235                            // Turn on Pull Up
236                            // 1 = on, 0 = off
237                            port.$puex.modify(|r, w| {
238                                w.bits(r.bits() | (1 << $i))
239                            });
240
241                        }
242
243                        $PTXi {_mode: PhantomData}
244                    }
245
246                    /// Configure as PushPull output
247                    pub fn into_push_pull_output(self) -> $PTXi<Output<PushPull>> {
248                        unsafe {
249                            let gpio = &(*$GPIOx::ptr());
250                            let port = &(*PORT::ptr());
251
252                            // Turn off Pull Up
253                            port.$puex.modify(|r, w| {
254                                w.bits(r.bits() & !(1 << $i))
255                            });
256
257                            // Disable input (temporarily hiZ)
258                            gpio.pidr.modify(|r, w| {
259                                w.bits(r.bits() | (1 << $i))
260                            });
261
262                            // set to output
263                            gpio.pddr.modify(|r,w| {
264                                w.bits(r.bits() | (1 << $i))
265                            });
266
267                        }
268
269                        $PTXi {_mode: PhantomData}
270                    }
271
272                    /// Configure into High Impedence output
273                    pub fn into_high_impedence(self) -> $PTXi<HighImpedence> {
274                        unsafe {
275                            let gpio = &(*$GPIOx::ptr());
276                            let port = &(*PORT::ptr());
277
278                            // Turn off Pull Up
279                            port.$puex.modify(|r, w| {
280                                w.bits(r.bits() & !(1 << $i))
281                            });
282
283
284                            // Make HiZ (disable input)
285                            gpio.pidr.modify(|r, w| {
286                                w.bits(r.bits() & (1 << $i))
287                            });
288
289                            // Set to Input
290                            gpio.pddr.modify(|r, w| {
291                                w.bits(r.bits() & !(1 << $i))
292                            });
293
294                        }
295                        $PTXi {_mode: PhantomData}
296                    }
297                }
298
299                impl<MODE> OutputPin for $PTXi<Output<MODE>> {
300                    type Error = Infallible;
301
302                    fn set_high(&mut self) -> Result<(), Self::Error> {
303                        // Atomically set high via stateless register
304                        unsafe {
305                            (*$GPIOx::ptr()).psor.write(|w| {
306                                w.bits(1 << $i)
307                            });
308                        }
309                        Ok(())
310                    }
311
312                    fn set_low(&mut self) -> Result<(), Self::Error> {
313                        // Atomically set low via statelss register
314                        unsafe {
315                            (*$GPIOx::ptr()).pcor.write(|w| {
316                                w.bits(1 << $i)
317                            });
318                        }
319                        Ok(())
320                    }
321                }
322
323                impl<MODE> StatefulOutputPin for $PTXi<Output<MODE>> {
324                    fn is_set_high(&self) -> Result<bool, Self::Error> {
325                        Ok(!self.is_set_low()?)
326                    }
327                    fn is_set_low(&self) -> Result<bool, Self::Error> {
328                        // Atomically check truthiness of bit in port
329                        Ok(unsafe {
330                            (*$GPIOx::ptr()).pdor.read().bits() & (1 << $i)
331                        } == 0)
332                    }
333                }
334
335                impl<MODE> ToggleableOutputPin for $PTXi<Output<MODE>> {
336                    type Error = Infallible;
337
338                    fn toggle(&mut self) -> Result<(), Self::Error>{
339                        Ok(unsafe {
340                            (*$GPIOx::ptr()).ptor.write(|w| {
341                                w.bits(1 << $i)
342                            })
343                        })
344                    }
345                }
346
347                impl<MODE> InputPin for $PTXi<Input<MODE>> {
348                    type Error = Infallible;
349
350                    fn is_high(&self) -> Result<bool, Self::Error> {
351                        Ok(!self.is_low()?)
352                    }
353
354                    fn is_low(&self) -> Result<bool, Self::Error> {
355                        Ok(unsafe{
356                            (*$GPIOx::ptr()).pdir.read().bits() & (1 << $i)
357                        } == 0)
358                    }
359
360                }
361            )+
362
363            $(
364                // impl Into<$HighDrivePin<Output<HighDrive>>> for $HighDrivePin<DefaultMode> {
365                //     fn into(self) -> $HighDrivePin<Output<HighDrive>> {
366                //         self.into_high_drive_output()
367                //     }
368                // }
369
370                impl From<$HighDrivePin<DefaultMode>> for $HighDrivePin<Output<HighDrive>> {
371                    fn from(pin: $HighDrivePin<DefaultMode>) -> $HighDrivePin<Output<HighDrive>> {
372                        pin.into_high_drive_output()
373                    }
374                }
375
376                impl<MODE> $HighDrivePin<MODE> {
377                    /// Configure into push pull output
378                    ///
379                    /// The KEA series calls this high current drive
380                    /// This is only implemented for PTB4:5, PTD0:1, PTE0:1,
381                    /// and PTH0:1.
382                    pub fn into_high_drive_output(self) -> $HighDrivePin<Output<HighDrive>> {
383                        unsafe {
384                            let gpio = &(*$GPIOx::ptr());
385                            let port = &(*PORT::ptr());
386
387                            // Turn off Pull Up
388                            port.$puex.modify(|r, w| {
389                                w.bits(r.bits() & !(1 << $i2))
390                            });
391
392
393                            // Disable input (temporarily hiZ)
394                            gpio.pidr.modify(|r, w| {
395                                w.bits(r.bits() | (1 << $i2))
396                            });
397
398                            // Set to Output
399                            gpio.pddr.modify(|r,w| {
400                                w.bits(r.bits() | (1 << $i2))
401                            });
402
403                            // Enable high current drivers
404                            port.hdrve.modify(|r,w| {
405                                w.bits(r.bits() | (1 << $HighDriveIndex))
406                            });
407                        }
408
409                        $HighDrivePin {_mode: PhantomData}
410                    }
411                }
412            )+
413        }
414    }
415}
416
417gpio!(GPIOA, gpioa, puel, [
418    PTA: 0,
419    PTB: 1,
420    PTC: 2,
421    PTD: 3,
422], [
423    PTA0: (pta0, 0, 0),
424    PTA1: (pta1, 1, 0),
425    PTA2: (pta2, 2, 0),
426    PTA3: (pta3, 3, 0),
427    PTA4: (pta4, 4, 0),
428    PTA5: (pta5, 5, 0),
429    PTA6: (pta6, 6, 0),
430    PTA7: (pta7, 7, 0),
431    PTB0: (ptb0, 8, 2),
432    PTB1: (ptb1, 9, 2),
433    PTB2: (ptb2, 10, 2),
434    PTB3: (ptb3, 11, 2),
435    PTB4: (ptb4, 12, 2),
436    PTB5: (ptb5, 13, 2),
437    PTB6: (ptb6, 14, 2),
438    PTB7: (ptb7, 15, 2),
439    PTC0: (ptc0, 16, 4),
440    PTC1: (ptc1, 17, 4),
441    PTC2: (ptc2, 18, 4),
442    PTC3: (ptc3, 19, 4),
443    PTC4: (ptc4, 20, 4),
444    PTC5: (ptc5, 21, 4),
445    PTC6: (ptc6, 22, 4),
446    PTC7: (ptc7, 23, 4),
447    PTD0: (ptd0, 24, 6),
448    PTD1: (ptd1, 25, 6),
449    PTD2: (ptd2, 26, 6),
450    PTD3: (ptd3, 27, 6),
451    PTD4: (ptd4, 28, 6),
452    PTD5: (ptd5, 29, 6),
453    PTD6: (ptd6, 30, 6),
454    PTD7: (ptd7, 31, 6),
455], [
456    PTB4: (12, 0),
457    PTB5: (13, 1),
458    PTD0: (24, 2),
459    PTD1: (25, 3),
460]);
461
462gpio!(GPIOB, gpiob, pueh, [
463    PTE: 0,
464    PTF: 1,
465    PTG: 2,
466    PTH: 3,
467], [
468    PTE0: (pte0, 0, 8),
469    PTE1: (pte1, 1, 8),
470    PTE2: (pte2, 2, 8),
471    PTE3: (pte3, 3, 8),
472    PTE4: (pte4, 4, 8),
473    PTE5: (pte5, 5, 8),
474    PTE6: (pte6, 6, 8),
475    PTE7: (pte7, 7, 8),
476    PTF0: (ptf0, 8, 10),
477    PTF1: (ptf1, 9, 10),
478    PTF2: (ptf2, 10, 10),
479    PTF3: (ptf3, 11, 10),
480    PTF4: (ptf4, 12, 10),
481    PTF5: (ptf5, 13, 10),
482    PTF6: (ptf6, 14, 10),
483    PTF7: (ptf7, 15, 10),
484    PTG0: (ptg0, 16, 12),
485    PTG1: (ptg1, 17, 12),
486    PTG2: (ptg2, 18, 12),
487    PTG3: (ptg3, 19, 12),
488    PTH0: (pth0, 24, 14),
489    PTH1: (pth1, 25, 14),
490    PTH2: (pth2, 26, 14),
491    PTH6: (pth6, 30, 14),
492    PTH7: (pth7, 31, 14),
493], [
494    PTE0: (0, 4),
495    PTE1: (1, 5),
496    PTH0: (24, 6),
497    PTH1: (25, 7),
498]);