diff --git a/esp-hal/src/gpio/low_level/v1.rs b/esp-hal/src/gpio/low_level/v1.rs index 8028709b1fb..89bfbd71de0 100644 --- a/esp-hal/src/gpio/low_level/v1.rs +++ b/esp-hal/src/gpio/low_level/v1.rs @@ -45,16 +45,25 @@ pub(crate) fn set_interrupt_priority(priority: Priority) { } fn errata36(pin: &AnyPin<'_>, pull_up: bool, pull_down: bool) { - use crate::gpio::{LpPinWithResistors, Pin}; + use crate::gpio::{Pin, lp_io::low_level}; for_each_lp_function! { - (LP_GPIOn $( (($_sig:ident, LP_GPIOn, $_n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) ),* ) => { - const LP_IO_PINS: &[u8] = &[ $( $crate::peripherals::$gpio::NUMBER ),* ]; + (LP_GPIOn $( (($_sig:ident, LP_GPIOn, $n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) ),* ) => { + // The digital pin number, and the number the low-power registers index the pad by. + const LP_IO_PINS: &[(u8, u8)] = &[ $( ($crate::peripherals::$gpio::NUMBER, $n) ),* ]; }; }; - if LP_IO_PINS.contains(&pin.number()) && pin.is_output() { - pin.lp_pullup(pull_up); - pin.lp_pulldown(pull_down); + let lp = LP_IO_PINS + .iter() + .find(|(gpio, _)| *gpio == pin.number()) + .map(|(_, lp)| *lp); + + // The low-power registers of the pads that cannot pull anything warn instead. + if let Some(lp) = lp + && pin.is_output() + { + low_level::pullup_enable(lp, pull_up); + low_level::pulldown_enable(lp, pull_down); } } diff --git a/esp-hal/src/gpio/lp_io/low_level/esp32.rs b/esp-hal/src/gpio/lp_io/low_level/esp32.rs index 15120624861..021811fa114 100644 --- a/esp-hal/src/gpio/lp_io/low_level/esp32.rs +++ b/esp-hal/src/gpio/lp_io/low_level/esp32.rs @@ -11,61 +11,15 @@ macro_rules! lp_io_analog { fn lp_number(&self) -> u8 { $lp_pin } - - fn lp_set_config( - &self, - input_enable: bool, - mux: bool, - func: LpFunction, - ) { - RTC_IO::regs() - .$pin_reg - .modify(|_, w| unsafe { - w.[<$prefix fun_ie>]().bit(input_enable); - w.[<$prefix mux_sel>]().bit(mux); - w.[<$prefix fun_sel>]().bits(func as u8) - }); - } - - fn apply_wakeup(&self, wakeup: bool, level: crate::gpio::WakeEvent) { - RTC_IO::regs().pin($lp_pin).modify(|_, w| unsafe { - w.wakeup_enable().bit(wakeup); - w.int_type().bits(level as u8) - }); - } - - fn lp_pad_hold(&self, enable: bool) { - LPWR::regs() - .hold_force() - .modify(|_, w| w.$hold().bit(enable)); - } - } - - // Only output pins have PU/PD resistors. - for_each_gpio! { - ($n:tt, $pin_peri $in_afs:tt $out_afs:tt ($input:tt [Output])) => { - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl crate::gpio::LpPinWithResistors - for crate::peripherals::$pin_peri<'_> - { - fn lp_pullup(&self, enable: bool) { - pullup_enable($lp_pin, enable) - } - - fn lp_pulldown(&self, enable: bool) { - pulldown_enable($lp_pin, enable) - } - } - }; } impl crate::peripherals::$pin_peri<'_> { #[cfg(feature = "unstable")] pub(crate) fn set_analog_impl(&self) { - use crate::gpio::LpPin; + use crate::gpio::{LpPin, Pin}; output_enable(self.lp_number(), false); - set_open_drain_output(self.lp_number(), false); + set_open_drain_output(self.number(), false); RTC_IO::regs().$pin_reg.modify(|_, w| { w.[<$prefix fun_ie>]().clear_bit(); @@ -94,6 +48,34 @@ macro_rules! lp_io_analog { lp_io_analog!($pin_peri, $lp_pin, $pin_reg, $prefix, $hold); )+ + // Every pad has a register of its own, so the pad-specific work dispatches on the + // low-power number. + pub(crate) fn set_config(lp: u8, input_enable: bool, mux: bool, func: LpFunction) { + paste::paste! { + match lp { + $( + $lp_pin => { + RTC_IO::regs().$pin_reg.modify(|_, w| unsafe { + w.[<$prefix fun_ie>]().bit(input_enable); + w.[<$prefix mux_sel>]().bit(mux); + w.[<$prefix fun_sel>]().bits(func as u8) + }); + } + )+ + _ => unreachable!(), + } + } + } + + pub(crate) fn pad_hold(lp: u8, enable: bool) { + LPWR::regs().hold_force().modify(|_, w| { + match lp { + $( $lp_pin => w.$hold().bit(enable), )+ + _ => unreachable!(), + } + }); + } + macro_rules! set_one_pad_field { $( ($lp_pin, $field:ident, $enable:ident) => {{ @@ -176,39 +158,50 @@ macro_rules! set_pull_field { }}; } +// esp32 arms its pads through ext0 and ext1, not one by one. +#[expect(dead_code)] +pub(crate) fn apply_wakeup(lp: u8, wakeup: bool, event: crate::gpio::WakeEvent) { + RTC_IO::regs().pin(lp as usize).modify(|_, w| unsafe { + w.wakeup_enable().bit(wakeup); + w.int_type().bits(event as u8) + }); +} + #[expect(dead_code)] -pub(super) fn init_pin(pin: &impl crate::gpio::LpPin, input_enable: bool) -> u8 { - pin.lp_set_config(input_enable, true, LpFunction::LP_GPIO); - pin.lp_number() +pub(crate) fn init_pin(lp: u8, input_enable: bool) -> u8 { + set_config(lp, input_enable, true, LpFunction::LP_GPIO); + lp } -pub(super) fn output_enable(pin: u8, enable: bool) { +pub(crate) fn output_enable(lp: u8, enable: bool) { if enable { RTC_IO::regs() .enable_w1ts() - .write(|w| unsafe { w.enable_w1ts().bits(1 << pin) }); + .write(|w| unsafe { w.enable_w1ts().bits(1 << lp) }); } else { RTC_IO::regs() .enable_w1tc() - .write(|w| unsafe { w.enable_w1tc().bits(1 << pin) }); + .write(|w| unsafe { w.enable_w1tc().bits(1 << lp) }); } } #[expect(dead_code)] -pub(super) fn input_enable(pin: u8, enable: bool) { - set_pad_field!(pin, fun_ie, enable); +pub(crate) fn input_enable(lp: u8, enable: bool) { + set_pad_field!(lp, fun_ie, enable); } -pub(super) fn pullup_enable(pin: u8, enable: bool) { - set_pull_field!(pin, rue, enable); +pub(crate) fn pullup_enable(lp: u8, enable: bool) { + set_pull_field!(lp, rue, enable); } -pub(super) fn pulldown_enable(pin: u8, enable: bool) { - set_pull_field!(pin, rde, enable); +pub(crate) fn pulldown_enable(lp: u8, enable: bool) { + set_pull_field!(lp, rde, enable); } -pub(super) fn set_open_drain_output(pin: u8, enable: bool) { +// The pad driver bit lives in the digital GPIO peripheral, and this chip numbers its low-power +// pads differently, so this one takes the digital number. +pub(crate) fn set_open_drain_output(gpio: u8, enable: bool) { GPIO::regs() - .pin(pin as usize) + .pin(gpio as usize) .modify(|_, w| w.pad_driver().bit(enable)); } diff --git a/esp-hal/src/gpio/lp_io/low_level/esp32h2.rs b/esp-hal/src/gpio/lp_io/low_level/esp32h2.rs index 064d92a97a6..a7672de11b7 100644 --- a/esp-hal/src/gpio/lp_io/low_level/esp32h2.rs +++ b/esp-hal/src/gpio/lp_io/low_level/esp32h2.rs @@ -1,5 +1,5 @@ use crate::{ - gpio::{AlternateFunction, LpPin, LpPinWithResistors, WakeEvent, lp_io::LpFunction}, + gpio::{AlternateFunction, LpPin, lp_io::LpFunction}, peripherals::{GPIO, IO_MUX, LP_AON}, }; @@ -10,80 +10,46 @@ for_each_lp_function! { fn lp_number(&self) -> u8 { $pin } - - fn apply_wakeup(&self, wakeup: bool, level: WakeEvent) { - let mask = 1 << $pin; - LP_AON::regs().ext_wakeup_cntl().modify(|r, w| unsafe { - let select = r.ext_wakeup_sel().bits(); - let levels = r.ext_wakeup_lv().bits(); - - w.ext_wakeup_filter().set_bit(); - w.ext_wakeup_sel().bits(if wakeup { - select | mask - } else { - select & !mask - }); - w.ext_wakeup_lv().bits(if level == WakeEvent::HighLevel { - levels | mask - } else { - levels & !mask - }) - }); - } - - fn lp_pad_hold(&self, enable: bool) { - let mask = 1 << lp_pin_to_gpio($pin); - LP_AON::regs() - .gpio_hold0() - .modify(|r, w| unsafe { - let bits = r.gpio_hold0().bits(); - w.gpio_hold0().bits(if enable { - bits | mask - } else { - bits & !mask - }) - }); - } - - // The LP core reaches the pad through the digital IO MUX, so there is no low-power - // function to select. - fn lp_set_config(&self, input_enable: bool, _mux: bool, _func: LpFunction) { - IO_MUX::regs().gpio(lp_pin_to_gpio($pin) as usize) - .modify(|_, w| unsafe { - w.slp_sel().bit(false); - w.mcu_sel().bits(AlternateFunction::GPIO as u8); - w.fun_ie().bit(input_enable) - }); - } } + }; +} - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl LpPinWithResistors for crate::peripherals::$gpio<'_> { - fn lp_pullup(&self, enable: bool) { - pullup_enable($pin, enable); - } +pub(crate) fn pad_hold(lp: u8, enable: bool) { + let mask = 1 << lp_pin_to_gpio(lp); + LP_AON::regs().gpio_hold0().modify(|r, w| unsafe { + let bits = r.gpio_hold0().bits(); + w.gpio_hold0() + .bits(if enable { bits | mask } else { bits & !mask }) + }); +} - fn lp_pulldown(&self, enable: bool) { - pulldown_enable($pin, enable); - } - } - }; +/// Configures the pad. +/// +/// The low-power domain reaches the pad through the digital IO MUX, so there is no low-power +/// function to select. +pub(crate) fn set_config(lp: u8, input_enable: bool, _mux: bool, _func: LpFunction) { + IO_MUX::regs() + .gpio(lp_pin_to_gpio(lp) as usize) + .modify(|_, w| unsafe { + w.slp_sel().bit(false); + w.mcu_sel().bits(AlternateFunction::GPIO as u8); + w.fun_ie().bit(input_enable) + }); } #[expect(dead_code)] -pub(super) fn init_pin(pin: &impl LpPin, enable_input: bool) -> u8 { - let lp_pin = pin.lp_number(); - input_enable(lp_pin, enable_input); - lp_pin +pub(crate) fn init_pin(lp: u8, enable_input: bool) -> u8 { + input_enable(lp, enable_input); + lp } -fn lp_pin_to_gpio(pin: u8) -> u8 { - pin + 7 +fn lp_pin_to_gpio(lp: u8) -> u8 { + lp + 7 } #[expect(dead_code)] -pub(super) fn output_enable(pin: u8, enable: bool) { - let gpio = lp_pin_to_gpio(pin); +pub(crate) fn output_enable(lp: u8, enable: bool) { + let gpio = lp_pin_to_gpio(lp); if enable { GPIO::regs() .enable_w1ts() @@ -95,27 +61,31 @@ pub(super) fn output_enable(pin: u8, enable: bool) { } } -pub(super) fn input_enable(pin: u8, enable: bool) { +pub(crate) fn input_enable(lp: u8, enable: bool) { IO_MUX::regs() - .gpio(lp_pin_to_gpio(pin) as usize) + .gpio(lp_pin_to_gpio(lp) as usize) .modify(|_, w| w.fun_ie().bit(enable)); } -pub(super) fn pullup_enable(pin: u8, enable: bool) { +#[expect(dead_code)] +pub(crate) fn pullup_enable(lp: u8, enable: bool) { IO_MUX::regs() - .gpio(lp_pin_to_gpio(pin) as usize) + .gpio(lp_pin_to_gpio(lp) as usize) .modify(|_, w| w.fun_wpu().bit(enable)); } -pub(super) fn pulldown_enable(pin: u8, enable: bool) { +#[expect(dead_code)] +pub(crate) fn pulldown_enable(lp: u8, enable: bool) { IO_MUX::regs() - .gpio(lp_pin_to_gpio(pin) as usize) + .gpio(lp_pin_to_gpio(lp) as usize) .modify(|_, w| w.fun_wpd().bit(enable)); } +// The pad driver bit lives in the digital GPIO peripheral, and this chip numbers its low-power +// pads differently, so this one takes the digital number. #[expect(dead_code)] -pub(super) fn set_open_drain_output(pin: u8, enable: bool) { +pub(crate) fn set_open_drain_output(gpio: u8, enable: bool) { GPIO::regs() - .pin(pin as usize) + .pin(gpio as usize) .modify(|_, w| w.pad_driver().bit(enable)); } diff --git a/esp-hal/src/gpio/lp_io/low_level/esp32p4.rs b/esp-hal/src/gpio/lp_io/low_level/esp32p4.rs index 32fd2c6b743..cdecdaac3fe 100644 --- a/esp-hal/src/gpio/lp_io/low_level/esp32p4.rs +++ b/esp-hal/src/gpio/lp_io/low_level/esp32p4.rs @@ -1,116 +1,108 @@ use crate::{ gpio::{ LpPin, - LpPinWithResistors, - WakeEvent, lp_io::{LpFunction, LpInputSignal, LpOutputSignal}, }, peripherals::{LP_GPIO, LP_IO_MUX}, }; for_each_lp_function! { - (($lp_pin_name:ident, LP_GPIOn, $lp_pin:literal), $gpio:ident, $_af:ident, ($( $lp_in_af:ident => $lp_in_signal:ident )*) ($( $lp_out_af:ident => $lp_out_signal:ident )*)) => { + (($_lp_pin_name:ident, LP_GPIOn, $lp_pin:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => { impl LpPin for crate::peripherals::$gpio<'_> { fn lp_number(&self) -> u8 { $lp_pin } - - fn apply_wakeup(&self, wakeup: bool, level: WakeEvent) { - LP_GPIO::regs().pin($lp_pin).modify(|_, w| unsafe { - w.int_type().bits(level as u8); - w.wakeup_enable().bit(wakeup) - }); - } - - fn lp_pad_hold(&self, enable: bool) { - pad_hold_enable($lp_pin, enable); - } - - fn lp_set_config(&self, input_enable: bool, mux: bool, func: LpFunction) { - if mux { - LP_GPIO::regs() - .clk_en() - .modify(|_, w| w.reg_clk_en().set_bit()); - while LP_GPIO::regs().clk_en().read().reg_clk_en().bit_is_clear() {} - } - - LP_IO_MUX::regs().pad($lp_pin).modify(|_, w| unsafe { - w.mux_sel().bit(mux); - w.fun_ie().bit(input_enable); - w.fun_sel().bits(func as u8) - }); - } - - fn lp_input_signals(&self) -> &'static [(LpFunction, LpInputSignal)] { - &[$( (LpFunction::$lp_in_af, LpInputSignal::$lp_in_signal) ),*] - } - - fn lp_output_signals(&self) -> &'static [(LpFunction, LpOutputSignal)] { - &[$( (LpFunction::$lp_out_af, LpOutputSignal::$lp_out_signal) ),*] - } } + }; - impl LpPinWithResistors for crate::peripherals::$gpio<'_> { - fn lp_pullup(&self, enable: bool) { - pullup_enable($lp_pin, enable); + // The signal tables differ per pad, so they dispatch on the low-power number. + (LP_GPIOn $(( + ($_lp_pin_name:ident, LP_GPIOn, $lp_pin:literal), + $gpio:ident, + $_af:ident, + ($( $lp_in_af:ident => $lp_in_signal:ident )*) + ($( $lp_out_af:ident => $lp_out_signal:ident )*) + )),*) => { + pub(crate) fn input_signals(lp: u8) -> &'static [(LpFunction, LpInputSignal)] { + match lp { + $( $lp_pin => &[$( (LpFunction::$lp_in_af, LpInputSignal::$lp_in_signal) ),*], )* + _ => unreachable!(), } + } - fn lp_pulldown(&self, enable: bool) { - pulldown_enable($lp_pin, enable); + pub(crate) fn output_signals(lp: u8) -> &'static [(LpFunction, LpOutputSignal)] { + match lp { + $( $lp_pin => &[$( (LpFunction::$lp_out_af, LpOutputSignal::$lp_out_signal) ),*], )* + _ => unreachable!(), } } }; } -pub(super) fn init_pin(pin: &impl LpPin, input_enable: bool) -> u8 { - let lp_pin = pin.number(); - pin.lp_set_config(input_enable, true, LpFunction::LP_GPIO); - lp_pin +pub(crate) fn set_config(lp: u8, input_enable: bool, mux: bool, func: LpFunction) { + if mux { + LP_GPIO::regs() + .clk_en() + .modify(|_, w| w.reg_clk_en().set_bit()); + while LP_GPIO::regs().clk_en().read().reg_clk_en().bit_is_clear() {} + } + + LP_IO_MUX::regs().pad(lp as usize).modify(|_, w| unsafe { + w.mux_sel().bit(mux); + w.fun_ie().bit(input_enable); + w.fun_sel().bits(func as u8) + }); +} + +pub(crate) fn init_pin(lp: u8, input_enable: bool) -> u8 { + set_config(lp, input_enable, true, LpFunction::LP_GPIO); + lp } -pub(super) fn output_enable(pin: u8, enable: bool) { +pub(crate) fn output_enable(lp: u8, enable: bool) { if enable { LP_GPIO::regs() .enable_w1ts() - .write(|w| unsafe { w.bits(1 << pin) }); + .write(|w| unsafe { w.bits(1 << lp) }); } else { LP_GPIO::regs() .enable_w1tc() - .write(|w| unsafe { w.bits(1 << pin) }); + .write(|w| unsafe { w.bits(1 << lp) }); } } -pub(super) fn input_enable(pin: u8, enable: bool) { +pub(crate) fn input_enable(lp: u8, enable: bool) { LP_IO_MUX::regs() - .pad(pin as usize) + .pad(lp as usize) .modify(|_, w| w.slp_ie().bit(enable)); } -pub(super) fn pullup_enable(pin: u8, enable: bool) { +pub(crate) fn pullup_enable(lp: u8, enable: bool) { LP_IO_MUX::regs() - .pad(pin as usize) + .pad(lp as usize) .modify(|_, w| w.rue().bit(enable)); } -pub(super) fn pulldown_enable(pin: u8, enable: bool) { +pub(crate) fn pulldown_enable(lp: u8, enable: bool) { LP_IO_MUX::regs() - .pad(pin as usize) + .pad(lp as usize) .modify(|_, w| w.rde().bit(enable)); } -pub(super) fn pad_hold_enable(pin: u8, enable: bool) { +pub(crate) fn pad_hold(lp: u8, enable: bool) { LP_IO_MUX::regs().lp_pad_hold().modify(|r, w| unsafe { let bits = r.reg_lp_gpio_hold().bits(); w.reg_lp_gpio_hold().bits(if enable { - bits | (1 << pin) + bits | (1 << lp) } else { - bits & !(1 << pin) + bits & !(1 << lp) }) }); } -pub(super) fn set_open_drain_output(pin: u8, enable: bool) { +// The pad driver bit lives in the digital GPIO peripheral, so this one takes the digital number. +pub(crate) fn set_open_drain_output(gpio: u8, enable: bool) { crate::peripherals::GPIO::regs() - .pin(pin as usize) + .pin(gpio as usize) .modify(|_, w| w.pad_driver().bit(enable)); } diff --git a/esp-hal/src/gpio/lp_io/low_level/v2.rs b/esp-hal/src/gpio/lp_io/low_level/v2.rs index 9692d6100f1..05f8223f275 100644 --- a/esp-hal/src/gpio/lp_io/low_level/v2.rs +++ b/esp-hal/src/gpio/lp_io/low_level/v2.rs @@ -1,5 +1,5 @@ use crate::{ - gpio::{LpPin, LpPinWithResistors, WakeEvent, lp_io::LpFunction}, + gpio::{LpPin, WakeEvent, lp_io::LpFunction}, peripherals::{GPIO, LPWR, RTC_IO, SENS}, }; @@ -83,54 +83,50 @@ for_each_lp_function! { fn lp_number(&self) -> u8 { $n } - - fn lp_set_config(&self, input_enable: bool, mux: bool, func: LpFunction) { - enable_iomux_clk_gate(); - pin_reg!($gpio).modify(|_, w| unsafe { - w.fun_ie().bit(input_enable); - w.mux_sel().bit(mux); - w.fun_sel().bits(func as u8) - }); - } - - fn apply_wakeup(&self, wakeup: bool, level: WakeEvent) { - RTC_IO::regs().pin($n).modify(|_, w| unsafe { - w.wakeup_enable().bit(wakeup); - w.int_type().bits(level as u8) - }); - } - - fn lp_pad_hold(&self, enable: bool) { - LPWR::regs() - .pad_hold() - .modify(|_, w| hold_field!(w, $gpio).bit(enable)); - } } + }; - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl LpPinWithResistors for crate::peripherals::$gpio<'_> { - fn lp_pullup(&self, enable: bool) { - pullup_enable($n, enable); - } - - fn lp_pulldown(&self, enable: bool) { - pulldown_enable($n, enable); - } + // The hold register names a field per pad instead of indexing them, so this dispatches on the + // low-power number. + (LP_GPIOn $( (($_lp:ident, LP_GPIOn, $n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) ),*) => { + pub(crate) fn pad_hold(lp: u8, enable: bool) { + LPWR::regs().pad_hold().modify(|_, w| { + match lp { + $( $n => hold_field!(w, $gpio).bit(enable), )* + _ => unreachable!(), + } + }); } }; } +pub(crate) fn set_config(lp: u8, input_enable: bool, mux: bool, func: LpFunction) { + enable_iomux_clk_gate(); + with_pin_reg!(lp, |reg| reg.modify(|_, w| unsafe { + w.fun_ie().bit(input_enable); + w.mux_sel().bit(mux); + w.fun_sel().bits(func as u8) + })); +} + +pub(crate) fn apply_wakeup(lp: u8, wakeup: bool, event: WakeEvent) { + RTC_IO::regs().pin(lp as usize).modify(|_, w| unsafe { + w.wakeup_enable().bit(wakeup); + w.int_type().bits(event as u8) + }); +} + for_each_analog_function! { (($_ch:ident, ADCn_CHm, $_n:literal, $_m:literal), $gpio:ident) => { impl crate::peripherals::$gpio<'_> { #[cfg(feature = "unstable")] pub(crate) fn set_analog_impl(&self) { - use crate::gpio::LpPin; + use crate::gpio::{LpPin, Pin}; enable_iomux_clk_gate(); output_enable(self.lp_number(), false); - set_open_drain_output(self.lp_number(), false); + set_open_drain_output(self.number(), false); pin_reg!($gpio).modify(|_, w| { w.fun_ie().clear_bit(); @@ -144,50 +140,52 @@ for_each_analog_function! { }; } -pub(super) fn init_pin(pin: &impl LpPin, input_enable: bool) -> u8 { - pin.lp_set_config(input_enable, true, LpFunction::LP_GPIO); - pin.lp_number() +pub(crate) fn init_pin(lp: u8, input_enable: bool) -> u8 { + set_config(lp, input_enable, true, LpFunction::LP_GPIO); + lp } -pub(super) fn output_enable(pin: u8, enable: bool) { +pub(crate) fn output_enable(lp: u8, enable: bool) { if enable { RTC_IO::regs() .rtc_gpio_enable_w1ts() - .write(|w| unsafe { w.rtc_gpio_enable_w1ts().bits(1 << pin) }); + .write(|w| unsafe { w.rtc_gpio_enable_w1ts().bits(1 << lp) }); } else { RTC_IO::regs() .enable_w1tc() - .write(|w| unsafe { w.enable_w1tc().bits(1 << pin) }); + .write(|w| unsafe { w.enable_w1tc().bits(1 << lp) }); } } -pub(super) fn input_enable(pin: u8, enable: bool) { - with_pin_reg!(pin, |reg| reg.modify(|_, w| w.fun_ie().bit(enable))); +pub(crate) fn input_enable(lp: u8, enable: bool) { + with_pin_reg!(lp, |reg| reg.modify(|_, w| w.fun_ie().bit(enable))); } -pub(super) fn pullup_enable(pin: u8, enable: bool) { - with_pin_reg!(pin, |reg| reg.modify(|_, w| w.rue().bit(enable))); +pub(crate) fn pullup_enable(lp: u8, enable: bool) { + with_pin_reg!(lp, |reg| reg.modify(|_, w| w.rue().bit(enable))); } -pub(super) fn pulldown_enable(pin: u8, enable: bool) { - with_pin_reg!(pin, |reg| reg.modify(|_, w| w.rde().bit(enable))); +pub(crate) fn pulldown_enable(lp: u8, enable: bool) { + with_pin_reg!(lp, |reg| reg.modify(|_, w| w.rde().bit(enable))); } -pub(super) fn set_open_drain_output(pin: u8, enable: bool) { +// The pad driver bit lives in the digital GPIO peripheral, so this one takes the digital number. +pub(crate) fn set_open_drain_output(gpio: u8, enable: bool) { GPIO::regs() - .pin(pin as usize) + .pin(gpio as usize) .modify(|_, w| w.pad_driver().bit(enable)); } #[cfg(lp_i2c_master_driver_supported)] -pub(crate) fn reset_pin(pin: u8) { - output_enable(pin, false); - set_open_drain_output(pin, false); +pub(crate) fn reset_pin(lp: u8) { + output_enable(lp, false); + // Every low-power pad of these chips carries the same digital pin number. + set_open_drain_output(lp, false); // Resistors, input enable, the pad's LP function and whether it is muxed to the LP IO at all // are all held in this register. enable_iomux_clk_gate(); - with_pin_reg!(pin, |reg| reg.reset()); + with_pin_reg!(lp, |reg| reg.reset()); } fn enable_iomux_clk_gate() { diff --git a/esp-hal/src/gpio/lp_io/low_level/v3.rs b/esp-hal/src/gpio/lp_io/low_level/v3.rs index 7f7a3c16394..7dd47075974 100644 --- a/esp-hal/src/gpio/lp_io/low_level/v3.rs +++ b/esp-hal/src/gpio/lp_io/low_level/v3.rs @@ -1,102 +1,107 @@ use crate::{ - gpio::{AlternateFunction, LpPin, LpPinWithResistors, WakeEvent, lp_io::LpFunction}, + gpio::{AlternateFunction, LpPin, WakeEvent, lp_io::LpFunction}, peripherals::{GPIO, IO_MUX, LPWR}, }; for_each_lp_function! { (($_lp:ident, LP_GPIOn, $pin:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => { - paste::paste! { - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl LpPin for crate::peripherals::$gpio<'_> { - fn lp_number(&self) -> u8 { - $pin - } - - fn apply_wakeup(&self, wakeup: bool, level: WakeEvent) { - let gpio_wakeup = cfg_select! { - esp32c2 => LPWR::regs().cntl_gpio_wakeup(), - esp32c3 => LPWR::regs().gpio_wakeup(), - }; + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] + impl LpPin for crate::peripherals::$gpio<'_> { + fn lp_number(&self) -> u8 { + $pin + } + } + }; - gpio_wakeup.modify(|_, w| unsafe { - w.[]().bit(wakeup); - w.[]().bits(level as u8) - }); - } + // The wakeup and hold registers name a field per pad instead of indexing them, so these + // functions dispatch on the low-power number. + (LP_GPIOn $( (($_lp:ident, LP_GPIOn, $pin:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) ),*) => { + paste::paste! { + pub(crate) fn apply_wakeup(lp: u8, wakeup: bool, event: WakeEvent) { + let trigger = event as u8; - fn lp_pad_hold(&self, enable: bool) { - LPWR::regs() - .pad_hold() - .modify(|_, w| w.[]().bit(enable)); - } + let gpio_wakeup = cfg_select! { + esp32c2 => LPWR::regs().cntl_gpio_wakeup(), + esp32c3 => LPWR::regs().gpio_wakeup(), + }; - // The low-power domain reaches the pad through the digital IO MUX, so there is - // no low-power function to select. - fn lp_set_config(&self, input_enable: bool, _mux: bool, _func: LpFunction) { - IO_MUX::regs().gpio($pin) - .modify(|_, w| unsafe { - w.slp_sel().bit(false); - w.mcu_sel().bits(AlternateFunction::GPIO as u8); - w.fun_ie().bit(input_enable) - }); - } + gpio_wakeup.modify(|_, w| unsafe { + match lp { + $( + $pin => { + w.[]().bit(wakeup); + w.[]().bits(trigger) + } + )* + _ => unreachable!(), + } + }); } - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl LpPinWithResistors for crate::peripherals::$gpio<'_> { - fn lp_pullup(&self, enable: bool) { - pullup_enable($pin, enable) - } - - fn lp_pulldown(&self, enable: bool) { - pulldown_enable($pin, enable) - } + pub(crate) fn pad_hold(lp: u8, enable: bool) { + LPWR::regs().pad_hold().modify(|_, w| { + match lp { + $( $pin => w.[]().bit(enable), )* + _ => unreachable!(), + } + }); } } }; } +/// Configures the pad. +/// +/// The low-power domain reaches the pad through the digital IO MUX, so there is no low-power +/// function to select, and the low-power number is the digital pin number. +pub(crate) fn set_config(lp: u8, input_enable: bool, _mux: bool, _func: LpFunction) { + IO_MUX::regs().gpio(lp as usize).modify(|_, w| unsafe { + w.slp_sel().bit(false); + w.mcu_sel().bits(AlternateFunction::GPIO as u8); + w.fun_ie().bit(input_enable) + }); +} + #[expect(dead_code)] -pub(super) fn init_pin(pin: &impl LpPin, enable_input: bool) -> u8 { - let pin = pin.number(); - input_enable(pin, enable_input); - pin +pub(crate) fn init_pin(lp: u8, enable_input: bool) -> u8 { + input_enable(lp, enable_input); + lp } #[expect(dead_code)] -pub(super) fn output_enable(pin: u8, enable: bool) { +pub(crate) fn output_enable(lp: u8, enable: bool) { if enable { GPIO::regs() .enable_w1ts() - .write(|w| unsafe { w.enable_w1ts().bits(1 << pin) }); + .write(|w| unsafe { w.enable_w1ts().bits(1 << lp) }); } else { GPIO::regs() .enable_w1tc() - .write(|w| unsafe { w.enable_w1tc().bits(1 << pin) }); + .write(|w| unsafe { w.enable_w1tc().bits(1 << lp) }); } } -pub(super) fn input_enable(pin: u8, enable: bool) { +pub(crate) fn input_enable(lp: u8, enable: bool) { IO_MUX::regs() - .gpio(pin as usize) + .gpio(lp as usize) .modify(|_, w| w.fun_ie().bit(enable)); } -pub(super) fn pullup_enable(pin: u8, enable: bool) { +pub(crate) fn pullup_enable(lp: u8, enable: bool) { IO_MUX::regs() - .gpio(pin as usize) + .gpio(lp as usize) .modify(|_, w| w.fun_wpu().bit(enable)); } -pub(super) fn pulldown_enable(pin: u8, enable: bool) { +pub(crate) fn pulldown_enable(lp: u8, enable: bool) { IO_MUX::regs() - .gpio(pin as usize) + .gpio(lp as usize) .modify(|_, w| w.fun_wpd().bit(enable)); } #[expect(dead_code)] -pub(super) fn set_open_drain_output(pin: u8, enable: bool) { +pub(crate) fn set_open_drain_output(lp: u8, enable: bool) { GPIO::regs() - .pin(pin as usize) + .pin(lp as usize) .modify(|_, w| w.pad_driver().bit(enable)); } diff --git a/esp-hal/src/gpio/lp_io/low_level/v4.rs b/esp-hal/src/gpio/lp_io/low_level/v4.rs index ac601738470..5a275193ffa 100644 --- a/esp-hal/src/gpio/lp_io/low_level/v4.rs +++ b/esp-hal/src/gpio/lp_io/low_level/v4.rs @@ -1,5 +1,5 @@ use crate::{ - gpio::{LpPin, LpPinWithResistors, WakeEvent, lp_io::LpFunction}, + gpio::{LpPin, lp_io::LpFunction}, peripherals::LP_AON, }; @@ -8,7 +8,10 @@ cfg_select! { use crate::peripherals::{LP_IO as LP_GPIO, LP_IO as LP_IO_MUX}; } any(esp32c5, esp32c61) => { - use crate::peripherals::{LP_GPIO, LP_IO_MUX}; + // Only a low-power peripheral or core reads and drives the pads. + #[cfg(any(ulp_riscv_driver_supported, lp_io_has_gpio_matrix))] + use crate::peripherals::LP_GPIO; + use crate::peripherals::LP_IO_MUX; } } @@ -19,116 +22,94 @@ for_each_lp_function! { fn lp_number(&self) -> u8 { $pin } - - fn apply_wakeup(&self, wakeup: bool, level: WakeEvent) { - LP_GPIO::regs().pin($pin).modify(|_, w| unsafe { - w.wakeup_enable().bit(wakeup).int_type().bits(level as u8) - }); - } - - fn lp_pad_hold(&self, enable: bool) { - let mask = 1 << $pin; - LP_AON::regs() - .gpio_hold0() - .modify(|r, w| unsafe { - let bits = r.gpio_hold0().bits(); - w.gpio_hold0().bits(if enable { - bits | mask - } else { - bits & !mask - }) - }); - } - - fn lp_set_config(&self, input_enable: bool, mux: bool, func: LpFunction) { - let mask = 1 << $pin; - LP_AON::regs() - .gpio_mux() - .modify(|r, w| unsafe { - let bits = r.sel().bits(); - w.sel().bits(if mux { - bits | mask - } else { - bits & !mask - }) - }); - - LP_IO_MUX::regs().gpio($pin).modify(|_, w| unsafe { - w.slp_sel().bit(false); - w.fun_ie().bit(input_enable); - w.mcu_sel().bits(func as u8) - }); - } } + }; +} - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl LpPinWithResistors for crate::peripherals::$gpio<'_> { - fn lp_pullup(&self, enable: bool) { - pullup_enable($pin, enable); - } +pub(crate) fn pad_hold(lp: u8, enable: bool) { + let mask = 1 << lp; + LP_AON::regs().gpio_hold0().modify(|r, w| unsafe { + let bits = r.gpio_hold0().bits(); + w.gpio_hold0() + .bits(if enable { bits | mask } else { bits & !mask }) + }); +} - fn lp_pulldown(&self, enable: bool) { - pulldown_enable($pin, enable); - } - } - }; +pub(crate) fn set_config(lp: u8, input_enable: bool, mux: bool, func: LpFunction) { + let mask = 1 << lp; + LP_AON::regs().gpio_mux().modify(|r, w| unsafe { + let bits = r.sel().bits(); + w.sel().bits(if mux { bits | mask } else { bits & !mask }) + }); + + LP_IO_MUX::regs().gpio(lp as usize).modify(|_, w| unsafe { + w.slp_sel().bit(false); + w.fun_ie().bit(input_enable); + w.mcu_sel().bits(func as u8) + }); } #[cfg(any(ulp_riscv_driver_supported, lp_io_has_gpio_matrix))] -pub(super) fn init_pin(pin: &impl LpPin, input_enable: bool) -> u8 { - pin.lp_set_config(input_enable, true, LpFunction::LP_GPIO); - pin.number() +pub(crate) fn init_pin(lp: u8, input_enable: bool) -> u8 { + set_config(lp, input_enable, true, LpFunction::LP_GPIO); + lp } #[cfg(any(ulp_riscv_driver_supported, lp_io_has_gpio_matrix))] -pub(super) fn output_enable(pin: u8, enable: bool) { +pub(crate) fn output_enable(lp: u8, enable: bool) { if enable { LP_GPIO::regs() .out_enable_w1ts() - .write(|w| unsafe { w.enable_w1ts().bits(1 << pin) }); + .write(|w| unsafe { w.enable_w1ts().bits(1 << lp) }); } else { LP_GPIO::regs() .out_enable_w1tc() - .write(|w| unsafe { w.enable_w1tc().bits(1 << pin) }); + .write(|w| unsafe { w.enable_w1tc().bits(1 << lp) }); } } #[cfg(any(ulp_riscv_driver_supported, lp_io_has_gpio_matrix))] -pub(super) fn input_enable(pin: u8, enable: bool) { +pub(crate) fn input_enable(lp: u8, enable: bool) { LP_IO_MUX::regs() - .gpio(pin as usize) + .gpio(lp as usize) .modify(|_, w| w.fun_ie().bit(enable)); } -pub(super) fn pullup_enable(pin: u8, enable: bool) { +// A pad of these chips only needs its resistors set while a low-power core drives it: sleep uses +// ext1, which holds the pad instead. +#[cfg(any(ulp_riscv_driver_supported, lp_io_has_gpio_matrix))] +pub(crate) fn pullup_enable(lp: u8, enable: bool) { LP_IO_MUX::regs() - .gpio(pin as usize) + .gpio(lp as usize) .modify(|_, w| w.fun_wpu().bit(enable)); } -pub(super) fn pulldown_enable(pin: u8, enable: bool) { +#[cfg(any(ulp_riscv_driver_supported, lp_io_has_gpio_matrix))] +pub(crate) fn pulldown_enable(lp: u8, enable: bool) { LP_IO_MUX::regs() - .gpio(pin as usize) + .gpio(lp as usize) .modify(|_, w| w.fun_wpd().bit(enable)); } +// The pad driver bit lives in the low-power GPIO peripheral on these chips, so this takes the +// low-power number like its neighbours. #[cfg(any(ulp_riscv_driver_supported, lp_io_has_gpio_matrix))] -pub(super) fn set_open_drain_output(pin: u8, enable: bool) { +pub(crate) fn set_open_drain_output(lp: u8, enable: bool) { LP_GPIO::regs() - .pin(pin as usize) + .pin(lp as usize) .modify(|_, w| w.pad_driver().bit(enable)); } #[cfg(lp_i2c_master_driver_supported)] -pub(crate) fn reset_pin(pin: u8) { - output_enable(pin, false); - set_open_drain_output(pin, false); +pub(crate) fn reset_pin(lp: u8) { + output_enable(lp, false); + set_open_drain_output(lp, false); // Resistors, input enable and the pad's LP function all live in this register. - LP_IO_MUX::regs().gpio(pin as usize).reset(); + LP_IO_MUX::regs().gpio(lp as usize).reset(); // Hand the pad back to the digital IO MUX. LP_AON::regs() .gpio_mux() - .modify(|r, w| unsafe { w.sel().bits(r.sel().bits() & !(1 << pin)) }); + .modify(|r, w| unsafe { w.sel().bits(r.sel().bits() & !(1 << lp)) }); } diff --git a/esp-hal/src/gpio/lp_io/mod.rs b/esp-hal/src/gpio/lp_io/mod.rs index 46654262f0e..2cd66bc053f 100644 --- a/esp-hal/src/gpio/lp_io/mod.rs +++ b/esp-hal/src/gpio/lp_io/mod.rs @@ -73,7 +73,7 @@ define_lp_functions!(); #[cfg_attr(lp_io_version = "esp32h2", path = "low_level/esp32h2.rs")] #[cfg_attr(lp_io_version = "esp32p4", path = "low_level/esp32p4.rs")] #[cfg_attr(lp_io_version = "v4", path = "low_level/v4.rs")] -mod low_level; +pub(crate) mod low_level; /// Trait implemented by pins with a known low-power pin number. #[cfg(ulp_riscv_driver_supported)] @@ -96,7 +96,7 @@ pub(crate) fn connect_open_drain_signals( input: LpInputSignal, output: LpOutputSignal, ) { - let lp_pin = low_level::init_pin(pin, true); + let lp_pin = low_level::init_pin(pin.lp_number(), true); low_level::set_open_drain_output(pin.number(), true); low_level::input_enable(lp_pin, true); low_level::pullup_enable(lp_pin, true); @@ -117,20 +117,19 @@ pub(crate) use low_level::reset_pin; /// Configures an LP pin as an input and routes an LP peripheral's input signal to it. #[cfg(all(lp_io_has_gpio_matrix, lp_uart_driver_supported))] pub(crate) fn connect_input_signal(pin: &(impl LpPin + InputPin), input: LpInputSignal) { - let mux_af = pin - .lp_input_signals() + let lp_pin = pin.lp_number(); + + let mux_af = low_level::input_signals(lp_pin) .iter() .find(|(_, signal)| *signal == input) .map(|(af, _)| *af); - let lp_pin = match mux_af { - Some(af) => { - let lp_pin = pin.lp_number(); - pin.lp_set_config(true, true, af); - lp_pin + match mux_af { + Some(af) => low_level::set_config(lp_pin, true, true, af), + None => { + low_level::init_pin(lp_pin, true); } - None => low_level::init_pin(pin, true), - }; + } low_level::input_enable(lp_pin, true); route_input(lp_pin, input, mux_af.is_none()); @@ -139,18 +138,17 @@ pub(crate) fn connect_input_signal(pin: &(impl LpPin + InputPin), input: LpInput /// Configures an LP pin as an output and routes an LP peripheral's output signal to it. #[cfg(all(lp_io_has_gpio_matrix, lp_uart_driver_supported))] pub(crate) fn connect_output_signal(pin: &(impl LpPin + OutputPin), output: LpOutputSignal) { - let mux_af = pin - .lp_output_signals() + let lp_pin = pin.lp_number(); + + let mux_af = low_level::output_signals(lp_pin) .iter() .find(|(_, signal)| *signal == output) .map(|(af, _)| *af); match mux_af { - Some(af) => { - pin.lp_set_config(false, true, af); - } + Some(af) => low_level::set_config(lp_pin, false, true, af), None => { - let lp_pin = low_level::init_pin(pin, false); + low_level::init_pin(lp_pin, false); route_output(lp_pin, output); } } @@ -275,12 +273,13 @@ mod ulp_tokens { Self::new_untyped(pin) } - pub(super) fn new_untyped

