From fd9f7895f6deea2c0518ba25f070be56707188f8 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Fri, 5 Apr 2024 12:33:49 +0000 Subject: [PATCH] Extract inner modules of `gpio` module into their own files (#1397) * Extract inner modules of `gpio` module into their own files * Update `CHANGELOG.md` * Add missing doc comment in `gpio::lp_io` module --------- Co-authored-by: Scott Mabin --- esp-hal-procmacros/src/lib.rs | 2 +- esp-hal/CHANGELOG.md | 1 + esp-hal/src/gpio/etm.rs | 322 +++++++++++ esp-hal/src/gpio/lp_io.rs | 250 +++++++++ esp-hal/src/{gpio.rs => gpio/mod.rs} | 781 +-------------------------- esp-hal/src/gpio/rtc_io.rs | 185 +++++++ esp-hal/src/i2c.rs | 2 +- esp-hal/src/soc/esp32c6/gpio.rs | 2 +- esp-hal/src/soc/esp32p4/gpio.rs | 2 +- esp-hal/src/uart.rs | 2 +- examples/src/bin/lp_core_basic.rs | 2 +- examples/src/bin/lp_core_i2c.rs | 2 +- examples/src/bin/lp_core_uart.rs | 2 +- 13 files changed, 773 insertions(+), 782 deletions(-) create mode 100644 esp-hal/src/gpio/etm.rs create mode 100644 esp-hal/src/gpio/lp_io.rs rename esp-hal/src/{gpio.rs => gpio/mod.rs} (75%) create mode 100644 esp-hal/src/gpio/rtc_io.rs diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index 0f010570bb0..ab14c8da486 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -620,7 +620,7 @@ pub fn load_lp_code(input: TokenStream) -> TokenStream { let imports = quote! { use #hal_crate::lp_core::LpCore; use #hal_crate::lp_core::LpCoreWakeupSource; - use #hal_crate::gpio::lp_gpio::LowPowerPin; + use #hal_crate::gpio::lp_io::LowPowerPin; use #hal_crate::gpio::*; use #hal_crate::uart::lp_uart::LpUart; use #hal_crate::i2c::lp_i2c::LpI2c; diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index eeaf1c1a742..049cfaaea46 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -54,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `UsbSerialJtag` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument (#1377) - SYSTIMER and TIMG instances can now be created in async or blocking mode (#1348) - Runtime ISR binding for TWAI (#1384) +- ESP32-C6: The `gpio::lp_gpio` module has been renamed to `gpio::lp_io` to match the peripheral name (#1397) - Runtime ISR binding for assist_debug (#1395) - Runtime ISR binding for software interrupts, software interrupts are split now, interrupt-executor takes the software interrupt to use, interrupt-executor is easier to use (#1398) diff --git a/esp-hal/src/gpio/etm.rs b/esp-hal/src/gpio/etm.rs new file mode 100644 index 00000000000..853bab09b0c --- /dev/null +++ b/esp-hal/src/gpio/etm.rs @@ -0,0 +1,322 @@ +//! # Event Task Matrix Function +//! +//! ## Overview +//! +//! GPIO supports ETM function, that is, the ETM task of GPIO can be +//! triggered by the ETM event of any peripheral, or the ETM task of any +//! peripheral can be triggered by the ETM event of GPIO. +//! +//! The GPIO ETM provides eight task channels. The ETM tasks that each task +//! channel can receive are: +//! - SET: GPIO goes high when triggered +//! - CLEAR: GPIO goes low when triggered +//! - TOGGLE: GPIO toggle level when triggered. +//! +//! GPIO has eight event channels, and the ETM events that each event +//! channel can generate are: +//! - RISE_EDGE: Indicates that the output signal of the corresponding GPIO has +//! a rising edge +//! - FALL_EDGE: Indicates that the output signal of the corresponding GPIO has +//! a falling edge +//! - ANY_EDGE: Indicates that the output signal of the corresponding GPIO is +//! reversed +//! +//! ## Example +//! ```no_run +//! let led_task = gpio_ext.channel0_task.toggle(&mut led); +//! let button_event = gpio_ext.channel0_event.falling_edge(button); +//! ``` + +use crate::peripheral::{Peripheral, PeripheralRef}; + +/// All the GPIO ETM channels +#[non_exhaustive] +pub struct GpioEtmChannels<'d> { + _gpio_sd: PeripheralRef<'d, crate::peripherals::GPIO_SD>, + pub channel0_task: GpioEtmTaskChannel<0>, + pub channel0_event: GpioEtmEventChannel<0>, + pub channel1_task: GpioEtmTaskChannel<1>, + pub channel1_event: GpioEtmEventChannel<1>, + pub channel2_task: GpioEtmTaskChannel<2>, + pub channel2_event: GpioEtmEventChannel<2>, + pub channel3_task: GpioEtmTaskChannel<3>, + pub channel3_event: GpioEtmEventChannel<3>, + pub channel4_task: GpioEtmTaskChannel<4>, + pub channel4_event: GpioEtmEventChannel<4>, + pub channel5_task: GpioEtmTaskChannel<5>, + pub channel5_event: GpioEtmEventChannel<5>, + pub channel6_task: GpioEtmTaskChannel<6>, + pub channel6_event: GpioEtmEventChannel<6>, + pub channel7_task: GpioEtmTaskChannel<7>, + pub channel7_event: GpioEtmEventChannel<7>, +} + +impl<'d> GpioEtmChannels<'d> { + pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(peripheral); + + Self { + _gpio_sd: peripheral, + channel0_task: GpioEtmTaskChannel {}, + channel0_event: GpioEtmEventChannel {}, + channel1_task: GpioEtmTaskChannel {}, + channel1_event: GpioEtmEventChannel {}, + channel2_task: GpioEtmTaskChannel {}, + channel2_event: GpioEtmEventChannel {}, + channel3_task: GpioEtmTaskChannel {}, + channel3_event: GpioEtmEventChannel {}, + channel4_task: GpioEtmTaskChannel {}, + channel4_event: GpioEtmEventChannel {}, + channel5_task: GpioEtmTaskChannel {}, + channel5_event: GpioEtmEventChannel {}, + channel6_task: GpioEtmTaskChannel {}, + channel6_event: GpioEtmEventChannel {}, + channel7_task: GpioEtmTaskChannel {}, + channel7_event: GpioEtmEventChannel {}, + } + } +} + +/// An ETM controlled GPIO event +pub struct GpioEtmEventChannel {} + +impl GpioEtmEventChannel { + /// Trigger at rising edge + pub fn rising_edge<'d, PIN>( + self, + pin: impl Peripheral

+ 'd, + ) -> GpioEtmEventChannelRising<'d, PIN, C> + where + PIN: super::Pin, + { + crate::into_ref!(pin); + enable_event_channel(C, pin.number()); + GpioEtmEventChannelRising { _pin: pin } + } + + /// Trigger at falling edge + pub fn falling_edge<'d, PIN>( + self, + pin: impl Peripheral

+ 'd, + ) -> GpioEtmEventChannelFalling<'d, PIN, C> + where + PIN: super::Pin, + { + crate::into_ref!(pin); + enable_event_channel(C, pin.number()); + GpioEtmEventChannelFalling { _pin: pin } + } + + /// Trigger at any edge + pub fn any_edge<'d, PIN>( + self, + pin: impl Peripheral

+ 'd, + ) -> GpioEtmEventChannelAny<'d, PIN, C> + where + PIN: super::Pin, + { + crate::into_ref!(pin); + enable_event_channel(C, pin.number()); + GpioEtmEventChannelAny { _pin: pin } + } +} + +/// Event for rising edge +#[non_exhaustive] +pub struct GpioEtmEventChannelRising<'d, PIN, const C: u8> +where + PIN: super::Pin, +{ + _pin: PeripheralRef<'d, PIN>, +} + +impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmEventChannelRising<'d, PIN, C> where + PIN: super::Pin +{ +} + +impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelRising<'d, PIN, C> +where + PIN: super::Pin, +{ + fn id(&self) -> u8 { + 1 + C + } +} + +/// Event for falling edge +#[non_exhaustive] +pub struct GpioEtmEventChannelFalling<'d, PIN, const C: u8> +where + PIN: super::Pin, +{ + _pin: PeripheralRef<'d, PIN>, +} + +impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmEventChannelFalling<'d, PIN, C> where + PIN: super::Pin +{ +} + +impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelFalling<'d, PIN, C> +where + PIN: super::Pin, +{ + fn id(&self) -> u8 { + 9 + C + } +} + +/// Event for any edge +#[non_exhaustive] +pub struct GpioEtmEventChannelAny<'d, PIN, const C: u8> +where + PIN: super::Pin, +{ + _pin: PeripheralRef<'d, PIN>, +} + +impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmEventChannelAny<'d, PIN, C> where + PIN: super::Pin +{ +} + +impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelAny<'d, PIN, C> +where + PIN: super::Pin, +{ + fn id(&self) -> u8 { + 17 + C + } +} + +/// An ETM controlled GPIO task +pub struct GpioEtmTaskChannel {} + +impl GpioEtmTaskChannel { + // In theory we could have multiple pins assigned to the same task. Not sure how + // useful that would be. If we want to support it, the easiest would be + // to offer additional functions like `set2`, `set3` etc. where the + // number is the pin-count + + /// Task to set a high level + pub fn set<'d, PIN>(self, pin: impl Peripheral

