esp_hal/gpio/
rtc_io.rs

1//! RTC IO
2//!
3//! # Overview
4//!
5//! The hardware provides a couple of GPIO pins with low power (LP)
6//! capabilities and analog functions.
7//!
8//! ## Configuration
9//!
10//! These pins can be controlled by either IO MUX or RTC IO.
11//!
12//! If controlled by RTC IO, these pins will bypass IO MUX and GPIO
13//! matrix for the use by ULP and peripherals in RTC system.
14//!
15//! When configured as RTC GPIOs, the pins can still be controlled by ULP or
16//! the peripherals in RTC system during chip Deep-sleep, and wake up the
17//! chip from Deep-sleep.
18//!
19//! ## Examples
20//!
21//! ### Configure a ULP Pin as Output
22//!
23//! ```rust, no_run
24#![doc = crate::before_snippet!()]
25//! # use esp_hal::gpio::rtc_io::LowPowerOutput;
26//! // configure GPIO 1 as ULP output pin
27//! let lp_pin = LowPowerOutput::<'static, 1>::new(peripherals.GPIO1);
28//! # Ok(())
29//! # }
30//! ```
31
32use core::marker::PhantomData;
33
34use super::{InputPin, OutputPin, RtcPin};
35use crate::{
36    gpio::RtcFunction,
37    peripherals::{GPIO, RTC_IO},
38};
39
40/// A GPIO output pin configured for low power operation
41pub struct LowPowerOutput<'d, const PIN: u8> {
42    phantom: PhantomData<&'d ()>,
43}
44
45impl<'d, const PIN: u8> LowPowerOutput<'d, PIN> {
46    /// Create a new output pin for use by the low-power core
47    pub fn new<P>(pin: P) -> Self
48    where
49        P: OutputPin + RtcPin + 'd,
50    {
51        pin.rtc_set_config(false, true, RtcFunction::Rtc);
52
53        let this = Self {
54            phantom: PhantomData,
55        };
56        this.output_enable(true);
57
58        this
59    }
60
61    fn output_enable(&self, enable: bool) {
62        let rtc_io = RTC_IO::regs();
63
64        if enable {
65            rtc_io
66                .rtc_gpio_enable_w1ts()
67                .write(|w| unsafe { w.rtc_gpio_enable_w1ts().bits(1 << PIN) });
68        } else {
69            rtc_io
70                .enable_w1tc()
71                .write(|w| unsafe { w.enable_w1tc().bits(1 << PIN) });
72        }
73    }
74}
75
76/// A GPIO input pin configured for low power operation
77pub struct LowPowerInput<'d, const PIN: u8> {
78    phantom: PhantomData<&'d mut ()>,
79}
80
81impl<'d, const PIN: u8> LowPowerInput<'d, PIN> {
82    /// Create a new input pin for use by the low-power core
83    pub fn new<P>(pin: P) -> Self
84    where
85        P: InputPin + RtcPin + 'd,
86    {
87        pin.rtc_set_config(true, true, RtcFunction::Rtc);
88
89        let this = Self {
90            phantom: PhantomData,
91        };
92        this.input_enable(true);
93        this.pullup_enable(false);
94        this.pulldown_enable(false);
95
96        this
97    }
98
99    fn input_enable(&self, enable: bool) {
100        RTC_IO::regs()
101            .touch_pad(PIN as usize)
102            .modify(|_, w| w.fun_ie().bit(enable));
103    }
104
105    /// Sets pull-up enable for the pin
106    pub fn pullup_enable(&self, enable: bool) {
107        RTC_IO::regs()
108            .touch_pad(PIN as usize)
109            .modify(|_, w| w.rue().bit(enable));
110    }
111
112    /// Sets pull-down enable for the pin
113    pub fn pulldown_enable(&self, enable: bool) {
114        RTC_IO::regs()
115            .touch_pad(PIN as usize)
116            .modify(|_, w| w.rde().bit(enable));
117    }
118}
119
120/// A GPIO open-drain output pin configured for low power operation
121pub struct LowPowerOutputOpenDrain<'d, const PIN: u8> {
122    phantom: PhantomData<&'d ()>,
123}
124
125impl<'d, const PIN: u8> LowPowerOutputOpenDrain<'d, PIN> {
126    /// Create a new output pin for use by the low-power core
127    pub fn new<P>(pin: P) -> Self
128    where
129        P: InputPin + OutputPin + RtcPin + 'd,
130    {
131        pin.rtc_set_config(true, true, RtcFunction::Rtc);
132
133        let this = Self {
134            phantom: PhantomData,
135        };
136
137        this.set_open_drain_output(true);
138        this.input_enable(true);
139        this.pullup_enable(true);
140        this.pulldown_enable(false);
141        this.output_enable(true);
142
143        this
144    }
145
146    fn output_enable(&self, enable: bool) {
147        let rtc_io = RTC_IO::regs();
148
149        if enable {
150            rtc_io
151                .rtc_gpio_enable_w1ts()
152                .write(|w| unsafe { w.rtc_gpio_enable_w1ts().bits(1 << PIN) });
153        } else {
154            rtc_io
155                .enable_w1tc()
156                .write(|w| unsafe { w.enable_w1tc().bits(1 << PIN) });
157        }
158    }
159
160    fn input_enable(&self, enable: bool) {
161        RTC_IO::regs()
162            .touch_pad(PIN as usize)
163            .modify(|_, w| w.fun_ie().bit(enable));
164    }
165
166    /// Sets pull-up enable for the pin
167    pub fn pullup_enable(&self, enable: bool) {
168        RTC_IO::regs()
169            .touch_pad(PIN as usize)
170            .modify(|_, w| w.rue().bit(enable));
171    }
172
173    /// Sets pull-down enable for the pin
174    pub fn pulldown_enable(&self, enable: bool) {
175        RTC_IO::regs()
176            .touch_pad(PIN as usize)
177            .modify(|_, w| w.rde().bit(enable));
178    }
179
180    fn set_open_drain_output(&self, enable: bool) {
181        GPIO::regs()
182            .pin(PIN as usize)
183            .modify(|_, w| w.pad_driver().bit(enable));
184    }
185}