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(®isters, 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(®isters, 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(®isters, 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 ®isters,
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(®isters, (), &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 ®isters,
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(®isters, 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(®isters, 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(®isters, 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(®isters, 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(®isters, 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(®isters, 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(®isters, 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(®isters, 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}