+ 'd) -> GpioEtmTaskSet<'d, PIN, C> + where + PIN: super::Pin, + { + crate::into_ref!(pin); + enable_task_channel(C, pin.number()); + GpioEtmTaskSet { _pin: pin } + } + + /// Task to set a low level + pub fn clear<'d, PIN>(self, pin: impl Peripheral

+ 'd) -> GpioEtmTaskClear<'d, PIN, C> + where + PIN: super::Pin, + { + crate::into_ref!(pin); + enable_task_channel(C, pin.number()); + GpioEtmTaskClear { _pin: pin } + } + + /// Task to toggle the level + pub fn toggle<'d, PIN>( + self, + pin: impl Peripheral

+ 'd, + ) -> GpioEtmTaskToggle<'d, PIN, C> + where + PIN: super::Pin, + { + crate::into_ref!(pin); + enable_task_channel(C, pin.number()); + GpioEtmTaskToggle { _pin: pin } + } +} + +/// Task for set operation +#[non_exhaustive] +pub struct GpioEtmTaskSet<'d, PIN, const C: u8> +where + PIN: super::Pin, +{ + _pin: PeripheralRef<'d, PIN>, +} + +impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmTaskSet<'d, PIN, C> where + PIN: super::Pin +{ +} + +impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskSet<'d, PIN, C> +where + PIN: super::Pin, +{ + fn id(&self) -> u8 { + 1 + C + } +} + +/// Task for clear operation +#[non_exhaustive] +pub struct GpioEtmTaskClear<'d, PIN, const C: u8> { + _pin: PeripheralRef<'d, PIN>, +} + +impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmTaskClear<'d, PIN, C> where + PIN: super::Pin +{ +} + +impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskClear<'d, PIN, C> +where + PIN: super::Pin, +{ + fn id(&self) -> u8 { + 9 + C + } +} + +/// Task for toggle operation +#[non_exhaustive] +pub struct GpioEtmTaskToggle<'d, PIN, const C: u8> { + _pin: PeripheralRef<'d, PIN>, +} + +impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmTaskToggle<'d, PIN, C> where + PIN: super::Pin +{ +} + +impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskToggle<'d, PIN, C> +where + PIN: super::Pin, +{ + fn id(&self) -> u8 { + 17 + C + } +} + +fn enable_task_channel(channel: u8, pin: u8) { + let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() }; + let ptr = unsafe { gpio_sd.etm_task_p0_cfg().as_ptr().add(pin as usize / 4) }; + let shift = 8 * (pin as usize % 4); + // bit 0 = en, bit 1-3 = channel + unsafe { + ptr.write_volatile( + ptr.read_volatile() & !(0xf << shift) | 1 << shift | (channel as u32) << (shift + 1), + ); + } +} + +fn enable_event_channel(channel: u8, pin: u8) { + let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() }; + gpio_sd + .etm_event_ch_cfg(channel as usize) + .modify(|_, w| w.etm_ch0_event_en().clear_bit()); + gpio_sd + .etm_event_ch_cfg(channel as usize) + .modify(|_, w| w.etm_ch0_event_sel().variant(pin)); + gpio_sd + .etm_event_ch_cfg(channel as usize) + .modify(|_, w| w.etm_ch0_event_en().set_bit()); +} diff --git a/esp-hal/src/gpio/lp_io.rs b/esp-hal/src/gpio/lp_io.rs new file mode 100644 index 00000000000..e8bd21029d2 --- /dev/null +++ b/esp-hal/src/gpio/lp_io.rs @@ -0,0 +1,250 @@ +//! Low Power IO (LP_IO) +//! +//! # Overview +//! +//! The hardware provides a couple of GPIO pins with low power (LP) +//! capabilities and analog functions. These pins can be controlled by +//! either IO MUX or LP IO MUX. +//! +//! If controlled by LP IO MUX, these pins will bypass IO MUX and GPIO +//! matrix for the use by ULP and peripherals in LP system. +//! +//! When configured as LP GPIOs, the pins can still be controlled by ULP or +//! the peripherals in LP system during chip Deep-sleep, and wake up the +//! chip from Deep-sleep. +//! +//! # Example +//! ```no_run +//! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); +//! // configure GPIO 1 as LP output pin +//! let lp_pin = io.pins.gpio1.into_low_power().into_push_pull_output(); +//! ``` + +use core::marker::PhantomData; + +#[cfg(esp32c6)] +use super::OpenDrain; +use super::{Floating, Input, Output, PullDown, PullUp, PushPull, Unknown}; + +/// A GPIO pin configured for low power operation +pub struct LowPowerPin { + pub(crate) private: PhantomData, +} + +impl LowPowerPin { + #[doc(hidden)] + pub fn output_enable(&self, enable: bool) { + let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; + if enable { + lp_io + .out_enable_w1ts() + .write(|w| w.enable_w1ts().variant(1 << PIN)); + } else { + lp_io + .out_enable_w1tc() + .write(|w| w.enable_w1tc().variant(1 << PIN)); + } + } + + fn input_enable(&self, enable: bool) { + get_pin_reg(PIN).modify(|_, w| w.fun_ie().bit(enable)); + } + + fn pullup_enable(&self, enable: bool) { + get_pin_reg(PIN).modify(|_, w| w.fun_wpu().bit(enable)); + } + + fn pulldown_enable(&self, enable: bool) { + get_pin_reg(PIN).modify(|_, w| w.fun_wpd().bit(enable)); + } + + #[doc(hidden)] + pub fn set_level(&mut self, level: bool) { + let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; + if level { + lp_io + .out_data_w1ts() + .write(|w| w.out_data_w1ts().variant(1 << PIN)); + } else { + lp_io + .out_data_w1tc() + .write(|w| w.out_data_w1tc().variant(1 << PIN)); + } + } + + #[doc(hidden)] + pub fn get_level(&self) -> bool { + let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; + (lp_io.in_().read().data_next().bits() & 1 << PIN) != 0 + } + + /// Configures the pin as an input with the internal pull-up resistor + /// enabled. + pub fn into_pull_up_input(self) -> LowPowerPin, PIN> { + self.input_enable(true); + self.pullup_enable(true); + self.pulldown_enable(false); + LowPowerPin { + private: PhantomData, + } + } + + /// Configures the pin as an input with the internal pull-down resistor + /// enabled. + pub fn into_pull_down_input(self) -> LowPowerPin, PIN> { + self.input_enable(true); + self.pullup_enable(false); + self.pulldown_enable(true); + LowPowerPin { + private: PhantomData, + } + } + + /// Configures the pin as a floating input pin. + pub fn into_floating_input(self) -> LowPowerPin, PIN> { + self.input_enable(true); + self.pullup_enable(false); + self.pulldown_enable(false); + LowPowerPin { + private: PhantomData, + } + } + + /// Configures the pin as a push-pull output pin. + pub fn into_push_pull_output(self) -> LowPowerPin, PIN> { + self.output_enable(true); + LowPowerPin { + private: PhantomData, + } + } + + /// Configures the pin as an open-drain output pin. + pub fn into_open_drain_output(self) -> LowPowerPin { + use crate::peripherals::GPIO; + + let gpio = unsafe { &*GPIO::PTR }; + + gpio.pin(PIN as usize) + .modify(|_, w| w.pad_driver().bit(true)); + self.pulldown_enable(false); + self.into_pull_up_input().into_push_pull_output(); + + LowPowerPin { + private: PhantomData, + } + } +} + +pub(crate) fn init_low_power_pin(pin: u8) { + let lp_aon = unsafe { &*crate::peripherals::LP_AON::PTR }; + + lp_aon + .gpio_mux() + .modify(|r, w| w.sel().variant(r.sel().bits() | 1 << pin)); + + get_pin_reg(pin).modify(|_, w| w.mcu_sel().variant(0)); +} + +#[inline(always)] +fn get_pin_reg(pin: u8) -> &'static crate::peripherals::lp_io::GPIO0 { + // ideally we should change the SVD and make the GPIOx registers into an + // array + unsafe { + let lp_io = &*crate::peripherals::LP_IO::PTR; + let pin_ptr = (lp_io.gpio0().as_ptr()).add(pin as usize); + + &*(pin_ptr as *const esp32c6::generic::Reg) + } +} + +/// Configures a pin for use as a low power pin +pub trait IntoLowPowerPin { + fn into_low_power(self) -> LowPowerPin; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! lp_gpio { + ( + $($gpionum:literal)+ + ) => { + paste::paste!{ + $( + impl $crate::gpio::lp_io::IntoLowPowerPin<$gpionum> for GpioPin { + fn into_low_power(self) -> $crate::gpio::lp_io::LowPowerPin { + $crate::gpio::lp_io::init_low_power_pin($gpionum); + $crate::gpio::lp_io::LowPowerPin { + private: core::marker::PhantomData, + } + } + } + + impl $crate::gpio::RTCPin for GpioPin { + unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8) { + let lp_io = &*$crate::peripherals::LP_IO::ptr(); + lp_io.[< pin $gpionum >]().modify(|_, w| { + w.wakeup_enable().bit(wakeup).int_type().bits(level) + }); + } + + fn rtcio_pad_hold(&mut self, enable: bool) { + let mask = 1 << $gpionum; + unsafe { + let lp_aon = &*$crate::peripherals::LP_AON::ptr(); + + lp_aon.gpio_hold0().modify(|r, w| { + if enable { + w.gpio_hold0().bits(r.gpio_hold0().bits() | mask) + } else { + w.gpio_hold0().bits(r.gpio_hold0().bits() & !mask) + } + }); + } + } + + /// Set the LP properties of the pin. If `mux` is true then then pin is + /// routed to LP_IO, when false it is routed to IO_MUX. + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: $crate::gpio::RtcFunction) { + let mask = 1 << $gpionum; + unsafe { + // Select LP_IO + let lp_aon = &*$crate::peripherals::LP_AON::ptr(); + lp_aon + .gpio_mux() + .modify(|r, w| { + if mux { + w.sel().bits(r.sel().bits() | mask) + } else { + w.sel().bits(r.sel().bits() & !mask) + } + }); + + // Configure input, function and select normal operation registers + let lp_io = &*$crate::peripherals::LP_IO::ptr(); + lp_io.[< gpio $gpionum >]().modify(|_, w| { + w + .slp_sel().bit(false) + .fun_ie().bit(input_enable) + .mcu_sel().bits(func as u8) + }); + } + } + } + + impl $crate::gpio::RTCPinWithResistors for GpioPin { + fn rtcio_pullup(&mut self, enable: bool) { + let lp_io = unsafe { &*$crate::peripherals::LP_IO::ptr() }; + lp_io.[< gpio $gpionum >]().modify(|_, w| w.fun_wpu().bit(enable)); + } + + fn rtcio_pulldown(&mut self, enable: bool) { + let lp_io = unsafe { &*$crate::peripherals::LP_IO::ptr() }; + lp_io.[< gpio $gpionum >]().modify(|_, w| w.fun_wpd().bit(enable)); + } + } + )+ + } + } +} + +pub(crate) use lp_gpio; diff --git a/esp-hal/src/gpio.rs b/esp-hal/src/gpio/mod.rs similarity index 75% rename from esp-hal/src/gpio.rs rename to esp-hal/src/gpio/mod.rs index faae26d0f32..53ebadec5f2 100644 --- a/esp-hal/src/gpio.rs +++ b/esp-hal/src/gpio/mod.rs @@ -37,6 +37,13 @@ use crate::{ peripherals::{GPIO, IO_MUX}, }; +#[cfg(soc_etm)] +pub mod etm; +#[cfg(lp_io)] +pub mod lp_io; +#[cfg(all(rtc_io, not(esp32)))] +pub mod rtc_io; + /// Convenience type-alias for a no-pin / don't care - pin pub type NoPinType = Gpio0; @@ -2247,780 +2254,6 @@ macro_rules! analog { } } -#[cfg(soc_etm)] -pub mod etm { - //! # Event Task Matrix Function - //! - //! ## Overview - //! - //! GPIO supports ETM function, that is, the ETM task of GPIO can be - //! triggered by the ETM event of any peripheral, or the ETM task of any - //! peripheral can be triggered by the ETM event of GPIO. - //! - //! The GPIO ETM provides eight task channels. The ETM tasks that each task - //! channel can receive are: - //! - SET: GPIO goes high when triggered - //! - CLEAR: GPIO goes low when triggered - //! - TOGGLE: GPIO toggle level when triggered. - //! - //! GPIO has eight event channels, and the ETM events that each event - //! channel can generate are: - //! - RISE_EDGE: Indicates that the output signal of the corresponding GPIO - //! has a rising edge - //! - FALL_EDGE: Indicates that the output signal of the corresponding GPIO - //! has a falling edge - //! - ANY_EDGE: Indicates that the output signal of the corresponding GPIO - //! is reversed - //! - //! ## Example - //! ```no_run - //! let led_task = gpio_ext.channel0_task.toggle(&mut led); - //! let button_event = gpio_ext.channel0_event.falling_edge(button); - //! ``` - - use crate::peripheral::{Peripheral, PeripheralRef}; - - /// All the GPIO ETM channels - #[non_exhaustive] - pub struct GpioEtmChannels<'d> { - _gpio_sd: PeripheralRef<'d, crate::peripherals::GPIO_SD>, - pub channel0_task: GpioEtmTaskChannel<0>, - pub channel0_event: GpioEtmEventChannel<0>, - pub channel1_task: GpioEtmTaskChannel<1>, - pub channel1_event: GpioEtmEventChannel<1>, - pub channel2_task: GpioEtmTaskChannel<2>, - pub channel2_event: GpioEtmEventChannel<2>, - pub channel3_task: GpioEtmTaskChannel<3>, - pub channel3_event: GpioEtmEventChannel<3>, - pub channel4_task: GpioEtmTaskChannel<4>, - pub channel4_event: GpioEtmEventChannel<4>, - pub channel5_task: GpioEtmTaskChannel<5>, - pub channel5_event: GpioEtmEventChannel<5>, - pub channel6_task: GpioEtmTaskChannel<6>, - pub channel6_event: GpioEtmEventChannel<6>, - pub channel7_task: GpioEtmTaskChannel<7>, - pub channel7_event: GpioEtmEventChannel<7>, - } - - impl<'d> GpioEtmChannels<'d> { - pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { - crate::into_ref!(peripheral); - - Self { - _gpio_sd: peripheral, - channel0_task: GpioEtmTaskChannel {}, - channel0_event: GpioEtmEventChannel {}, - channel1_task: GpioEtmTaskChannel {}, - channel1_event: GpioEtmEventChannel {}, - channel2_task: GpioEtmTaskChannel {}, - channel2_event: GpioEtmEventChannel {}, - channel3_task: GpioEtmTaskChannel {}, - channel3_event: GpioEtmEventChannel {}, - channel4_task: GpioEtmTaskChannel {}, - channel4_event: GpioEtmEventChannel {}, - channel5_task: GpioEtmTaskChannel {}, - channel5_event: GpioEtmEventChannel {}, - channel6_task: GpioEtmTaskChannel {}, - channel6_event: GpioEtmEventChannel {}, - channel7_task: GpioEtmTaskChannel {}, - channel7_event: GpioEtmEventChannel {}, - } - } - } - - /// An ETM controlled GPIO event - pub struct GpioEtmEventChannel {} - - impl GpioEtmEventChannel { - /// Trigger at rising edge - pub fn rising_edge<'d, PIN>( - self, - pin: impl Peripheral

