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}