esp_hal/gpio/mod.rs
1//! # General Purpose Input/Output (GPIO)
2//!
3//! ## Overview
4//!
5//! Each pin can be used as a general-purpose I/O, or be connected to one or
6//! more internal peripheral signals.
7#![cfg_attr(
8 soc_etm,
9 doc = "The GPIO pins also provide tasks and events via the ETM interconnect system. For more information, see the [etm] module."
10)]
11#![doc = ""]
12//! ## Working with pins
13//!
14//! After initializing the HAL, you can access the individual pins using the
15//! [`crate::Peripherals`] struct. These pins can then be used as general
16//! purpose digital IO using pin drivers, or they can be passed to peripherals
17//! (such as SPI, UART, I2C, etc.), or can be [`split`]
18//! into peripheral signals for advanced use.
19//!
20//! Pin drivers can be created using [`Flex::new`], [`Input::new`] and
21//! [`Output::new`].
22//!
23//! Output pins can be configured to either push-pull or open-drain (active low)
24//! mode, with configurable drive strength and pull-up/pull-down resistors.
25//!
26//! Each pin is a different type initially. Internally, `esp-hal` will erase
27//! their types automatically, but they can also be converted into [`AnyPin`]
28//! manually by calling [`Pin::degrade`].
29//!
30//! The [`Io`] struct can also be used to configure the interrupt handler for
31//! GPIO interrupts. For more information, see the
32//! [`InterruptConfigurable::set_interrupt_handler`](crate::interrupt::InterruptConfigurable::set_interrupt_handler).
33//!
34//! This driver also implements pin-related traits from [embedded-hal] and
35//! [Wait](embedded_hal_async::digital::Wait) trait from [embedded-hal-async].
36//!
37//! ## GPIO interconnect
38//!
39//! Sometimes you may want to connect peripherals together without using
40//! external hardware. The [`interconnect`] module provides tools to achieve
41//! this using GPIO pins.
42//!
43//! To obtain peripheral signals, use the [`split`] method to split a
44//! pin into an input and output signal. Alternatively, you may use
45//! [`Flex::split`], [`Flex::into_peripheral_output`],
46//! [`Flex::peripheral_input`], and similar methods to split a pin driver into
47//! an input and output signal. You can then pass these signals to the
48//! peripheral drivers similar to how you would pass a pin.
49//!
50//! [embedded-hal]: embedded_hal
51//! [embedded-hal-async]: embedded_hal_async
52//! [`split`]: crate::peripherals::GPIO0::split
53
54crate::unstable_module! {
55 pub mod interconnect;
56
57 #[cfg(soc_etm)]
58 pub mod etm;
59
60 #[cfg(lp_io)]
61 pub mod lp_io;
62
63 #[cfg(all(rtc_io, not(esp32)))]
64 pub mod rtc_io;
65}
66
67mod asynch;
68mod embedded_hal_impls;
69pub(crate) mod interrupt;
70mod placeholder;
71
72use core::fmt::Display;
73
74use interrupt::*;
75pub use placeholder::NoPin;
76use portable_atomic::AtomicU32;
77use strum::EnumCount;
78
79#[cfg(any(lp_io, rtc_cntl))]
80use crate::peripherals::{handle_rtcio, handle_rtcio_with_resistors};
81pub use crate::soc::gpio::*;
82use crate::{
83 interrupt::{InterruptHandler, Priority},
84 peripherals::{GPIO, IO_MUX, Interrupt, handle_gpio_input, handle_gpio_output},
85 private::{self, Sealed},
86};
87
88/// Represents a pin-peripheral connection that, when dropped, disconnects the
89/// peripheral from the pin.
90///
91/// This only needs to be applied to output signals, as it's not possible to
92/// connect multiple inputs to the same peripheral signal.
93#[derive(Debug)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95pub(crate) struct PinGuard {
96 pin: u8,
97 signal: OutputSignal,
98}
99
100impl crate::private::Sealed for PinGuard {}
101
102impl PinGuard {
103 pub(crate) fn new(pin: AnyPin<'_>, signal: OutputSignal) -> Self {
104 Self {
105 pin: pin.number(),
106 signal,
107 }
108 }
109
110 pub(crate) fn new_unconnected(signal: OutputSignal) -> Self {
111 Self {
112 pin: u8::MAX,
113 signal,
114 }
115 }
116
117 #[cfg(any(esp32, esp32s2))]
118 pub(crate) fn pin_number(&self) -> Option<u8> {
119 if self.pin == u8::MAX {
120 None
121 } else {
122 Some(self.pin)
123 }
124 }
125}
126
127impl Drop for PinGuard {
128 fn drop(&mut self) {
129 if self.pin != u8::MAX {
130 let pin = unsafe { AnyPin::steal(self.pin) };
131 self.signal.disconnect_from(&pin);
132 }
133 }
134}
135
136/// Event used to trigger interrupts.
137#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
138#[cfg_attr(feature = "defmt", derive(defmt::Format))]
139pub enum Event {
140 /// Interrupts trigger on rising pin edge.
141 RisingEdge = 1,
142 /// Interrupts trigger on falling pin edge.
143 FallingEdge = 2,
144 /// Interrupts trigger on either rising or falling pin edges.
145 AnyEdge = 3,
146 /// Interrupts trigger on low level
147 LowLevel = 4,
148 /// Interrupts trigger on high level
149 HighLevel = 5,
150}
151
152impl From<WakeEvent> for Event {
153 fn from(value: WakeEvent) -> Self {
154 match value {
155 WakeEvent::LowLevel => Event::LowLevel,
156 WakeEvent::HighLevel => Event::HighLevel,
157 }
158 }
159}
160
161/// Event used to wake up from light sleep.
162#[instability::unstable]
163#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
164#[cfg_attr(feature = "defmt", derive(defmt::Format))]
165pub enum WakeEvent {
166 /// Wake on low level
167 LowLevel = 4,
168 /// Wake on high level
169 HighLevel = 5,
170}
171
172/// Digital input or output level.
173///
174/// `Level` can be used to control a GPIO output, and it can act as a peripheral
175/// signal and be connected to peripheral inputs and outputs.
176///
177/// When connected to a peripheral
178/// input, the peripheral will read the corresponding level from that signal.
179///
180/// When connected to a peripheral output, the level will be ignored.
181#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
182#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183pub enum Level {
184 /// Low
185 Low,
186 /// High
187 High,
188}
189
190impl Sealed for Level {}
191
192impl core::ops::Not for Level {
193 type Output = Self;
194
195 fn not(self) -> Self {
196 match self {
197 Self::Low => Self::High,
198 Self::High => Self::Low,
199 }
200 }
201}
202
203impl From<bool> for Level {
204 fn from(val: bool) -> Self {
205 match val {
206 true => Self::High,
207 false => Self::Low,
208 }
209 }
210}
211
212impl From<Level> for bool {
213 fn from(level: Level) -> bool {
214 match level {
215 Level::Low => false,
216 Level::High => true,
217 }
218 }
219}
220
221/// Errors that can occur when configuring a pin to be a wakeup source.
222#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
223#[cfg_attr(feature = "defmt", derive(defmt::Format))]
224#[instability::unstable]
225#[non_exhaustive]
226pub enum WakeConfigError {
227 /// Returned when trying to configure a pin to wake up from light sleep on
228 /// an edge trigger, which is not supported.
229 EdgeTriggeringNotSupported,
230}
231
232impl Display for WakeConfigError {
233 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
234 match self {
235 WakeConfigError::EdgeTriggeringNotSupported => {
236 write!(
237 f,
238 "Edge triggering is not supported for wake-up from light sleep"
239 )
240 }
241 }
242 }
243}
244
245impl core::error::Error for WakeConfigError {}
246
247/// Pull setting for a GPIO.
248#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
249#[cfg_attr(feature = "defmt", derive(defmt::Format))]
250pub enum Pull {
251 /// No pull
252 None,
253 /// Pull up
254 Up,
255 /// Pull down
256 Down,
257}
258
259/// Drive strength (values are approximates)
260#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, PartialOrd, Ord)]
261#[cfg_attr(feature = "defmt", derive(defmt::Format))]
262pub enum DriveStrength {
263 /// Drive strength of approximately 5mA.
264 _5mA = 0,
265 /// Drive strength of approximately 10mA.
266 _10mA = 1,
267 /// Drive strength of approximately 20mA.
268 _20mA = 2,
269 /// Drive strength of approximately 40mA.
270 _40mA = 3,
271}
272
273/// Alternate functions
274///
275/// GPIO pins can be configured for various functions, such as GPIO
276/// or being directly connected to a peripheral's signal like UART, SPI, etc.
277/// The `AlternateFunction` enum allows selecting one of several functions that
278/// a pin can perform, rather than using it as a general-purpose input or
279/// output.
280///
281/// The different variants correspond to different functionality depending on
282/// the chip and the specific pin. For more information, refer to your chip's
283#[doc(hidden)]
284#[doc = crate::trm_markdown_link!("iomuxgpio")]
285#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
286#[cfg_attr(feature = "defmt", derive(defmt::Format))]
287pub enum AlternateFunction {
288 /// Alternate function 0.
289 _0 = 0,
290 /// Alternate function 1.
291 _1 = 1,
292 /// Alternate function 2.
293 _2 = 2,
294 /// Alternate function 3.
295 _3 = 3,
296 /// Alternate function 4.
297 _4 = 4,
298 /// Alternate function 5.
299 _5 = 5,
300}
301
302impl TryFrom<usize> for AlternateFunction {
303 type Error = ();
304
305 fn try_from(value: usize) -> Result<Self, Self::Error> {
306 match value {
307 0 => Ok(AlternateFunction::_0),
308 1 => Ok(AlternateFunction::_1),
309 2 => Ok(AlternateFunction::_2),
310 3 => Ok(AlternateFunction::_3),
311 4 => Ok(AlternateFunction::_4),
312 5 => Ok(AlternateFunction::_5),
313 _ => Err(()),
314 }
315 }
316}
317
318/// RTC function
319#[instability::unstable]
320#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
321#[cfg_attr(feature = "defmt", derive(defmt::Format))]
322pub enum RtcFunction {
323 /// RTC mode.
324 Rtc = 0,
325 /// Digital mode.
326 Digital = 1,
327}
328
329/// Trait implemented by RTC pins
330#[instability::unstable]
331pub trait RtcPin: Pin {
332 /// RTC number of the pin
333 #[cfg(xtensa)]
334 fn rtc_number(&self) -> u8;
335
336 /// Configure the pin
337 #[cfg(any(xtensa, esp32c6))]
338 #[doc(hidden)]
339 fn rtc_set_config(&self, input_enable: bool, mux: bool, func: RtcFunction);
340
341 /// Enable or disable PAD_HOLD
342 #[doc(hidden)]
343 fn rtcio_pad_hold(&self, enable: bool);
344
345 /// # Safety
346 ///
347 /// The `level` argument needs to be a valid setting for the
348 /// `rtc_cntl.gpio_wakeup.gpio_pinX_int_type`.
349 #[cfg(any(esp32c3, esp32c2, esp32c6))]
350 #[doc(hidden)]
351 unsafe fn apply_wakeup(&self, wakeup: bool, level: u8);
352}
353
354/// Trait implemented by RTC pins which supporting internal pull-up / pull-down
355/// resistors.
356#[instability::unstable]
357#[cfg(any(lp_io, rtc_cntl))]
358pub trait RtcPinWithResistors: RtcPin {
359 /// Enable/disable the internal pull-up resistor
360 #[doc(hidden)]
361 fn rtcio_pullup(&self, enable: bool);
362 /// Enable/disable the internal pull-down resistor
363 #[doc(hidden)]
364 fn rtcio_pulldown(&self, enable: bool);
365}
366
367/// Common trait implemented by pins
368pub trait Pin: Sealed {
369 /// GPIO number
370 fn number(&self) -> u8;
371
372 /// Type-erase this pin into an [`AnyPin`].
373 ///
374 /// This function converts pin singletons (`GPIO0<'_>`, …), which are all
375 /// different types, into the same type. It is useful for creating
376 /// arrays of pins, or avoiding generics.
377 ///
378 /// ## Example
379 ///
380 /// ```rust, no_run
381 #[doc = crate::before_snippet!()]
382 /// use esp_hal::gpio::{AnyPin, Pin, Output, OutputConfig, Level};
383 /// use esp_hal::delay::Delay;
384 ///
385 /// fn toggle_pins(pins: [AnyPin; 2], delay: &mut Delay) {
386 /// let [red, blue] = pins;
387 /// let mut red = Output::new(
388 /// red,
389 /// Level::High,
390 /// OutputConfig::default(),
391 /// );
392 /// let mut blue = Output::new(
393 /// blue,
394 /// Level::Low,
395 /// OutputConfig::default(),
396 /// );
397 ///
398 /// loop {
399 /// red.toggle();
400 /// blue.toggle();
401 /// delay.delay_millis(500);
402 /// }
403 /// }
404 ///
405 /// let pins: [AnyPin; 2] = [
406 /// peripherals.GPIO5.degrade(),
407 /// peripherals.GPIO6.degrade(),
408 /// ];
409 ///
410 /// let mut delay = Delay::new();
411 /// toggle_pins(pins, &mut delay);
412 /// # Ok(())
413 /// # }
414 /// ```
415 fn degrade<'d>(self) -> AnyPin<'d>
416 where
417 Self: Sized + 'd,
418 {
419 unsafe { AnyPin::steal(self.number()) }
420 }
421
422 #[doc(hidden)]
423 fn output_signals(&self, _: private::Internal) -> &'static [(AlternateFunction, OutputSignal)];
424
425 #[doc(hidden)]
426 fn input_signals(&self, _: private::Internal) -> &'static [(AlternateFunction, InputSignal)];
427}
428
429/// Trait implemented by pins which can be used as inputs.
430pub trait InputPin: Pin {}
431
432/// Trait implemented by pins which can be used as outputs.
433pub trait OutputPin: Pin {}
434
435/// Trait implemented by pins which can be used as analog pins
436#[instability::unstable]
437pub trait AnalogPin: Pin {
438 /// Configure the pin for analog operation
439 #[doc(hidden)]
440 fn set_analog(&self, _: private::Internal);
441}
442
443/// Trait implemented by pins which can be used as Touchpad pins
444#[cfg(touch)]
445#[instability::unstable]
446pub trait TouchPin: Pin {
447 /// Configure the pin for analog operation
448 #[doc(hidden)]
449 fn set_touch(&self, _: private::Internal);
450
451 /// Reads the pin's touch measurement register
452 #[doc(hidden)]
453 fn touch_measurement(&self, _: private::Internal) -> u16;
454
455 /// Maps the pin nr to the touch pad nr
456 #[doc(hidden)]
457 fn touch_nr(&self, _: private::Internal) -> u8;
458
459 /// Set a pins touch threshold for interrupts.
460 #[doc(hidden)]
461 fn set_threshold(&self, threshold: u16, _: private::Internal);
462}
463
464#[doc(hidden)]
465#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, EnumCount)]
466#[cfg_attr(feature = "defmt", derive(defmt::Format))]
467pub enum GpioBank {
468 _0,
469 #[cfg(gpio_bank_1)]
470 _1,
471}
472
473impl GpioBank {
474 fn async_operations(self) -> &'static AtomicU32 {
475 static FLAGS: [AtomicU32; GpioBank::COUNT] = [const { AtomicU32::new(0) }; GpioBank::COUNT];
476
477 &FLAGS[self as usize]
478 }
479
480 fn offset(self) -> u8 {
481 match self {
482 Self::_0 => 0,
483 #[cfg(gpio_bank_1)]
484 Self::_1 => 32,
485 }
486 }
487
488 fn write_out_en(self, word: u32, enable: bool) {
489 if enable {
490 self.write_out_en_set(word);
491 } else {
492 self.write_out_en_clear(word);
493 }
494 }
495
496 fn write_out_en_clear(self, word: u32) {
497 match self {
498 Self::_0 => GPIO::regs()
499 .enable_w1tc()
500 .write(|w| unsafe { w.bits(word) }),
501 #[cfg(gpio_bank_1)]
502 Self::_1 => GPIO::regs()
503 .enable1_w1tc()
504 .write(|w| unsafe { w.bits(word) }),
505 };
506 }
507
508 fn write_out_en_set(self, word: u32) {
509 match self {
510 Self::_0 => GPIO::regs()
511 .enable_w1ts()
512 .write(|w| unsafe { w.bits(word) }),
513 #[cfg(gpio_bank_1)]
514 Self::_1 => GPIO::regs()
515 .enable1_w1ts()
516 .write(|w| unsafe { w.bits(word) }),
517 };
518 }
519
520 fn read_input(self) -> u32 {
521 match self {
522 Self::_0 => GPIO::regs().in_().read().bits(),
523 #[cfg(gpio_bank_1)]
524 Self::_1 => GPIO::regs().in1().read().bits(),
525 }
526 }
527
528 fn read_output(self) -> u32 {
529 match self {
530 Self::_0 => GPIO::regs().out().read().bits(),
531 #[cfg(gpio_bank_1)]
532 Self::_1 => GPIO::regs().out1().read().bits(),
533 }
534 }
535
536 fn read_interrupt_status(self) -> u32 {
537 match self {
538 Self::_0 => GPIO::regs().status().read().bits(),
539 #[cfg(gpio_bank_1)]
540 Self::_1 => GPIO::regs().status1().read().bits(),
541 }
542 }
543
544 fn write_interrupt_status_clear(self, word: u32) {
545 match self {
546 Self::_0 => GPIO::regs()
547 .status_w1tc()
548 .write(|w| unsafe { w.bits(word) }),
549 #[cfg(gpio_bank_1)]
550 Self::_1 => GPIO::regs()
551 .status1_w1tc()
552 .write(|w| unsafe { w.bits(word) }),
553 };
554 }
555
556 fn write_output(self, word: u32, set: bool) {
557 if set {
558 self.write_output_set(word);
559 } else {
560 self.write_output_clear(word);
561 }
562 }
563
564 fn write_output_set(self, word: u32) {
565 match self {
566 Self::_0 => GPIO::regs().out_w1ts().write(|w| unsafe { w.bits(word) }),
567 #[cfg(gpio_bank_1)]
568 Self::_1 => GPIO::regs().out1_w1ts().write(|w| unsafe { w.bits(word) }),
569 };
570 }
571
572 fn write_output_clear(self, word: u32) {
573 match self {
574 Self::_0 => GPIO::regs().out_w1tc().write(|w| unsafe { w.bits(word) }),
575 #[cfg(gpio_bank_1)]
576 Self::_1 => GPIO::regs().out1_w1tc().write(|w| unsafe { w.bits(word) }),
577 };
578 }
579}
580
581/// Any GPIO pin.
582#[derive(Debug)]
583#[cfg_attr(feature = "defmt", derive(defmt::Format))]
584pub struct AnyPin<'lt> {
585 pub(crate) pin: u8,
586 pub(crate) _lifetime: core::marker::PhantomData<&'lt mut ()>,
587}
588
589/// Workaround to make D+ and D- work on the ESP32-C3 and ESP32-S3, which by
590/// default are assigned to the `USB_SERIAL_JTAG` peripheral.
591#[cfg(usb_device)]
592fn disable_usb_pads(gpionum: u8) {
593 cfg_if::cfg_if! {
594 if #[cfg(esp32c3)] {
595 let pins = [18, 19];
596 } else if #[cfg(esp32c6)] {
597 let pins = [12, 13];
598 } else if #[cfg(esp32h2)] {
599 let pins = [26, 27];
600 } else if #[cfg(esp32s3)] {
601 let pins = [19, 20];
602 } else {
603 compile_error!("Please define USB pins for this chip");
604 }
605 }
606
607 if pins.contains(&gpionum) {
608 crate::peripherals::USB_DEVICE::regs()
609 .conf0()
610 .modify(|_, w| {
611 w.usb_pad_enable().clear_bit();
612 w.dm_pullup().clear_bit();
613 w.dm_pulldown().clear_bit();
614 w.dp_pullup().clear_bit();
615 w.dp_pulldown().clear_bit()
616 });
617 }
618}
619
620/// General Purpose Input/Output driver
621#[derive(Debug)]
622#[cfg_attr(feature = "defmt", derive(defmt::Format))]
623#[instability::unstable]
624pub struct Io<'d> {
625 _io_mux: IO_MUX<'d>,
626}
627
628impl<'d> Io<'d> {
629 /// Initialize the I/O driver.
630 #[instability::unstable]
631 pub fn new(_io_mux: IO_MUX<'d>) -> Self {
632 Io { _io_mux }
633 }
634
635 /// Set the interrupt priority for GPIO interrupts.
636 ///
637 /// # Panics
638 ///
639 /// Panics if passed interrupt handler is invalid (e.g. has priority
640 /// `None`)
641 #[instability::unstable]
642 pub fn set_interrupt_priority(&self, prio: Priority) {
643 interrupt::set_interrupt_priority(Interrupt::GPIO, prio);
644 }
645
646 #[cfg_attr(
647 not(multi_core),
648 doc = "Registers an interrupt handler for all GPIO pins."
649 )]
650 #[cfg_attr(
651 multi_core,
652 doc = "Registers an interrupt handler for all GPIO pins on the current core."
653 )]
654 #[doc = ""]
655 /// Note that when using interrupt handlers registered by this function, or
656 /// by defining a `#[no_mangle] unsafe extern "C" fn GPIO()` function, we do
657 /// **not** clear the interrupt status register or the interrupt enable
658 /// setting for you. Based on your use case, you need to do one of this
659 /// yourself:
660 ///
661 /// - Disabling the interrupt enable setting for the GPIO pin allows you to
662 /// handle an event once per call to [`listen()`]. Using this method, the
663 /// [`is_interrupt_set()`] method will return `true` if the interrupt is
664 /// set even after your handler has finished running.
665 /// - Clearing the interrupt status register allows you to handle an event
666 /// repeatedly after [`listen()`] is called. Using this method,
667 /// [`is_interrupt_set()`] will return `false` after your handler has
668 /// finished running.
669 ///
670 /// [`listen()`]: Input::listen
671 /// [`is_interrupt_set()`]: Input::is_interrupt_set
672 ///
673 /// # Panics
674 ///
675 /// Panics if passed interrupt handler is invalid (e.g. has priority
676 /// `None`)
677 #[instability::unstable]
678 pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
679 for core in crate::system::Cpu::other() {
680 crate::interrupt::disable(core, Interrupt::GPIO);
681 }
682 self.set_interrupt_priority(handler.priority());
683 unsafe { crate::interrupt::bind_interrupt(Interrupt::GPIO, user_gpio_interrupt_handler) };
684 USER_INTERRUPT_HANDLER.store(handler.handler());
685 }
686}
687
688impl crate::private::Sealed for Io<'_> {}
689
690#[instability::unstable]
691impl crate::interrupt::InterruptConfigurable for Io<'_> {
692 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
693 self.set_interrupt_handler(handler);
694 }
695}
696
697#[doc(hidden)]
698#[macro_export]
699macro_rules! if_output_pin {
700 // Base case: not an Output pin, substitute the else branch
701 ({ $($then:tt)* } else { $($else:tt)* }) => { $($else)* };
702
703 // First is an Output pin, skip checking and substitute the then branch
704 (Output $(, $other:ident)* { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
705
706 // First is not an Output pin, check the rest
707 ($not:ident $(, $other:ident)* { $($then:tt)* } else { $($else:tt)* }) => {
708 $crate::if_output_pin!($($other),* { $($then)* } else { $($else)* })
709 };
710}
711
712#[doc(hidden)]
713#[macro_export]
714macro_rules! if_rtcio_pin {
715 // Base case: not an RtcIo pin, substitute the else branch
716 ({ $($then:tt)* } else { $($else:tt)* }) => { $($else)* };
717
718 // First is an RtcIo pin, skip checking and substitute the then branch
719 (RtcIo $(, $other:ident)* { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
720 (RtcIoInput $(, $other:ident)* { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
721
722 // First is not an RtcIo pin, check the rest
723 ($not:ident $(, $other:ident)* { $($then:tt)* } else { $($else:tt)* }) => {
724 $crate::if_rtcio_pin!($($other),* { $($then)* } else { $($else)* })
725 };
726}
727
728#[doc(hidden)]
729#[macro_export]
730macro_rules! io_type {
731 (Input, $gpionum:literal) => {
732 impl $crate::gpio::InputPin for paste::paste!( [<GPIO $gpionum>]<'_> ) {}
733 };
734 (Output, $gpionum:literal) => {
735 impl $crate::gpio::OutputPin for paste::paste!( [<GPIO $gpionum>]<'_> ) {}
736 };
737 (Analog, $gpionum:literal) => {
738 // FIXME: the implementation shouldn't be in the GPIO module
739 #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))]
740 #[cfg(feature = "unstable")]
741 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
742 impl $crate::gpio::AnalogPin for paste::paste!( [<GPIO $gpionum>]<'_> ) {
743 /// Configures the pin for analog mode.
744 fn set_analog(&self, _: $crate::private::Internal) {
745 use $crate::peripherals::GPIO;
746
747 $crate::gpio::io_mux_reg($gpionum).modify(|_, w| unsafe {
748 w.mcu_sel().bits(1);
749 w.fun_ie().clear_bit();
750 w.fun_wpu().clear_bit();
751 w.fun_wpd().clear_bit()
752 });
753
754 GPIO::regs()
755 .enable_w1tc()
756 .write(|w| unsafe { w.bits(1 << $gpionum) });
757 }
758 }
759 };
760 ($other:ident, $gpionum:literal) => {
761 // TODO
762 };
763}
764
765#[doc(hidden)]
766#[macro_export]
767macro_rules! gpio {
768 (
769 $(
770 ($gpionum:literal, [$($type:tt),*]
771 $(
772 ( $( $af_input_num:literal => $af_input_signal:ident )* )
773 ( $( $af_output_num:literal => $af_output_signal:ident )* )
774 )?
775 )
776 )+
777 ) => {
778 paste::paste! {
779 $(
780 impl<'d> [< GPIO $gpionum >]<'d> {
781 /// Split the pin into an input and output signal.
782 ///
783 /// Peripheral signals allow connecting peripherals together without using
784 /// external hardware.
785 ///
786 /// # Safety
787 ///
788 /// The caller must ensure that peripheral drivers don't configure the same
789 /// GPIO at the same time in multiple places. This includes clones of the
790 /// `InputSignal` struct, as well as the `OutputSignal` struct.
791 ///
792 /// ```rust, no_run
793 #[doc = $crate::before_snippet!()]
794 /// let (rx, tx) = unsafe { peripherals.GPIO2.split() };
795 /// // rx and tx can then be passed to different peripherals to connect them.
796 /// # Ok(())
797 /// # }
798 /// ```
799 #[instability::unstable]
800 pub unsafe fn split(self) -> ($crate::gpio::interconnect::InputSignal<'d>, $crate::gpio::interconnect::OutputSignal<'d>) {
801 use $crate::gpio::Pin;
802
803 // FIXME: we should implement this in the gpio macro for output pins, but we
804 // should also have an input-only alternative for pins that can't be used as
805 // outputs.
806
807 // This goes through AnyPin which calls `init_gpio` as needed.
808 unsafe { self.degrade().split() }
809 }
810 }
811
812 $(
813 $crate::io_type!($type, $gpionum);
814 )*
815
816 impl $crate::gpio::Pin for [<GPIO $gpionum>]<'_> {
817 #[inline(always)]
818 fn number(&self) -> u8 {
819 $gpionum
820 }
821
822 fn output_signals(&self, _: $crate::private::Internal) -> &'static [($crate::gpio::AlternateFunction, $crate::gpio::OutputSignal)] {
823 &[
824 $(
825 $(
826 (
827 $crate::gpio::AlternateFunction::[< _ $af_output_num >],
828 $crate::gpio::OutputSignal::$af_output_signal
829 ),
830 )*
831 )?
832 ]
833 }
834
835 fn input_signals(&self, _: $crate::private::Internal) -> &'static [($crate::gpio::AlternateFunction, $crate::gpio::InputSignal)] {
836 &[
837 $(
838 $(
839 (
840 $crate::gpio::AlternateFunction::[< _ $af_input_num >],
841 $crate::gpio::InputSignal::$af_input_signal
842 ),
843 )*
844 )?
845 ]
846 }
847 }
848
849 impl<'lt> From<[<GPIO $gpionum>]<'lt>> for $crate::gpio::AnyPin<'lt> {
850 fn from(pin: [<GPIO $gpionum>]<'lt>) -> Self {
851 $crate::gpio::Pin::degrade(pin)
852 }
853 }
854 )+
855
856 impl $crate::gpio::AnyPin<'_> {
857 /// Conjure a new GPIO pin out of thin air.
858 ///
859 /// # Safety
860 ///
861 /// The caller must ensure that only one instance of a pin is in use at one time.
862 ///
863 /// # Panics
864 ///
865 /// Panics if the pin with the given number does not exist.
866 pub unsafe fn steal(pin: u8) -> Self {
867 const PINS: &[u8] = &[$($gpionum),*];
868 assert!(PINS.contains(&pin), "Pin {} does not exist", pin);
869 Self { pin, _lifetime: core::marker::PhantomData }
870 }
871
872 /// Unsafely clone the pin.
873 ///
874 /// # Safety
875 ///
876 /// Ensure that only one instance of a pin is in use at one time.
877 pub unsafe fn clone_unchecked(&self) -> Self {
878 Self {
879 pin: self.pin,
880 _lifetime: core::marker::PhantomData,
881 }
882 }
883
884 /// Create a new AnyPin object that is limited to the lifetime of the
885 /// passed reference.
886 pub fn reborrow(&mut self) -> $crate::gpio::AnyPin<'_> {
887 unsafe { self.clone_unchecked() }
888 }
889
890 pub(crate) fn is_output(&self) -> bool {
891 match self.pin {
892 $(
893 $gpionum => $crate::if_output_pin!($($type),* { true } else { false }),
894 )+
895 _ => false,
896 }
897 }
898 }
899
900 // These macros call the code block on the actually contained GPIO pin.
901
902 #[doc(hidden)]
903 macro_rules! handle_gpio_output {
904 ($this:expr, $inner:ident, $code:tt) => {
905 match $this.number() {
906 $(
907 $gpionum => $crate::if_output_pin!($($type),* {{
908 #[allow(unused_mut)]
909 let mut $inner = unsafe { $crate::peripherals::[<GPIO $gpionum>]::steal() };
910 $code
911 }} else {{
912 panic!("Unsupported")
913 }}),
914 )+
915 _ => unreachable!(),
916 }
917 }
918 }
919
920 #[doc(hidden)]
921 macro_rules! handle_gpio_input {
922 ($this:expr, $inner:ident, $code:tt) => {
923 match $this.number() {
924 $(
925 $gpionum => {{
926 #[allow(unused_mut)]
927 let mut $inner = unsafe { $crate::peripherals::[<GPIO $gpionum>]::steal() };
928 $code
929 }},
930 )+
931 _ => unreachable!(),
932 }
933 }
934 }
935
936 pub(crate) use handle_gpio_output;
937 pub(crate) use handle_gpio_input;
938
939 cfg_if::cfg_if! {
940 if #[cfg(any(lp_io, rtc_cntl))] {
941 #[doc(hidden)]
942 macro_rules! handle_rtcio {
943 ($this:expr, $inner:ident, $code:tt) => {
944 match $this.number() {
945 $(
946 $gpionum => $crate::if_rtcio_pin!($($type),* {{
947 #[allow(unused_mut)]
948 #[allow(unused_unsafe)]
949 let mut $inner = unsafe { $crate::peripherals::[<GPIO $gpionum>]::steal() };
950 $code
951 }} else {{
952 panic!("Unsupported")
953 }}),
954 )+
955 _ => unreachable!(),
956 }
957 }
958 }
959
960 #[doc(hidden)]
961 macro_rules! handle_rtcio_with_resistors {
962 ($this:expr, $inner:ident, $code:tt) => {
963 match $this.number() {
964 $(
965 $gpionum => $crate::if_rtcio_pin!($($type),* {
966 $crate::if_output_pin!($($type),* {{
967 #[allow(unused_mut)]
968 let mut $inner = unsafe { $crate::peripherals::[<GPIO $gpionum>]::steal() };
969 $code
970 }} else {{
971 panic!("Unsupported")
972 }})
973 } else {{
974 panic!("Unsupported")
975 }}),
976 )+
977 _ => unreachable!(),
978 }
979 }
980 }
981
982 pub(crate) use handle_rtcio;
983 pub(crate) use handle_rtcio_with_resistors;
984 }
985 }
986 }
987 };
988}
989
990/// The drive mode of the output pin.
991#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
992#[cfg_attr(feature = "defmt", derive(defmt::Format))]
993pub enum DriveMode {
994 /// Push-pull output.
995 ///
996 /// The driver actively sets the output voltage level for both high and low
997 /// logical [`Level`]s.
998 PushPull,
999
1000 /// Open drain output.
1001 ///
1002 /// The driver actively pulls the output voltage level low for the low
1003 /// logical [`Level`], but leaves the high level floating, which is then
1004 /// determined by external hardware, or internal pull-up/pull-down
1005 /// resistors.
1006 #[cfg_attr(
1007 feature = "unstable",
1008 doc = "\n\nEnable the input related functionality by using [Output::into_flex] and enabling input via [Flex::set_input_enable]"
1009 )]
1010 OpenDrain,
1011}
1012
1013/// Output pin configuration.
1014///
1015/// This struct is used to configure the drive mode, drive strength, and pull
1016/// direction of an output pin. By default, the configuration is set to:
1017/// - Drive mode: [`DriveMode::PushPull`]
1018/// - Drive strength: [`DriveStrength::_20mA`]
1019/// - Pull direction: [`Pull::None`] (no pull resistors connected)
1020#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1021#[derive(Debug, Clone, Copy, PartialEq, Eq, procmacros::BuilderLite)]
1022#[non_exhaustive]
1023pub struct OutputConfig {
1024 /// Output drive mode.
1025 drive_mode: DriveMode,
1026
1027 /// Pin drive strength.
1028 drive_strength: DriveStrength,
1029
1030 /// Pin pull direction.
1031 pull: Pull,
1032}
1033
1034impl Default for OutputConfig {
1035 fn default() -> Self {
1036 Self {
1037 drive_mode: DriveMode::PushPull,
1038 drive_strength: DriveStrength::_20mA,
1039 pull: Pull::None,
1040 }
1041 }
1042}
1043
1044/// Push-pull digital output.
1045///
1046/// This driver configures the GPIO pin to be an output driver.
1047#[derive(Debug)]
1048#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1049pub struct Output<'d> {
1050 pin: Flex<'d>,
1051}
1052
1053impl private::Sealed for Output<'_> {}
1054
1055impl<'d> Output<'d> {
1056 /// Creates a new GPIO output driver.
1057 ///
1058 /// The `initial_level` parameter sets the initial output level of the pin.
1059 /// The `config` parameter sets the drive mode, drive strength, and pull
1060 /// direction of the pin.
1061 ///
1062 /// ## Example
1063 ///
1064 /// The following example configures `GPIO5` to pulse a LED once. The
1065 /// example assumes that the LED is connected such that it is on when
1066 /// the pin is low.
1067 ///
1068 /// ```rust, no_run
1069 #[doc = crate::before_snippet!()]
1070 /// use esp_hal::gpio::{Level, Output, OutputConfig};
1071 /// use esp_hal::delay::Delay;
1072 ///
1073 /// fn blink_once(led: &mut Output<'_>, delay: &mut Delay) {
1074 /// led.set_low();
1075 /// delay.delay_millis(500);
1076 /// led.set_high();
1077 /// }
1078 ///
1079 /// let config = OutputConfig::default();
1080 /// let mut led = Output::new(peripherals.GPIO5, Level::High, config);
1081 /// let mut delay = Delay::new();
1082 ///
1083 /// blink_once(&mut led, &mut delay);
1084 /// # Ok(())
1085 /// # }
1086 /// ```
1087 // FIXME: when https://github.com/esp-rs/esp-hal/issues/2839 is resolved, add an appropriate `# Error` entry.
1088 #[inline]
1089 pub fn new(pin: impl OutputPin + 'd, initial_level: Level, config: OutputConfig) -> Self {
1090 // Set up the pin
1091 let mut this = Self {
1092 pin: Flex::new(pin),
1093 };
1094 this.set_level(initial_level);
1095 this.apply_config(&config);
1096 this.pin.pin.set_output_enable(true);
1097
1098 this
1099 }
1100
1101 /// Turns the pin object into a peripheral
1102 /// [output][interconnect::OutputSignal].
1103 ///
1104 /// The output signal can be passed to peripherals in place of an output
1105 /// pin.
1106 ///
1107 /// Note that the signal returned by this function is
1108 /// [frozen](interconnect::OutputSignal::freeze).
1109 ///
1110 /// ```rust, no_run
1111 #[doc = crate::before_snippet!()]
1112 /// # use esp_hal::gpio::{Output, OutputConfig, Level};
1113 /// # let config = OutputConfig::default();
1114 /// let pin1_gpio = Output::new(peripherals.GPIO1, Level::High, config);
1115 /// let output = pin1_gpio.into_peripheral_output();
1116 /// # Ok(())
1117 /// # }
1118 /// ```
1119 #[inline]
1120 #[instability::unstable]
1121 pub fn into_peripheral_output(self) -> interconnect::OutputSignal<'d> {
1122 self.pin.into_peripheral_output()
1123 }
1124
1125 /// Change the configuration.
1126 #[inline]
1127 pub fn apply_config(&mut self, config: &OutputConfig) {
1128 self.pin.apply_output_config(config)
1129 }
1130
1131 /// Set the output as high.
1132 #[inline]
1133 pub fn set_high(&mut self) {
1134 self.set_level(Level::High)
1135 }
1136
1137 /// Set the output as low.
1138 #[inline]
1139 pub fn set_low(&mut self) {
1140 self.set_level(Level::Low)
1141 }
1142
1143 /// Set the output level.
1144 #[inline]
1145 pub fn set_level(&mut self, level: Level) {
1146 self.pin.set_level(level)
1147 }
1148
1149 /// Returns whether the pin is set to high level.
1150 ///
1151 /// This function reads back the value set using `set_level`, `set_high` or
1152 /// `set_low`. It does not need the input stage to be enabled.
1153 #[inline]
1154 pub fn is_set_high(&self) -> bool {
1155 self.output_level() == Level::High
1156 }
1157
1158 /// Returns whether the pin is set to low level.
1159 ///
1160 /// This function reads back the value set using `set_level`, `set_high` or
1161 /// `set_low`. It does not need the input stage to be enabled.
1162 #[inline]
1163 pub fn is_set_low(&self) -> bool {
1164 self.output_level() == Level::Low
1165 }
1166
1167 /// Returns which level the pin is set to.
1168 ///
1169 /// This function reads back the value set using `set_level`, `set_high` or
1170 /// `set_low`. It does not need the input stage to be enabled.
1171 #[inline]
1172 pub fn output_level(&self) -> Level {
1173 self.pin.output_level()
1174 }
1175
1176 /// Toggles the pin output.
1177 ///
1178 /// If the pin was previously set to high, it will be set to low, and vice
1179 /// versa.
1180 #[inline]
1181 pub fn toggle(&mut self) {
1182 self.pin.toggle();
1183 }
1184
1185 /// Converts the pin driver into a [`Flex`] driver.
1186 #[inline]
1187 #[instability::unstable]
1188 pub fn into_flex(self) -> Flex<'d> {
1189 self.pin
1190 }
1191}
1192
1193/// Input pin configuration.
1194#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1195#[derive(Debug, Clone, Copy, PartialEq, Eq, procmacros::BuilderLite)]
1196#[non_exhaustive]
1197pub struct InputConfig {
1198 /// Initial pull of the pin.
1199 pull: Pull,
1200}
1201
1202impl Default for InputConfig {
1203 fn default() -> Self {
1204 Self { pull: Pull::None }
1205 }
1206}
1207
1208/// Digital input.
1209///
1210/// This driver configures the GPIO pin to be an input. Input drivers read the
1211/// voltage of their pins and convert it to a logical [`Level`].
1212#[derive(Debug)]
1213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1214pub struct Input<'d> {
1215 pin: Flex<'d>,
1216}
1217
1218impl private::Sealed for Input<'_> {}
1219
1220impl<'d> Input<'d> {
1221 /// Creates a new GPIO input.
1222 ///
1223 /// The `pull` parameter configures internal pull-up or pull-down
1224 /// resistors.
1225 ///
1226 /// ## Example
1227 ///
1228 /// The following example configures `GPIO5` to read a button press. The
1229 /// example assumes that the button is connected such that the pin is low
1230 /// when the button is pressed.
1231 ///
1232 /// ```rust, no_run
1233 #[doc = crate::before_snippet!()]
1234 /// use esp_hal::gpio::{Level, Input, InputConfig, Pull};
1235 /// use esp_hal::delay::Delay;
1236 ///
1237 /// fn print_when_pressed(button: &mut Input<'_>, delay: &mut Delay) {
1238 /// let mut was_pressed = false;
1239 /// loop {
1240 /// let is_pressed = button.is_low();
1241 /// if is_pressed && !was_pressed {
1242 /// println!("Button pressed!");
1243 /// }
1244 /// was_pressed = is_pressed;
1245 /// delay.delay_millis(100);
1246 /// }
1247 /// }
1248 ///
1249 /// let config = InputConfig::default().with_pull(Pull::Up);
1250 /// let mut button = Input::new(peripherals.GPIO5, config);
1251 /// let mut delay = Delay::new();
1252 ///
1253 /// print_when_pressed(&mut button, &mut delay);
1254 /// # Ok(())
1255 /// # }
1256 /// ```
1257 // FIXME: when https://github.com/esp-rs/esp-hal/issues/2839 is resolved, add an appropriate `# Error` entry.
1258 #[inline]
1259 pub fn new(pin: impl InputPin + 'd, config: InputConfig) -> Self {
1260 let mut pin = Flex::new(pin);
1261
1262 pin.set_output_enable(false);
1263 pin.set_input_enable(true);
1264 pin.apply_input_config(&config);
1265
1266 Self { pin }
1267 }
1268
1269 /// Returns a peripheral [input][interconnect::InputSignal] connected to
1270 /// this pin.
1271 ///
1272 /// The input signal can be passed to peripherals in place of an input pin.
1273 ///
1274 /// Note that the signal returned by this function is
1275 /// [frozen](interconnect::InputSignal::freeze).
1276 ///
1277 /// ```rust, no_run
1278 #[doc = crate::before_snippet!()]
1279 /// # use esp_hal::gpio::{Input, InputConfig, Pull};
1280 /// let config = InputConfig::default().with_pull(Pull::Up);
1281 /// let pin1_gpio = Input::new(peripherals.GPIO1, config);
1282 /// let pin1 = pin1_gpio.peripheral_input();
1283 /// # Ok(())
1284 /// # }
1285 /// ```
1286 #[inline]
1287 #[instability::unstable]
1288 pub fn peripheral_input(&self) -> interconnect::InputSignal<'d> {
1289 self.pin.peripheral_input()
1290 }
1291
1292 /// Get whether the pin input level is high.
1293 #[inline]
1294 pub fn is_high(&self) -> bool {
1295 self.level() == Level::High
1296 }
1297
1298 /// Get whether the pin input level is low.
1299 #[inline]
1300 pub fn is_low(&self) -> bool {
1301 self.level() == Level::Low
1302 }
1303
1304 /// Get the current pin input level.
1305 #[inline]
1306 pub fn level(&self) -> Level {
1307 self.pin.level()
1308 }
1309
1310 /// Change the configuration.
1311 pub fn apply_config(&mut self, config: &InputConfig) {
1312 self.pin.apply_input_config(config)
1313 }
1314
1315 /// Listen for interrupts.
1316 ///
1317 /// The interrupts will be handled by the handler set using
1318 /// [`Io::set_interrupt_handler`]. All GPIO pins share the same
1319 /// interrupt handler.
1320 ///
1321 /// Note that [`Event::LowLevel`] and [`Event::HighLevel`] are fired
1322 /// continuously when the pin is low or high, respectively. You must use
1323 /// a custom interrupt handler to stop listening for these events,
1324 /// otherwise your program will be stuck in a loop as long as the pin is
1325 /// reading the corresponding level.
1326 ///
1327 /// ## Examples
1328 ///
1329 /// ### Print something when a button is pressed.
1330 /// ```rust, no_run
1331 #[doc = crate::before_snippet!()]
1332 /// use esp_hal::gpio::{Event, Input, InputConfig, Pull, Io};
1333 ///
1334 /// let mut io = Io::new(peripherals.IO_MUX);
1335 /// io.set_interrupt_handler(handler);
1336 ///
1337 /// // Set up the input and store it in the static variable.
1338 /// // This example uses a push button that is high when not
1339 /// // pressed and low when pressed.
1340 /// let config = InputConfig::default().with_pull(Pull::Up);
1341 /// let mut button = Input::new(peripherals.GPIO5, config);
1342 ///
1343 /// critical_section::with(|cs| {
1344 /// // Here we are listening for a low level to demonstrate
1345 /// // that you need to stop listening for level interrupts,
1346 /// // but usually you'd probably use `FallingEdge`.
1347 /// button.listen(Event::LowLevel);
1348 /// BUTTON.borrow_ref_mut(cs).replace(button);
1349 /// });
1350 /// # Ok(())
1351 /// # }
1352 ///
1353 /// // Outside of your `main` function:
1354 ///
1355 /// # use esp_hal::gpio::Input;
1356 /// use core::cell::RefCell;
1357 /// use critical_section::Mutex;
1358 ///
1359 /// // You will need to store the `Input` object in a static variable so
1360 /// // that the interrupt handler can access it.
1361 /// static BUTTON: Mutex<RefCell<Option<Input>>> =
1362 /// Mutex::new(RefCell::new(None));
1363 ///
1364 /// #[handler]
1365 /// fn handler() {
1366 /// critical_section::with(|cs| {
1367 /// let mut button = BUTTON.borrow_ref_mut(cs);
1368 /// let Some(button) = button.as_mut() else {
1369 /// // Some other interrupt has occurred
1370 /// // before the button was set up.
1371 /// return;
1372 /// };
1373 ///
1374 /// if button.is_interrupt_set() {
1375 /// print!("Button pressed");
1376 ///
1377 /// // If you want to stop listening for interrupts, you need to
1378 /// // call `unlisten` here. If you comment this line, the
1379 /// // interrupt will fire continuously while the button
1380 /// // is pressed.
1381 /// button.unlisten();
1382 /// }
1383 /// });
1384 /// }
1385 /// ```
1386 #[inline]
1387 #[instability::unstable]
1388 pub fn listen(&mut self, event: Event) {
1389 self.pin.listen(event);
1390 }
1391
1392 /// Stop listening for interrupts
1393 #[inline]
1394 #[instability::unstable]
1395 pub fn unlisten(&mut self) {
1396 self.pin.unlisten();
1397 }
1398
1399 /// Clear the interrupt status bit for this Pin
1400 #[inline]
1401 #[instability::unstable]
1402 pub fn clear_interrupt(&mut self) {
1403 self.pin.clear_interrupt();
1404 }
1405
1406 /// Checks if the interrupt status bit for this Pin is set
1407 #[inline]
1408 #[instability::unstable]
1409 pub fn is_interrupt_set(&self) -> bool {
1410 self.pin.is_interrupt_set()
1411 }
1412
1413 /// Enable as a wake-up source.
1414 ///
1415 /// This will unlisten for interrupts
1416 ///
1417 /// # Error
1418 /// Configuring pin to wake up from light sleep on an edge
1419 /// trigger is currently not supported, corresponding variant of
1420 /// [`WakeConfigError`] will be returned.
1421 #[instability::unstable]
1422 #[inline]
1423 pub fn wakeup_enable(&mut self, enable: bool, event: WakeEvent) -> Result<(), WakeConfigError> {
1424 self.pin.wakeup_enable(enable, event)
1425 }
1426
1427 /// Converts the pin driver into a [`Flex`] driver.
1428 #[inline]
1429 #[instability::unstable]
1430 pub fn into_flex(self) -> Flex<'d> {
1431 self.pin
1432 }
1433}
1434
1435/// Flexible pin driver.
1436///
1437/// This pin driver can act as either input, or output, or both at the same
1438/// time. The input and output are (not counting the shared pull direction)
1439/// separately configurable, and they have independent enable states.
1440///
1441/// Enabling the input stage does not change the output stage, and vice versa.
1442/// Disabling the input or output stages don't forget their configuration.
1443/// Disabling the output stage will not change the output level, but it will
1444/// disable the driver.
1445#[derive(Debug)]
1446#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1447pub struct Flex<'d> {
1448 pin: AnyPin<'d>,
1449}
1450
1451impl private::Sealed for Flex<'_> {}
1452
1453impl<'d> Flex<'d> {
1454 /// Create flexible pin driver for a [Pin].
1455 /// No mode change happens.
1456 #[inline]
1457 #[instability::unstable]
1458 pub fn new(pin: impl Pin + 'd) -> Self {
1459 let pin = pin.degrade();
1460
1461 // Before each use, reset the GPIO to a known state.
1462 pin.init_gpio();
1463
1464 Self { pin }
1465 }
1466
1467 fn number(&self) -> u8 {
1468 self.pin.number()
1469 }
1470
1471 // Input functions
1472
1473 /// Applies the given input configuration to the pin.
1474 ///
1475 /// This function does not set the pin as input (i.e. it does not enable the
1476 /// input buffer). Note that the pull direction is common between the
1477 /// input and output configuration.
1478 #[inline]
1479 #[instability::unstable]
1480 pub fn apply_input_config(&mut self, config: &InputConfig) {
1481 self.pin.apply_input_config(config);
1482 }
1483
1484 /// Enable or disable the GPIO pin input buffer.
1485 #[inline]
1486 #[instability::unstable]
1487 pub fn set_input_enable(&mut self, enable_input: bool) {
1488 self.pin.set_input_enable(enable_input);
1489 }
1490
1491 /// Get whether the pin input level is high.
1492 #[inline]
1493 #[instability::unstable]
1494 pub fn is_high(&self) -> bool {
1495 self.level() == Level::High
1496 }
1497
1498 /// Get whether the pin input level is low.
1499 #[inline]
1500 #[instability::unstable]
1501 pub fn is_low(&self) -> bool {
1502 self.level() == Level::Low
1503 }
1504
1505 /// Get the current pin input level.
1506 #[inline]
1507 #[instability::unstable]
1508 pub fn level(&self) -> Level {
1509 self.pin.is_input_high().into()
1510 }
1511
1512 /// Listen for interrupts.
1513 ///
1514 /// See [`Input::listen`] for more information and an example.
1515 #[inline]
1516 #[instability::unstable]
1517 pub fn listen(&mut self, event: Event) {
1518 // Unwrap can't fail currently as listen_with_options is only supposed to return
1519 // an error if wake_up_from_light_sleep is true.
1520 unwrap!(self.pin.listen_with_options(event, true, false, false));
1521 }
1522
1523 /// Stop listening for interrupts.
1524 #[inline]
1525 #[instability::unstable]
1526 pub fn unlisten(&mut self) {
1527 GPIO_LOCK.lock(|| {
1528 set_int_enable(self.pin.number(), Some(0), 0, false);
1529 });
1530 }
1531
1532 fn unlisten_and_clear(&mut self) {
1533 GPIO_LOCK.lock(|| {
1534 set_int_enable(self.pin.number(), Some(0), 0, false);
1535 self.clear_interrupt();
1536 });
1537 }
1538
1539 /// Check if the pin is listening for interrupts.
1540 #[inline]
1541 #[instability::unstable]
1542 pub fn is_listening(&self) -> bool {
1543 is_int_enabled(self.pin.number())
1544 }
1545
1546 /// Clear the interrupt status bit for this Pin
1547 #[inline]
1548 #[instability::unstable]
1549 pub fn clear_interrupt(&mut self) {
1550 self.pin
1551 .bank()
1552 .write_interrupt_status_clear(self.pin.mask());
1553 }
1554
1555 /// Checks if the interrupt status bit for this Pin is set
1556 #[inline]
1557 #[instability::unstable]
1558 pub fn is_interrupt_set(&self) -> bool {
1559 self.pin.bank().read_interrupt_status() & self.pin.mask() != 0
1560 }
1561
1562 /// Enable as a wake-up source.
1563 ///
1564 /// This will unlisten for interrupts
1565 ///
1566 /// # Error
1567 /// Configuring pin to wake up from light sleep on an edge
1568 /// trigger is currently not supported, corresponding variant of
1569 /// [`WakeConfigError`] will be returned.
1570 #[inline]
1571 #[instability::unstable]
1572 pub fn wakeup_enable(&mut self, enable: bool, event: WakeEvent) -> Result<(), WakeConfigError> {
1573 self.pin
1574 .listen_with_options(event.into(), false, false, enable)
1575 }
1576
1577 // Output functions
1578
1579 /// Applies the given output configuration to the pin.
1580 ///
1581 /// This function does not set the pin to output (i.e. it does not enable
1582 /// the output driver). Note that the pull direction is common between
1583 /// the input and output configuration.
1584 #[inline]
1585 #[instability::unstable]
1586 pub fn apply_output_config(&mut self, config: &OutputConfig) {
1587 self.pin.apply_output_config(config);
1588 }
1589
1590 /// Enable or disable the GPIO pin output driver.
1591 ///
1592 /// The output level will be set to the last value. Use [`Self::set_high`],
1593 /// [`Self::set_low`] or [`Self::set_level`] to set the output level before
1594 /// enabling the output.
1595 ///
1596 /// This function does not disable the input buffer.
1597 #[inline]
1598 #[instability::unstable]
1599 pub fn set_output_enable(&mut self, enable_output: bool) {
1600 self.pin.set_output_enable(enable_output);
1601 }
1602
1603 /// Set the output as high.
1604 #[inline]
1605 #[instability::unstable]
1606 pub fn set_high(&mut self) {
1607 self.set_level(Level::High)
1608 }
1609
1610 /// Set the output as low.
1611 #[inline]
1612 #[instability::unstable]
1613 pub fn set_low(&mut self) {
1614 self.set_level(Level::Low)
1615 }
1616
1617 /// Set the output level.
1618 #[inline]
1619 #[instability::unstable]
1620 pub fn set_level(&mut self, level: Level) {
1621 self.pin.set_output_high(level.into());
1622 }
1623
1624 /// Is the output pin set as high?
1625 #[inline]
1626 #[instability::unstable]
1627 pub fn is_set_high(&self) -> bool {
1628 self.output_level() == Level::High
1629 }
1630
1631 /// Is the output pin set as low?
1632 #[inline]
1633 #[instability::unstable]
1634 pub fn is_set_low(&self) -> bool {
1635 self.output_level() == Level::Low
1636 }
1637
1638 /// What level output is set to
1639 #[inline]
1640 #[instability::unstable]
1641 pub fn output_level(&self) -> Level {
1642 self.pin.is_set_high().into()
1643 }
1644
1645 /// Toggle pin output
1646 #[inline]
1647 #[instability::unstable]
1648 pub fn toggle(&mut self) {
1649 let level = self.output_level();
1650 self.set_level(!level);
1651 }
1652
1653 // Other/common functions
1654
1655 /// Returns a peripheral [input][interconnect::InputSignal] connected to
1656 /// this pin.
1657 ///
1658 /// The input signal can be passed to peripherals in place of an input pin.
1659 ///
1660 /// Note that the signal returned by this function is
1661 /// [frozen](interconnect::InputSignal::freeze).
1662 ///
1663 /// ```rust, no_run
1664 #[doc = crate::before_snippet!()]
1665 /// # use esp_hal::gpio::Flex;
1666 /// let pin1_gpio = Flex::new(peripherals.GPIO1);
1667 /// // Can be passed as an input.
1668 /// let pin1 = pin1_gpio.peripheral_input();
1669 /// // You can keep using the Flex, as well as connect the pin to a
1670 /// // peripheral input.
1671 /// # Ok(())
1672 /// # }
1673 /// ```
1674 #[inline]
1675 #[instability::unstable]
1676 pub fn peripheral_input(&self) -> interconnect::InputSignal<'d> {
1677 self.pin.set_input_enable(true);
1678 unsafe {
1679 // Safety: the signal is frozen by this function.
1680 self.pin.clone_unchecked().split_no_init().0.freeze()
1681 }
1682 }
1683
1684 /// Split the pin into an input and output signal pair.
1685 ///
1686 /// Peripheral signals allow connecting peripherals together without using
1687 /// external hardware.
1688 ///
1689 /// Note that the signals returned by this function is
1690 /// [frozen](interconnect::InputSignal::freeze).
1691 ///
1692 /// ```rust, no_run
1693 #[doc = crate::before_snippet!()]
1694 /// # use esp_hal::gpio::Flex;
1695 /// let pin1 = Flex::new(peripherals.GPIO1);
1696 /// let (input, output) = pin1.split();
1697 /// # Ok(())
1698 /// # }
1699 /// ```
1700 #[inline]
1701 #[instability::unstable]
1702 pub fn split(
1703 self,
1704 ) -> (
1705 interconnect::InputSignal<'d>,
1706 interconnect::OutputSignal<'d>,
1707 ) {
1708 let input = self.peripheral_input();
1709 let output = self.into_peripheral_output();
1710
1711 (input, output)
1712 }
1713
1714 /// Split the pin into an [Input] and an [Output] driver pair.
1715 ///
1716 /// Note that the signal returned by this function is
1717 /// [frozen](interconnect::InputSignal::freeze). On the other hand,
1718 /// the pin driver is free to change settings.
1719 ///
1720 /// This function allows you to configure an input-output pin, then keep
1721 /// working with the output half. This is mainly intended for testing,
1722 /// allowing you to drive a peripheral from a signal generated by
1723 /// software.
1724 ///
1725 /// # Safety
1726 ///
1727 /// The caller must ensure that the pins are not being configured via their
1728 /// `apply_config` functions in the same time in multiple places. The pin
1729 /// drivers must not be turned back into `Flex`, unless one of the
1730 /// drivers is dropped first.
1731 // TODO is this enough? Register-wise config is the only non-atomic operation, but is it
1732 // actually safe to have two drivers on the same pin, otherwise? Perhaps it would be better
1733 // to implement ehal traits for signals?
1734 #[inline]
1735 #[instability::unstable]
1736 pub unsafe fn split_into_drivers(self) -> (Input<'d>, Output<'d>) {
1737 self.pin.set_input_enable(true);
1738 let input = Input {
1739 pin: Flex {
1740 pin: unsafe { self.pin.clone_unchecked() },
1741 },
1742 };
1743 let output = Output { pin: self };
1744
1745 (input, output)
1746 }
1747
1748 /// Turns the pin object into a peripheral
1749 /// [output][interconnect::OutputSignal].
1750 ///
1751 /// The output signal can be passed to peripherals in place of an output
1752 /// pin.
1753 ///
1754 /// Note that the signal returned by this function is
1755 /// [frozen](interconnect::OutputSignal::freeze).
1756 ///
1757 /// ```rust, no_run
1758 #[doc = crate::before_snippet!()]
1759 /// # use esp_hal::gpio::Flex;
1760 /// let pin1_gpio = Flex::new(peripherals.GPIO1);
1761 /// // Can be passed as an output.
1762 /// let pin1 = pin1_gpio.into_peripheral_output();
1763 /// # Ok(())
1764 /// # }
1765 /// ```
1766 #[inline]
1767 #[instability::unstable]
1768 pub fn into_peripheral_output(self) -> interconnect::OutputSignal<'d> {
1769 unsafe {
1770 // Safety: the signals are frozen by this function.
1771 self.pin.split_no_init().1.freeze()
1772 }
1773 }
1774}
1775
1776impl private::Sealed for AnyPin<'_> {}
1777
1778impl<'lt> AnyPin<'lt> {
1779 fn bank(&self) -> GpioBank {
1780 #[cfg(gpio_bank_1)]
1781 if self.number() >= 32 {
1782 return GpioBank::_1;
1783 }
1784
1785 GpioBank::_0
1786 }
1787
1788 #[inline]
1789 /// Resets the GPIO to a known state.
1790 ///
1791 /// This function needs to be called before using the GPIO pin:
1792 /// - Before converting it into signals
1793 /// - Before using it as an input or output
1794 pub(crate) fn init_gpio(&self) {
1795 #[cfg(usb_device)]
1796 disable_usb_pads(self.number());
1797
1798 self.set_output_enable(false);
1799
1800 GPIO::regs()
1801 .func_out_sel_cfg(self.number() as usize)
1802 .modify(|_, w| unsafe { w.out_sel().bits(OutputSignal::GPIO as OutputSignalType) });
1803
1804 // Use RMW to not overwrite sleep configuration
1805 io_mux_reg(self.number()).modify(|_, w| unsafe {
1806 w.mcu_sel().bits(GPIO_FUNCTION as u8);
1807 w.fun_ie().clear_bit();
1808 w.slp_sel().clear_bit()
1809 });
1810 }
1811
1812 /// Split the pin into an input and output signal.
1813 ///
1814 /// Peripheral signals allow connecting peripherals together without
1815 /// using external hardware.
1816 ///
1817 /// Creating an input signal enables the pin's input buffer.
1818 ///
1819 /// # Safety
1820 ///
1821 /// The caller must ensure that peripheral drivers don't configure the same
1822 /// GPIO at the same time in multiple places. This includes clones of the
1823 /// `InputSignal` struct, as well as the `OutputSignal` struct.
1824 ///
1825 /// # Panics
1826 ///
1827 /// This function panics if the pin is not an output pin.
1828 ///
1829 /// ```rust, no_run
1830 #[doc = crate::before_snippet!()]
1831 /// # use esp_hal::gpio::{AnyPin, Pin};
1832 /// let pin1 = peripherals.GPIO1.degrade();
1833 /// let (input, output) = unsafe { pin1.split() };
1834 /// # Ok(())
1835 /// # }
1836 /// ```
1837 #[inline]
1838 #[instability::unstable]
1839 pub unsafe fn split(
1840 self,
1841 ) -> (
1842 interconnect::InputSignal<'lt>,
1843 interconnect::OutputSignal<'lt>,
1844 ) {
1845 assert!(self.is_output());
1846
1847 // Before each use, reset the GPIO to a known state.
1848 self.init_gpio();
1849 self.set_input_enable(true);
1850
1851 let (input, output) = unsafe { self.split_no_init() };
1852
1853 // We don't know if the input signal(s) will support bypassing the GPIO matrix.
1854 // Since the bypass option is common between input and output halves of
1855 // a single GPIO, we can't assume anything about the output, either.
1856 let output = output.with_gpio_matrix_forced(true);
1857
1858 (input, output)
1859 }
1860
1861 /// Convert the pin into an input signal.
1862 ///
1863 /// Peripheral signals allow connecting peripherals together without
1864 /// using external hardware.
1865 ///
1866 /// Creating an input signal enables the pin's input buffer.
1867 ///
1868 /// # Safety
1869 ///
1870 /// The caller must ensure that peripheral drivers don't configure the same
1871 /// GPIO at the same time in multiple places. This includes clones of the
1872 /// `InputSignal` struct.
1873 #[inline]
1874 #[instability::unstable]
1875 pub unsafe fn into_input_signal(self) -> interconnect::InputSignal<'lt> {
1876 // Before each use, reset the GPIO to a known state.
1877 self.init_gpio();
1878 self.set_input_enable(true);
1879
1880 let (input, _) = unsafe { self.split_no_init() };
1881
1882 input
1883 }
1884
1885 /// Convert the pin into an output signal.
1886 ///
1887 /// Peripheral signals allow connecting peripherals together without
1888 /// using external hardware.
1889 ///
1890 /// # Panics
1891 ///
1892 /// This function panics if the pin is not an output pin.
1893 #[inline]
1894 #[instability::unstable]
1895 pub fn into_output_signal(self) -> interconnect::OutputSignal<'lt> {
1896 assert!(self.is_output());
1897
1898 // Before each use, reset the GPIO to a known state.
1899 self.init_gpio();
1900
1901 // AnyPin is used as output only, we can allow bypassing the GPIO matrix.
1902 let (_, output) = unsafe { self.split_no_init() };
1903
1904 output
1905 }
1906
1907 unsafe fn split_no_init(
1908 self,
1909 ) -> (
1910 interconnect::InputSignal<'lt>,
1911 interconnect::OutputSignal<'lt>,
1912 ) {
1913 let input = interconnect::InputSignal::new(unsafe { self.clone_unchecked() });
1914 let output = interconnect::OutputSignal::new(self);
1915
1916 // Since InputSignal can be cloned, we have no way of knowing how many signals
1917 // end up being configured, and in what order. If multiple signals are
1918 // passed to peripherals, and one of them would allow GPIO alternate
1919 // function configurations, it would mean that the GPIO MCU_SEL bit's
1920 // final value would depend on the order of operations.
1921 let input = input.with_gpio_matrix_forced(true);
1922
1923 (input, output)
1924 }
1925
1926 #[inline]
1927 pub(crate) fn set_alternate_function(&self, alternate: AlternateFunction) {
1928 io_mux_reg(self.number()).modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8) });
1929 }
1930
1931 // /// Enable/disable sleep-mode
1932 // #[inline]
1933 // fn sleep_mode(&mut self, on: bool, _: private::Internal) {
1934 // io_mux_reg(self.number()).modify(|_, w| w.slp_sel().bit(on));
1935 // }
1936
1937 /// Enable or disable the GPIO pin output buffer.
1938 #[inline]
1939 pub(crate) fn set_output_enable(&self, enable: bool) {
1940 assert!(self.is_output() || !enable);
1941 self.bank().write_out_en(self.mask(), enable);
1942 }
1943
1944 /// Enable input for the pin
1945 #[inline]
1946 pub(crate) fn set_input_enable(&self, on: bool) {
1947 io_mux_reg(self.number()).modify(|_, w| w.fun_ie().bit(on));
1948 }
1949
1950 #[inline]
1951 pub(crate) fn apply_input_config(&self, config: &InputConfig) {
1952 let pull_up = config.pull == Pull::Up;
1953 let pull_down = config.pull == Pull::Down;
1954
1955 #[cfg(esp32)]
1956 crate::soc::gpio::errata36(unsafe { self.clone_unchecked() }, pull_up, pull_down);
1957
1958 io_mux_reg(self.number()).modify(|_, w| {
1959 w.fun_wpd().bit(pull_down);
1960 w.fun_wpu().bit(pull_up)
1961 });
1962 }
1963
1964 fn clear_interrupt(&self) {
1965 self.bank().write_interrupt_status_clear(self.mask());
1966 }
1967
1968 fn with_gpio_lock<F, R>(&self, f: F) -> R
1969 where
1970 F: FnOnce() -> R,
1971 {
1972 // If the pin is listening, we need to take a critical section to prevent racing
1973 // with the interrupt handler.
1974 if is_int_enabled(self.number()) {
1975 GPIO_LOCK.lock(f)
1976 } else {
1977 f()
1978 }
1979 }
1980
1981 fn listen_with_options(
1982 &self,
1983 event: Event,
1984 int_enable: bool,
1985 nmi_enable: bool,
1986 wake_up_from_light_sleep: bool,
1987 ) -> Result<(), WakeConfigError> {
1988 if wake_up_from_light_sleep {
1989 match event {
1990 Event::AnyEdge | Event::RisingEdge | Event::FallingEdge => {
1991 return Err(WakeConfigError::EdgeTriggeringNotSupported);
1992 }
1993 _ => {}
1994 }
1995 }
1996
1997 self.with_gpio_lock(|| {
1998 // Clear the interrupt status bit for this Pin, just in case the user forgot.
1999 // Since we disabled the interrupt in the handler, it's not possible to
2000 // trigger a new interrupt before we re-enable it here.
2001 self.clear_interrupt();
2002
2003 set_int_enable(
2004 self.number(),
2005 Some(gpio_intr_enable(int_enable, nmi_enable)),
2006 event as u8,
2007 wake_up_from_light_sleep,
2008 );
2009 });
2010 Ok(())
2011 }
2012
2013 #[inline]
2014 fn apply_output_config(&self, config: &OutputConfig) {
2015 let pull_up = config.pull == Pull::Up;
2016 let pull_down = config.pull == Pull::Down;
2017
2018 #[cfg(esp32)]
2019 crate::soc::gpio::errata36(unsafe { self.clone_unchecked() }, pull_up, pull_down);
2020
2021 io_mux_reg(self.number()).modify(|_, w| {
2022 unsafe { w.fun_drv().bits(config.drive_strength as u8) };
2023 w.fun_wpu().bit(pull_up);
2024 w.fun_wpd().bit(pull_down);
2025 w
2026 });
2027
2028 self.with_gpio_lock(|| {
2029 GPIO::regs().pin(self.number() as usize).modify(|_, w| {
2030 w.pad_driver()
2031 .bit(config.drive_mode == DriveMode::OpenDrain)
2032 });
2033 });
2034 }
2035
2036 #[inline]
2037 fn mask(&self) -> u32 {
2038 1 << (self.number() % 32)
2039 }
2040
2041 /// The current state of the input
2042 #[inline]
2043 pub(crate) fn is_input_high(&self) -> bool {
2044 self.bank().read_input() & self.mask() != 0
2045 }
2046
2047 /// Set the pin's level to high or low
2048 #[inline]
2049 pub(crate) fn set_output_high(&self, high: bool) {
2050 self.bank().write_output(self.mask(), high);
2051 }
2052
2053 /// Is the output set to high
2054 #[inline]
2055 pub(crate) fn is_set_high(&self) -> bool {
2056 self.bank().read_output() & self.mask() != 0
2057 }
2058}
2059
2060impl Pin for AnyPin<'_> {
2061 #[inline(always)]
2062 fn number(&self) -> u8 {
2063 self.pin
2064 }
2065
2066 fn output_signals(&self, _: private::Internal) -> &'static [(AlternateFunction, OutputSignal)] {
2067 handle_gpio_output!(self, target, {
2068 Pin::output_signals(&target, private::Internal)
2069 })
2070 }
2071
2072 fn input_signals(&self, _: private::Internal) -> &'static [(AlternateFunction, InputSignal)] {
2073 handle_gpio_input!(self, target, {
2074 Pin::input_signals(&target, private::Internal)
2075 })
2076 }
2077}
2078
2079impl InputPin for AnyPin<'_> {}
2080impl OutputPin for AnyPin<'_> {}
2081
2082#[cfg(any(lp_io, rtc_cntl))]
2083impl RtcPin for AnyPin<'_> {
2084 #[cfg(xtensa)]
2085 #[allow(unused_braces, reason = "False positive")]
2086 fn rtc_number(&self) -> u8 {
2087 handle_rtcio!(self, target, { RtcPin::rtc_number(&target) })
2088 }
2089
2090 #[cfg(any(xtensa, esp32c6))]
2091 fn rtc_set_config(&self, input_enable: bool, mux: bool, func: RtcFunction) {
2092 handle_rtcio!(self, target, {
2093 RtcPin::rtc_set_config(&target, input_enable, mux, func)
2094 })
2095 }
2096
2097 #[allow(unused_braces, reason = "False positive")]
2098 fn rtcio_pad_hold(&self, enable: bool) {
2099 handle_rtcio!(self, target, { RtcPin::rtcio_pad_hold(&target, enable) })
2100 }
2101
2102 #[cfg(any(esp32c2, esp32c3, esp32c6))]
2103 unsafe fn apply_wakeup(&self, wakeup: bool, level: u8) {
2104 unsafe {
2105 handle_rtcio!(self, target, {
2106 RtcPin::apply_wakeup(&target, wakeup, level)
2107 })
2108 }
2109 }
2110}
2111
2112#[cfg(any(lp_io, rtc_cntl))]
2113impl RtcPinWithResistors for AnyPin<'_> {
2114 fn rtcio_pullup(&self, enable: bool) {
2115 handle_rtcio_with_resistors!(self, target, {
2116 RtcPinWithResistors::rtcio_pullup(&target, enable)
2117 })
2118 }
2119
2120 fn rtcio_pulldown(&self, enable: bool) {
2121 handle_rtcio_with_resistors!(self, target, {
2122 RtcPinWithResistors::rtcio_pulldown(&target, enable)
2123 })
2124 }
2125}
2126
2127/// Set GPIO event listening.
2128///
2129/// - `gpio_num`: the pin to configure
2130/// - `int_ena`: maskable and non-maskable CPU interrupt bits. None to leave
2131/// unchanged.
2132/// - `int_type`: interrupt type, see [Event] (or 0 to disable)
2133/// - `wake_up_from_light_sleep`: whether to wake up from light sleep
2134fn set_int_enable(gpio_num: u8, int_ena: Option<u8>, int_type: u8, wake_up_from_light_sleep: bool) {
2135 GPIO::regs().pin(gpio_num as usize).modify(|_, w| unsafe {
2136 if let Some(int_ena) = int_ena {
2137 w.int_ena().bits(int_ena);
2138 }
2139 w.int_type().bits(int_type);
2140 w.wakeup_enable().bit(wake_up_from_light_sleep)
2141 });
2142}
2143
2144fn is_int_enabled(gpio_num: u8) -> bool {
2145 GPIO::regs().pin(gpio_num as usize).read().int_ena().bits() != 0
2146}