+ 'd, - ) -> GpioEtmEventChannelRising<'d, PIN, C> - where - PIN: super::Pin, - { - crate::into_ref!(pin); - enable_event_channel(C, pin.number()); - GpioEtmEventChannelRising { _pin: pin } - } - - /// Trigger at falling edge - pub fn falling_edge<'d, PIN>( - self, - pin: impl Peripheral

+ 'd, - ) -> GpioEtmEventChannelFalling<'d, PIN, C> - where - PIN: super::Pin, - { - crate::into_ref!(pin); - enable_event_channel(C, pin.number()); - GpioEtmEventChannelFalling { _pin: pin } - } - - /// Trigger at any edge - pub fn any_edge<'d, PIN>( - self, - pin: impl Peripheral

+ 'd, - ) -> GpioEtmEventChannelAny<'d, PIN, C> - where - PIN: super::Pin, - { - crate::into_ref!(pin); - enable_event_channel(C, pin.number()); - GpioEtmEventChannelAny { _pin: pin } - } - } - - /// Event for rising edge - #[non_exhaustive] - pub struct GpioEtmEventChannelRising<'d, PIN, const C: u8> - where - PIN: super::Pin, - { - _pin: PeripheralRef<'d, PIN>, - } - - impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmEventChannelRising<'d, PIN, C> where - PIN: super::Pin - { - } - - impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelRising<'d, PIN, C> - where - PIN: super::Pin, - { - fn id(&self) -> u8 { - 1 + C - } - } - - /// Event for falling edge - #[non_exhaustive] - pub struct GpioEtmEventChannelFalling<'d, PIN, const C: u8> - where - PIN: super::Pin, - { - _pin: PeripheralRef<'d, PIN>, - } - - impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmEventChannelFalling<'d, PIN, C> where - PIN: super::Pin - { - } - - impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelFalling<'d, PIN, C> - where - PIN: super::Pin, - { - fn id(&self) -> u8 { - 9 + C - } - } - - /// Event for any edge - #[non_exhaustive] - pub struct GpioEtmEventChannelAny<'d, PIN, const C: u8> - where - PIN: super::Pin, - { - _pin: PeripheralRef<'d, PIN>, - } - - impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmEventChannelAny<'d, PIN, C> where - PIN: super::Pin - { - } - - impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelAny<'d, PIN, C> - where - PIN: super::Pin, - { - fn id(&self) -> u8 { - 17 + C - } - } - - /// An ETM controlled GPIO task - pub struct GpioEtmTaskChannel {} - - impl GpioEtmTaskChannel { - // In theory we could have multiple pins assigned to the same task. Not sure how - // useful that would be. If we want to support it, the easiest would be - // to offer additional functions like `set2`, `set3` etc. where the - // number is the pin-count - - /// Task to set a high level - pub fn set<'d, PIN>(self, pin: impl Peripheral

