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 <scott@mabez.dev>
This commit is contained in:
Jesse Braham 2024-04-05 12:33:49 +00:00 committed by GitHub
parent b3bc28efef
commit fd9f7895f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 773 additions and 782 deletions

View File

@ -620,7 +620,7 @@ pub fn load_lp_code(input: TokenStream) -> TokenStream {
let imports = quote! { let imports = quote! {
use #hal_crate::lp_core::LpCore; use #hal_crate::lp_core::LpCore;
use #hal_crate::lp_core::LpCoreWakeupSource; 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::gpio::*;
use #hal_crate::uart::lp_uart::LpUart; use #hal_crate::uart::lp_uart::LpUart;
use #hal_crate::i2c::lp_i2c::LpI2c; use #hal_crate::i2c::lp_i2c::LpI2c;

View File

@ -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) - `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) - SYSTIMER and TIMG instances can now be created in async or blocking mode (#1348)
- Runtime ISR binding for TWAI (#1384) - 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 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) - 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)

322
esp-hal/src/gpio/etm.rs Normal file
View File

@ -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<P = crate::peripherals::GPIO_SD> + '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<const C: u8> {}
impl<const C: u8> GpioEtmEventChannel<C> {
/// Trigger at rising edge
pub fn rising_edge<'d, PIN>(
self,
pin: impl Peripheral<P = PIN> + '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<P = PIN> + '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<P = PIN> + '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<const C: u8> {}
impl<const C: u8> GpioEtmTaskChannel<C> {
// 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<P = PIN> + '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<P = PIN> + '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<P = PIN> + '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());
}

250
esp-hal/src/gpio/lp_io.rs Normal file
View File

@ -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<MODE, const PIN: u8> {
pub(crate) private: PhantomData<MODE>,
}
impl<MODE, const PIN: u8> LowPowerPin<MODE, PIN> {
#[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<Input<PullUp>, 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<Input<PullDown>, 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<Input<Floating>, 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<Output<PushPull>, 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<OpenDrain, PIN> {
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<esp32c6::lp_io::gpio0::GPIO0_SPEC>)
}
}
/// Configures a pin for use as a low power pin
pub trait IntoLowPowerPin<const PIN: u8> {
fn into_low_power(self) -> LowPowerPin<Unknown, { PIN }>;
}
#[doc(hidden)]
#[macro_export]
macro_rules! lp_gpio {
(
$($gpionum:literal)+
) => {
paste::paste!{
$(
impl<MODE> $crate::gpio::lp_io::IntoLowPowerPin<$gpionum> for GpioPin<MODE, $gpionum> {
fn into_low_power(self) -> $crate::gpio::lp_io::LowPowerPin<Unknown, $gpionum> {
$crate::gpio::lp_io::init_low_power_pin($gpionum);
$crate::gpio::lp_io::LowPowerPin {
private: core::marker::PhantomData,
}
}
}
impl<MODE> $crate::gpio::RTCPin for GpioPin<MODE, $gpionum> {
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<MODE> $crate::gpio::RTCPinWithResistors for GpioPin<MODE, $gpionum> {
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;

View File

@ -37,6 +37,13 @@ use crate::{
peripherals::{GPIO, IO_MUX}, 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 /// Convenience type-alias for a no-pin / don't care - pin
pub type NoPinType = Gpio0<Unknown>; pub type NoPinType = Gpio0<Unknown>;
@ -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<P = crate::peripherals::GPIO_SD> + '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<const C: u8> {}
impl<const C: u8> GpioEtmEventChannel<C> {
/// Trigger at rising edge
pub fn rising_edge<'d, PIN>(
self,
pin: impl Peripheral<P = PIN> + '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<P = PIN> + '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<P = PIN> + '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<const C: u8> {}
impl<const C: u8> GpioEtmTaskChannel<C> {
// 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<P = PIN> + '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<P = PIN> + '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<P = PIN> + '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<MODE, const PIN: u8> {
pub(crate) private: PhantomData<MODE>,
}
/// Configures a pin for use as a low power pin
pub trait IntoLowPowerPin<const PIN: u8> {
fn into_low_power(self) -> LowPowerPin<Unknown, { PIN }>;
}
impl<MODE, const PIN: u8> LowPowerPin<MODE, PIN> {
#[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<Input<PullUp>, 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<Input<PullDown>, 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<Input<Floating>, 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<Output<PushPull>, 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<OpenDrain, PIN> {
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<esp32s3::rtc_io::touch_pad0::TOUCH_PAD0_SPEC>)
}
}
#[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<esp32s2::rtc_io::touch_pad::TOUCH_PAD_SPEC>)
}
}
}
#[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<MODE, const PIN: u8> {
pub(crate) private: PhantomData<MODE>,
}
impl<MODE, const PIN: u8> LowPowerPin<MODE, PIN> {
#[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<Input<PullUp>, 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<Input<PullDown>, 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<Input<Floating>, 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<Output<PushPull>, PIN> {
self.output_enable(true);
LowPowerPin {
private: PhantomData,
}
}
pub fn into_open_drain_output(self) -> LowPowerPin<OpenDrain, PIN> {
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<esp32c6::lp_io::gpio0::GPIO0_SPEC>)
}
}
/// Configures a pin for use as a low power pin
pub trait IntoLowPowerPin<const PIN: u8> {
fn into_low_power(self) -> LowPowerPin<Unknown, { PIN }>;
}
#[doc(hidden)]
#[macro_export]
macro_rules! lp_gpio {
(
$($gpionum:literal)+
) => {
paste::paste!{
$(
impl<MODE> $crate::gpio::lp_gpio::IntoLowPowerPin<$gpionum> for GpioPin<MODE, $gpionum> {
fn into_low_power(self) -> $crate::gpio::lp_gpio::LowPowerPin<Unknown, $gpionum> {
$crate::gpio::lp_gpio::init_low_power_pin($gpionum);
$crate::gpio::lp_gpio::LowPowerPin {
private: core::marker::PhantomData,
}
}
}
impl<MODE> $crate::gpio::RTCPin for GpioPin<MODE, $gpionum> {
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<MODE> $crate::gpio::RTCPinWithResistors for GpioPin<MODE, $gpionum> {
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")] #[cfg(feature = "async")]
mod asynch { mod asynch {
use core::task::{Context, Poll}; use core::task::{Context, Poll};

185
esp-hal/src/gpio/rtc_io.rs Normal file
View File

@ -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<MODE, const PIN: u8> {
pub(crate) private: PhantomData<MODE>,
}
/// Configures a pin for use as a low power pin
pub trait IntoLowPowerPin<const PIN: u8> {
fn into_low_power(self) -> LowPowerPin<Unknown, { PIN }>;
}
impl<MODE, const PIN: u8> LowPowerPin<MODE, PIN> {
#[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<Input<PullUp>, 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<Input<PullDown>, 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<Input<Floating>, 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<Output<PushPull>, 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<OpenDrain, PIN> {
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<esp32s3::rtc_io::touch_pad0::TOUCH_PAD0_SPEC>)
}
}
#[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<esp32s2::rtc_io::touch_pad::TOUCH_PAD_SPEC>)
}
}

View File

@ -1764,7 +1764,7 @@ pub mod lp_i2c {
use fugit::HertzU32; use fugit::HertzU32;
use crate::{ use crate::{
gpio::{lp_gpio::LowPowerPin, OpenDrain}, gpio::{lp_io::LowPowerPin, OpenDrain},
peripherals::{LP_CLKRST, LP_I2C0}, peripherals::{LP_CLKRST, LP_I2C0},
}; };

View File

@ -321,7 +321,7 @@ crate::gpio::analog! {
7 7
} }
crate::gpio::lp_gpio::lp_gpio! { crate::gpio::lp_io::lp_gpio! {
0 0
1 1
2 2

View File

@ -458,7 +458,7 @@ crate::gpio::gpio! {
// crate::gpio::analog! { // crate::gpio::analog! {
// } // }
// crate::gpio::lp_gpio::lp_gpio! { // crate::gpio::lp_io::lp_gpio! {
// 0 // 0
// 1 // 1
// 2 // 2

View File

@ -2012,7 +2012,7 @@ mod asynch {
#[cfg(lp_uart)] #[cfg(lp_uart)]
pub mod lp_uart { pub mod lp_uart {
use crate::{ use crate::{
gpio::{lp_gpio::LowPowerPin, Floating, Input, Output, PushPull}, gpio::{lp_io::LowPowerPin, Floating, Input, Output, PushPull},
peripherals::{LP_CLKRST, LP_UART}, peripherals::{LP_CLKRST, LP_UART},
uart::{config, config::Config}, uart::{config, config::Config},
}; };

View File

@ -12,7 +12,7 @@
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
gpio::{lp_gpio::IntoLowPowerPin, IO}, gpio::{lp_io::IntoLowPowerPin, IO},
lp_core::{LpCore, LpCoreWakeupSource}, lp_core::{LpCore, LpCoreWakeupSource},
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,

View File

@ -12,7 +12,7 @@
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
gpio::{lp_gpio::IntoLowPowerPin, IO}, gpio::{lp_io::IntoLowPowerPin, IO},
i2c::lp_i2c::LpI2c, i2c::lp_i2c::LpI2c,
lp_core::{LpCore, LpCoreWakeupSource}, lp_core::{LpCore, LpCoreWakeupSource},
peripherals::Peripherals, peripherals::Peripherals,

View File

@ -13,7 +13,7 @@
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
clock::ClockControl, clock::ClockControl,
gpio::{lp_gpio::IntoLowPowerPin, IO}, gpio::{lp_io::IntoLowPowerPin, IO},
lp_core::{LpCore, LpCoreWakeupSource}, lp_core::{LpCore, LpCoreWakeupSource},
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,