atsam4_hal/
gpio.rs

1//! General Purpose Input / Output
2use {
3    core::convert::Infallible,
4    core::marker::PhantomData,
5    hal::digital::v2::{toggleable, InputPin, IoPin, OutputPin, PinState, StatefulOutputPin},
6    paste::paste,
7};
8
9#[cfg(feature = "atsam4e")]
10use {
11    crate::clock::PioDClock,
12    crate::pac::{piod, PIOD},
13};
14
15#[cfg(feature = "atsam4e_e")]
16use {
17    crate::clock::{PioCClock, PioEClock},
18    crate::pac::{pioc, pioe, PIOC, PIOE},
19};
20
21#[cfg(any(feature = "atsam4e", feature = "atsam4n", feature = "atsam4s"))]
22use {
23    crate::clock::{Enabled, PioAClock, PioBClock},
24    crate::pac::MATRIX,
25    crate::pac::{pioa, piob, PIOA, PIOB},
26};
27
28#[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c"))]
29use {
30    crate::clock::PioCClock,
31    crate::pac::{pioc, PIOC},
32};
33
34/// The GpioExt trait allows splitting the PORT hardware into
35/// its constituent pin parts.
36pub trait GpioExt {
37    type Parts;
38
39    /// Consume and split the device into its constituent parts
40    fn split(self) -> Self::Parts;
41}
42pub struct Ports {
43    pioa: PhantomData<(PIOA, PioAClock<Enabled>)>,
44    piob: PhantomData<(PIOB, PioBClock<Enabled>)>,
45    #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
46    pioc: PhantomData<(PIOC, PioCClock<Enabled>)>,
47    #[cfg(feature = "atsam4e")]
48    piod: PhantomData<(PIOD, PioDClock<Enabled>)>,
49    #[cfg(feature = "atsam4e_e")]
50    pioe: PhantomData<(PIOE, PioEClock<Enabled>)>,
51}
52
53impl Ports {
54    pub fn new(
55        _pioa: (PIOA, PioAClock<Enabled>),
56        _piob: (PIOB, PioBClock<Enabled>),
57        #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))] _pioc: (
58            PIOC,
59            PioCClock<Enabled>,
60        ),
61        #[cfg(feature = "atsam4e")] _piod: (PIOD, PioDClock<Enabled>),
62        #[cfg(feature = "atsam4e_e")] _pioe: (PIOE, PioEClock<Enabled>),
63    ) -> Self {
64        // The above arguments are consumed here...never to be seen again.
65        Ports {
66            pioa: PhantomData,
67            piob: PhantomData,
68            #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
69            pioc: PhantomData,
70            #[cfg(feature = "atsam4e")]
71            piod: PhantomData,
72            #[cfg(feature = "atsam4e_e")]
73            pioe: PhantomData,
74        }
75    }
76}
77
78/// Represents a pin configured for input.
79/// The MODE type is typically one of `Floating`, `PullDown` or
80/// `PullUp`.
81pub struct Input<MODE> {
82    _mode: PhantomData<MODE>,
83}
84
85/// Represents a pin configured for output.
86/// The MODE type is typically one of `PushPull`, or
87/// `OpenDrain`.
88pub struct Output<MODE> {
89    _mode: PhantomData<MODE>,
90}
91
92/// Peripheral Function A
93pub struct PfA;
94/// Peripheral Function B
95pub struct PfB;
96/// Peripheral Function C
97pub struct PfC;
98/// Peripheral Function D
99pub struct PfD;
100/// System Function
101pub struct SysFn;
102/// Extra Function
103pub struct ExFn;
104
105/// Floating Input
106pub struct Floating;
107/// Pulled down Input
108pub struct PullDown;
109/// Pulled up Input
110pub struct PullUp;
111
112/// Totem Pole aka Push-Pull
113pub struct PushPull;
114/// Open drain output
115pub struct OpenDrain;
116
117macro_rules! pins {
118    ([
119        $($PinTypeA:ident: ($pin_identA:ident, $pin_noA:expr, $extfnA:ident),)*
120    ],[
121        $($PinTypeB:ident: ($pin_identB:ident, $pin_noB:expr, $extfnB:ident, $sysioB:ident),)*
122    ],[
123        $($PinTypeC:ident: ($pin_identC:ident, $pin_noC:expr, $extfnC:ident),)*
124    ],[
125        $($PinTypeD:ident: ($pin_identD:ident, $pin_noD:expr),)*
126    ],[
127        $($PinTypeE:ident: ($pin_identE:ident, $pin_noE:expr),)*
128    ]) => {
129        /// Holds the GPIO broken out pin instances (consumes the Ports object)
130        pub struct Pins {
131            $(
132                /// Pin $pin_identA
133                pub $pin_identA: $PinTypeA<Input<Floating>>,
134            )*
135            $(
136                /// Pin $pin_identB
137                pub $pin_identB: $PinTypeB<Input<Floating>>,
138            )*
139            $(
140                /// Pin $pin_identC
141                #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
142                pub $pin_identC: $PinTypeC<Input<Floating>>,
143            )*
144            $(
145                /// Pin $pin_identD
146                #[cfg(feature = "atsam4e")]
147                pub $pin_identD: $PinTypeD<Input<Floating>>,
148            )*
149            $(
150                /// Pin $pin_identE
151                #[cfg(feature = "atsam4e_e")]
152                pub $pin_identE: $PinTypeE<Input<Floating>>,
153            )*
154        }
155
156        impl GpioExt for Ports {
157            type Parts = Pins;
158
159            /// Split the PORT peripheral into discrete pins
160            fn split(self) -> Pins {
161                Pins {
162                    $(
163                        $pin_identA: $PinTypeA { _mode: PhantomData },
164                    )*
165                    $(
166                        $pin_identB: $PinTypeB { _mode: PhantomData },
167                    )*
168                    $(
169                        #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
170                        $pin_identC: $PinTypeC { _mode: PhantomData },
171                    )*
172                    $(
173                        #[cfg(feature = "atsam4e")]
174                        $pin_identD: $PinTypeD { _mode: PhantomData },
175                    )*
176                    $(
177                        #[cfg(feature = "atsam4e_e")]
178                        $pin_identE: $PinTypeE { _mode: PhantomData },
179                    )*
180                }
181            }
182        }
183
184        $(
185            pin!($PinTypeA, $pin_identA, $pin_noA, PIOA, pioa);
186            pin_sysio!($PinTypeA, $pin_noA, false);
187            pin_extrafn!($PinTypeA, $extfnA);
188        )*
189        pin_generic!(PIOA);
190        $(
191            pin!($PinTypeB, $pin_identB, $pin_noB, PIOB, piob);
192            pin_sysio!($PinTypeB, $pin_noB, $sysioB);
193            pin_extrafn!($PinTypeB, $extfnB);
194        )*
195        pin_generic!(PIOB);
196        $(
197            #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
198            pin!($PinTypeC, $pin_identC, $pin_noC, PIOC, pioc);
199            #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
200            pin_sysio!($PinTypeC, $pin_noC, false);
201            #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
202            pin_extrafn!($PinTypeC, $extfnC);
203        )*
204        #[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e_e"))]
205        pin_generic!(PIOC);
206        $(
207            #[cfg(feature = "atsam4e")]
208            pin!($PinTypeD, $pin_identD, $pin_noD, PIOD, piod);
209            #[cfg(feature = "atsam4e")]
210            pin_sysio!($PinTypeD, $pin_noD, false);
211        )*
212        #[cfg(feature = "atsam4e")]
213        pin_generic!(PIOD);
214        $(
215            #[cfg(feature = "atsam4e_e")]
216            pin!($PinTypeE, $pin_identE, $pin_noE, PIOE, pioe);
217            #[cfg(feature = "atsam4e_e")]
218            pin_sysio!($PinTypeE, $pin_noE, false);
219        )*
220        #[cfg(feature = "atsam4e_e")]
221        pin_generic!(PIOE);
222    };
223}
224
225/// Extra Function
226/// These function do not do any setup, they are solely for assigning Rust ownership to specific
227/// pins based on their intended use. To simplify, all functions (even if there are multiple)
228/// are defined as ExFn.
229macro_rules! pin_extrafn {
230    (
231        $PinType:ident,
232        true
233    ) => {
234        impl<MODE> $PinType<MODE> {
235            pub fn into_extra_function(self, _matrix: &MATRIX) -> $PinType<ExFn> {
236                $PinType { _mode: PhantomData }
237            }
238        }
239    };
240    (
241        $PinType:ident,
242        false
243    ) => {};
244}
245
246/// System I/O Configuration setup
247/// Some IO pins have an extra configuration used to disable some special default peripheral config
248/// This must be set in order to use those pins as GPIO (or other peripherals).
249/// The macro here adds the necessary register calls to make this happen for those pins.
250macro_rules! pin_sysio {
251    (
252        $PinType:ident,
253        $i:expr,
254        false
255    ) => {
256        impl<MODE> $PinType<MODE> {
257            fn prepare_pin_for_function_use(&mut self) {
258                unsafe {
259                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable Pullup
260                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable Pulldown
261                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable Multi-drive (open drain)
262                    self.ifscdr().write_with_zero(|w| w.bits(1 << $i)); // Disable Glitch filter (Debounce)
263                }
264            }
265
266            fn prepare_pin_for_input_use(&mut self) {
267                self.disable_pin_interrupt(); // Disable interrupt
268                unsafe {
269                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
270                    self.odr().write_with_zero(|w| w.bits(1 << $i)); // Disable output mode
271                }
272            }
273
274            pub fn into_peripheral_function_a(mut self, _matrix: &MATRIX) -> $PinType<PfA> {
275                self.prepare_pin_for_function_use();
276                self.abcdsr1()
277                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
278                self.abcdsr2()
279                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
280                self.disable_pin();
281
282                $PinType { _mode: PhantomData }
283            }
284
285            pub fn into_peripheral_function_b(mut self, _matrix: &MATRIX) -> $PinType<PfB> {
286                self.prepare_pin_for_function_use();
287                self.abcdsr1()
288                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); // Set up peripheral function
289                self.abcdsr2()
290                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
291                self.disable_pin();
292
293                $PinType { _mode: PhantomData }
294            }
295
296            pub fn into_peripheral_function_c(mut self, _matrix: &MATRIX) -> $PinType<PfC> {
297                self.prepare_pin_for_function_use();
298                self.abcdsr1()
299                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); // Set up peripheral function
300                self.abcdsr2()
301                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
302                self.disable_pin();
303
304                $PinType { _mode: PhantomData }
305            }
306
307            pub fn into_peripheral_function_d(mut self, _matrix: &MATRIX) -> $PinType<PfD> {
308                self.prepare_pin_for_function_use();
309                self.abcdsr1()
310                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); // Set up peripheral function
311                self.abcdsr2()
312                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
313                self.disable_pin();
314
315                $PinType { _mode: PhantomData }
316            }
317
318            pub fn into_floating_input(mut self, _matrix: &MATRIX) -> $PinType<Input<Floating>> {
319                self.prepare_pin_for_input_use();
320                unsafe {
321                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-up
322                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-down
323                }
324                self.enable_pin();
325
326                $PinType { _mode: PhantomData }
327            }
328
329            pub fn into_pull_down_input(mut self, _matrix: &MATRIX) -> $PinType<Input<PullDown>> {
330                self.prepare_pin_for_input_use();
331                unsafe {
332                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-up (this must happen first when enabling pull-down resistors)
333                    self.ppder().write_with_zero(|w| w.bits(1 << $i)); // Enable pull-down
334                }
335                self.enable_pin();
336
337                $PinType { _mode: PhantomData }
338            }
339
340            pub fn into_pull_up_input(mut self, _matrix: &MATRIX) -> $PinType<Input<PullUp>> {
341                self.prepare_pin_for_input_use();
342                unsafe {
343                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-down
344                    self.puer().write_with_zero(|w| w.bits(1 << $i)); // Enable pull-up
345                }
346                self.enable_pin();
347
348                $PinType { _mode: PhantomData }
349            }
350
351            /// Configures the pin to operate as an open drain output
352            pub fn into_open_drain_output(
353                mut self,
354                _matrix: &MATRIX,
355            ) -> $PinType<Output<OpenDrain>> {
356                self.disable_pin_interrupt();
357                unsafe {
358                    self.mder().write_with_zero(|w| w.bits(1 << $i)); // Enable open-drain/multi-drive
359                    self.oer().write_with_zero(|w| w.bits(1 << $i)); // Enable output mode
360                }
361                self.enable_pin(); // Enable pio mode (disables peripheral control of pin)
362
363                $PinType { _mode: PhantomData }
364            }
365
366            /// Configures the pin to operate as a push-pull output
367            pub fn into_push_pull_output(mut self, _matrix: &MATRIX) -> $PinType<Output<PushPull>> {
368                self.disable_pin_interrupt();
369                unsafe {
370                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
371                    self.oer().write_with_zero(|w| w.bits(1 << $i)); // Enable output mode
372                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
373                }
374
375                $PinType { _mode: PhantomData }
376            }
377        }
378    };
379
380    (
381        $PinType:ident,
382        $i:expr,
383        true
384    ) => {
385        impl<MODE> $PinType<MODE> {
386            paste! {
387                /// Clears bit to enable system function
388                pub fn into_system_function(self, matrix: &MATRIX) -> $PinType<SysFn> {
389                    matrix.ccfg_sysio.modify(|_, w| w.[<sysio $i>]().clear_bit());
390
391                    $PinType { _mode: PhantomData }
392                }
393
394                /// Sets bit to disable system function
395                fn disable_system_function(&self, matrix: &MATRIX) {
396                    matrix.ccfg_sysio.modify(|_, w| w.[<sysio $i>]().set_bit());
397                }
398            }
399
400            fn prepare_pin_for_function_use(&mut self) {
401                unsafe {
402                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable Pullup
403                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable Pulldown
404                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable Multi-drive (open drain)
405                    self.ifscdr().write_with_zero(|w| w.bits(1 << $i)); // Disable Glitch filter (Debounce)
406                }
407            }
408
409            fn prepare_pin_for_input_use(&mut self) {
410                self.disable_pin_interrupt(); // Disable interrupt
411                unsafe {
412                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
413                    self.odr().write_with_zero(|w| w.bits(1 << $i)); // Disable output mode
414                }
415            }
416
417            pub fn into_peripheral_function_a(mut self, matrix: &MATRIX) -> $PinType<PfA> {
418                self.prepare_pin_for_function_use();
419                self.disable_system_function(matrix);
420                self.abcdsr1()
421                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
422                self.abcdsr2()
423                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
424                self.disable_pin();
425
426                $PinType { _mode: PhantomData }
427            }
428
429            pub fn into_peripheral_function_b(mut self, matrix: &MATRIX) -> $PinType<PfB> {
430                self.prepare_pin_for_function_use();
431                self.disable_system_function(matrix);
432                self.abcdsr1()
433                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); // Set up peripheral function
434                self.abcdsr2()
435                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
436                self.disable_pin();
437
438                $PinType { _mode: PhantomData }
439            }
440
441            pub fn into_peripheral_function_c(mut self, matrix: &MATRIX) -> $PinType<PfC> {
442                self.prepare_pin_for_function_use();
443                self.disable_system_function(matrix);
444                self.abcdsr1()
445                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); // Set up peripheral function
446                self.abcdsr2()
447                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
448                self.disable_pin();
449
450                $PinType { _mode: PhantomData }
451            }
452
453            pub fn into_peripheral_function_d(mut self, matrix: &MATRIX) -> $PinType<PfD> {
454                self.prepare_pin_for_function_use();
455                self.disable_system_function(matrix);
456                self.abcdsr1()
457                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); // Set up peripheral function
458                self.abcdsr2()
459                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
460                self.disable_pin();
461
462                $PinType { _mode: PhantomData }
463            }
464
465            pub fn into_floating_input(mut self, matrix: &MATRIX) -> $PinType<Input<Floating>> {
466                self.prepare_pin_for_input_use();
467                self.disable_system_function(matrix);
468                unsafe {
469                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-up
470                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-down
471                }
472                self.enable_pin();
473
474                $PinType { _mode: PhantomData }
475            }
476
477            pub fn into_pull_down_input(mut self, matrix: &MATRIX) -> $PinType<Input<PullDown>> {
478                self.prepare_pin_for_input_use();
479                self.disable_system_function(matrix);
480                unsafe {
481                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-up (this must happen first when enabling pull-down resistors)
482                    self.ppder().write_with_zero(|w| w.bits(1 << $i)); // Enable pull-down
483                }
484                self.enable_pin();
485
486                $PinType { _mode: PhantomData }
487            }
488
489            pub fn into_pull_up_input(mut self, matrix: &MATRIX) -> $PinType<Input<PullUp>> {
490                self.prepare_pin_for_input_use();
491                self.disable_system_function(matrix);
492                unsafe {
493                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-down
494                    self.puer().write_with_zero(|w| w.bits(1 << $i)); // Enable pull-up
495                }
496                self.enable_pin();
497
498                $PinType { _mode: PhantomData }
499            }
500
501            /// Configures the pin to operate as an open drain output
502            pub fn into_open_drain_output(
503                mut self,
504                matrix: &MATRIX,
505            ) -> $PinType<Output<OpenDrain>> {
506                self.disable_pin_interrupt();
507                self.disable_system_function(matrix);
508                unsafe {
509                    self.mder().write_with_zero(|w| w.bits(1 << $i)); // Enable open-drain/multi-drive
510                    self.oer().write_with_zero(|w| w.bits(1 << $i)); // Enable output mode
511                }
512                self.enable_pin(); // Enable pio mode (disables peripheral control of pin)
513
514                $PinType { _mode: PhantomData }
515            }
516
517            /// Configures the pin to operate as a push-pull output
518            pub fn into_push_pull_output(mut self, matrix: &MATRIX) -> $PinType<Output<PushPull>> {
519                self.disable_pin_interrupt();
520                self.disable_system_function(matrix);
521                unsafe {
522                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
523                    self.oer().write_with_zero(|w| w.bits(1 << $i)); // Enable output mode
524                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
525                }
526
527                $PinType { _mode: PhantomData }
528            }
529        }
530    };
531}
532
533macro_rules! pin {
534    (
535        $PinType:ident,
536        $pin_ident:ident,
537        $i:expr,
538        $PIO:ident,
539        $pio:ident
540    ) => {
541        pub struct $PinType<MODE> {
542            _mode: PhantomData<MODE>,
543        }
544
545        impl<MODE> $PinType<MODE> {
546            pub(crate) fn puer(&mut self) -> &$pio::PUER {
547                unsafe { &(*$PIO::ptr()).puer }
548            }
549
550            pub(crate) fn pudr(&mut self) -> &$pio::PUDR {
551                unsafe { &(*$PIO::ptr()).pudr }
552            }
553
554            pub(crate) fn _ier(&mut self) -> &$pio::IER {
555                unsafe { &(*$PIO::ptr()).ier }
556            }
557
558            pub(crate) fn idr(&mut self) -> &$pio::IDR {
559                unsafe { &(*$PIO::ptr()).idr }
560            }
561
562            pub(crate) fn ppder(&mut self) -> &$pio::PPDER {
563                unsafe { &(*$PIO::ptr()).ppder }
564            }
565
566            pub(crate) fn ppddr(&mut self) -> &$pio::PPDDR {
567                unsafe { &(*$PIO::ptr()).ppddr }
568            }
569
570            pub(crate) fn abcdsr1(&mut self) -> &$pio::ABCDSR {
571                unsafe { &(*$PIO::ptr()).abcdsr[0] }
572            }
573
574            pub(crate) fn abcdsr2(&mut self) -> &$pio::ABCDSR {
575                unsafe { &(*$PIO::ptr()).abcdsr[1] }
576            }
577
578            pub(crate) fn mder(&mut self) -> &$pio::MDER {
579                unsafe { &(*$PIO::ptr()).mder }
580            }
581
582            pub(crate) fn mddr(&mut self) -> &$pio::MDDR {
583                unsafe { &(*$PIO::ptr()).mddr }
584            }
585
586            pub(crate) fn oer(&mut self) -> &$pio::OER {
587                unsafe { &(*$PIO::ptr()).oer }
588            }
589
590            pub(crate) fn odr(&mut self) -> &$pio::ODR {
591                unsafe { &(*$PIO::ptr()).odr }
592            }
593
594            pub(crate) fn per(&mut self) -> &$pio::PER {
595                unsafe { &(*$PIO::ptr()).per }
596            }
597
598            pub(crate) fn pdr(&mut self) -> &$pio::PDR {
599                unsafe { &(*$PIO::ptr()).pdr }
600            }
601
602            pub(crate) fn sodr(&mut self) -> &$pio::SODR {
603                unsafe { &(*$PIO::ptr()).sodr }
604            }
605
606            pub(crate) fn codr(&mut self) -> &$pio::CODR {
607                unsafe { &(*$PIO::ptr()).codr }
608            }
609
610            pub(crate) fn ifscdr(&mut self) -> &$pio::IFSCDR {
611                unsafe { &(*$PIO::ptr()).ifscdr }
612            }
613
614            pub(crate) fn odsr(&self) -> &$pio::ODSR {
615                unsafe { &(*$PIO::ptr()).odsr }
616            }
617
618            pub(crate) fn pdsr(&self) -> &$pio::PDSR {
619                unsafe { &(*$PIO::ptr()).pdsr }
620            }
621
622            fn enable_pin(&mut self) {
623                unsafe { self.per().write_with_zero(|w| w.bits(1 << $i)) };
624            }
625
626            fn disable_pin(&mut self) {
627                unsafe { self.pdr().write_with_zero(|w| w.bits(1 << $i)) };
628            }
629
630            fn _enable_pin_interrupt(&mut self) {
631                unsafe { self._ier().write_with_zero(|w| w.bits(1 << $i)) };
632            }
633
634            fn disable_pin_interrupt(&mut self) {
635                unsafe { self.idr().write_with_zero(|w| w.bits(1 << $i)) };
636            }
637        }
638
639        impl<MODE> InputPin for $PinType<Input<MODE>> {
640            type Error = Infallible;
641
642            fn is_high(&self) -> Result<bool, Self::Error> {
643                Ok(self.pdsr().read().bits() & (1 << $i) != 0)
644            }
645
646            fn is_low(&self) -> Result<bool, Self::Error> {
647                Ok(self.pdsr().read().bits() & (1 << $i) == 0)
648            }
649        }
650
651        impl<MODE> OutputPin for $PinType<Output<MODE>> {
652            type Error = Infallible;
653
654            fn set_high(&mut self) -> Result<(), Self::Error> {
655                unsafe { self.sodr().write_with_zero(|w| w.bits(1 << $i)) };
656                Ok(())
657            }
658
659            fn set_low(&mut self) -> Result<(), Self::Error> {
660                unsafe { self.codr().write_with_zero(|w| w.bits(1 << $i)) };
661                Ok(())
662            }
663        }
664
665        impl<MODE> StatefulOutputPin for $PinType<Output<MODE>> {
666            fn is_set_high(&self) -> Result<bool, Self::Error> {
667                Ok(self.odsr().read().bits() & (1 << $i) != 0)
668            }
669
670            fn is_set_low(&self) -> Result<bool, Self::Error> {
671                Ok(self.odsr().read().bits() & (1 << $i) == 0)
672            }
673        }
674
675        /// Software toggle (uses StatefulOutputPin and OutputPin)
676        impl<MODE> toggleable::Default for $PinType<Output<MODE>> {}
677
678        impl IoPin<$PinType<Input<Floating>>, Self> for $PinType<Output<PushPull>> {
679            type Error = Infallible;
680            fn into_input_pin(mut self) -> Result<$PinType<Input<Floating>>, Self::Error> {
681                unsafe {
682                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
683                    self.odr().write_with_zero(|w| w.bits(1 << $i)); // Disable output mode
684                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-up
685                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-down
686                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
687                }
688
689                Ok($PinType { _mode: PhantomData })
690            }
691            fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
692                self.set_state(state).unwrap();
693                Ok(self)
694            }
695        }
696
697        impl IoPin<$PinType<Input<PullDown>>, Self> for $PinType<Output<PushPull>> {
698            type Error = Infallible;
699            fn into_input_pin(mut self) -> Result<$PinType<Input<PullDown>>, Self::Error> {
700                unsafe {
701                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
702                    self.odr().write_with_zero(|w| w.bits(1 << $i)); // Disable output mode
703                    self.pudr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-up
704                    self.ppder().write_with_zero(|w| w.bits(1 << $i)); // Enable pull-down
705                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
706                }
707
708                Ok($PinType { _mode: PhantomData })
709            }
710            fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
711                self.set_state(state).unwrap();
712                Ok(self)
713            }
714        }
715
716        impl IoPin<$PinType<Input<PullUp>>, Self> for $PinType<Output<PushPull>> {
717            type Error = Infallible;
718            fn into_input_pin(mut self) -> Result<$PinType<Input<PullUp>>, Self::Error> {
719                unsafe {
720                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
721                    self.odr().write_with_zero(|w| w.bits(1 << $i)); // Disable output mode
722                    self.puer().write_with_zero(|w| w.bits(1 << $i)); // Enable pull-up
723                    self.ppddr().write_with_zero(|w| w.bits(1 << $i)); // Disable pull-down
724                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
725                }
726
727                Ok($PinType { _mode: PhantomData })
728            }
729            fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
730                self.set_state(state).unwrap();
731                Ok(self)
732            }
733        }
734
735        impl IoPin<Self, $PinType<Output<PushPull>>> for $PinType<Input<Floating>> {
736            type Error = Infallible;
737            fn into_input_pin(self) -> Result<Self, Self::Error> {
738                Ok(self)
739            }
740            fn into_output_pin(
741                mut self,
742                state: PinState,
743            ) -> Result<$PinType<Output<PushPull>>, Self::Error> {
744                unsafe {
745                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
746                    self.oer().write_with_zero(|w| w.bits(1 << $i)); // Enable output mode
747                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
748                    match state {
749                        PinState::Low => {
750                            self.codr().write_with_zero(|w| w.bits(1 << $i));
751                        }
752                        PinState::High => {
753                            self.sodr().write_with_zero(|w| w.bits(1 << $i));
754                        }
755                    }
756                }
757
758                Ok($PinType { _mode: PhantomData })
759            }
760        }
761
762        impl IoPin<Self, $PinType<Output<PushPull>>> for $PinType<Input<PullDown>> {
763            type Error = Infallible;
764            fn into_input_pin(self) -> Result<Self, Self::Error> {
765                Ok(self)
766            }
767            fn into_output_pin(
768                mut self,
769                state: PinState,
770            ) -> Result<$PinType<Output<PushPull>>, Self::Error> {
771                unsafe {
772                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
773                    self.oer().write_with_zero(|w| w.bits(1 << $i)); // Enable output mode
774                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
775                    match state {
776                        PinState::Low => {
777                            self.codr().write_with_zero(|w| w.bits(1 << $i));
778                        }
779                        PinState::High => {
780                            self.sodr().write_with_zero(|w| w.bits(1 << $i));
781                        }
782                    }
783                }
784
785                Ok($PinType { _mode: PhantomData })
786            }
787        }
788
789        impl IoPin<Self, $PinType<Output<PushPull>>> for $PinType<Input<PullUp>> {
790            type Error = Infallible;
791            fn into_input_pin(self) -> Result<Self, Self::Error> {
792                Ok(self)
793            }
794            fn into_output_pin(
795                mut self,
796                state: PinState,
797            ) -> Result<$PinType<Output<PushPull>>, Self::Error> {
798                unsafe {
799                    self.mddr().write_with_zero(|w| w.bits(1 << $i)); // Disable open-drain/multi-drive
800                    self.oer().write_with_zero(|w| w.bits(1 << $i)); // Enable output mode
801                    self.per().write_with_zero(|w| w.bits(1 << $i)); // Enable pio mode (disables peripheral control of pin)
802                    match state {
803                        PinState::Low => {
804                            self.codr().write_with_zero(|w| w.bits(1 << $i));
805                        }
806                        PinState::High => {
807                            self.sodr().write_with_zero(|w| w.bits(1 << $i));
808                        }
809                    }
810                }
811
812                Ok($PinType { _mode: PhantomData })
813            }
814        }
815
816        paste! {
817            impl<MODE> $PinType<MODE> {
818                /// Erases the pin number from the type
819                #[inline]
820                fn into_generic(self) -> [<$PIO Generic>]<MODE> {
821                    [<$PIO Generic>] {
822                        i: $i,
823                        _mode: PhantomData,
824                    }
825                }
826
827                /// Erases the pin number and port from the type
828                ///
829                /// This is useful when you want to collect the pins into an array where you
830                /// need all the elements to have the same type
831                pub fn downgrade(self) -> PioX<MODE> {
832                    self.into_generic().downgrade()
833                }
834            }
835        }
836    };
837}
838
839macro_rules! pin_generic {
840    (
841        $port:ident
842    ) => {
843        paste! {
844            pub struct [<$port Generic>]<MODE> {
845                i: u8,
846                _mode: PhantomData<MODE>,
847            }
848
849            impl<MODE> [<$port Generic>]<MODE> {
850                pub fn downgrade(self) -> PioX<MODE> {
851                    PioX::$port(self)
852                }
853            }
854
855            impl<MODE> OutputPin for [<$port Generic>]<Output<MODE>> {
856                type Error = Infallible;
857                fn set_high(&mut self) -> Result<(), Self::Error> {
858                    Ok(unsafe { (*$port::ptr()).sodr.write_with_zero(|w| w.bits(1 << self.i) ) })
859                }
860
861                fn set_low(&mut self) -> Result<(), Self::Error> {
862                    Ok(unsafe { (*$port::ptr()).codr.write_with_zero(|w| w.bits(1 << self.i) ) })
863                }
864            }
865
866            impl<MODE> InputPin for [<$port Generic>]<Input<MODE>> {
867                type Error = Infallible;
868                fn is_high(&self) -> Result<bool, Self::Error> {
869                    Ok(unsafe { (*$port::ptr()).pdsr.read().bits() & (1 << self.i)} != 0)
870                }
871
872                fn is_low(&self) -> Result<bool, Self::Error> {
873                    Ok(unsafe { (*$port::ptr()).pdsr.read().bits() & (1 << self.i)} == 0)
874                }
875            }
876
877            impl <MODE> StatefulOutputPin for [<$port Generic>]<Output<MODE>> {
878                fn is_set_high(&self) -> Result<bool, Self::Error> {
879                    Ok(unsafe { (*$port::ptr()).odsr.read().bits() & (1 << self.i)} != 0)
880                }
881
882                fn is_set_low(&self) -> Result<bool, Self::Error> {
883                    Ok(unsafe { (*$port::ptr()).odsr.read().bits() & (1 << self.i)} == 0)
884                }
885            }
886
887            impl <MODE> toggleable::Default for [<$port Generic>]<Output<MODE>> {}
888
889            impl IoPin<[<$port Generic>]<Input<Floating>>, Self> for [<$port Generic>]<Output<PushPull>> {
890                type Error = Infallible;
891                fn into_input_pin(self) -> Result<[<$port Generic>]<Input<Floating>>, Self::Error> {
892                    unsafe {
893                        (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable open-drain/multi-drive
894                        (*$port::ptr()).odr.write_with_zero(|w| w.bits(1 << self.i)); // Disable output mode
895                        (*$port::ptr()).pudr.write_with_zero(|w| w.bits(1 << self.i)); // Disable pull-up
896                        (*$port::ptr()).ppddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable pull-down
897                        (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << self.i)); // Enable pio mode (disables peripheral control of pin)
898                    }
899
900                    Ok([<$port Generic>] { i: self.i, _mode: PhantomData })
901                }
902                fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
903                    self.set_state(state).unwrap();
904                    Ok(self)
905                }
906            }
907
908            impl IoPin<[<$port Generic>]<Input<PullDown>>, Self> for [<$port Generic>]<Output<PushPull>> {
909                type Error = Infallible;
910                fn into_input_pin(self) -> Result<[<$port Generic>]<Input<PullDown>>, Self::Error> {
911                    unsafe {
912                        (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable open-drain/multi-drive
913                        (*$port::ptr()).odr.write_with_zero(|w| w.bits(1 << self.i)); // Disable output mode
914                        (*$port::ptr()).pudr.write_with_zero(|w| w.bits(1 << self.i)); // Disable pull-up
915                        (*$port::ptr()).ppder.write_with_zero(|w| w.bits(1 << self.i)); // Enable pull-down
916                        (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << self.i)); // Enable pio mode (disables peripheral control of pin)
917                    }
918
919                    Ok([<$port Generic>] { i: self.i, _mode: PhantomData })
920                }
921                fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
922                    self.set_state(state).unwrap();
923                    Ok(self)
924                }
925            }
926
927            impl IoPin<[<$port Generic>]<Input<PullUp>>, Self> for [<$port Generic>]<Output<PushPull>> {
928                type Error = Infallible;
929                fn into_input_pin(self) -> Result<[<$port Generic>]<Input<PullUp>>, Self::Error> {
930                    unsafe {
931                        (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable open-drain/multi-drive
932                        (*$port::ptr()).odr.write_with_zero(|w| w.bits(1 << self.i)); // Disable output mode
933                        (*$port::ptr()).puer.write_with_zero(|w| w.bits(1 << self.i)); // Enable pull-up
934                        (*$port::ptr()).ppddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable pull-down
935                        (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << self.i)); // Enable pio mode (disables peripheral control of pin)
936                    }
937
938                    Ok([<$port Generic>] { i: self.i, _mode: PhantomData })
939                }
940                fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
941                    self.set_state(state).unwrap();
942                    Ok(self)
943                }
944            }
945
946            impl IoPin<Self, [<$port Generic>]<Output<PushPull>>> for [<$port Generic>]<Input<Floating>> {
947                type Error = Infallible;
948                fn into_input_pin(self) -> Result<Self, Self::Error> {
949                    Ok(self)
950                }
951                fn into_output_pin(self, state: PinState) -> Result<[<$port Generic>]<Output<PushPull>>, Self::Error> {
952                    unsafe {
953                        (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable open-drain/multi-drive
954                        (*$port::ptr()).oer.write_with_zero(|w| w.bits(1 << self.i)); // Enable output mode
955                        (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << self.i)); // Enable pio mode (disables peripheral control of pin)
956                        match state {
957                            PinState::Low => {
958                                (*$port::ptr()).codr.write_with_zero(|w| w.bits(1 << self.i) );
959                            }
960                            PinState::High => {
961                                (*$port::ptr()).sodr.write_with_zero(|w| w.bits(1 << self.i) );
962                            }
963                        }
964                    }
965
966                    Ok( [<$port Generic>] { i: self.i, _mode: PhantomData } )
967                }
968            }
969
970            impl IoPin<Self, [<$port Generic>]<Output<PushPull>>> for [<$port Generic>]<Input<PullDown>> {
971                type Error = Infallible;
972                fn into_input_pin(self) -> Result<Self, Self::Error> {
973                    Ok(self)
974                }
975                fn into_output_pin(self, state: PinState) -> Result<[<$port Generic>]<Output<PushPull>>, Self::Error> {
976                    unsafe {
977                        (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable open-drain/multi-drive
978                        (*$port::ptr()).oer.write_with_zero(|w| w.bits(1 << self.i)); // Enable output mode
979                        (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << self.i)); // Enable pio mode (disables peripheral control of pin)
980                        match state {
981                            PinState::Low => {
982                                (*$port::ptr()).codr.write_with_zero(|w| w.bits(1 << self.i) );
983                            }
984                            PinState::High => {
985                                (*$port::ptr()).sodr.write_with_zero(|w| w.bits(1 << self.i) );
986                            }
987                        }
988                    }
989
990                    Ok( [<$port Generic>] { i: self.i, _mode: PhantomData } )
991                }
992            }
993
994            impl IoPin<Self, [<$port Generic>]<Output<PushPull>>> for [<$port Generic>]<Input<PullUp>> {
995                type Error = Infallible;
996                fn into_input_pin(self) -> Result<Self, Self::Error> {
997                    Ok(self)
998                }
999                fn into_output_pin(self, state: PinState) -> Result<[<$port Generic>]<Output<PushPull>>, Self::Error> {
1000                    unsafe {
1001                        (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << self.i)); // Disable open-drain/multi-drive
1002                        (*$port::ptr()).oer.write_with_zero(|w| w.bits(1 << self.i)); // Enable output mode
1003                        (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << self.i)); // Enable pio mode (disables peripheral control of pin)
1004                        match state {
1005                            PinState::Low => {
1006                                (*$port::ptr()).codr.write_with_zero(|w| w.bits(1 << self.i) );
1007                            }
1008                            PinState::High => {
1009                                (*$port::ptr()).sodr.write_with_zero(|w| w.bits(1 << self.i) );
1010                            }
1011                        }
1012                    }
1013
1014                    Ok( [<$port Generic>] { i: self.i, _mode: PhantomData } )
1015                }
1016            }
1017        }
1018    };
1019}
1020
1021#[cfg(feature = "atsam4e")]
1022pins!([
1023    Pa0: (pa0, 0, true), // WKUP0
1024    Pa1: (pa1, 1, true), // WKUP1
1025    Pa2: (pa2, 2, true), // WKUP2
1026    Pa3: (pa3, 3, false),
1027    Pa4: (pa4, 4, true), // WKUP3
1028    Pa5: (pa5, 5, true), // WKUP4
1029    Pa6: (pa6, 6, false),
1030    Pa7: (pa7, 7, false),
1031    Pa8: (pa8, 8, true), // WKUP5
1032    Pa9: (pa9, 9, true), // WKUP6
1033    Pa10: (pa10, 10, false),
1034    Pa11: (pa11, 11, true), // WKUP7
1035    Pa12: (pa12, 12, false),
1036    Pa13: (pa13, 13, false),
1037    Pa14: (pa14, 14, true), // WKUP8
1038    Pa15: (pa15, 15, true), // WKUP14/PIODCEN1
1039    Pa16: (pa16, 16, true), // WKUP15/PIODCEN2
1040    Pa17: (pa17, 17, true), // AFE0_AD0
1041    Pa18: (pa18, 18, true), // AFE0_AD1
1042    Pa19: (pa19, 19, true), // AFE0_AD2/WKUP9
1043    Pa20: (pa20, 20, true), // AFE0_AD3/WKUP10
1044    Pa21: (pa21, 21, true), // AFE1_AD2
1045    Pa22: (pa22, 22, true), // AFE1_AD3
1046    Pa23: (pa23, 23, true), // PIODCCLK
1047    Pa24: (pa24, 24, true), // PIODC0
1048    Pa25: (pa25, 25, true), // PIODC1
1049    Pa26: (pa26, 26, true), // PIODC2
1050    Pa27: (pa27, 27, true), // PIODC3
1051    Pa28: (pa28, 28, true), // PIODC4
1052    Pa29: (pa29, 29, true), // PIODC5
1053    Pa30: (pa30, 30, true), // WKUP11/PIODC6
1054    Pa31: (pa31, 31, true), // PIODC7
1055],[
1056    Pb0: (pb0, 0, true, false), // AFE0_AD4/RTCOUT0
1057    Pb1: (pb1, 1, true, false), // AFE0_AD5/RTCOUT1
1058    Pb2: (pb2, 2, true, false), // AFE1_AD0/WKUP12
1059    Pb3: (pb3, 3, true, false), // AFE1_AD1
1060    Pb4: (pb4, 4, false, true), // | SYSIO4 - TDI
1061    Pb5: (pb5, 5, true, true), // WKUP13 | SYSIO5 - TDO/TRACESWO
1062    Pb6: (pb6, 6, false, true), // | SYSIO6 - TMS/SWDIO
1063    Pb7: (pb7, 7, false, true), // | SYSIO7 - TCK/SWCLK
1064    Pb8: (pb8, 8, false, false),
1065    Pb9: (pb9, 9, false, false),
1066    Pb10: (pb10, 10, false, true), // | SYSIO10 - DDM
1067    Pb11: (pb11, 11, false, true), // | SYSIO11 - DDP
1068    Pb12: (pb12, 12, false, true), // | SYSIO12 - ERASE
1069    Pb13: (pb13, 13, true, false), // DAC0
1070    Pb14: (pb14, 14, true, false), // DAC1
1071
1072    // PB15-31 do not exist.
1073],
1074[
1075    Pc0: (pc0, 0, true), // AFE0_AD14
1076    Pc1: (pc1, 1, true), // AFE1_AD4
1077    Pc2: (pc2, 2, true), // AFE1_AD5
1078    Pc3: (pc3, 3, true), // AFE1_AD6
1079    Pc4: (pc4, 4, true), // AFE1_AD7
1080    Pc5: (pc5, 5, false),
1081    Pc6: (pc6, 6, false),
1082    Pc7: (pc7, 7, false),
1083    Pc8: (pc8, 8, false),
1084    Pc9: (pc9, 9, false),
1085    Pc10: (pc10, 10, false),
1086    Pc11: (pc11, 11, false),
1087    Pc12: (pc12, 12, true), // AFE0_AD8
1088    Pc13: (pc13, 13, true), // AFE0_AD6
1089    Pc14: (pc14, 14, false),
1090    Pc15: (pc15, 15, true), // AFE0_AD7
1091    Pc16: (pc16, 16, false),
1092    Pc17: (pc17, 17, false),
1093    Pc18: (pc18, 18, false),
1094    Pc19: (pc19, 19, false),
1095    Pc20: (pc20, 20, false),
1096    Pc21: (pc21, 21, false),
1097    Pc22: (pc22, 22, false),
1098    Pc23: (pc23, 23, false),
1099    Pc24: (pc24, 24, false),
1100    Pc25: (pc25, 25, false),
1101    Pc26: (pc26, 26, true), // AFE0_AD12
1102    Pc27: (pc27, 27, true), // AFE0_AD13
1103    Pc28: (pc28, 28, false),
1104    Pc29: (pc29, 29, true), // AFE0_AD9
1105    Pc30: (pc30, 30, true), // AFE0_AD10
1106    Pc31: (pc31, 31, true), // AFE0_AD11
1107],
1108[
1109    Pd0: (pd0, 0),
1110    Pd1: (pd1, 1),
1111    Pd2: (pd2, 2),
1112    Pd3: (pd3, 3),
1113    Pd4: (pd4, 4),
1114    Pd5: (pd5, 5),
1115    Pd6: (pd6, 6),
1116    Pd7: (pd7, 7),
1117    Pd8: (pd8, 8),
1118    Pd9: (pd9, 9),
1119    Pd10: (pd10, 10),
1120    Pd11: (pd11, 11),
1121    Pd12: (pd12, 12),
1122    Pd13: (pd13, 13),
1123    Pd14: (pd14, 14),
1124    Pd15: (pd15, 15),
1125    Pd16: (pd16, 16),
1126    Pd17: (pd17, 17),
1127    Pd18: (pd18, 18),
1128    Pd19: (pd19, 19),
1129    Pd20: (pd20, 20),
1130    Pd21: (pd21, 21),
1131    Pd22: (pd22, 22),
1132    Pd23: (pd23, 23),
1133    Pd24: (pd24, 24),
1134    Pd25: (pd25, 25),
1135    Pd26: (pd26, 26),
1136    Pd27: (pd27, 27),
1137    Pd28: (pd28, 28),
1138    Pd29: (pd29, 29),
1139    Pd30: (pd30, 30),
1140    Pd31: (pd31, 31),
1141],
1142[
1143    Pe0: (pe0, 0),
1144    Pe1: (pe1, 1),
1145    Pe2: (pe2, 2),
1146    Pe3: (pe3, 3),
1147    Pe4: (pe4, 4),
1148    Pe5: (pe5, 5),
1149
1150    // Pe6-31 do not exist.
1151]);
1152
1153#[cfg(feature = "atsam4n")]
1154pins!([
1155    Pa0: (pa0, 0, true), // WKUP0
1156    Pa1: (pa1, 1, true), // WKUP1
1157    Pa2: (pa2, 2, true), // WKUP2
1158    Pa3: (pa3, 3, false),
1159    Pa4: (pa4, 4, true), // WKUP3
1160    Pa5: (pa5, 5, true), // WKUP4
1161    Pa6: (pa6, 6, false),
1162    Pa7: (pa7, 7, false),
1163    Pa8: (pa8, 8, true), // WKUP5
1164    Pa9: (pa9, 9, true), // WKUP6
1165    Pa10: (pa10, 10, false),
1166    Pa11: (pa11, 11, true), // WKUP7
1167    Pa12: (pa12, 12, false),
1168    Pa13: (pa13, 13, false),
1169    Pa14: (pa14, 14, true), // WKUP8
1170    Pa15: (pa15, 15, true), // WKUP14
1171    Pa16: (pa16, 16, true), // WKUP15
1172    Pa17: (pa17, 17, true), // AD0
1173    Pa18: (pa18, 18, true), // AD1
1174    Pa19: (pa19, 19, true), // AD2/WKUP9
1175    Pa20: (pa20, 20, true), // AD3/WKUP10
1176    Pa21: (pa21, 21, true), // AD8
1177    Pa22: (pa22, 22, true), // AD9
1178    Pa23: (pa23, 23, false),
1179    Pa24: (pa24, 24, false),
1180    Pa25: (pa25, 25, false),
1181    Pa26: (pa26, 26, false),
1182    Pa27: (pa27, 27, false),
1183    Pa28: (pa28, 28, false),
1184    Pa29: (pa29, 29, false),
1185    Pa30: (pa30, 30, true), // WKUP11
1186    Pa31: (pa31, 31, false),
1187],[
1188    Pb0: (pb0, 0, true, false), // AD4
1189    Pb1: (pb1, 1, true, false), // AD5
1190    Pb2: (pb2, 2, true, false), // AD6/WKUP12
1191    Pb3: (pb3, 3, true, false), // AD7
1192    Pb4: (pb4, 4, false, true), // | SYSIO4 - TDI
1193    Pb5: (pb5, 5, true, true), // WKUP13 | SYSIO5 - TDO/TRACESWO
1194    Pb6: (pb6, 6, false, true), // | SYSIO6 - TMS/SWDIO
1195    Pb7: (pb7, 7, false, true), // | SYSIO7 - TCK/SWCLK
1196    Pb8: (pb8, 8, false, false),
1197    Pb9: (pb9, 9, false, false),
1198    Pb10: (pb10, 10, false, false),
1199    Pb11: (pb11, 11, false, false),
1200    Pb12: (pb12, 12, false, true), // | SYSIO12 - ERASE
1201    Pb13: (pb13, 13, true, false), // DAC0
1202    Pb14: (pb14, 14, false, false),
1203
1204    // PB15-31 do not exist.
1205],
1206[
1207    Pc0: (pc0, 0, false),
1208    Pc1: (pc1, 1, false),
1209    Pc2: (pc2, 2, false),
1210    Pc3: (pc3, 3, false),
1211    Pc4: (pc4, 4, false),
1212    Pc5: (pc5, 5, false),
1213    Pc6: (pc6, 6, false),
1214    Pc7: (pc7, 7, false),
1215    Pc8: (pc8, 8, false),
1216    Pc9: (pc9, 9, false),
1217    Pc10: (pc10, 10, false),
1218    Pc11: (pc11, 11, false),
1219    Pc12: (pc12, 12, true), // AD12
1220    Pc13: (pc13, 13, true), // AD10
1221    Pc14: (pc14, 14, false),
1222    Pc15: (pc15, 15, true), // AD11
1223    Pc16: (pc16, 16, false),
1224    Pc17: (pc17, 17, false),
1225    Pc18: (pc18, 18, false),
1226    Pc19: (pc19, 19, false),
1227    Pc20: (pc20, 20, false),
1228    Pc21: (pc21, 21, false),
1229    Pc22: (pc22, 22, false),
1230    Pc23: (pc23, 23, false),
1231    Pc24: (pc24, 24, false),
1232    Pc25: (pc25, 25, false),
1233    Pc26: (pc26, 26, false),
1234    Pc27: (pc27, 27, false),
1235    Pc28: (pc28, 28, false),
1236    Pc29: (pc29, 29, true), // AD13
1237    Pc30: (pc30, 30, true), // AD14
1238    Pc31: (pc31, 31, true), // AD15
1239], [], []);
1240
1241#[cfg(feature = "atsam4s")]
1242pins!([
1243    Pa0: (pa0, 0, true), // WKUP0
1244    Pa1: (pa1, 1, true), // WKUP1
1245    Pa2: (pa2, 2, true), // WKUP2
1246    Pa3: (pa3, 3, false),
1247    Pa4: (pa4, 4, true), // WKUP3
1248    Pa5: (pa5, 5, true), // WKUP4
1249    Pa6: (pa6, 6, false),
1250    Pa7: (pa7, 7, false),
1251    Pa8: (pa8, 8, true), // WKUP5
1252    Pa9: (pa9, 9, true), // WKUP6
1253    Pa10: (pa10, 10, false),
1254    Pa11: (pa11, 11, true), // WKUP7
1255    Pa12: (pa12, 12, false),
1256    Pa13: (pa13, 13, false),
1257    Pa14: (pa14, 14, true), // WKUP8
1258    Pa15: (pa15, 15, true), // WKUP14/PIODCEN1
1259    Pa16: (pa16, 16, true), // WKUP15/PIODCEN2
1260    Pa17: (pa17, 17, true), // AD0
1261    Pa18: (pa18, 18, true), // AD1
1262    Pa19: (pa19, 19, true), // AD2/WKUP9
1263    Pa20: (pa20, 20, true), // AD3/WKUP10
1264    Pa21: (pa21, 21, true), // AD8
1265    Pa22: (pa22, 22, true), // AD9
1266    Pa23: (pa23, 23, true), // PIODCCLK
1267    Pa24: (pa24, 24, true), // PIODC0
1268    Pa25: (pa25, 25, true), // PIODC1
1269    Pa26: (pa26, 26, true), // PIODC2
1270    Pa27: (pa27, 27, true), // PIODC3
1271    Pa28: (pa28, 28, true), // PIODC4
1272    Pa29: (pa29, 29, true), // PIODC5
1273    Pa30: (pa30, 30, true), // WKUP11/PIODC6
1274    Pa31: (pa31, 31, true), // PIODC7
1275],[
1276    Pb0: (pb0, 0, true, false), // AD4/RTCOUT0
1277    Pb1: (pb1, 1, true, false), // AD5/RTCOUT1
1278    Pb2: (pb2, 2, true, false), // AD6/WKUP12
1279    Pb3: (pb3, 3, true, false), // AD7
1280    Pb4: (pb4, 4, false, true), // | SYSIO4 - TDI
1281    Pb5: (pb5, 5, true, true), // WKUP13 | SYSIO5 - TDO/TRACESWO
1282    Pb6: (pb6, 6, false, true), // | SYSIO6 - TMS/SWDIO
1283    Pb7: (pb7, 7, false, true), // | SYSIO7 - TCK/SWCLK
1284    Pb8: (pb8, 8, false, false),
1285    Pb9: (pb9, 9, false, false),
1286    Pb10: (pb10, 10, false, true), // | SYSIO10 - DDM
1287    Pb11: (pb11, 11, false, true), // | SYSIO11 - DDP
1288    Pb12: (pb12, 12, false, true), // | SYSIO12 - ERASE
1289    Pb13: (pb13, 13, true, false), // DAC0
1290    Pb14: (pb14, 14, true, false), // DAC1
1291
1292    // PB15-31 do not exist.
1293],
1294[
1295    Pc0: (pc0, 0, false),
1296    Pc1: (pc1, 1, false),
1297    Pc2: (pc2, 2, false),
1298    Pc3: (pc3, 3, false),
1299    Pc4: (pc4, 4, false),
1300    Pc5: (pc5, 5, false),
1301    Pc6: (pc6, 6, false),
1302    Pc7: (pc7, 7, false),
1303    Pc8: (pc8, 8, false),
1304    Pc9: (pc9, 9, false),
1305    Pc10: (pc10, 10, false),
1306    Pc11: (pc11, 11, false),
1307    Pc12: (pc12, 12, true), // AD12
1308    Pc13: (pc13, 13, true), // AD10
1309    Pc14: (pc14, 14, false),
1310    Pc15: (pc15, 15, true), // AD11
1311    Pc16: (pc16, 16, false),
1312    Pc17: (pc17, 17, false),
1313    Pc18: (pc18, 18, false),
1314    Pc19: (pc19, 19, false),
1315    Pc20: (pc20, 20, false),
1316    Pc21: (pc21, 21, false),
1317    Pc22: (pc22, 22, false),
1318    Pc23: (pc23, 23, false),
1319    Pc24: (pc24, 24, false),
1320    Pc25: (pc25, 25, false),
1321    Pc26: (pc26, 26, false),
1322    Pc27: (pc27, 27, false),
1323    Pc28: (pc28, 28, false),
1324    Pc29: (pc29, 29, true), // AD13
1325    Pc30: (pc30, 30, true), // AD14
1326    Pc31: (pc31, 31, false),
1327], [], []);
1328
1329#[macro_export]
1330macro_rules! define_pin_map {
1331    ($(#[$topattr:meta])* struct $Type:ident,
1332     $( $(#[$attr:meta])* pin $name:ident = $pin_ident:ident<$pin_type:ty, $into_method:ident>),+ , ) => {
1333
1334        paste! {
1335            $(#[$topattr])*
1336            pub struct $Type {
1337                $(
1338                    $(#[$attr])*
1339                    pub $name: [<P $pin_ident>]<$pin_type>
1340                ),+
1341            }
1342        }
1343
1344        impl $Type {
1345            /// Returns the pins for the device
1346            paste! {
1347                pub fn new(ports: Ports, matrix: &MATRIX) -> Self {
1348                    let pins = ports.split();
1349                    // Create local pins with the correct type so we can put them into the
1350                    // pin structure below.
1351                    $(
1352                        let [<new_pin $pin_ident>] = pins.[<p $pin_ident>].$into_method(matrix);
1353                    )+
1354                    $Type {
1355                        $(
1356                            $name: [<new_pin $pin_ident>]
1357                        ),+
1358                    }
1359                }
1360            }
1361        }
1362    }
1363}
1364
1365macro_rules! impl_pxx {
1366    ($(($port:ident)),*) => {
1367        paste! {
1368            pub enum PioX<MODE> {
1369                $(
1370                    $port([<$port Generic>]<MODE>)
1371                ),*
1372            }
1373
1374            impl<MODE> OutputPin for PioX<Output<MODE>> {
1375                type Error = Infallible;
1376                fn set_high(&mut self) -> Result<(), Infallible> {
1377                    match self {
1378                        $(PioX::$port(pin) => pin.set_high()),*
1379                    }
1380                }
1381
1382                fn set_low(&mut self) -> Result<(), Infallible> {
1383                    match self {
1384                        $(PioX::$port(pin) => pin.set_low()),*
1385                    }
1386                }
1387            }
1388
1389            impl<MODE> StatefulOutputPin for PioX<Output<MODE>> {
1390                fn is_set_high(&self) -> Result<bool, Self::Error> {
1391                    match self {
1392                        $(PioX::$port(pin) => pin.is_set_high()),*
1393                    }
1394                }
1395
1396                fn is_set_low(&self) -> Result<bool, Self::Error> {
1397                    match self {
1398                        $(PioX::$port(pin) => pin.is_set_low()),*
1399                    }
1400                }
1401            }
1402
1403            impl<MODE> InputPin for PioX<Input<MODE>> {
1404                type Error = Infallible;
1405                fn is_high(&self) -> Result<bool, Infallible> {
1406                    match self {
1407                        $(PioX::$port(pin) => pin.is_high()),*
1408                    }
1409                }
1410
1411                fn is_low(&self) -> Result<bool, Infallible> {
1412                    match self {
1413                        $(PioX::$port(pin) => pin.is_low()),*
1414                    }
1415                }
1416            }
1417
1418            impl <MODE> toggleable::Default for PioX<Output<MODE>> {}
1419
1420            impl IoPin<PioX<Input<Floating>>, Self> for PioX<Output<PushPull>> {
1421                type Error = Infallible;
1422                fn into_input_pin(self) -> Result<PioX<Input<Floating>>, Self::Error> {
1423                    unsafe {
1424                        match self {
1425                            $(PioX::$port(pin) => {
1426                                (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable open-drain/multi-drive
1427                                (*$port::ptr()).odr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable output mode
1428                                (*$port::ptr()).pudr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable pull-up
1429                                (*$port::ptr()).ppddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable pull-down
1430                                (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pio mode (disables peripheral control of pin)
1431
1432                                Ok(PioX::$port([<$port Generic>] { i: pin.i, _mode: PhantomData }))
1433                            })*
1434                        }
1435                    }
1436
1437                }
1438                fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
1439                    self.set_state(state).unwrap();
1440                    Ok(self)
1441                }
1442            }
1443
1444            impl IoPin<PioX<Input<PullDown>>, Self> for PioX<Output<PushPull>> {
1445                type Error = Infallible;
1446                fn into_input_pin(self) -> Result<PioX<Input<PullDown>>, Self::Error> {
1447                    unsafe {
1448                        match self {
1449                            $(PioX::$port(pin) => {
1450                                (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable open-drain/multi-drive
1451                                (*$port::ptr()).odr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable output mode
1452                                (*$port::ptr()).pudr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable pull-up
1453                                (*$port::ptr()).ppder.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pull-down
1454                                (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pio mode (disables peripheral control of pin)
1455
1456                                Ok(PioX::$port([<$port Generic>] { i: pin.i, _mode: PhantomData }))
1457                            })*
1458                        }
1459                    }
1460
1461                }
1462                fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
1463                    self.set_state(state).unwrap();
1464                    Ok(self)
1465                }
1466            }
1467
1468            impl IoPin<PioX<Input<PullUp>>, Self> for PioX<Output<PushPull>> {
1469                type Error = Infallible;
1470                fn into_input_pin(self) -> Result<PioX<Input<PullUp>>, Self::Error> {
1471                    unsafe {
1472                        match self {
1473                            $(PioX::$port(pin) => {
1474                                (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable open-drain/multi-drive
1475                                (*$port::ptr()).odr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable output mode
1476                                (*$port::ptr()).puer.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pull-up
1477                                (*$port::ptr()).ppddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable pull-down
1478                                (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pio mode (disables peripheral control of pin)
1479
1480                                Ok(PioX::$port([<$port Generic>] { i: pin.i, _mode: PhantomData }))
1481                            })*
1482                        }
1483                    }
1484
1485                }
1486                fn into_output_pin(mut self, state: PinState) -> Result<Self, Self::Error> {
1487                    self.set_state(state).unwrap();
1488                    Ok(self)
1489                }
1490            }
1491
1492            impl IoPin<Self, PioX<Output<PushPull>>> for PioX<Input<Floating>> {
1493                type Error = Infallible;
1494                fn into_input_pin(self) -> Result<Self, Self::Error> {
1495                    Ok(self)
1496                }
1497                fn into_output_pin(self, state: PinState) -> Result<PioX<Output<PushPull>>, Self::Error> {
1498                    unsafe {
1499                        match self {
1500                            $(PioX::$port(pin) => {
1501                                (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable open-drain/multi-drive
1502                                (*$port::ptr()).oer.write_with_zero(|w| w.bits(1 << pin.i)); // Enable output mode
1503                                (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pio mode (disables peripheral control of pin)
1504                                match state {
1505                                    PinState::Low => {
1506                                        (*$port::ptr()).codr.write_with_zero(|w| w.bits(1 << pin.i) );
1507                                    }
1508                                    PinState::High => {
1509                                        (*$port::ptr()).sodr.write_with_zero(|w| w.bits(1 << pin.i) );
1510                                    }
1511                                }
1512
1513                                Ok(PioX::$port([<$port Generic>] { i: pin.i, _mode: PhantomData }))
1514                            })*
1515                        }
1516                    }
1517                }
1518            }
1519
1520            impl IoPin<Self, PioX<Output<PushPull>>> for PioX<Input<PullDown>> {
1521                type Error = Infallible;
1522                fn into_input_pin(self) -> Result<Self, Self::Error> {
1523                    Ok(self)
1524                }
1525                fn into_output_pin(self, state: PinState) -> Result<PioX<Output<PushPull>>, Self::Error> {
1526                    unsafe {
1527                        match self {
1528                            $(PioX::$port(pin) => {
1529                                (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable open-drain/multi-drive
1530                                (*$port::ptr()).oer.write_with_zero(|w| w.bits(1 << pin.i)); // Enable output mode
1531                                (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pio mode (disables peripheral control of pin)
1532                                match state {
1533                                    PinState::Low => {
1534                                        (*$port::ptr()).codr.write_with_zero(|w| w.bits(1 << pin.i) );
1535                                    }
1536                                    PinState::High => {
1537                                        (*$port::ptr()).sodr.write_with_zero(|w| w.bits(1 << pin.i) );
1538                                    }
1539                                }
1540
1541                                Ok(PioX::$port([<$port Generic>] { i: pin.i, _mode: PhantomData }))
1542                            })*
1543                        }
1544                    }
1545                }
1546            }
1547
1548            impl IoPin<Self, PioX<Output<PushPull>>> for PioX<Input<PullUp>> {
1549                type Error = Infallible;
1550                fn into_input_pin(self) -> Result<Self, Self::Error> {
1551                    Ok(self)
1552                }
1553                fn into_output_pin(self, state: PinState) -> Result<PioX<Output<PushPull>>, Self::Error> {
1554                    unsafe {
1555                        match self {
1556                            $(PioX::$port(pin) => {
1557                                (*$port::ptr()).mddr.write_with_zero(|w| w.bits(1 << pin.i)); // Disable open-drain/multi-drive
1558                                (*$port::ptr()).oer.write_with_zero(|w| w.bits(1 << pin.i)); // Enable output mode
1559                                (*$port::ptr()).per.write_with_zero(|w| w.bits(1 << pin.i)); // Enable pio mode (disables peripheral control of pin)
1560                                match state {
1561                                    PinState::Low => {
1562                                        (*$port::ptr()).codr.write_with_zero(|w| w.bits(1 << pin.i) );
1563                                    }
1564                                    PinState::High => {
1565                                        (*$port::ptr()).sodr.write_with_zero(|w| w.bits(1 << pin.i) );
1566                                    }
1567                                }
1568
1569                                Ok(PioX::$port([<$port Generic>] { i: pin.i, _mode: PhantomData }))
1570                            })*
1571                        }
1572                    }
1573                }
1574            }
1575        }
1576    }
1577}
1578
1579#[cfg(not(any(feature = "atsam4n_c", feature = "atsam4s_c", feature = "atsam4e")))]
1580impl_pxx! {
1581    (PIOA),
1582    (PIOB)
1583}
1584
1585#[cfg(any(feature = "atsam4n_c", feature = "atsam4s_c"))]
1586impl_pxx! {
1587    (PIOA),
1588    (PIOB),
1589    (PIOC)
1590}
1591
1592#[cfg(feature = "atsam4e_c")]
1593impl_pxx! {
1594    (PIOA),
1595    (PIOB),
1596    (PIOD)
1597}
1598
1599#[cfg(feature = "atsam4e_e")]
1600impl_pxx! {
1601    (PIOA),
1602    (PIOB),
1603    (PIOC),
1604    (PIOD),
1605    (PIOE)
1606}