avr_hal_generic/
port.rs

1//! Digital IO implementations for the `PORT#` peripherals
2//!
3//! Please take a look at the documentation for [`Pin`] for a detailed explanation.
4
5use core::marker::PhantomData;
6use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
7use embedded_hal_v0::digital::v2::{InputPin as InputPinV0, OutputPin as OutputPinV0};
8
9pub trait PinMode: crate::Sealed {}
10/// GPIO pin modes
11pub mod mode {
12    use core::marker::PhantomData;
13
14    pub trait Io: crate::Sealed + super::PinMode {}
15
16    /// Pin is configured as a digital output.
17    pub struct Output;
18    impl super::PinMode for Output {}
19    impl Io for Output {}
20    impl crate::Sealed for Output {}
21
22    /// Pin is configured as a digital output with open drain behaviour
23    pub struct OpenDrain;
24    impl super::PinMode for OpenDrain {}
25    impl Io for OpenDrain {}
26    impl crate::Sealed for OpenDrain {}
27
28    pub struct PwmOutput<TC> {
29        pub(crate) _timer: PhantomData<TC>,
30    }
31    impl<TC> super::PinMode for PwmOutput<TC> {}
32    impl<TC> crate::Sealed for PwmOutput<TC> {}
33
34    pub trait InputMode: crate::Sealed {}
35
36    /// Pin is configured as digital input (floating or pulled-up).
37    pub struct Input<IMODE = AnyInput> {
38        pub(crate) _imode: PhantomData<IMODE>,
39    }
40    impl<IMODE: InputMode> super::PinMode for Input<IMODE> {}
41    impl<IMODE: InputMode> Io for Input<IMODE> {}
42    impl<IMODE: InputMode> crate::Sealed for Input<IMODE> {}
43
44    /// Floating input, used like `Input<Floating>`.
45    pub struct Floating;
46    impl InputMode for Floating {}
47    impl crate::Sealed for Floating {}
48
49    /// Pulled-up input, used like `Input<PullUp>`.
50    pub struct PullUp;
51    impl InputMode for PullUp {}
52    impl crate::Sealed for PullUp {}
53
54    /// Any input (floating or pulled-up), used like `Input<AnyInput>`.
55    pub struct AnyInput;
56    impl InputMode for AnyInput {}
57    impl crate::Sealed for AnyInput {}
58
59    /// Pin is configured as an analog input (for the ADC).
60    pub struct Analog;
61}
62
63pub trait PinOps {
64    type Dynamic;
65
66    fn into_dynamic(self) -> Self::Dynamic;
67
68    unsafe fn out_set(&mut self);
69    unsafe fn out_clear(&mut self);
70    unsafe fn out_toggle(&mut self);
71    unsafe fn out_get(&self) -> bool;
72
73    unsafe fn in_get(&self) -> bool;
74
75    unsafe fn make_output(&mut self);
76    unsafe fn make_input(&mut self, pull_up: bool);
77}
78
79/// Representation of an MCU pin.
80///
81/// # Design Rationale
82/// We want individual types per pin to model constraints which depend on a specific pin.  For
83/// example, some peripherals are internally hard-wired to certain pins of the MCU.
84///
85/// Additionally, the mode of a pin should also be a part of the type to model enforcement of pins
86/// being in a certain mode and preventing misuse like for example calling `set_high()` on a pin
87/// configured as input.
88///
89/// To do this, the [`Pin`] type is generic over the `MODE` (input, output, ...) and the `PIN`
90/// (pd0, pb5, pc6, ...).
91///
92/// Of course, in some applications one does not care about the specific pin used.  For these
93/// situations, the specific pin types can be "downgraded" into a dynamic type that can represent
94/// any pin.  See [Downgrading](#downgrading) for more details.
95///
96/// # Instantiation
97/// The `Peripherals` struct in HAL and board-support crates usually contains a `.pins` field which
98/// is of type `Pins`.  This `Pins` struct in turn has fields for each individual pin, in its
99/// default mode.  You can then move the pin out of this struct to reconfigure it (examples in this
100/// documentation are for `atmega-hal`):
101///
102/// ```ignore
103/// use atmega_hal::port::{Pin, mode, self};
104///
105/// let dp = atmega_hal::Peripherals::take().unwrap();
106/// let pins = atmega_hal::pins!(dp);
107///
108/// let output: Pin<mode::Output, port::PD3> = pins.pd3.into_output();
109/// ```
110pub struct Pin<MODE, PIN> {
111    pub(crate) pin: PIN,
112    pub(crate) _mode: PhantomData<MODE>,
113}
114
115impl<PIN: PinOps> Pin<mode::Input<mode::Floating>, PIN> {
116    #[doc(hidden)]
117    pub fn new(pin: PIN) -> Self {
118        Pin {
119            pin,
120            _mode: PhantomData,
121        }
122    }
123}
124
125/// # Configuration
126/// To change the mode of a pin, use one of the following conversion functions.  They consume the
127/// original [`Pin`] and return one with the desired mode.  Only when a pin is in the correct mode,
128/// does it have the mode-relevant methods availailable (e.g. `set_high()` is only available for
129/// `Output` pins).
130impl<PIN: PinOps, MODE: mode::Io> Pin<MODE, PIN> {
131    /// Convert this pin into an output pin, setting the state to low.
132    /// See [Digital Output](#digital-output).
133    pub fn into_output(mut self) -> Pin<mode::Output, PIN> {
134        unsafe { self.pin.out_clear() };
135        unsafe { self.pin.make_output() };
136        Pin {
137            pin: self.pin,
138            _mode: PhantomData,
139        }
140    }
141
142    /// Convert this pin into an output pin, setting the state to high.
143    /// See [Digital Output](#digital-output).
144    pub fn into_output_high(mut self) -> Pin<mode::Output, PIN> {
145        unsafe { self.pin.out_set() };
146        unsafe { self.pin.make_output() };
147        Pin {
148            pin: self.pin,
149            _mode: PhantomData,
150        }
151    }
152
153    /// Convert this pin into an open-drain output pin, setting the state to low.
154    /// See [Digital Output Open Drain](#digital-output-open-drain)
155    pub fn into_opendrain(mut self) -> Pin<mode::OpenDrain, PIN> {
156        unsafe { self.pin.out_clear() };
157        unsafe { self.pin.make_output() };
158        Pin {
159            pin: self.pin,
160            _mode: PhantomData,
161        }
162    }
163
164    /// Convert this pin into an open-drain output pin, setting the state to high.
165    /// See [Digital Output Open Drain](#digital-output-open-drain)
166    pub fn into_opendrain_high(mut self) -> Pin<mode::OpenDrain, PIN> {
167        unsafe { self.pin.make_input(false) };
168        Pin {
169            pin: self.pin,
170            _mode: PhantomData,
171        }
172    }
173
174    /// Convert this pin into a floating input pin.  See [Digital Input](#digital-input).
175    ///
176    /// *Note*: To read deterministic values from the pin, it must be externally pulled to a
177    /// defined level (either VCC or GND).
178    pub fn into_floating_input(mut self) -> Pin<mode::Input<mode::Floating>, PIN> {
179        unsafe { self.pin.make_input(false) };
180        Pin {
181            pin: self.pin,
182            _mode: PhantomData,
183        }
184    }
185
186    /// Convert this pin into a pulled-up input pin.  See [Digital Input](#digital-input).
187    ///
188    /// With no external circuit pulling the pin low, it will be read high.
189    pub fn into_pull_up_input(mut self) -> Pin<mode::Input<mode::PullUp>, PIN> {
190        unsafe { self.pin.make_input(true) };
191        Pin {
192            pin: self.pin,
193            _mode: PhantomData,
194        }
195    }
196
197    /// Convert this pin into an analog input (ADC channel).  See [Analog Input](#analog-input).
198    ///
199    /// Some pins can be repurposed as ADC channels.  For those pins, the `into_analog_input()`
200    /// method is available.
201    pub fn into_analog_input<H, ADC, CLOCK>(
202        self,
203        adc: &mut crate::adc::Adc<H, ADC, CLOCK>,
204    ) -> Pin<mode::Analog, PIN>
205    where
206        Pin<mode::Analog, PIN>: crate::adc::AdcChannel<H, ADC>,
207        ADC: crate::adc::AdcOps<H>,
208        CLOCK: crate::clock::Clock,
209    {
210        let mut new = Pin {
211            pin: self.pin,
212            _mode: PhantomData,
213        };
214        adc.enable_pin(&new);
215        unsafe { new.pin.make_input(false) };
216        new
217    }
218}
219
220/// # Downgrading
221/// For applications where the exact pin is irrelevant, a specific pin can be downgraded to a
222/// "dynamic pin" which can represent any pin:
223///
224/// ```ignore
225/// use atmega_hal::port::{Pin, mode};
226///
227/// let dp = atmega_hal::Peripherals::take().unwrap();
228/// let pins = atmega_hal::pins!(dp);
229///
230/// let any_output_pin1: Pin<mode::Output> = pins.pd0.into_output().downgrade();
231/// let any_output_pin2: Pin<mode::Output> = pins.pd1.into_output().downgrade();
232///
233/// // Because they now have the same type, you can, for example, stuff them into an array:
234/// let pins: [Pin<mode::Output>; 2] = [any_output_pin1, any_output_pin2];
235/// ```
236impl<PIN: PinOps, MODE: mode::Io> Pin<MODE, PIN> {
237    /// "Erase" type-level information about which specific pin is represented.
238    ///
239    /// *Note*: The returned "dynamic" pin has runtime overhead compared to a specific pin.
240    pub fn downgrade(self) -> Pin<MODE, PIN::Dynamic> {
241        Pin {
242            pin: self.pin.into_dynamic(),
243            _mode: PhantomData,
244        }
245    }
246}
247
248/// # Input-Mode Downgrading
249/// There is a second kind of downgrading: In some cases it is not important whether an input pin
250/// is configured as [`mode::PullUp`] or [`mode::Floating`].  For this, you can "forget" the
251/// concrete input mode, leaving you with a type that is the same for pull-up or floating inputs:
252///
253/// ```ignore
254/// use atmega_hal::port::{Pin, mode};
255///
256/// let dp = atmega_hal::Peripherals::take().unwrap();
257/// let pins = atmega_hal::pins!(dp);
258///
259/// // This demo uses downgraded pins, but it works just as well
260/// // with non-downgraded ones!
261/// let input_pin1: Pin<mode::Input<mode::Floating>> = pins.pd0
262///     .into_floating_input()
263///     .downgrade();
264/// let input_pin2: Pin<mode::Input<mode::Floating>> = pins.pd1
265///     .into_pull_up_input()
266///     .downgrade();
267///
268/// // With the input mode "forgotten", they have the same type now,
269/// // even if electically different.
270/// let any_inputs: [Pin<mode::Input>; 2] = [
271///     input_pin1.forget_imode(),
272///     input_pin2.forget_imode(),
273/// ];
274/// ```
275impl<PIN: PinOps, IMODE> Pin<mode::Input<IMODE>, PIN> {
276    /// "Erase" type-level information about whether the pin is currently a pull-up or a floating
277    /// input.
278    pub fn forget_imode(self) -> Pin<mode::Input, PIN> {
279        Pin {
280            pin: self.pin,
281            _mode: PhantomData,
282        }
283    }
284}
285
286/// # Digital Output
287impl<PIN: PinOps> Pin<mode::Output, PIN> {
288    /// Set pin high (pull it to supply voltage).
289    #[inline]
290    pub fn set_high(&mut self) {
291        unsafe { self.pin.out_set() }
292    }
293
294    /// Set pin low (pull it to GND).
295    #[inline]
296    pub fn set_low(&mut self) {
297        unsafe { self.pin.out_clear() }
298    }
299
300    /// Toggle a high pin to low and a low pin to high.
301    #[inline]
302    pub fn toggle(&mut self) {
303        unsafe { self.pin.out_toggle() }
304    }
305
306    /// Check whether the pin is set high.
307    ///
308    /// *Note*: The electrical state of the pin might differ due to external circuitry.
309    #[inline]
310    pub fn is_set_high(&self) -> bool {
311        unsafe { self.pin.out_get() }
312    }
313
314    /// Check whether the pin is set low.
315    ///
316    /// *Note*: The electrical state of the pin might differ due to external circuitry.
317    #[inline]
318    pub fn is_set_low(&self) -> bool {
319        !unsafe { self.pin.out_get() }
320    }
321}
322
323// Implements OutputPinV0 from embedded-hal to make sure external libraries work
324impl<PIN: PinOps> OutputPinV0 for Pin<mode::Output, PIN> {
325    type Error = core::convert::Infallible;
326
327    fn set_high(&mut self) -> Result<(), Self::Error> {
328        self.set_high();
329        Ok(())
330    }
331
332    fn set_low(&mut self) -> Result<(), Self::Error> {
333        self.set_low();
334        Ok(())
335    }
336}
337
338impl<PIN: PinOps> ErrorType for Pin<mode::Output, PIN> {
339    type Error = core::convert::Infallible;
340}
341
342impl<PIN: PinOps> OutputPin for Pin<mode::Output, PIN> {
343    fn set_low(&mut self) -> Result<(), Self::Error> {
344        self.set_low();
345        Ok(())
346    }
347
348    fn set_high(&mut self) -> Result<(), Self::Error> {
349        self.set_high();
350        Ok(())
351    }
352}
353
354impl<PIN: PinOps> StatefulOutputPin for Pin<mode::Output, PIN> {
355    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
356        Ok((*self).is_set_high())
357    }
358
359    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
360        Ok((*self).is_set_low())
361    }
362}
363
364/// # Digital Output Open Drain
365impl<PIN: PinOps> Pin<mode::OpenDrain, PIN> {
366    /// Set the pin high (Input without PullUp so it is floating)
367    #[inline]
368    pub fn set_high(&mut self) {
369        unsafe { self.pin.make_input(false) }
370    }
371
372    /// Set pin low (pull it to GND, Output to low).
373    #[inline]
374    pub fn set_low(&mut self) {
375        unsafe { self.pin.make_output() }
376    }
377
378    /// Check whether the pin is set high.
379    ///
380    /// *Note*: The electrical state of the pin might differ due to external circuitry.
381    #[inline]
382    pub fn is_high(&self) -> bool {
383        unsafe { self.pin.in_get() }
384    }
385
386    /// Check whether the pin is set low.
387    ///
388    /// *Note*: The electrical state of the pin might differ due to external circuitry.
389    #[inline]
390    pub fn is_low(&self) -> bool {
391        !self.is_high()
392    }
393}
394
395// Implements OutputPinV0 from embedded-hal to make sure external libraries work
396impl<PIN: PinOps> OutputPinV0 for Pin<mode::OpenDrain, PIN> {
397    type Error = core::convert::Infallible;
398
399    fn set_high(&mut self) -> Result<(), Self::Error> {
400        self.set_high();
401        Ok(())
402    }
403
404    fn set_low(&mut self) -> Result<(), Self::Error> {
405        self.set_low();
406        Ok(())
407    }
408}
409
410impl<PIN: PinOps> OutputPin for Pin<mode::OpenDrain, PIN> {
411    fn set_low(&mut self) -> Result<(), Self::Error> {
412        self.set_low();
413        Ok(())
414    }
415
416    fn set_high(&mut self) -> Result<(), Self::Error> {
417        self.set_high();
418        Ok(())
419    }
420}
421
422impl<PIN: PinOps> StatefulOutputPin for Pin<mode::OpenDrain, PIN> {
423    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
424        Ok((*self).is_high())
425    }
426
427    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
428        Ok((*self).is_low())
429    }
430}
431
432// Implements InputPinV0 from embedded-hal to make sure external libraries work
433impl<PIN: PinOps> InputPinV0 for Pin<mode::OpenDrain, PIN> {
434    type Error = core::convert::Infallible;
435
436    fn is_high(&self) -> Result<bool, Self::Error> {
437        Ok(self.is_high())
438    }
439
440    fn is_low(&self) -> Result<bool, Self::Error> {
441        Ok(self.is_low())
442    }
443}
444
445impl<PIN: PinOps> ErrorType for Pin<mode::OpenDrain, PIN> {
446    type Error = core::convert::Infallible;
447}
448
449impl<PIN: PinOps> InputPin for Pin<mode::OpenDrain, PIN> {
450    fn is_high(&mut self) -> Result<bool, Self::Error> {
451        Ok((*self).is_high())
452    }
453
454    fn is_low(&mut self) -> Result<bool, Self::Error> {
455        Ok((*self).is_low())
456    }
457}
458
459// Implements InputPinV0 from embedded-hal to make sure external libraries work
460impl<PIN: PinOps, IMODE: mode::InputMode> InputPinV0 for Pin<mode::Input<IMODE>, PIN> {
461    type Error = core::convert::Infallible;
462
463    fn is_high(&self) -> Result<bool, Self::Error> {
464        Ok(self.is_high())
465    }
466
467    fn is_low(&self) -> Result<bool, Self::Error> {
468        Ok(self.is_low())
469    }
470}
471
472impl<PIN: PinOps, IMODE: mode::InputMode> ErrorType for Pin<mode::Input<IMODE>, PIN> {
473    type Error = core::convert::Infallible;
474}
475
476impl<PIN: PinOps, IMODE: mode::InputMode> InputPin for Pin<mode::Input<IMODE>, PIN> {
477    fn is_high(&mut self) -> Result<bool, Self::Error> {
478        Ok((*self).is_high())
479    }
480
481    fn is_low(&mut self) -> Result<bool, Self::Error> {
482        Ok((*self).is_low())
483    }
484}
485
486/// # Digital Input
487impl<PIN: PinOps, IMODE: mode::InputMode> Pin<mode::Input<IMODE>, PIN> {
488    /// Check whether the pin is driven high.
489    #[inline]
490    pub fn is_high(&self) -> bool {
491        unsafe { self.pin.in_get() }
492    }
493
494    /// Check whether the pin is driven low.
495    #[inline]
496    pub fn is_low(&self) -> bool {
497        !unsafe { self.pin.in_get() }
498    }
499}
500
501/// # Analog Input
502///
503/// Some pins can be configured as ADC channels.  For those pins, `analog_read()` can be used to
504/// read the voltage.  `analog_read()` corresponds to a blocking ADC read:
505///
506/// ```
507/// let dp = atmega_hal::Peripherals::take().unwrap();
508/// let pins = atmega_hal::pins!(dp);
509/// let mut adc = atmega_hal::Adc::new(dp.ADC, Default::default());
510///
511/// let a0 = pins.pc0.into_analog_input(&mut adc);
512///
513/// let voltage = a0.analog_read(&mut adc);
514/// // ^- this is equivalent to -v
515/// let voltage = adc.read_blocking(&a0);
516/// ```
517impl<PIN: PinOps> Pin<mode::Analog, PIN> {
518    pub fn analog_read<H, ADC, CLOCK>(&self, adc: &mut crate::adc::Adc<H, ADC, CLOCK>) -> u16
519    where
520        Pin<mode::Analog, PIN>: crate::adc::AdcChannel<H, ADC>,
521        ADC: crate::adc::AdcOps<H>,
522        CLOCK: crate::clock::Clock,
523    {
524        adc.read_blocking(self)
525    }
526
527    /// Convert this pin into a generic [`Channel`][adc-channel] type.
528    ///
529    /// The generic channel type can be used to store multiple channels in an array.
530    ///
531    /// [adc-channel]: crate::adc::Channel
532    pub fn into_channel<H, ADC>(self) -> crate::adc::Channel<H, ADC>
533    where
534        Pin<mode::Analog, PIN>: crate::adc::AdcChannel<H, ADC>,
535        ADC: crate::adc::AdcOps<H>,
536    {
537        crate::adc::Channel::new(self)
538    }
539
540    /// Convert this pin to a floating digital input pin.
541    ///
542    /// The pin is re-enabled in the digital input buffer and is no longer usable as an analog
543    /// input. You can get to other digital modes by calling one of the usual `into_...` methods
544    /// on the return value of this function.
545    pub fn into_digital<H, ADC, CLOCK>(
546        self,
547        adc: &mut crate::adc::Adc<H, ADC, CLOCK>,
548    ) -> Pin<mode::Input<mode::Floating>, PIN>
549    where
550        Pin<mode::Analog, PIN>: crate::adc::AdcChannel<H, ADC>,
551        ADC: crate::adc::AdcOps<H>,
552        CLOCK: crate::clock::Clock,
553    {
554        adc.disable_pin(&self);
555        Pin {
556            pin: self.pin,
557            _mode: PhantomData,
558        }
559    }
560}
561
562#[macro_export]
563macro_rules! impl_port_traditional_base {
564    (
565        $chip_supports_atomic_toggle:literal,
566        $(#[$pins_attr:meta])*
567        enum Ports {
568            $($name:ident: $port:ty = [$($pin:literal),+],)+
569        }
570    ) => {
571        /// Type-alias for a pin type which can represent any concrete pin.
572        ///
573        /// Sometimes it is easier to handle pins if they are all of the same type.  By default,
574        /// each pin gets its own distinct type in `avr-hal`, but by
575        /// [downgrading][avr_hal_generic::port::Pin#downgrading], you can cast them into this
576        /// "dynamic" type.  Do note, however, that using this dynamic type has a runtime cost.
577        pub type Pin<MODE, PIN = Dynamic> = $crate::port::Pin<MODE, PIN>;
578
579        $crate::paste::paste! {
580            $(#[$pins_attr])*
581            pub struct Pins {
582                $($(pub [<p $name:lower $pin>]: Pin<
583                    mode::Input<mode::Floating>,
584                    [<P $name $pin>],
585                >,)+)+
586            }
587
588            impl Pins {
589                pub fn new(
590                    $(_: $port,)+
591                ) -> Self {
592                    Self {
593                        $($([<p $name:lower $pin>]: $crate::port::Pin::new(
594                            [<P $name $pin>] { _private: (), }
595                        ),)+)+
596                    }
597                }
598            }
599        }
600
601        $crate::paste::paste! {
602            #[repr(u8)]
603            pub enum DynamicPort {
604                $([<PORT $name>]),+
605            }
606        }
607
608        pub struct Dynamic {
609            port: DynamicPort,
610            // We'll store the mask instead of the pin number because this allows much less code to
611            // be generated for the trait method implementations.
612            mask: u8,
613        }
614
615        impl Dynamic {
616            fn new(port: DynamicPort, num: u8) -> Self {
617                Self {
618                    port,
619                    mask: 1u8 << num,
620                }
621            }
622        }
623
624        $crate::paste::paste! {
625            impl $crate::port::PinOps for Dynamic {
626                type Dynamic = Self;
627
628                #[inline]
629                fn into_dynamic(self) -> Self::Dynamic {
630                    self
631                }
632
633                #[inline]
634                unsafe fn out_set(&mut self) {
635                    match self.port {
636                        $(DynamicPort::[<PORT $name>] => (*<$port>::ptr()).[<port $name:lower>].modify(|r, w| {
637                            w.bits(r.bits() | self.mask)
638                        }),)+
639                    }
640                }
641
642                #[inline]
643                unsafe fn out_clear(&mut self) {
644                    match self.port {
645                        $(DynamicPort::[<PORT $name>] => (*<$port>::ptr()).[<port $name:lower>].modify(|r, w| {
646                            w.bits(r.bits() & !self.mask)
647                        }),)+
648                    }
649                }
650
651                #[inline]
652                unsafe fn out_toggle(&mut self) {
653                    match self.port {
654                        $(DynamicPort::[<PORT $name>] => {
655                            if $chip_supports_atomic_toggle {
656                                (*<$port>::ptr()).[<pin $name:lower>].write(|w| {
657                                    w.bits(self.mask)
658                                })
659                            } else {
660                                // This read-modify-write sequence cannot be optimized into a single sbi/cbi instruction,
661                                // so it is wrapped in a critical section which ensures we will never hit a race-condition here.
662                                $crate::avr_device::interrupt::free(|_| {
663                                    (*<$port>::ptr()).[<port $name:lower>].modify(|r, w| {
664                                        w.bits(r.bits() ^ self.mask)
665                                    })
666                                })
667                            }
668                        },)+
669                    }
670                }
671
672                #[inline]
673                unsafe fn out_get(&self) -> bool {
674                    match self.port {
675                        $(DynamicPort::[<PORT $name>] => {
676                            (*<$port>::ptr()).[<port $name:lower>].read().bits() & self.mask != 0
677                        })+
678                    }
679                }
680
681                #[inline]
682                unsafe fn in_get(&self) -> bool {
683                    match self.port {
684                        $(DynamicPort::[<PORT $name>] => {
685                            (*<$port>::ptr()).[<pin $name:lower>].read().bits() & self.mask != 0
686                        })+
687                    }
688                }
689
690                #[inline]
691                unsafe fn make_output(&mut self) {
692                    match self.port {
693                        $(DynamicPort::[<PORT $name>] => (*<$port>::ptr()).[<ddr $name:lower>].modify(|r, w| {
694                            w.bits(r.bits() | self.mask)
695                        }),)+
696                    }
697                }
698
699                #[inline]
700                unsafe fn make_input(&mut self, pull_up: bool) {
701                    match self.port {
702                        $(DynamicPort::[<PORT $name>] => (*<$port>::ptr()).[<ddr $name:lower>].modify(|r, w| {
703                            w.bits(r.bits() & !self.mask)
704                        }),)+
705                    }
706                    if pull_up {
707                        self.out_set()
708                    } else {
709                        self.out_clear()
710                    }
711                }
712            }
713        }
714
715        $crate::paste::paste! {
716            $($(
717                pub struct [<P $name $pin>] {
718                    _private: ()
719                }
720
721                impl $crate::port::PinOps for [<P $name $pin>] {
722                    type Dynamic = Dynamic;
723
724                    #[inline]
725                    fn into_dynamic(self) -> Self::Dynamic {
726                        Dynamic::new(DynamicPort::[<PORT $name>], $pin)
727                    }
728
729                    #[inline]
730                    unsafe fn out_set(&mut self) {
731                        (*<$port>::ptr()).[<port $name:lower>].modify(|_, w| {
732                            w.[<p $name:lower $pin>]().set_bit()
733                        })
734                    }
735
736                    #[inline]
737                    unsafe fn out_clear(&mut self) {
738                        (*<$port>::ptr()).[<port $name:lower>].modify(|_, w| {
739                            w.[<p $name:lower $pin>]().clear_bit()
740                        })
741                    }
742
743                    #[inline]
744                    unsafe fn out_toggle(&mut self) {
745                        if $chip_supports_atomic_toggle {
746                            (*<$port>::ptr()).[<pin $name:lower>].write(|w| {
747                                w.[<p $name:lower $pin>]().set_bit()
748                            })
749                        } else {
750                            // This read-modify-write sequence cannot be optimized into a single sbi/cbi instruction,
751                            // so it is wrapped in a critical section which ensures we will never hit a race-condition here.
752                            $crate::avr_device::interrupt::free(|_| {
753                                (*<$port>::ptr()).[<port $name:lower>].modify(|r, w| {
754                                    w.[<p $name:lower $pin>]().bit(!r.[<p $name:lower $pin>]().bit())
755                                })
756                            })
757                        }
758                    }
759
760                    #[inline]
761                    unsafe fn out_get(&self) -> bool {
762                        (*<$port>::ptr()).[<port $name:lower>].read().[<p $name:lower $pin>]().bit()
763                    }
764
765                    #[inline]
766                    unsafe fn in_get(&self) -> bool {
767                        (*<$port>::ptr()).[<pin $name:lower>].read().[<p $name:lower $pin>]().bit()
768                    }
769
770                    #[inline]
771                    unsafe fn make_output(&mut self) {
772                        (*<$port>::ptr()).[<ddr $name:lower>].modify(|_, w| {
773                            w.[<p $name:lower $pin>]().set_bit()
774                        })
775                    }
776
777                    #[inline]
778                    unsafe fn make_input(&mut self, pull_up: bool) {
779                        (*<$port>::ptr()).[<ddr $name:lower>].modify(|_, w| {
780                            w.[<p $name:lower $pin>]().clear_bit()
781                        });
782                        if pull_up {
783                            self.out_set()
784                        } else {
785                            self.out_clear()
786                        }
787                    }
788                }
789            )+)+
790        }
791    };
792}
793
794/// A macro that implements port handling for a microcontroller.
795#[macro_export]
796macro_rules! impl_port_traditional {
797    ($($tts:tt)*)  => {
798        $crate::impl_port_traditional_base!(true, $($tts)*);
799    };
800}
801
802/// A macro that implements port handling for an old microcontroller,
803/// that does not support toggling the output via the PIN register.
804#[macro_export]
805macro_rules! impl_port_traditional_old {
806    ($($tts:tt)*)  => {
807        $crate::impl_port_traditional_base!(false, $($tts)*);
808    };
809}
810
811#[macro_export]
812macro_rules! renamed_pins {
813    (
814        $(#[$pins_attr:meta])*
815        pub struct Pins {
816            $($(#[$pin_attr:meta])* pub $pin_name:ident: $pin_type:ty = $pin_orig:ident,)+
817        }
818
819        impl Pins {
820            type Pin = $pin_wrapper:ident;
821            type McuPins = $mcu_pins:ty;
822        }
823    ) => {
824        $crate::paste::paste! {
825            $(#[$pins_attr])*
826            pub struct Pins {
827                    $(pub $pin_name: $pin_wrapper<
828                        $crate::port::mode::Input<$crate::port::mode::Floating>,
829                        [<$pin_name:upper>],
830                    >,)+
831            }
832        }
833
834        $crate::paste::paste! {
835            $($(#[$pin_attr])* pub type [<$pin_name:upper>] = $pin_type;)+
836        }
837
838        impl Pins {
839            pub fn with_mcu_pins(pins: $mcu_pins) -> Self {
840                Self {
841                    $($pin_name: pins.$pin_orig,)+
842                }
843            }
844        }
845    };
846}