(pin: P) -> Self + /// Takes a pad that the caller has checked to be the low-power pin numbered `PIN`. + pub(super) fn new_untyped

(_pin: P) -> Self where - P: LpPin + OutputPin + 'd, + P: Pin + 'd, { - let lp_pin = low_level::init_pin(&pin, false); - low_level::output_enable(lp_pin, true); + low_level::init_pin(PIN, false); + low_level::output_enable(PIN, true); Self { phantom: PhantomData, @@ -304,14 +303,15 @@ mod ulp_tokens { Self::new_untyped(pin) } - pub(super) fn new_untyped

(pin: P) -> Self + /// Takes a pad that the caller has checked to be the low-power pin numbered `PIN`. + pub(super) fn new_untyped

(_pin: P) -> Self where - P: LpPin + InputPin + 'd, + P: Pin + 'd, { - let lp_pin = low_level::init_pin(&pin, true); - low_level::input_enable(lp_pin, true); - low_level::pullup_enable(lp_pin, false); - low_level::pulldown_enable(lp_pin, false); + low_level::init_pin(PIN, true); + low_level::input_enable(PIN, true); + low_level::pullup_enable(PIN, false); + low_level::pulldown_enable(PIN, false); Self { phantom: PhantomData, @@ -345,17 +345,18 @@ mod ulp_tokens { Self::new_untyped(pin) } + /// Takes a pad that the caller has checked to be the low-power pin numbered `PIN`. pub(super) fn new_untyped

(pin: P) -> Self where - P: LpPin + InputPin + OutputPin + 'd, + P: Pin + 'd, { let gpio = pin.number(); - let lp_pin = low_level::init_pin(&pin, true); + low_level::init_pin(PIN, true); low_level::set_open_drain_output(gpio, true); - low_level::input_enable(lp_pin, true); - low_level::pullup_enable(lp_pin, true); - low_level::pulldown_enable(lp_pin, false); - low_level::output_enable(lp_pin, true); + low_level::input_enable(PIN, true); + low_level::pullup_enable(PIN, true); + low_level::pulldown_enable(PIN, false); + low_level::output_enable(PIN, true); Self { phantom: PhantomData, diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 316a6e775ee..3a3021e50a6 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -356,52 +356,17 @@ impl TryFrom for AlternateFunction { } } -/// Trait implemented by low-power pins +/// Trait implemented by the pins that the low-power domain can reach. +/// +/// The low-power domain numbers these pads on its own, and the number is what the low-power +/// registers take. Only some chips give the same pad the same number in both domains, so keep the +/// two apart: pass [`Self::lp_number`] to the low-power registers, and [`Pin::number`] to the +/// digital ones. #[instability::unstable] #[cfg(lp_io_driver_supported)] pub trait LpPin: Pin { /// LP number of the pin fn lp_number(&self) -> u8; - - /// Enables or disables the input path in the low-power domain, selects whether the pad belongs - /// to the low-power domain (`mux` is `true`) or to the digital GPIO peripheral, and selects the - /// pad's low-power function. - /// - /// `func` has no effect while the pad belongs to the digital GPIO peripheral. - #[doc(hidden)] - fn lp_set_config(&self, input_enable: bool, mux: bool, func: lp_io::LpFunction); - - /// Enable or disable PAD_HOLD - #[doc(hidden)] - fn lp_pad_hold(&self, enable: bool); - - /// Enables or disables waking up the chip when the pad reaches `level`. - #[doc(hidden)] - fn apply_wakeup(&self, wakeup: bool, level: WakeEvent); - - /// LP IO MUX functions on this pad that carry LP peripheral input signals. - #[cfg(lp_io_has_gpio_matrix)] - #[doc(hidden)] - fn lp_input_signals(&self) -> &'static [(lp_io::LpFunction, lp_io::LpInputSignal)]; - - /// LP IO MUX functions on this pad that carry LP peripheral output signals. - #[cfg(lp_io_has_gpio_matrix)] - #[doc(hidden)] - fn lp_output_signals(&self) -> &'static [(lp_io::LpFunction, lp_io::LpOutputSignal)]; -} - -/// Trait implemented by low-power pins which support internal pull-up / pull-down -/// resistors. -#[instability::unstable] -#[cfg(lp_io_driver_supported)] -pub trait LpPinWithResistors: LpPin { - /// Enable/disable the internal pull-up resistor - #[doc(hidden)] - fn lp_pullup(&self, enable: bool); - - /// Enable/disable the internal pull-down resistor - #[doc(hidden)] - fn lp_pulldown(&self, enable: bool); } /// Common trait implemented by pins @@ -1674,9 +1639,9 @@ impl<'lt> AnyPin<'lt> { #[cfg(lp_io_driver_supported)] for_each_lp_function! { - (($_signal:ident, LP_GPIOn, $_lp_pin:literal), $gpio:ident, $af:ident, $_lp_in:tt $_lp_out:tt) => { + (($_signal:ident, LP_GPIOn, $lp_pin:literal), $gpio:ident, $af:ident, $_lp_in:tt $_lp_out:tt) => { if self.number() == crate::peripherals::$gpio::NUMBER { - LpPin::lp_set_config(self, false, false, lp_io::LpFunction::$af); + lp_io::low_level::set_config($lp_pin, false, false, lp_io::LpFunction::$af); } }; } @@ -2161,117 +2126,6 @@ impl AnyPin<'_> { } } -#[cold] -#[allow(unused)] -fn pin_does_not_support_function(pin: u8, function: &str) { - panic!("Pin {} is not an {}", pin, function) -} - -#[cfg(lp_io_driver_supported)] -macro_rules! for_each_lp_pin { - (@impl $ident:ident, $target:ident, $gpio:ident, $code:tt) => { - if $ident.number() == $crate::peripherals::$gpio::NUMBER { - #[allow(unused_mut)] - let mut $target = unsafe { $crate::peripherals::$gpio::steal() }; - return $code; - } - }; - - (($ident:ident, $target:ident) => $code:tt;) => { - for_each_lp_function! { - (($_sig:ident, LP_GPIOn, $_n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => { - for_each_lp_pin!(@impl $ident, $target, $gpio, $code) - }; - } - unreachable!(); - }; -} - -#[cfg(lp_io_driver_supported)] -macro_rules! for_each_lp_output_pin { - (@impl $ident:ident, $target:ident, $gpio:ident, $code:tt, $kind:literal) => { - if $ident.number() == $crate::peripherals::$gpio::NUMBER { - for_each_gpio! { - // If the pin is an output pin, generate $code - ($n:tt, $gpio $in_afs:tt $out_afs:tt ($input:tt [Output])) => { - #[allow(unused_mut)] - let mut $target = unsafe { $crate::peripherals::$gpio::steal() }; - return $code; - }; - // If the pin is not an output pin, generate a panic - ($n:tt, $gpio $in_afs:tt $out_afs:tt ($input:tt [])) => { - pin_does_not_support_function($crate::peripherals::$gpio::NUMBER, $kind) - }; - } - } - }; - - (($ident:ident, $target:ident) => $code:tt;) => { - for_each_lp_function! { - (($_sig:ident, LP_GPIOn, $_n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => { - for_each_lp_output_pin!(@impl $ident, $target, $gpio, $code, "LP_IO output") - }; - } - unreachable!(); - }; -} - -#[cfg(lp_io_driver_supported)] -impl LpPin for AnyPin<'_> { - fn lp_number(&self) -> u8 { - for_each_lp_pin! { - (self, target) => { LpPin::lp_number(&target) }; - } - } - - fn lp_set_config(&self, input_enable: bool, mux: bool, func: lp_io::LpFunction) { - for_each_lp_pin! { - (self, target) => { LpPin::lp_set_config(&target, input_enable, mux, func) }; - } - } - - fn lp_pad_hold(&self, enable: bool) { - for_each_lp_pin! { - (self, target) => { LpPin::lp_pad_hold(&target, enable) }; - } - } - - fn apply_wakeup(&self, wakeup: bool, level: WakeEvent) { - for_each_lp_pin! { - (self, target) => { LpPin::apply_wakeup(&target, wakeup, level) }; - } - } - - #[cfg(lp_io_has_gpio_matrix)] - fn lp_input_signals(&self) -> &'static [(lp_io::LpFunction, lp_io::LpInputSignal)] { - for_each_lp_pin! { - (self, target) => { LpPin::lp_input_signals(&target) }; - } - } - - #[cfg(lp_io_has_gpio_matrix)] - fn lp_output_signals(&self) -> &'static [(lp_io::LpFunction, lp_io::LpOutputSignal)] { - for_each_lp_pin! { - (self, target) => { LpPin::lp_output_signals(&target) }; - } - } -} - -#[cfg(lp_io_driver_supported)] -impl LpPinWithResistors for AnyPin<'_> { - fn lp_pullup(&self, enable: bool) { - for_each_lp_output_pin! { - (self, target) => { LpPinWithResistors::lp_pullup(&target, enable) }; - } - } - - fn lp_pulldown(&self, enable: bool) { - for_each_lp_output_pin! { - (self, target) => { LpPinWithResistors::lp_pulldown(&target, enable) }; - } - } -} - for_each_gpio! { ($n:literal, $gpio:ident $af_ins:tt $af_outs:tt ([Input] $output:tt)) => { impl InputPin for crate::peripherals::$gpio<'_> { diff --git a/esp-hal/src/i2c/lp_i2c/lp_i2c.rs b/esp-hal/src/i2c/lp_i2c/lp_i2c.rs index 539fcb51e45..cb6f2a62566 100644 --- a/esp-hal/src/i2c/lp_i2c/lp_i2c.rs +++ b/esp-hal/src/i2c/lp_i2c/lp_i2c.rs @@ -168,7 +168,7 @@ fn configure_pad(pin: &impl LpPin, function: LpFunction) { }); } - pin.lp_set_config(true, true, function); + crate::gpio::lp_io::low_level::set_config(ionum as u8, true, true, function); } impl<'d> LpI2c<'d> { diff --git a/esp-hal/src/i2c/lp_i2c/rtc_i2c.rs b/esp-hal/src/i2c/lp_i2c/rtc_i2c.rs index 7aa082a96f2..02a8a2a9e86 100644 --- a/esp-hal/src/i2c/lp_i2c/rtc_i2c.rs +++ b/esp-hal/src/i2c/lp_i2c/rtc_i2c.rs @@ -4,23 +4,28 @@ //! address. use crate::{ - gpio::{LpPin, lp_io::LpFunction}, + gpio::{ + LpPin, + lp_io::{LpFunction, low_level}, + }, i2c::lp_i2c::{Error, LpI2c, Scl, Sda}, peripherals::{GPIO, RTC_IO, SENS}, time::Duration, }; fn bind_pin(pin: &impl LpPin, function: LpFunction) { + let lp = pin.lp_number(); + GPIO::regs() .pin(pin.number() as usize) .modify(|_, w| w.pad_driver().bit(true)); RTC_IO::regs() - .touch_pad(pin.number() as usize) + .touch_pad(lp as usize) .modify(|_, w| w.rue().bit(true).rde().bit(false)); RTC_IO::regs() .rtc_gpio_enable_w1ts() - .write(|w| unsafe { w.rtc_gpio_enable_w1ts().bits(1 << pin.number()) }); - pin.lp_set_config(true, true, function); + .write(|w| unsafe { w.rtc_gpio_enable_w1ts().bits(1 << lp) }); + low_level::set_config(lp, true, true, function); } for_each_lp_function! { diff --git a/esp-hal/src/rtc_cntl/sleep/mod.rs b/esp-hal/src/rtc_cntl/sleep/mod.rs index 8b806b0ddc7..559c28dcfdc 100644 --- a/esp-hal/src/rtc_cntl/sleep/mod.rs +++ b/esp-hal/src/rtc_cntl/sleep/mod.rs @@ -16,20 +16,15 @@ use enumset::EnumSet; +#[cfg(any( + esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32p4 +))] +use crate::gpio::LpPin as RtcIoWakeupPinType; use crate::{ peripherals::LPWR, rtc_cntl::{Rtc, WakeupSource}, }; -cfg_select! { - any(esp32, esp32s2, esp32s3) => { - use crate::gpio::LpPin as RtcIoWakeupPinType; - } - any(esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32p4) => { - use crate::gpio::LpPinWithResistors as RtcIoWakeupPinType; - } -} - #[cfg(soc_has_pmu)] mod pmu_common; diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext0.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext0.rs index 093a9b0439a..ae9f084150b 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext0.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext0.rs @@ -1,7 +1,10 @@ use core::cell::RefCell; use crate::{ - gpio::{Level, lp_io::LpFunction}, + gpio::{ + Level, + lp_io::{LpFunction, low_level}, + }, peripherals::{LPWR, RTC_IO}, rtc_cntl::{ Rtc, @@ -73,9 +76,12 @@ impl WakeSource for Ext0WakeupSource

{ triggers.insert(WakeupSource::Ext0); // set pin to RTC function - self.pin - .borrow_mut() - .lp_set_config(true, true, LpFunction::LP_GPIO); + low_level::set_config( + self.pin.borrow().lp_number(), + true, + true, + LpFunction::LP_GPIO, + ); unsafe { // set pin register field @@ -95,8 +101,11 @@ impl Drop for Ext0WakeupSource

{ // should we have saved the pin configuration first? // set pin back to IO_MUX (input_enable and func have no effect when pin is sent // to IO_MUX) - self.pin - .borrow_mut() - .lp_set_config(true, false, LpFunction::LP_GPIO); + low_level::set_config( + self.pin.borrow().lp_number(), + true, + false, + LpFunction::LP_GPIO, + ); } } diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/esp32p4.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/esp32p4.rs index 4a3df08970f..91fa65dd5a9 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/esp32p4.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/esp32p4.rs @@ -1,5 +1,9 @@ use crate::{ - gpio::{Level, LpPin, lp_io::LpFunction}, + gpio::{ + Level, + LpPin, + lp_io::{LpFunction, low_level}, + }, peripherals::PMU, rtc_cntl::{ Rtc, @@ -19,8 +23,8 @@ impl Ext1WakeupSource<'_, '_> { pub(in crate::rtc_cntl::sleep) fn wake_io_reset() { fn uninit_pin(pin: impl LpPin, wakeup_pins: u32) { if wakeup_pins & (1 << pin.number()) != 0 { - pin.lp_pad_hold(false); - pin.lp_set_config(false, false, LpFunction::LP_GPIO); + low_level::pad_hold(pin.lp_number(), false); + low_level::set_config(pin.lp_number(), false, false, LpFunction::LP_GPIO); } } @@ -53,8 +57,8 @@ impl WakeSource for Ext1WakeupSource<'_, '_> { Level::Low => 0, }; - pin.lp_set_config(true, true, LpFunction::LP_GPIO); - pin.lp_pad_hold(true); + low_level::set_config(pin.lp_number(), true, true, LpFunction::LP_GPIO); + low_level::pad_hold(pin.lp_number(), true); } PMU::regs() @@ -77,7 +81,7 @@ impl Drop for Ext1WakeupSource<'_, '_> { fn drop(&mut self) { let mut pins = self.pins.borrow_mut(); for (pin, _level) in pins.iter_mut() { - pin.lp_set_config(true, false, LpFunction::LP_GPIO); + low_level::set_config(pin.lp_number(), true, false, LpFunction::LP_GPIO); } } } diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/mod.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/mod.rs index 2cdb6f5dba8..97d3b2bd586 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/mod.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/mod.rs @@ -23,7 +23,7 @@ mod implementation; /// # use esp_hal::delay::Delay; /// # use esp_hal::rtc_cntl::{reset_reason, sleep::{Ext1WakeupSource, LowPower, TimerWakeupSource}, wakeup_cause, SocResetReason}; /// # use esp_hal::system::Cpu; -/// # use esp_hal::gpio::{Input, InputConfig, Level, Pull, LpPinWithResistors}; +/// # use esp_hal::gpio::{Input, InputConfig, Level, Pull, LpPin}; /// # use esp_hal::time::Duration; /// # /// let delay = Delay::new(); @@ -41,7 +41,7 @@ mod implementation; /// /// core::mem::drop(pin_low_input); /// -/// let wakeup_pins: &mut [(&mut dyn LpPinWithResistors, Level)] = +/// let wakeup_pins: &mut [(&mut dyn LpPin, Level)] = /// &mut [ /// (&mut peripherals.__pin_low__, Level::Low), /// (&mut peripherals.__pin_high__, Level::High), diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v1.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v1.rs index 69c599bc642..7efd48e739c 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v1.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v1.rs @@ -1,5 +1,8 @@ use crate::{ - gpio::{Level, lp_io::LpFunction}, + gpio::{ + Level, + lp_io::{LpFunction, low_level}, + }, peripherals::LPWR, rtc_cntl::{ Rtc, @@ -23,9 +26,11 @@ impl WakeSource for Ext1WakeupSource<'_, '_> { let mut pins = self.pins.borrow_mut(); let mut bits = 0u32; for pin in pins.iter_mut() { - pin.lp_set_config(true, true, LpFunction::LP_GPIO); - pin.lp_pad_hold(true); - bits |= 1 << pin.lp_number(); + let lp_pin = pin.lp_number(); + + low_level::set_config(lp_pin, true, true, LpFunction::LP_GPIO); + low_level::pad_hold(lp_pin, true); + bits |= 1 << lp_pin; } LPWR::regs() @@ -45,7 +50,7 @@ impl Drop for Ext1WakeupSource<'_, '_> { fn drop(&mut self) { let mut pins = self.pins.borrow_mut(); for pin in pins.iter_mut() { - pin.lp_set_config(true, false, LpFunction::LP_GPIO); + low_level::set_config(pin.lp_number(), true, false, LpFunction::LP_GPIO); } } } diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v2.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v2.rs index b212c2e3beb..7818eb003c0 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v2.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/ext1/v2.rs @@ -1,5 +1,9 @@ use crate::{ - gpio::{Level, LpPin, lp_io::LpFunction}, + gpio::{ + Level, + LpPin, + lp_io::{LpFunction, low_level}, + }, peripherals::LP_AON, rtc_cntl::{ Rtc, @@ -25,10 +29,10 @@ impl Ext1WakeupSource<'_, '_> { let pin_number = pin.lp_number(); if wakeup_pins & (1 << pin_number) != 0 { - pin.lp_pad_hold(false); + low_level::pad_hold(pin_number, false); cfg_select! { esp32h2 => pin.degrade().init_gpio(), - _ => pin.lp_set_config(false, false, LpFunction::LP_GPIO), + _ => low_level::set_config(pin_number, false, false, LpFunction::LP_GPIO), } } } @@ -63,8 +67,8 @@ impl WakeSource for Ext1WakeupSource<'_, '_> { Level::Low => 0, }; - pin.lp_set_config(true, !cfg!(esp32h2), LpFunction::LP_GPIO); - pin.lp_pad_hold(true); + low_level::set_config(pin_number, true, !cfg!(esp32h2), LpFunction::LP_GPIO); + low_level::pad_hold(pin_number, true); } LP_AON::regs() @@ -84,10 +88,12 @@ impl Drop for Ext1WakeupSource<'_, '_> { fn drop(&mut self) { let mut pins = self.pins.borrow_mut(); for (pin, _level) in pins.iter_mut() { + let pin_number = pin.lp_number(); + if cfg!(esp32h2) { - pin.lp_pad_hold(false); + low_level::pad_hold(pin_number, false); } - pin.lp_set_config(true, false, LpFunction::LP_GPIO); + low_level::set_config(pin_number, true, false, LpFunction::LP_GPIO); } } } diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/c2c3.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/c2c3.rs index ad093c4080a..7b2a7f08876 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/c2c3.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/c2c3.rs @@ -1,29 +1,31 @@ use super::RtcioWakeupSource; use crate::{ - gpio::{AlternateFunction, Level, LpPinWithResistors, OutputSignal, WakeEvent}, + gpio::{AlternateFunction, Level, LpPin, OutputSignal, WakeEvent, lp_io::low_level}, peripherals::{GPIO, IO_MUX, LPWR}, rtc_cntl::{Rtc, RtcSleepConfig, WakeSource, WakeTriggers, WakeupSource}, }; impl RtcioWakeupSource<'_, '_> { - fn apply_pin(&self, pin: &mut dyn LpPinWithResistors, level: Level) { + fn apply_pin(&self, pin: &mut dyn LpPin, level: Level) { + let lp_pin = pin.lp_number(); + // The pullup/pulldown part is like in gpio_deep_sleep_wakeup_prepare let level = match level { Level::High => { - pin.lp_pullup(false); - pin.lp_pulldown(true); + low_level::pullup_enable(lp_pin, false); + low_level::pulldown_enable(lp_pin, true); WakeEvent::HighLevel } Level::Low => { - pin.lp_pullup(true); - pin.lp_pulldown(false); + low_level::pullup_enable(lp_pin, true); + low_level::pulldown_enable(lp_pin, false); WakeEvent::LowLevel } }; - pin.lp_pad_hold(true); + low_level::pad_hold(lp_pin, true); // apply_wakeup does the same as idf's esp_deep_sleep_enable_gpio_wakeup - pin.apply_wakeup(true, level); + low_level::apply_wakeup(lp_pin, true, level); } } diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/mod.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/mod.rs index 44db2928042..8bfad58249f 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/mod.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/mod.rs @@ -11,10 +11,6 @@ use crate::{gpio::Level, rtc_cntl::sleep::RtcIoWakeupPinType}; cfg(any(esp32c3, esp32c2)) => "GPIO3", cfg(any(esp32s2, esp32s3)) => "GPIO18" }, - "rtc_pin_trait" => { - cfg(any(esp32c3, esp32c2)) => "gpio::LpPinWithResistors", - cfg(any(esp32s2, esp32s3)) => "gpio::LpPin" - }, )] /// RTC_IO wakeup source /// @@ -42,7 +38,7 @@ use crate::{gpio::Level, rtc_cntl::sleep::RtcIoWakeupPinType}; /// /// let delay = Delay::new(); /// let timer = TimerWakeupSource::new(Duration::from_secs(10)); -/// let wakeup_pins: &mut [(&mut dyn __rtc_pin_trait__, Level)] = &mut [ +/// let wakeup_pins: &mut [(&mut dyn gpio::LpPin, Level)] = &mut [ /// (&mut peripherals.__pin0__, Level::Low), /// (&mut peripherals.__pin1__, Level::High), /// ]; diff --git a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/s2s3.rs b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/s2s3.rs index c62b3095743..59acefa2a95 100644 --- a/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/s2s3.rs +++ b/esp-hal/src/rtc_cntl/sleep/wakeup_sources/rtcio/s2s3.rs @@ -1,14 +1,22 @@ use super::RtcioWakeupSource; use crate::{ - gpio::{Level, LpPin, WakeEvent, lp_io::LpFunction}, + gpio::{ + Level, + LpPin, + WakeEvent, + lp_io::{LpFunction, low_level}, + }, rtc_cntl::{Rtc, RtcSleepConfig, WakeSource, WakeTriggers, WakeupSource}, }; impl RtcioWakeupSource<'_, '_> { fn apply_pin(&self, pin: &mut dyn LpPin, level: Level) { - pin.lp_set_config(true, true, LpFunction::LP_GPIO); + let lp_pin = pin.lp_number(); - pin.apply_wakeup( + low_level::set_config(lp_pin, true, true, LpFunction::LP_GPIO); + + low_level::apply_wakeup( + lp_pin, true, match level { Level::Low => WakeEvent::LowLevel, @@ -63,7 +71,7 @@ impl Drop for RtcioWakeupSource<'_, '_> { // to IO_MUX) let mut pins = self.pins.borrow_mut(); for (pin, _level) in pins.iter_mut() { - pin.lp_set_config(true, false, LpFunction::LP_GPIO); + low_level::set_config(pin.lp_number(), true, false, LpFunction::LP_GPIO); } } } diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index bff77ac90c4..b2d31afc67b 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -109,14 +109,15 @@ macro_rules! touch { impl $crate::gpio::TouchPin for $crate::peripherals::$pin_peri<'_> { fn set_touch(&self, _: $crate::private::Internal) { use $crate::peripherals::{GPIO, RTC_IO, SENS}; - use $crate::gpio::LpPin; + use $crate::gpio::{LpPin, Pin}; let gpio = GPIO::regs(); let rtcio = RTC_IO::regs(); let sens = SENS::regs(); - // Pad to normal mode (not open-drain) - gpio.pin(self.lp_number() as usize).write(|w| w.pad_driver().clear_bit()); + // Pad to normal mode (not open-drain). This register belongs to the digital GPIO + // peripheral, which numbers the pad differently. + gpio.pin(self.number() as usize).write(|w| w.pad_driver().clear_bit()); // clear output rtcio diff --git a/esp-hal/src/uart/lp_uart.rs b/esp-hal/src/uart/lp_uart.rs index dc521e06689..a7220e547d3 100644 --- a/esp-hal/src/uart/lp_uart.rs +++ b/esp-hal/src/uart/lp_uart.rs @@ -1,7 +1,12 @@ //! Low-power UART use crate::{ - gpio::{InputPin, LpPin, OutputPin, lp_io::LpFunction}, + gpio::{ + InputPin, + LpPin, + OutputPin, + lp_io::{LpFunction, low_level}, + }, peripherals::{LP_CLKRST, LP_UART, LPWR}, uart::{DataBits, Parity, StopBits}, }; @@ -50,14 +55,14 @@ for_each_lp_function! { fn connect_tx(&self) { // The output enable is left to the peripheral: selecting a function other than // LP GPIO takes the pad's direction out of the LP GPIO peripheral's hands. - self.lp_set_config(false, true, LpFunction::$af); + low_level::set_config(self.lp_number(), false, true, LpFunction::$af); } } }; (LP_UART_RXD, $gpio:ident, $af:ident) => { impl Rx for crate::peripherals::$gpio<'_> { fn connect_rx(&self) { - self.lp_set_config(true, true, LpFunction::$af); + low_level::set_config(self.lp_number(), true, true, LpFunction::$af); } } }; diff --git a/qa-test/src/bin/sleep_timer_lpio.rs b/qa-test/src/bin/sleep_timer_lpio.rs index 1c5a46e3a92..07be3d7e42d 100644 --- a/qa-test/src/bin/sleep_timer_lpio.rs +++ b/qa-test/src/bin/sleep_timer_lpio.rs @@ -16,7 +16,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::{Level, LpPinWithResistors}, + gpio::{Level, LpPin}, main, rtc_cntl::{ SocResetReason, @@ -63,7 +63,7 @@ fn main() -> ! { let delay = Delay::new(); let timer = TimerWakeupSource::new(Duration::from_secs(10)); - let wakeup_pins: &mut [(&mut dyn LpPinWithResistors, Level)] = + let wakeup_pins: &mut [(&mut dyn LpPin, Level)] = &mut [(&mut pin_low, Level::Low), (&mut pin_high, Level::High)]; let rtcio = Ext1WakeupSource::new(wakeup_pins); diff --git a/qa-test/src/bin/sleep_timer_rtcio.rs b/qa-test/src/bin/sleep_timer_rtcio.rs index bf23084fec7..6d5e1a7baa5 100644 --- a/qa-test/src/bin/sleep_timer_rtcio.rs +++ b/qa-test/src/bin/sleep_timer_rtcio.rs @@ -54,7 +54,7 @@ fn main() -> ! { let mut pin3 = peripherals.GPIO3; let _pin2_input = Input::new(pin2.reborrow(), config); - let wakeup_pins: &mut [(&mut dyn gpio::LpPinWithResistors, Level)] = + let wakeup_pins: &mut [(&mut dyn gpio::LpPin, Level)] = &mut [(&mut pin2, Level::Low), (&mut pin3, Level::High)]; } any(feature = "esp32s2", feature = "esp32s3") => {