Skip to main content

esp_hal/gpio/lp_io/low_level/
v3.rs

1use crate::{
2    gpio::{AlternateFunction, Level, LpPin, lp_io::LpFunction},
3    peripherals::{GPIO, IO_MUX, LPWR},
4};
5
6for_each_lp_function! {
7    (($_lp:ident, LP_GPIOn, $pin:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => {
8        #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
9        impl LpPin for crate::peripherals::$gpio<'_> {
10            fn lp_number(&self) -> u8 {
11                $pin
12            }
13        }
14    };
15
16    // The wakeup register and the hold register have one named field for each pad, and no index, so
17    // these functions select the field by the low-power number.
18    (LP_GPIOn $( (($_lp:ident, LP_GPIOn, $pin:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) ),*) => {
19        paste::paste! {
20            pub(crate) fn apply_wakeup(lp: u8, wakeup: bool, level: Level) {
21                let trigger = crate::gpio::lp_io::wake_trigger(level);
22
23                let gpio_wakeup = cfg_select! {
24                    esp32c2 => LPWR::regs().cntl_gpio_wakeup(),
25                    esp32c3 => LPWR::regs().gpio_wakeup(),
26                };
27
28                gpio_wakeup.modify(|_, w| unsafe {
29                    match lp {
30                        $(
31                            $pin => {
32                                w.[<gpio_pin $pin _wakeup_enable>]().bit(wakeup);
33                                w.[<gpio_pin $pin _int_type>]().bits(trigger)
34                            }
35                        )*
36                        _ => unreachable!(),
37                    }
38                });
39            }
40
41            pub(crate) fn pad_hold(lp: u8, enable: bool) {
42                LPWR::regs().pad_hold().modify(|_, w| {
43                    match lp {
44                        $( $pin => w.[<gpio_pin $pin _hold>]().bit(enable), )*
45                        _ => unreachable!(),
46                    }
47                });
48            }
49
50            /// Returns whether something holds the pad.
51            pub(crate) fn is_pad_held(lp: u8) -> bool {
52                let r = LPWR::regs().pad_hold().read();
53                match lp {
54                    $( $pin => r.[<gpio_pin $pin _hold>]().bit_is_set(), )*
55                    _ => unreachable!(),
56                }
57            }
58
59            /// Returns the pads that can wake the chip through the per-pin path, as a mask of
60            /// low-power numbers.
61            #[cfg(sleep_driver_supported)]
62            pub(crate) fn wakeup_enabled_mask() -> u32 {
63                let gpio_wakeup = cfg_select! {
64                    esp32c2 => LPWR::regs().cntl_gpio_wakeup().read(),
65                    esp32c3 => LPWR::regs().gpio_wakeup().read(),
66                };
67
68                let mut mask = 0;
69                $(
70                    if gpio_wakeup.[<gpio_pin $pin _wakeup_enable>]().bit_is_set() {
71                        mask |= 1 << $pin;
72                    }
73                )*
74                mask
75            }
76        }
77    };
78}
79
80/// Takes or releases the hold of the pad of `gpio`.
81///
82/// The register numbers the pads of the digital supply the way the digital registers do, and the
83/// low-power pads have their own register.
84pub(crate) fn digital_pad_hold(gpio: u8, enable: bool) {
85    let mask = 1 << gpio;
86    LPWR::regs().dig_pad_hold().modify(|r, w| unsafe {
87        let bits = r.dig_pad_hold().bits();
88        w.dig_pad_hold()
89            .bits(if enable { bits | mask } else { bits & !mask })
90    });
91}
92
93/// Returns whether something holds the pad of `gpio`.
94pub(crate) fn is_digital_pad_held(gpio: u8) -> bool {
95    LPWR::regs().dig_pad_hold().read().dig_pad_hold().bits() & (1 << gpio) != 0
96}
97
98/// Configures the pad.
99///
100/// The low-power domain reaches the pad through the digital IO MUX. There is thus no low-power
101/// function to select, and the low-power number is the digital pin number.
102pub(crate) fn set_config(lp: u8, input_enable: bool, _mux: bool, _func: LpFunction) {
103    IO_MUX::regs().gpio(lp as usize).modify(|_, w| unsafe {
104        w.slp_sel().bit(false);
105        w.mcu_sel().bits(AlternateFunction::GPIO as u8);
106        w.fun_ie().bit(input_enable)
107    });
108}
109
110#[expect(dead_code)]
111pub(crate) fn init_pin(lp: u8, enable_input: bool) -> u8 {
112    input_enable(lp, enable_input);
113    lp
114}
115
116#[expect(dead_code)]
117pub(crate) fn output_enable(lp: u8, enable: bool) {
118    if enable {
119        GPIO::regs()
120            .enable_w1ts()
121            .write(|w| unsafe { w.enable_w1ts().bits(1 << lp) });
122    } else {
123        GPIO::regs()
124            .enable_w1tc()
125            .write(|w| unsafe { w.enable_w1tc().bits(1 << lp) });
126    }
127}
128
129pub(crate) fn input_enable(lp: u8, enable: bool) {
130    IO_MUX::regs()
131        .gpio(lp as usize)
132        .modify(|_, w| w.fun_ie().bit(enable));
133}
134
135#[expect(dead_code)]
136pub(crate) fn set_open_drain_output(lp: u8, enable: bool) {
137    GPIO::regs()
138        .pin(lp as usize)
139        .modify(|_, w| w.pad_driver().bit(enable));
140}