lpc8xx_hal/
gpio.rs

1//! API for General Purpose I/O (GPIO)
2//!
3//! The entry point to this API is [`GPIO`]. It can be used to initialize the
4//! peripheral, and is required to convert instances of [`Pin`] to a
5//! [`GpioPin`], which provides the core GPIO API.
6//!
7//! The GPIO peripheral is described in the following user manuals:
8//! - LPC82x user manual, chapter 9
9//! - LPC84x user manual, chapter 12
10//!
11//! # Examples
12//!
13//! Initialize a GPIO pin and set its output to HIGH:
14//!
15//! ``` no_run
16//! use lpc8xx_hal::{
17//!     prelude::*,
18//!     Peripherals,
19//!     gpio,
20//! };
21//!
22//! let mut p = Peripherals::take().unwrap();
23//!
24//! let mut syscon = p.SYSCON.split();
25//!
26//! #[cfg(feature = "82x")]
27//! let gpio = p.GPIO;
28//! #[cfg(feature = "845")]
29//! let gpio = p.GPIO.enable(&mut syscon.handle);
30//!
31//! let pio0_12 = p.pins.pio0_12.into_output_pin(
32//!     gpio.tokens.pio0_12,
33//!     gpio::Level::High,
34//! );
35//! ```
36//!
37//! Please refer to the [examples in the repository] for more example code.
38//!
39//! [`GPIO`]: struct.GPIO.html
40//! [`Pin`]: ../pins/struct.Pin.html
41//! [`GpioPin`]: struct.GpioPin.html
42//! [examples in the repository]: https://github.com/lpc-rs/lpc8xx-hal/tree/master/examples
43
44use core::marker::PhantomData;
45
46use embedded_hal::digital::v2::{
47    InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin,
48};
49use embedded_hal_alpha::digital::blocking::{
50    InputPin as InputPinAlpha, OutputPin as OutputPinAlpha,
51    StatefulOutputPin as StatefulOutputPinAlpha,
52    ToggleableOutputPin as ToggleableOutputPinAlpha,
53};
54use void::Void;
55
56use crate::{init_state, pac, pins, syscon};
57
58#[cfg(feature = "845")]
59use crate::pac::gpio::{CLR, DIRCLR, DIRSET, NOT, PIN, SET};
60#[cfg(feature = "82x")]
61use crate::pac::gpio::{
62    CLR0 as CLR, DIRCLR0 as DIRCLR, DIRSET0 as DIRSET, NOT0 as NOT,
63    PIN0 as PIN, SET0 as SET,
64};
65
66use self::direction::{Direction, DynamicPinErr};
67
68/// Interface to the GPIO peripheral
69///
70/// Controls the GPIO peripheral. Can be used to enable, disable, or free the
71/// peripheral. For GPIO-functionality directly related to pins, please refer
72/// to [`GpioPin`].
73///
74/// Use [`Peripherals`] to gain access to an instance of this struct.
75///
76/// Please refer to the [module documentation] for more information.
77///
78/// [`GpioPin`]: struct.GpioPin.html
79/// [`Peripherals`]: ../struct.Peripherals.html
80/// [module documentation]: index.html
81pub struct GPIO<State = init_state::Enabled> {
82    pub(crate) gpio: pac::GPIO,
83    _state: PhantomData<State>,
84
85    /// Tokens representing all pins
86    ///
87    /// Since the [`enable`] and [`disable`] methods consume `self`, they can
88    /// only be called, if all tokens are available. This means, any tokens that
89    /// have been moved out while the peripheral was enabled, prevent the
90    /// peripheral from being disabled (unless those tokens are moved back into
91    /// their original place).
92    ///
93    /// As using a pin for GPIO requires such a token, it is impossible to
94    /// disable the GPIO peripheral while pins are used for GPIO.
95    ///
96    /// [`enable`]: #method.enable
97    /// [`disable`]: #method.disable
98    pub tokens: pins::Tokens<State>,
99}
100
101impl<State> GPIO<State> {
102    pub(crate) fn new(gpio: pac::GPIO) -> Self {
103        GPIO {
104            gpio,
105            _state: PhantomData,
106
107            tokens: pins::Tokens::new(),
108        }
109    }
110
111    /// Return the raw peripheral
112    ///
113    /// This method serves as an escape hatch from the HAL API. It returns the
114    /// raw peripheral, allowing you to do whatever you want with it, without
115    /// limitations imposed by the API.
116    ///
117    /// If you are using this method because a feature you need is missing from
118    /// the HAL API, please [open an issue] or, if an issue for your feature
119    /// request already exists, comment on the existing issue, so we can
120    /// prioritize it accordingly.
121    ///
122    /// [open an issue]: https://github.com/lpc-rs/lpc8xx-hal/issues
123    pub fn free(self) -> pac::GPIO {
124        self.gpio
125    }
126}
127
128impl GPIO<init_state::Disabled> {
129    /// Enable the GPIO peripheral
130    ///
131    /// This method is only available, if `GPIO` is in the [`Disabled`] state.
132    /// Code that attempts to call this method when the peripheral is already
133    /// enabled will not compile.
134    ///
135    /// Consumes this instance of `GPIO` and returns another instance that has
136    /// its `State` type parameter set to [`Enabled`].
137    ///
138    /// [`Disabled`]: ../init_state/struct.Disabled.html
139    /// [`Enabled`]: ../init_state/struct.Enabled.html
140    pub fn enable(
141        self,
142        syscon: &mut syscon::Handle,
143    ) -> GPIO<init_state::Enabled> {
144        syscon.enable_clock(&self.gpio);
145
146        // Only works, if all tokens are available.
147        let tokens = self.tokens.switch_state();
148
149        GPIO {
150            gpio: self.gpio,
151            _state: PhantomData,
152            tokens,
153        }
154    }
155}
156
157impl GPIO<init_state::Enabled> {
158    /// Disable the GPIO peripheral
159    ///
160    /// This method is only available, if `GPIO` is in the [`Enabled`] state.
161    /// Code that attempts to call this method when the peripheral is already
162    /// disabled will not compile.
163    ///
164    /// Consumes this instance of `GPIO` and returns another instance that has
165    /// its `State` type parameter set to [`Disabled`].
166    ///
167    /// [`Enabled`]: ../init_state/struct.Enabled.html
168    /// [`Disabled`]: ../init_state/struct.Disabled.html
169    pub fn disable(
170        self,
171        syscon: &mut syscon::Handle,
172    ) -> GPIO<init_state::Disabled> {
173        syscon.disable_clock(&self.gpio);
174
175        // Only works, if all tokens are available.
176        let tokens = self.tokens.switch_state();
177
178        GPIO {
179            gpio: self.gpio,
180            _state: PhantomData,
181            tokens,
182        }
183    }
184}
185
186/// A pin used for general purpose I/O (GPIO).
187///
188/// This struct is a wrapper around the representation of a specific pin `P`– it enables said pin
189/// to be used as a GPIO pin.
190///
191/// You can get access to an instance of this struct by switching a pin to the
192/// GPIO state, using [`Pin::into_input_pin`] or [`Pin::into_output_pin`].
193///
194/// # `embedded-hal` traits
195/// - While in input mode
196///   - [`embedded_hal::digital::v2::InputPin`] for reading the pin state
197/// - While in output mode
198///   - [`embedded_hal::digital::v2::OutputPin`] for setting the pin state
199///   - [`embedded_hal::digital::v2::StatefulOutputPin`] for reading the pin output state
200///   - [`embedded_hal::digital::v2::ToggleableOutputPin`] for toggling the pin state
201///
202/// [`Pin::into_input_pin`]: ../pins/struct.Pin.html#method.into_input_pin
203/// [`Pin::into_output_pin`]: ../pins/struct.Pin.html#method.into_output_pin
204/// [`embedded_hal::digital::v2::InputPin`]: #impl-InputPin
205/// [`embedded_hal::digital::v2::OutputPin`]: #impl-OutputPin
206/// [`embedded_hal::digital::v2::StatefulOutputPin`]: #impl-StatefulOutputPin
207/// [`embedded_hal::digital::v2::ToggleableOutputPin`]: #impl-ToggleableOutputPin
208pub struct GpioPin<P, D> {
209    inner: P, // holds port, id and mask for this specific pin
210    _direction: D,
211}
212
213impl<P, D> GpioPin<P, D>
214where
215    P: pins::Trait,
216    D: Direction,
217{
218    pub(crate) fn new(inner: P, arg: D::SwitchArg) -> Self {
219        // This is sound, as we only write to stateless registers, restricting
220        // ourselves to the bit that belongs to the pin represented by `P`.
221        // Since all other instances of `GpioPin` are doing the same, there are
222        // no race conditions.
223        let gpio = unsafe { &*pac::GPIO::ptr() };
224        let registers = Registers::new(gpio);
225        let direction = D::switch(&registers, arg, &inner);
226
227        Self {
228            inner,
229            _direction: direction,
230        }
231    }
232
233    /// Get identifying information about this pin in the form of a [`pins::Trait`]
234    ///
235    /// [`pins::Trait`]: ../pins/trait.Trait.html
236    pub fn inner(&self) -> &P {
237        &self.inner
238    }
239
240    /// Indicates wether the voltage at the pin is currently HIGH
241    /// This is not accessible to the user to avoid confusion because `is_high()`
242    /// semantics differ depending on pin direction. It is only used to implement
243    /// `is_high()` and `is_set_high()` respectively for the different direction types.
244    pub(crate) fn is_high_inner(&self) -> bool {
245        let gpio = unsafe { &*pac::GPIO::ptr() };
246        let registers = Registers::new(gpio);
247
248        is_high(&registers, self.inner())
249    }
250}
251
252impl<P> GpioPin<P, direction::Input>
253where
254    P: pins::Trait,
255{
256    /// Set pin direction to output
257    ///
258    /// This method is only available while the pin is in input mode.
259    ///
260    /// Consumes the pin instance and returns a new instance that is in output
261    /// mode, making the methods to set the output level available.
262    pub fn into_output(self, initial: Level) -> GpioPin<P, direction::Output> {
263        // This is sound, as we only do a stateless write to a bit that no other
264        // `GpioPin` instance writes to.
265        let gpio = unsafe { &*pac::GPIO::ptr() };
266        let registers = Registers::new(gpio);
267
268        let direction =
269            direction::Output::switch(&registers, initial, self.inner());
270
271        GpioPin {
272            inner: self.inner,
273            _direction: direction,
274        }
275    }
276
277    /// Set pin direction to dynamic (i.e. changeable at runtime)
278    ///
279    /// This method is only available when the pin is not already in dynamic mode.
280    ///
281    /// Consumes the pin instance and returns a new instance that is in dynamic
282    /// mode, making the methods to change direction as well as read/set levels
283    /// (depending on the current diection) available.
284    pub fn into_dynamic(
285        self,
286        initial_level: Level,
287        initial_direction: pins::DynamicPinDirection,
288    ) -> GpioPin<P, direction::Dynamic> {
289        // This is sound, as we only do a stateless write to a bit that no other
290        // `GpioPin` instance writes to.
291        let gpio = unsafe { &*pac::GPIO::ptr() };
292        let registers = Registers::new(gpio);
293
294        // always switch to ensure initial level and direction are set correctly
295        let new_direction = direction::Dynamic::switch(
296            &registers,
297            (initial_level, initial_direction),
298            self.inner(),
299        );
300
301        GpioPin {
302            inner: self.inner,
303            _direction: new_direction,
304        }
305    }
306
307    /// Indicates wether the voltage at the pin is currently HIGH
308    ///
309    /// This method is only available, if two conditions are met:
310    /// - The pin is in the GPIO state.
311    /// - The pin direction is set to input.
312    ///
313    /// See [`Pin::into_input_pin`] and [`into_input`]. Unless both of these
314    /// conditions are met, code trying to call this method will not compile.
315    ///
316    /// [`Pin::into_input_pin`]: ../pins/struct.Pin.html#method.into_input_pin
317    /// [`into_input`]: #method.into_input
318    pub fn is_high(&self) -> bool {
319        self.is_high_inner()
320    }
321
322    /// Indicates wether the pin input is LOW
323    ///
324    /// This method is only available, if two conditions are met:
325    /// - The pin is in the GPIO state.
326    /// - The pin direction is set to input.
327    ///
328    /// See [`Pin::into_input_pin`] and [`into_input`]. Unless both of these
329    /// conditions are met, code trying to call this method will not compile.
330    ///
331    /// [`Pin::into_input_pin`]: ../pins/struct.Pin.html#method.into_input_pin
332    /// [`into_input`]: #method.into_input
333    pub fn is_low(&self) -> bool {
334        !self.is_high()
335    }
336
337    /// Returns the current voltage level at this pin.
338    ///
339    /// This method is only available, if two conditions are met:
340    /// - The pin is in the GPIO state.
341    /// - The pin direction is set to input.
342    ///
343    /// See [`Pin::into_input_pin`] and [`into_input`]. Unless both of these
344    /// conditions are met, code trying to call this method will not compile.
345    ///
346    /// [`Pin::into_input_pin`]: ../pins/struct.Pin.html#method.into_input_pin
347    /// [`into_input`]: #method.into_input
348    pub fn get_level(&self) -> Level {
349        Level::from_pin(&self)
350    }
351}
352
353impl<P> GpioPin<P, direction::Output>
354where
355    P: pins::Trait,
356{
357    /// Set pin direction to input
358    ///
359    /// This method is only available while the pin is in output mode.
360    ///
361    /// Consumes the pin instance and returns a new instance that is in output
362    /// mode, making the methods to set the output level available.
363    pub fn into_input(self) -> GpioPin<P, direction::Input> {
364        // This is sound, as we only do a stateless write to a bit that no other
365        // `GpioPin` instance writes to.
366        let gpio = unsafe { &*pac::GPIO::ptr() };
367        let registers = Registers::new(gpio);
368
369        let direction = direction::Input::switch(&registers, (), &self.inner);
370
371        GpioPin {
372            inner: self.inner,
373            _direction: direction,
374        }
375    }
376
377    /// Set pin direction to dynamic (i.e. changeable at runtime)
378    ///
379    /// This method is only available when the pin is not already in dynamic mode.
380    ///
381    /// Consumes the pin instance and returns a new instance that is in dynamic
382    /// mode, making the methods to change direction as well as read/set levels
383    /// (depending on the current diection) available.
384    pub fn into_dynamic(
385        self,
386        initial_level: Level,
387        initial_direction: pins::DynamicPinDirection,
388    ) -> GpioPin<P, direction::Dynamic> {
389        // This is sound, as we only do a stateless write to a bit that no other
390        // `GpioPin` instance writes to.
391        let gpio = unsafe { &*pac::GPIO::ptr() };
392        let registers = Registers::new(gpio);
393
394        // always switch to ensure initial level and direction are set correctly
395        let new_direction = direction::Dynamic::switch(
396            &registers,
397            (initial_level, initial_direction),
398            &self.inner,
399        );
400
401        GpioPin {
402            inner: self.inner,
403            _direction: new_direction,
404        }
405    }
406
407    /// Set the pin output to HIGH
408    ///
409    /// This method is only available, if two conditions are met:
410    /// - The pin is in the GPIO state.
411    /// - The pin direction is set to output.
412    ///
413    /// See [`Pin::into_output_pin`] and [`into_output`]. Unless both of these
414    /// conditions are met, code trying to call this method will not compile.
415    ///
416    /// [`Pin::into_output_pin`]: ../pins/struct.Pin.html#method.into_output_pin
417    /// [`into_output`]: #method.into_output
418    pub fn set_high(&mut self) {
419        // This is sound, as we only do a stateless write to a bit that no other
420        // `GpioPin` instance writes to.
421        let gpio = unsafe { &*pac::GPIO::ptr() };
422        let registers = Registers::new(gpio);
423
424        set_high(&registers, self.inner());
425    }
426
427    /// Set the pin output to LOW
428    ///
429    /// This method is only available, if two conditions are met:
430    /// - The pin is in the GPIO state.
431    /// - The pin direction is set to output.
432    ///
433    /// See [`Pin::into_output_pin`] and [`into_output`]. Unless both of these
434    /// conditions are met, code trying to call this method will not compile.
435    ///
436    /// [`Pin::into_output_pin`]: ../pins/struct.Pin.html#method.into_output_pin
437    /// [`into_output`]: #method.into_output
438    pub fn set_low(&mut self) {
439        // This is sound, as we only do a stateless write to a bit that no other
440        // `GpioPin` instance writes to.
441        let gpio = unsafe { &*pac::GPIO::ptr() };
442        let registers = Registers::new(gpio);
443
444        set_low(&registers, self.inner());
445    }
446
447    /// Indicates whether the pin output is currently set to HIGH
448    ///
449    /// This method is only available, if two conditions are met:
450    /// - The pin is in the GPIO state.
451    /// - The pin direction is set to output.
452    ///
453    /// See [`Pin::into_output_pin`] and [`into_output`]. Unless both of these
454    /// conditions are met, code trying to call this method will not compile.
455    ///
456    /// [`Pin::into_output_pin`]: ../pins/struct.Pin.html#method.into_output_pin
457    /// [`into_output`]: #method.into_output
458    pub fn is_set_high(&self) -> bool {
459        // This is sound, as we only read a bit from a register.
460        let gpio = unsafe { &*pac::GPIO::ptr() };
461        let registers = Registers::new(gpio);
462
463        is_high(&registers, self.inner())
464    }
465
466    /// Indicates whether the pin output is currently set to LOW
467    ///
468    /// This method is only available, if two conditions are met:
469    /// - The pin is in the GPIO state.
470    /// - The pin direction is set to output.
471    ///
472    /// See [`Pin::into_output_pin`] and [`into_output`]. Unless both of these
473    /// conditions are met, code trying to call this method will not compile.
474    ///
475    /// [`Pin::into_output_pin`]: ../pins/struct.Pin.html#method.into_output_pin
476    /// [`into_output`]: #method.into_output
477    pub fn is_set_low(&self) -> bool {
478        !self.is_set_high()
479    }
480
481    /// Returns the level to which this pin is currently set
482    ///
483    /// This method is only available, if two conditions are met:
484    /// - The pin is in the GPIO state.
485    /// - The pin direction is set to output.
486    ///
487    /// See [`Pin::into_output_pin`] and [`into_output`]. Unless both of these
488    /// conditions are met, code trying to call this method will not compile.
489    ///
490    /// [`Pin::into_output_pin`]: ../pins/struct.Pin.html#method.into_output_pin
491    /// [`into_output`]: #method.into_output
492    pub fn get_set_level(&self) -> Level {
493        match self.is_set_high() {
494            true => Level::High,
495            false => Level::Low,
496        }
497    }
498
499    /// Toggle the pin output
500    ///
501    /// This method is only available, if two conditions are met:
502    /// - The pin is in the GPIO state.
503    /// - The pin direction is set to output.
504    ///
505    /// See [`Pin::into_output_pin`] and [`into_output`]. Unless both of these
506    /// conditions are met, code trying to call this method will not compile.
507    ///
508    /// [`Pin::into_output_pin`]: ../pins/struct.Pin.html#method.into_output_pin
509    /// [`into_output`]: #method.into_output
510    pub fn toggle(&mut self) {
511        // This is sound, as we only do a stateless write to a bit that no other
512        // `GpioPin` instance writes to.
513        let gpio = unsafe { &*pac::GPIO::ptr() };
514        let registers = Registers::new(gpio);
515
516        registers.not[usize::from(self.inner().port())]
517            .write(|w| unsafe { w.notp().bits(self.inner().mask()) });
518    }
519}
520
521impl<P> GpioPin<P, direction::Dynamic>
522where
523    P: pins::Trait,
524{
525    /// Tell us whether this pin's direction is currently set to Output.
526    pub fn direction_is_output(&self) -> bool {
527        return self._direction.current_direction
528            == pins::DynamicPinDirection::Output;
529    }
530
531    /// Tell us whether this pin's direction is currently set to Input.
532    pub fn direction_is_input(&self) -> bool {
533        return !self.direction_is_output();
534    }
535
536    /// Switch pin direction to input. If the pin is already an input pin, this does nothing.
537    pub fn switch_to_input(&mut self) {
538        if self._direction.current_direction == pins::DynamicPinDirection::Input
539        {
540            return;
541        }
542
543        // This is sound, as we only do a stateless write to a bit that no other
544        // `GpioPin` instance writes to.
545        let gpio = unsafe { &*pac::GPIO::ptr() };
546        let registers = Registers::new(gpio);
547
548        // switch direction
549        set_direction_input(&registers, self.inner());
550        self._direction.current_direction = pins::DynamicPinDirection::Input;
551    }
552
553    /// Switch pin direction to output with output level set to `level`.
554    /// If the pin is already an output pin, this function only switches its level to `level`.
555    pub fn switch_to_output(&mut self, level: Level) {
556        // First set the output level, before we switch the mode.
557        match level {
558            Level::High => self.set_high(),
559            Level::Low => self.set_low(),
560        }
561
562        // we are already in output, nothing else to do
563        if self._direction.current_direction
564            == pins::DynamicPinDirection::Output
565        {
566            return;
567        }
568
569        // This is sound, as we only do a stateless write to a bit that no other
570        // `GpioPin` instance writes to.
571        let gpio = unsafe { &*pac::GPIO::ptr() };
572        let registers = Registers::new(gpio);
573
574        // Now that the output level is configured, we can safely switch to
575        // output mode, without risking an undesired signal between now and
576        // the first call to `set_high`/`set_low`.
577        set_direction_output(&registers, self.inner());
578        self._direction.current_direction = pins::DynamicPinDirection::Output;
579    }
580
581    /// Set the pin level to High.
582    /// Note that this will be executed regardless of the current pin direction.
583    /// This enables you to set the initial pin level *before* switching to output
584    pub fn set_high(&mut self) {
585        // This is sound, as we only do a stateless write to a bit that no other
586        // `GpioPin` instance writes to.
587        let gpio = unsafe { &*pac::GPIO::ptr() };
588        let registers = Registers::new(gpio);
589
590        set_high(&registers, self.inner());
591    }
592
593    /// Set the pin level to Low.
594    /// Note that this will be executed regardless of the current pin direction.
595    /// This enables you to set the initial pin level *before* switching to output
596    pub fn set_low(&mut self) {
597        // This is sound, as we only do a stateless write to a bit that no other
598        // `GpioPin` instance writes to.
599        let gpio = unsafe { &*pac::GPIO::ptr() };
600        let registers = Registers::new(gpio);
601
602        set_low(&registers, self.inner());
603    }
604
605    /// Returns the current voltage level at this pin.
606    /// This can be used when the pin is in any direction:
607    ///
608    /// If it is currently an Output pin, it indicates to which level the pin is set
609    /// If it is currently an Input pin, it indicates the level currently present at this pin
610    ///
611    /// This method is only available, if the pin has been set to dynamic mode.
612    /// See [`Pin::into_dynamic_pin`].
613    /// Unless this condition is met, code trying to call this method will not compile.
614    ///
615    /// [`Pin::into_dynamic_pin`]: crate::pins::Pin::into_dynamic_pin
616    pub fn get_level(&self) -> Level {
617        Level::from_pin(&self)
618    }
619}
620
621impl<P> OutputPin for GpioPin<P, direction::Dynamic>
622where
623    P: pins::Trait,
624{
625    type Error = DynamicPinErr;
626
627    fn set_high(&mut self) -> Result<(), Self::Error> {
628        // NOTE: this check is kind of redundant but since both `set_high()`s are public I
629        // didn't want to either leave it out of `self.set_high()` or return an OK here
630        // when there's really an error
631        // (applies to all Dynamic Pin impls)
632        match self._direction.current_direction {
633            pins::DynamicPinDirection::Output => {
634                // Call the inherent method defined above.
635                Ok(self.set_high())
636            }
637            pins::DynamicPinDirection::Input => {
638                Err(Self::Error::WrongDirection)
639            }
640        }
641    }
642
643    fn set_low(&mut self) -> Result<(), Self::Error> {
644        match self._direction.current_direction {
645            pins::DynamicPinDirection::Output => {
646                // Call the inherent method defined above.
647                Ok(self.set_low())
648            }
649            pins::DynamicPinDirection::Input => {
650                Err(Self::Error::WrongDirection)
651            }
652        }
653    }
654}
655
656impl<P> StatefulOutputPin for GpioPin<P, direction::Dynamic>
657where
658    P: pins::Trait,
659{
660    fn is_set_high(&self) -> Result<bool, Self::Error> {
661        match self._direction.current_direction {
662            pins::DynamicPinDirection::Output => {
663                // Re-use level reading function
664                self.is_set_high()
665            }
666            pins::DynamicPinDirection::Input => {
667                Err(Self::Error::WrongDirection)
668            }
669        }
670    }
671
672    fn is_set_low(&self) -> Result<bool, Self::Error> {
673        match self._direction.current_direction {
674            pins::DynamicPinDirection::Output => {
675                // Re-use level reading function
676                self.is_set_low()
677            }
678            pins::DynamicPinDirection::Input => {
679                Err(Self::Error::WrongDirection)
680            }
681        }
682    }
683}
684
685impl<P> InputPin for GpioPin<P, direction::Dynamic>
686where
687    P: pins::Trait,
688{
689    type Error = DynamicPinErr;
690
691    fn is_high(&self) -> Result<bool, Self::Error> {
692        match self._direction.current_direction {
693            pins::DynamicPinDirection::Output => {
694                Err(Self::Error::WrongDirection)
695            }
696            pins::DynamicPinDirection::Input => {
697                // Call the inherent method defined above.
698                Ok(self.is_high_inner())
699            }
700        }
701    }
702
703    fn is_low(&self) -> Result<bool, Self::Error> {
704        match self._direction.current_direction {
705            pins::DynamicPinDirection::Output => {
706                Err(Self::Error::WrongDirection)
707            }
708            pins::DynamicPinDirection::Input => {
709                // Call the inherent method defined above.
710                Ok(!self.is_high_inner())
711            }
712        }
713    }
714}
715
716impl<P> InputPin for GpioPin<P, direction::Input>
717where
718    P: pins::Trait,
719{
720    type Error = Void;
721
722    fn is_high(&self) -> Result<bool, Self::Error> {
723        // Call the inherent method defined above.
724        Ok(self.is_high())
725    }
726
727    fn is_low(&self) -> Result<bool, Self::Error> {
728        // Call the inherent method defined above.
729        Ok(self.is_low())
730    }
731}
732
733impl<P> InputPinAlpha for GpioPin<P, direction::Input>
734where
735    P: pins::Trait,
736{
737    type Error = Void;
738
739    fn is_high(&self) -> Result<bool, Self::Error> {
740        // Call the inherent method defined above.
741        Ok(self.is_high())
742    }
743
744    fn is_low(&self) -> Result<bool, Self::Error> {
745        // Call the inherent method defined above.
746        Ok(self.is_low())
747    }
748}
749
750impl<P> OutputPin for GpioPin<P, direction::Output>
751where
752    P: pins::Trait,
753{
754    type Error = Void;
755
756    fn set_high(&mut self) -> Result<(), Self::Error> {
757        // Call the inherent method defined above.
758        Ok(self.set_high())
759    }
760
761    fn set_low(&mut self) -> Result<(), Self::Error> {
762        // Call the inherent method defined above.
763        Ok(self.set_low())
764    }
765}
766
767impl<P> OutputPinAlpha for GpioPin<P, direction::Output>
768where
769    P: pins::Trait,
770{
771    type Error = Void;
772
773    fn set_high(&mut self) -> Result<(), Self::Error> {
774        // Call the inherent method defined above.
775        Ok(self.set_high())
776    }
777
778    fn set_low(&mut self) -> Result<(), Self::Error> {
779        // Call the inherent method defined above.
780        Ok(self.set_low())
781    }
782}
783
784impl<P> StatefulOutputPin for GpioPin<P, direction::Output>
785where
786    P: pins::Trait,
787{
788    fn is_set_high(&self) -> Result<bool, Self::Error> {
789        // Call the inherent method defined above.
790        Ok(self.is_set_high())
791    }
792
793    fn is_set_low(&self) -> Result<bool, Self::Error> {
794        // Call the inherent method defined above.
795        Ok(self.is_set_low())
796    }
797}
798
799impl<P> StatefulOutputPinAlpha for GpioPin<P, direction::Output>
800where
801    P: pins::Trait,
802{
803    fn is_set_high(&self) -> Result<bool, Self::Error> {
804        // Call the inherent method defined above.
805        Ok(self.is_set_high())
806    }
807
808    fn is_set_low(&self) -> Result<bool, Self::Error> {
809        // Call the inherent method defined above.
810        Ok(self.is_set_low())
811    }
812}
813
814impl<P> ToggleableOutputPin for GpioPin<P, direction::Output>
815where
816    P: pins::Trait,
817{
818    type Error = Void;
819
820    fn toggle(&mut self) -> Result<(), Self::Error> {
821        // Call the inherent method defined above.
822        Ok(self.toggle())
823    }
824}
825
826impl<P> ToggleableOutputPinAlpha for GpioPin<P, direction::Output>
827where
828    P: pins::Trait,
829{
830    type Error = Void;
831
832    fn toggle(&mut self) -> Result<(), Self::Error> {
833        // Call the inherent method defined above.
834        Ok(self.toggle())
835    }
836}
837
838/// The voltage level of a pin
839#[derive(Debug, Copy, Clone)]
840pub enum Level {
841    /// High voltage
842    High,
843
844    /// Low voltage
845    Low,
846}
847
848impl Level {
849    fn from_pin<P: pins::Trait, D: Direction>(pin: &GpioPin<P, D>) -> Self {
850        match pin.is_high_inner() {
851            true => Level::High,
852            false => Level::Low,
853        }
854    }
855}
856
857fn set_high(registers: &Registers, inner: &impl pins::Trait) {
858    registers.set[usize::from(inner.port())]
859        .write(|w| unsafe { w.setp().bits(inner.mask()) });
860}
861
862fn set_low(registers: &Registers, inner: &impl pins::Trait) {
863    registers.clr[usize::from(inner.port())]
864        .write(|w| unsafe { w.clrp().bits(inner.mask()) });
865}
866
867fn is_high(registers: &Registers, inner: &impl pins::Trait) -> bool {
868    registers.pin[usize::from(inner.port())]
869        .read()
870        .port()
871        .bits()
872        & inner.mask()
873        == inner.mask()
874}
875
876// For internal use only.
877// Use the direction helpers of `GpioPin<P, direction::Output>` and `GpioPin<P, direction::Dynamic>`
878// instead.
879fn set_direction_output(registers: &Registers, inner: &impl pins::Trait) {
880    registers.dirset[usize::from(inner.port())]
881        .write(|w| unsafe { w.dirsetp().bits(inner.mask()) });
882}
883
884// For internal use only.
885// Use the direction helpers of `GpioPin<P, direction::Input>` and `GpioPin<P, direction::Dynamic>`
886// instead.
887fn set_direction_input(registers: &Registers, inner: &impl pins::Trait) {
888    registers.dirclr[usize::from(inner.port())]
889        .write(|w| unsafe { w.dirclrp().bits(inner.mask()) });
890}
891
892/// This is an internal type that should be of no concern to users of this crate
893pub struct Registers<'gpio> {
894    dirset: &'gpio [DIRSET],
895    dirclr: &'gpio [DIRCLR],
896    pin: &'gpio [PIN],
897    set: &'gpio [SET],
898    clr: &'gpio [CLR],
899    not: &'gpio [NOT],
900}
901
902impl<'gpio> Registers<'gpio> {
903    /// Create a new instance of `Registers` from the provided register block
904    ///
905    /// If the reference to `RegisterBlock` is not exclusively owned by the
906    /// caller, accessing all registers is still completely race-free, as long
907    /// as the following rules are upheld:
908    /// - Never write to `pin`, only use it for reading.
909    /// - For all other registers, only set bits that no other callers are
910    ///   setting.
911    fn new(gpio: &'gpio pac::gpio::RegisterBlock) -> Self {
912        #[cfg(feature = "82x")]
913        {
914            use core::slice;
915
916            Self {
917                dirset: slice::from_ref(&gpio.dirset0),
918                dirclr: slice::from_ref(&gpio.dirclr0),
919                pin: slice::from_ref(&gpio.pin0),
920                set: slice::from_ref(&gpio.set0),
921                clr: slice::from_ref(&gpio.clr0),
922                not: slice::from_ref(&gpio.not0),
923            }
924        }
925
926        #[cfg(feature = "845")]
927        Self {
928            dirset: &gpio.dirset,
929            dirclr: &gpio.dirclr,
930            pin: &gpio.pin,
931            set: &gpio.set,
932            clr: &gpio.clr,
933            not: &gpio.not,
934        }
935    }
936}
937
938/// Contains types to indicate the direction of GPIO pins
939///
940/// Please refer to [`GpioPin`] for documentation on how these types are used.
941///
942/// [`GpioPin`]: ../struct.GpioPin.html
943pub mod direction {
944    use crate::pins;
945
946    use super::{Level, Registers};
947
948    /// Implemented by types that indicate GPIO pin direction
949    ///
950    /// The [`GpioPin`] type uses this trait as a bound for its type parameter.
951    /// This is done for documentation purposes, to clearly show which types can
952    /// be used for this parameter. Other than that, this trait should not be
953    /// relevant to users of this crate.
954    ///
955    /// [`GpioPin`]: ../struct.GpioPin.html
956    pub trait Direction {
957        /// The argument of the `switch` method
958        type SwitchArg;
959
960        /// Switch a pin to this direction
961        ///
962        /// This method is for internal use only. Any changes to it won't be
963        /// considered breaking changes.
964        fn switch<P: pins::Trait>(
965            _: &Registers,
966            _: Self::SwitchArg,
967            _: &P,
968        ) -> Self;
969    }
970
971    /// Marks a GPIO pin as being configured for input
972    ///
973    /// This type is used as a type parameter of [`GpioPin`]. Please refer to
974    /// the documentation there to see how this type is used.
975    ///
976    /// [`GpioPin`]: ../struct.GpioPin.html
977    pub struct Input(());
978
979    impl Direction for Input {
980        type SwitchArg = ();
981
982        fn switch<P: pins::Trait>(
983            registers: &Registers,
984            _: Self::SwitchArg,
985            inner: &P,
986        ) -> Self {
987            super::set_direction_input(registers, inner);
988            Self(())
989        }
990    }
991
992    /// Marks a GPIO pin as being configured for output
993    ///
994    /// This type is used as a type parameter of [`GpioPin`]. Please refer to
995    /// the documentation there to see how this type is used.
996    ///
997    /// [`GpioPin`]: ../struct.GpioPin.html
998    pub struct Output(());
999
1000    impl Direction for Output {
1001        type SwitchArg = Level;
1002
1003        fn switch<P: pins::Trait>(
1004            registers: &Registers,
1005            initial: Level,
1006            inner: &P,
1007        ) -> Self {
1008            // First set the output level, before we switch the mode.
1009            match initial {
1010                Level::High => super::set_high(registers, inner),
1011                Level::Low => super::set_low(registers, inner),
1012            }
1013
1014            // Now that the output level is configured, we can safely switch to
1015            // output mode, without risking an undesired signal between now and
1016            // the first call to `set_high`/`set_low`.
1017            super::set_direction_output(&registers, inner);
1018
1019            Self(())
1020        }
1021    }
1022
1023    /// Marks a GPIO pin as being run-time configurable for in/output
1024    /// Initial direction is Output
1025    ///
1026    /// This type is used as a type parameter of [`GpioPin`]. Please refer to
1027    /// the documentation there to see how this type is used.
1028    ///
1029    /// [`GpioPin`]: ../struct.GpioPin.html
1030    pub struct Dynamic {
1031        pub(super) current_direction: pins::DynamicPinDirection,
1032    }
1033
1034    /// Error that can be thrown by operations on a Dynamic pin
1035    #[derive(Copy, Clone, Debug)]
1036    pub enum DynamicPinErr {
1037        /// you called a function that is not applicable to the pin's current direction
1038        WrongDirection,
1039    }
1040
1041    impl Direction for Dynamic {
1042        type SwitchArg = (Level, pins::DynamicPinDirection);
1043
1044        fn switch<P: pins::Trait>(
1045            registers: &Registers,
1046            initial: Self::SwitchArg,
1047            inner: &P,
1048        ) -> Self {
1049            let (level, current_direction) = initial;
1050
1051            // First set the output level, before we switch the mode.
1052            match level {
1053                Level::High => super::set_high(registers, inner),
1054                Level::Low => super::set_low(registers, inner),
1055            }
1056
1057            match current_direction {
1058                pins::DynamicPinDirection::Input => {
1059                    // Now that the output level is configured, we can safely switch to
1060                    // output mode, without risking an undesired signal between now and
1061                    // the first call to `set_high`/`set_low`.
1062                    super::set_direction_input(registers, inner);
1063                }
1064                pins::DynamicPinDirection::Output => {
1065                    // Now that the output level is configured, we can safely switch to
1066                    // output mode, without risking an undesired signal between now and
1067                    // the first call to `set_high`/`set_low`.
1068                    super::set_direction_output(registers, inner);
1069                }
1070            }
1071
1072            Self { current_direction }
1073        }
1074    }
1075}