+ 'd) -> GpioEtmTaskSet<'d, PIN, C> - where - PIN: super::Pin, - { - crate::into_ref!(pin); - enable_task_channel(C, pin.number()); - GpioEtmTaskSet { _pin: pin } - } - - /// Task to set a low level - pub fn clear<'d, PIN>( - self, - pin: impl Peripheral

+ 'd, - ) -> GpioEtmTaskClear<'d, PIN, C> - where - PIN: super::Pin, - { - crate::into_ref!(pin); - enable_task_channel(C, pin.number()); - GpioEtmTaskClear { _pin: pin } - } - - /// Task to toggle the level - pub fn toggle<'d, PIN>( - self, - pin: impl Peripheral

+ 'd, - ) -> GpioEtmTaskToggle<'d, PIN, C> - where - PIN: super::Pin, - { - crate::into_ref!(pin); - enable_task_channel(C, pin.number()); - GpioEtmTaskToggle { _pin: pin } - } - } - - /// Task for set operation - #[non_exhaustive] - pub struct GpioEtmTaskSet<'d, PIN, const C: u8> - where - PIN: super::Pin, - { - _pin: PeripheralRef<'d, PIN>, - } - - impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmTaskSet<'d, PIN, C> where - PIN: super::Pin - { - } - - impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskSet<'d, PIN, C> - where - PIN: super::Pin, - { - fn id(&self) -> u8 { - 1 + C - } - } - - /// Task for clear operation - #[non_exhaustive] - pub struct GpioEtmTaskClear<'d, PIN, const C: u8> { - _pin: PeripheralRef<'d, PIN>, - } - - impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmTaskClear<'d, PIN, C> where - PIN: super::Pin - { - } - - impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskClear<'d, PIN, C> - where - PIN: super::Pin, - { - fn id(&self) -> u8 { - 9 + C - } - } - - /// Task for toggle operation - #[non_exhaustive] - pub struct GpioEtmTaskToggle<'d, PIN, const C: u8> { - _pin: PeripheralRef<'d, PIN>, - } - - impl<'d, PIN, const C: u8> crate::private::Sealed for GpioEtmTaskToggle<'d, PIN, C> where - PIN: super::Pin - { - } - - impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskToggle<'d, PIN, C> - where - PIN: super::Pin, - { - fn id(&self) -> u8 { - 17 + C - } - } - - fn enable_task_channel(channel: u8, pin: u8) { - let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() }; - let ptr = unsafe { gpio_sd.etm_task_p0_cfg().as_ptr().add(pin as usize / 4) }; - let shift = 8 * (pin as usize % 4); - // bit 0 = en, bit 1-3 = channel - unsafe { - ptr.write_volatile( - ptr.read_volatile() & !(0xf << shift) - | 1 << shift - | (channel as u32) << (shift + 1), - ); - } - } - - fn enable_event_channel(channel: u8, pin: u8) { - let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() }; - gpio_sd - .etm_event_ch_cfg(channel as usize) - .modify(|_, w| w.etm_ch0_event_en().clear_bit()); - gpio_sd - .etm_event_ch_cfg(channel as usize) - .modify(|_, w| w.etm_ch0_event_sel().variant(pin)); - gpio_sd - .etm_event_ch_cfg(channel as usize) - .modify(|_, w| w.etm_ch0_event_en().set_bit()); - } -} - -#[cfg(all(rtc_io, not(esp32)))] -pub mod rtc_io { - //! RTC IO - //! - //! # Overview - //! - //! The hardware provides a couple of GPIO pins with low power (LP) - //! capabilities and analog functions. These pins can be controlled by - //! either IO MUX or RTC IO. - //! - //! If controlled by RTC IO, these pins will bypass IO MUX and GPIO - //! matrix for the use by ULP and peripherals in RTC system. - //! - //! When configured as RTC GPIOs, the pins can still be controlled by ULP or - //! the peripherals in RTC system during chip Deep-sleep, and wake up the - //! chip from Deep-sleep. - //! - //! # Example - //! ```no_run - //! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - //! // configure GPIO 1 as ULP output pin - //! let lp_pin = io.pins.gpio1.into_low_power().into_push_pull_output(); - //! ``` - - use core::marker::PhantomData; - - #[cfg(esp32c6)] - use super::OpenDrain; - use super::{Floating, Input, Output, PullDown, PullUp, PushPull, Unknown}; - - /// A GPIO pin configured for low power operation - pub struct LowPowerPin { - pub(crate) private: PhantomData, - } - - /// Configures a pin for use as a low power pin - pub trait IntoLowPowerPin { - fn into_low_power(self) -> LowPowerPin; - } - - impl LowPowerPin { - #[doc(hidden)] - pub fn output_enable(&self, enable: bool) { - let rtc_io = unsafe { crate::peripherals::RTC_IO::steal() }; - if enable { - // TODO align PAC - #[cfg(esp32s2)] - rtc_io - .rtc_gpio_enable_w1ts() - .write(|w| w.reg_rtcio_reg_gpio_enable_w1ts().variant(1 << PIN)); - - #[cfg(esp32s3)] - rtc_io - .rtc_gpio_enable_w1ts() - .write(|w| w.rtc_gpio_enable_w1ts().variant(1 << PIN)); - } else { - rtc_io - .enable_w1tc() - .write(|w| w.enable_w1tc().variant(1 << PIN)); - } - } - - fn input_enable(&self, enable: bool) { - get_pin_reg(PIN).modify(|_, w| w.fun_ie().bit(enable)); - } - - fn pullup_enable(&self, enable: bool) { - get_pin_reg(PIN).modify(|_, w| w.rue().bit(enable)); - } - - fn pulldown_enable(&self, enable: bool) { - get_pin_reg(PIN).modify(|_, w| w.rde().bit(enable)); - } - - #[doc(hidden)] - pub fn set_level(&mut self, level: bool) { - let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR }; - - // TODO align PACs - #[cfg(esp32s2)] - if level { - rtc_io - .rtc_gpio_out_w1ts() - .write(|w| w.gpio_out_data_w1ts().variant(1 << PIN)); - } else { - rtc_io - .rtc_gpio_out_w1tc() - .write(|w| w.gpio_out_data_w1tc().variant(1 << PIN)); - } - - #[cfg(esp32s3)] - if level { - rtc_io - .rtc_gpio_out_w1ts() - .write(|w| w.rtc_gpio_out_data_w1ts().variant(1 << PIN)); - } else { - rtc_io - .rtc_gpio_out_w1tc() - .write(|w| w.rtc_gpio_out_data_w1tc().variant(1 << PIN)); - } - } - - #[doc(hidden)] - pub fn get_level(&self) -> bool { - let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR }; - (rtc_io.rtc_gpio_in().read().bits() & 1 << PIN) != 0 - } - - /// Configures the pin as an input with the internal pull-up resistor - /// enabled. - pub fn into_pull_up_input(self) -> LowPowerPin, PIN> { - self.input_enable(true); - self.pullup_enable(true); - self.pulldown_enable(false); - LowPowerPin { - private: PhantomData, - } - } - - /// Configures the pin as an input with the internal pull-down resistor - /// enabled. - pub fn into_pull_down_input(self) -> LowPowerPin, PIN> { - self.input_enable(true); - self.pullup_enable(false); - self.pulldown_enable(true); - LowPowerPin { - private: PhantomData, - } - } - - /// Configures the pin as a floating input pin. - pub fn into_floating_input(self) -> LowPowerPin, PIN> { - self.input_enable(true); - self.pullup_enable(false); - self.pulldown_enable(false); - LowPowerPin { - private: PhantomData, - } - } - - /// Configures the pin as an output pin. - pub fn into_push_pull_output(self) -> LowPowerPin, PIN> { - self.output_enable(true); - LowPowerPin { - private: PhantomData, - } - } - - #[cfg(esp32c6)] - /// Configures the pin as an pullup input and a push pull output pin. - pub fn into_open_drain_output(self) -> LowPowerPin { - self.into_pull_up_input(); - self.into_push_pull_output(); - use crate::peripherals::GPIO; - - let gpio = unsafe { &*GPIO::PTR }; - - gpio.pin(PIN).modify(|_, w| w.pad_driver().bit(true)); - self.pulldown_enable(false); - - LowPowerPin { - private: PhantomData, - } - } - } - - #[cfg(esp32s3)] - #[inline(always)] - fn get_pin_reg(pin: u8) -> &'static crate::peripherals::rtc_io::TOUCH_PAD0 { - unsafe { - let rtc_io = &*crate::peripherals::RTC_IO::PTR; - let pin_ptr = (rtc_io.touch_pad0().as_ptr()).add(pin as usize); - - &*(pin_ptr - as *const esp32s3::generic::Reg) - } - } - - #[cfg(esp32s2)] - #[inline(always)] - fn get_pin_reg(pin: u8) -> &'static crate::peripherals::rtc_io::TOUCH_PAD { - unsafe { - let rtc_io = &*crate::peripherals::RTC_IO::PTR; - let pin_ptr = (rtc_io.touch_pad(0).as_ptr()).add(pin as usize); - - &*(pin_ptr as *const esp32s2::generic::Reg) - } - } -} - -#[cfg(lp_io)] -pub mod lp_gpio { - //! Low Power IO (LP_IO) - //! - //! # Overview - //! - //! The hardware provides a couple of GPIO pins with low power (LP) - //! capabilities and analog functions. These pins can be controlled by - //! either IO MUX or LP IO MUX. - //! - //! If controlled by LP IO MUX, these pins will bypass IO MUX and GPIO - //! matrix for the use by ULP and peripherals in LP system. - //! - //! When configured as LP GPIOs, the pins can still be controlled by ULP or - //! the peripherals in LP system during chip Deep-sleep, and wake up the - //! chip from Deep-sleep. - //! - //! # Example - //! ```no_run - //! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - //! // configure GPIO 1 as LP output pin - //! let lp_pin = io.pins.gpio1.into_low_power().into_push_pull_output(); - //! ``` - - use core::marker::PhantomData; - - #[cfg(esp32c6)] - use super::OpenDrain; - use super::{Floating, Input, Output, PullDown, PullUp, PushPull, Unknown}; - - /// A GPIO pin configured for low power operation - pub struct LowPowerPin { - pub(crate) private: PhantomData, - } - - impl LowPowerPin { - #[doc(hidden)] - pub fn output_enable(&self, enable: bool) { - let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; - if enable { - lp_io - .out_enable_w1ts() - .write(|w| w.enable_w1ts().variant(1 << PIN)); - } else { - lp_io - .out_enable_w1tc() - .write(|w| w.enable_w1tc().variant(1 << PIN)); - } - } - - fn input_enable(&self, enable: bool) { - get_pin_reg(PIN).modify(|_, w| w.fun_ie().bit(enable)); - } - - fn pullup_enable(&self, enable: bool) { - get_pin_reg(PIN).modify(|_, w| w.fun_wpu().bit(enable)); - } - - fn pulldown_enable(&self, enable: bool) { - get_pin_reg(PIN).modify(|_, w| w.fun_wpd().bit(enable)); - } - - #[doc(hidden)] - pub fn set_level(&mut self, level: bool) { - let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; - if level { - lp_io - .out_data_w1ts() - .write(|w| w.out_data_w1ts().variant(1 << PIN)); - } else { - lp_io - .out_data_w1tc() - .write(|w| w.out_data_w1tc().variant(1 << PIN)); - } - } - - #[doc(hidden)] - pub fn get_level(&self) -> bool { - let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; - (lp_io.in_().read().data_next().bits() & 1 << PIN) != 0 - } - - /// Configures the pin as an input with the internal pull-up resistor - /// enabled. - pub fn into_pull_up_input(self) -> LowPowerPin, PIN> { - self.input_enable(true); - self.pullup_enable(true); - self.pulldown_enable(false); - LowPowerPin { - private: PhantomData, - } - } - - /// Configures the pin as an input with the internal pull-down resistor - /// enabled. - pub fn into_pull_down_input(self) -> LowPowerPin, PIN> { - self.input_enable(true); - self.pullup_enable(false); - self.pulldown_enable(true); - LowPowerPin { - private: PhantomData, - } - } - - /// Configures the pin as a floating input pin. - pub fn into_floating_input(self) -> LowPowerPin, PIN> { - self.input_enable(true); - self.pullup_enable(false); - self.pulldown_enable(false); - LowPowerPin { - private: PhantomData, - } - } - - /// Configures the pin as an output pin. - pub fn into_push_pull_output(self) -> LowPowerPin, PIN> { - self.output_enable(true); - LowPowerPin { - private: PhantomData, - } - } - - pub fn into_open_drain_output(self) -> LowPowerPin { - use crate::peripherals::GPIO; - - let gpio = unsafe { &*GPIO::PTR }; - - gpio.pin(PIN as usize) - .modify(|_, w| w.pad_driver().bit(true)); - self.pulldown_enable(false); - self.into_pull_up_input().into_push_pull_output(); - - LowPowerPin { - private: PhantomData, - } - } - } - - pub(crate) fn init_low_power_pin(pin: u8) { - let lp_aon = unsafe { &*crate::peripherals::LP_AON::PTR }; - - lp_aon - .gpio_mux() - .modify(|r, w| w.sel().variant(r.sel().bits() | 1 << pin)); - - get_pin_reg(pin).modify(|_, w| w.mcu_sel().variant(0)); - } - - #[inline(always)] - fn get_pin_reg(pin: u8) -> &'static crate::peripherals::lp_io::GPIO0 { - // ideally we should change the SVD and make the GPIOx registers into an - // array - unsafe { - let lp_io = &*crate::peripherals::LP_IO::PTR; - let pin_ptr = (lp_io.gpio0().as_ptr()).add(pin as usize); - - &*(pin_ptr as *const esp32c6::generic::Reg) - } - } - - /// Configures a pin for use as a low power pin - pub trait IntoLowPowerPin { - fn into_low_power(self) -> LowPowerPin; - } - - #[doc(hidden)] - #[macro_export] - macro_rules! lp_gpio { - ( - $($gpionum:literal)+ - ) => { - paste::paste!{ - $( - impl $crate::gpio::lp_gpio::IntoLowPowerPin<$gpionum> for GpioPin { - fn into_low_power(self) -> $crate::gpio::lp_gpio::LowPowerPin { - $crate::gpio::lp_gpio::init_low_power_pin($gpionum); - $crate::gpio::lp_gpio::LowPowerPin { - private: core::marker::PhantomData, - } - } - } - - impl $crate::gpio::RTCPin for GpioPin { - unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8) { - let lp_io = &*$crate::peripherals::LP_IO::ptr(); - lp_io.[< pin $gpionum >]().modify(|_, w| { - w.wakeup_enable().bit(wakeup).int_type().bits(level) - }); - } - - fn rtcio_pad_hold(&mut self, enable: bool) { - let mask = 1 << $gpionum; - unsafe { - let lp_aon = &*$crate::peripherals::LP_AON::ptr(); - - lp_aon.gpio_hold0().modify(|r, w| { - if enable { - w.gpio_hold0().bits(r.gpio_hold0().bits() | mask) - } else { - w.gpio_hold0().bits(r.gpio_hold0().bits() & !mask) - } - }); - } - } - - /// Set the LP properties of the pin. If `mux` is true then then pin is - /// routed to LP_IO, when false it is routed to IO_MUX. - fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: $crate::gpio::RtcFunction) { - let mask = 1 << $gpionum; - unsafe { - // Select LP_IO - let lp_aon = &*$crate::peripherals::LP_AON::ptr(); - lp_aon - .gpio_mux() - .modify(|r, w| { - if mux { - w.sel().bits(r.sel().bits() | mask) - } else { - w.sel().bits(r.sel().bits() & !mask) - } - }); - - // Configure input, function and select normal operation registers - let lp_io = &*$crate::peripherals::LP_IO::ptr(); - lp_io.[< gpio $gpionum >]().modify(|_, w| { - w - .slp_sel().bit(false) - .fun_ie().bit(input_enable) - .mcu_sel().bits(func as u8) - }); - } - } - } - - impl $crate::gpio::RTCPinWithResistors for GpioPin { - fn rtcio_pullup(&mut self, enable: bool) { - let lp_io = unsafe { &*$crate::peripherals::LP_IO::ptr() }; - lp_io.[< gpio $gpionum >]().modify(|_, w| w.fun_wpu().bit(enable)); - } - - fn rtcio_pulldown(&mut self, enable: bool) { - let lp_io = unsafe { &*$crate::peripherals::LP_IO::ptr() }; - lp_io.[< gpio $gpionum >]().modify(|_, w| w.fun_wpd().bit(enable)); - } - } - )+ - } - } - } - - pub(crate) use lp_gpio; -} - #[cfg(feature = "async")] mod asynch { use core::task::{Context, Poll}; diff --git a/esp-hal/src/gpio/rtc_io.rs b/esp-hal/src/gpio/rtc_io.rs new file mode 100644 index 00000000000..8c1f8fa3fac --- /dev/null +++ b/esp-hal/src/gpio/rtc_io.rs @@ -0,0 +1,185 @@ +//! RTC IO +//! +//! # Overview +//! +//! The hardware provides a couple of GPIO pins with low power (LP) +//! capabilities and analog functions. These pins can be controlled by +//! either IO MUX or RTC IO. +//! +//! If controlled by RTC IO, these pins will bypass IO MUX and GPIO +//! matrix for the use by ULP and peripherals in RTC system. +//! +//! When configured as RTC GPIOs, the pins can still be controlled by ULP or +//! the peripherals in RTC system during chip Deep-sleep, and wake up the +//! chip from Deep-sleep. +//! +//! # Example +//! ```no_run +//! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); +//! // configure GPIO 1 as ULP output pin +//! let lp_pin = io.pins.gpio1.into_low_power().into_push_pull_output(); +//! ``` + +use core::marker::PhantomData; + +#[cfg(esp32c6)] +use super::OpenDrain; +use super::{Floating, Input, Output, PullDown, PullUp, PushPull, Unknown}; + +/// A GPIO pin configured for low power operation +pub struct LowPowerPin { + pub(crate) private: PhantomData, +} + +/// Configures a pin for use as a low power pin +pub trait IntoLowPowerPin { + fn into_low_power(self) -> LowPowerPin; +} + +impl LowPowerPin { + #[doc(hidden)] + pub fn output_enable(&self, enable: bool) { + let rtc_io = unsafe { crate::peripherals::RTC_IO::steal() }; + if enable { + // TODO align PAC + #[cfg(esp32s2)] + rtc_io + .rtc_gpio_enable_w1ts() + .write(|w| w.reg_rtcio_reg_gpio_enable_w1ts().variant(1 << PIN)); + + #[cfg(esp32s3)] + rtc_io + .rtc_gpio_enable_w1ts() + .write(|w| w.rtc_gpio_enable_w1ts().variant(1 << PIN)); + } else { + rtc_io + .enable_w1tc() + .write(|w| w.enable_w1tc().variant(1 << PIN)); + } + } + + fn input_enable(&self, enable: bool) { + get_pin_reg(PIN).modify(|_, w| w.fun_ie().bit(enable)); + } + + fn pullup_enable(&self, enable: bool) { + get_pin_reg(PIN).modify(|_, w| w.rue().bit(enable)); + } + + fn pulldown_enable(&self, enable: bool) { + get_pin_reg(PIN).modify(|_, w| w.rde().bit(enable)); + } + + #[doc(hidden)] + pub fn set_level(&mut self, level: bool) { + let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR }; + + // TODO align PACs + #[cfg(esp32s2)] + if level { + rtc_io + .rtc_gpio_out_w1ts() + .write(|w| w.gpio_out_data_w1ts().variant(1 << PIN)); + } else { + rtc_io + .rtc_gpio_out_w1tc() + .write(|w| w.gpio_out_data_w1tc().variant(1 << PIN)); + } + + #[cfg(esp32s3)] + if level { + rtc_io + .rtc_gpio_out_w1ts() + .write(|w| w.rtc_gpio_out_data_w1ts().variant(1 << PIN)); + } else { + rtc_io + .rtc_gpio_out_w1tc() + .write(|w| w.rtc_gpio_out_data_w1tc().variant(1 << PIN)); + } + } + + #[doc(hidden)] + pub fn get_level(&self) -> bool { + let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR }; + (rtc_io.rtc_gpio_in().read().bits() & 1 << PIN) != 0 + } + + /// Configures the pin as an input with the internal pull-up resistor + /// enabled. + pub fn into_pull_up_input(self) -> LowPowerPin, PIN> { + self.input_enable(true); + self.pullup_enable(true); + self.pulldown_enable(false); + LowPowerPin { + private: PhantomData, + } + } + + /// Configures the pin as an input with the internal pull-down resistor + /// enabled. + pub fn into_pull_down_input(self) -> LowPowerPin, PIN> { + self.input_enable(true); + self.pullup_enable(false); + self.pulldown_enable(true); + LowPowerPin { + private: PhantomData, + } + } + + /// Configures the pin as a floating input pin. + pub fn into_floating_input(self) -> LowPowerPin, PIN> { + self.input_enable(true); + self.pullup_enable(false); + self.pulldown_enable(false); + LowPowerPin { + private: PhantomData, + } + } + + /// Configures the pin as an output pin. + pub fn into_push_pull_output(self) -> LowPowerPin, PIN> { + self.output_enable(true); + LowPowerPin { + private: PhantomData, + } + } + + #[cfg(esp32c6)] + /// Configures the pin as an pullup input and a push pull output pin. + pub fn into_open_drain_output(self) -> LowPowerPin { + self.into_pull_up_input(); + self.into_push_pull_output(); + use crate::peripherals::GPIO; + + let gpio = unsafe { &*GPIO::PTR }; + + gpio.pin(PIN).modify(|_, w| w.pad_driver().bit(true)); + self.pulldown_enable(false); + + LowPowerPin { + private: PhantomData, + } + } +} + +#[cfg(esp32s3)] +#[inline(always)] +fn get_pin_reg(pin: u8) -> &'static crate::peripherals::rtc_io::TOUCH_PAD0 { + unsafe { + let rtc_io = &*crate::peripherals::RTC_IO::PTR; + let pin_ptr = (rtc_io.touch_pad0().as_ptr()).add(pin as usize); + + &*(pin_ptr as *const esp32s3::generic::Reg) + } +} + +#[cfg(esp32s2)] +#[inline(always)] +fn get_pin_reg(pin: u8) -> &'static crate::peripherals::rtc_io::TOUCH_PAD { + unsafe { + let rtc_io = &*crate::peripherals::RTC_IO::PTR; + let pin_ptr = (rtc_io.touch_pad(0).as_ptr()).add(pin as usize); + + &*(pin_ptr as *const esp32s2::generic::Reg) + } +} diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 9db81e89b03..2fefe496bfb 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -1764,7 +1764,7 @@ pub mod lp_i2c { use fugit::HertzU32; use crate::{ - gpio::{lp_gpio::LowPowerPin, OpenDrain}, + gpio::{lp_io::LowPowerPin, OpenDrain}, peripherals::{LP_CLKRST, LP_I2C0}, }; diff --git a/esp-hal/src/soc/esp32c6/gpio.rs b/esp-hal/src/soc/esp32c6/gpio.rs index 26d198ee6f8..5d67968c332 100644 --- a/esp-hal/src/soc/esp32c6/gpio.rs +++ b/esp-hal/src/soc/esp32c6/gpio.rs @@ -321,7 +321,7 @@ crate::gpio::analog! { 7 } -crate::gpio::lp_gpio::lp_gpio! { +crate::gpio::lp_io::lp_gpio! { 0 1 2 diff --git a/esp-hal/src/soc/esp32p4/gpio.rs b/esp-hal/src/soc/esp32p4/gpio.rs index 5c854046820..a2b60c92f66 100644 --- a/esp-hal/src/soc/esp32p4/gpio.rs +++ b/esp-hal/src/soc/esp32p4/gpio.rs @@ -458,7 +458,7 @@ crate::gpio::gpio! { // crate::gpio::analog! { // } -// crate::gpio::lp_gpio::lp_gpio! { +// crate::gpio::lp_io::lp_gpio! { // 0 // 1 // 2 diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 5eb4033a224..e21177b07a9 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -2012,7 +2012,7 @@ mod asynch { #[cfg(lp_uart)] pub mod lp_uart { use crate::{ - gpio::{lp_gpio::LowPowerPin, Floating, Input, Output, PushPull}, + gpio::{lp_io::LowPowerPin, Floating, Input, Output, PushPull}, peripherals::{LP_CLKRST, LP_UART}, uart::{config, config::Config}, }; diff --git a/examples/src/bin/lp_core_basic.rs b/examples/src/bin/lp_core_basic.rs index 9d3b839217a..53cd5bb9756 100644 --- a/examples/src/bin/lp_core_basic.rs +++ b/examples/src/bin/lp_core_basic.rs @@ -12,7 +12,7 @@ use esp_backtrace as _; use esp_hal::{ - gpio::{lp_gpio::IntoLowPowerPin, IO}, + gpio::{lp_io::IntoLowPowerPin, IO}, lp_core::{LpCore, LpCoreWakeupSource}, peripherals::Peripherals, prelude::*, diff --git a/examples/src/bin/lp_core_i2c.rs b/examples/src/bin/lp_core_i2c.rs index f7e3adc0a3b..bcfa647eaaf 100644 --- a/examples/src/bin/lp_core_i2c.rs +++ b/examples/src/bin/lp_core_i2c.rs @@ -12,7 +12,7 @@ use esp_backtrace as _; use esp_hal::{ - gpio::{lp_gpio::IntoLowPowerPin, IO}, + gpio::{lp_io::IntoLowPowerPin, IO}, i2c::lp_i2c::LpI2c, lp_core::{LpCore, LpCoreWakeupSource}, peripherals::Peripherals, diff --git a/examples/src/bin/lp_core_uart.rs b/examples/src/bin/lp_core_uart.rs index d12591d325d..d602c866e99 100644 --- a/examples/src/bin/lp_core_uart.rs +++ b/examples/src/bin/lp_core_uart.rs @@ -13,7 +13,7 @@ use esp_backtrace as _; use esp_hal::{ clock::ClockControl, - gpio::{lp_gpio::IntoLowPowerPin, IO}, + gpio::{lp_io::IntoLowPowerPin, IO}, lp_core::{LpCore, LpCoreWakeupSource}, peripherals::Peripherals, prelude::*,