esp_hal/gpio/lp_io/low_level/
v2.rs1use crate::{
2 gpio::{Level, LpPin, lp_io::LpFunction},
3 peripherals::{GPIO, LPWR, RTC_IO, SENS},
4};
5
6#[rustfmt::skip]
7macro_rules! pin_reg {
8 (GPIO0) => { RTC_IO::regs().touch_pad(0) };
9 (GPIO1) => { RTC_IO::regs().touch_pad(1) };
10 (GPIO2) => { RTC_IO::regs().touch_pad(2) };
11 (GPIO3) => { RTC_IO::regs().touch_pad(3) };
12 (GPIO4) => { RTC_IO::regs().touch_pad(4) };
13 (GPIO5) => { RTC_IO::regs().touch_pad(5) };
14 (GPIO6) => { RTC_IO::regs().touch_pad(6) };
15 (GPIO7) => { RTC_IO::regs().touch_pad(7) };
16 (GPIO8) => { RTC_IO::regs().touch_pad(8) };
17 (GPIO9) => { RTC_IO::regs().touch_pad(9) };
18 (GPIO10) => { RTC_IO::regs().touch_pad(10) };
19 (GPIO11) => { RTC_IO::regs().touch_pad(11) };
20 (GPIO12) => { RTC_IO::regs().touch_pad(12) };
21 (GPIO13) => { RTC_IO::regs().touch_pad(13) };
22 (GPIO14) => { RTC_IO::regs().touch_pad(14) };
23 (GPIO15) => { RTC_IO::regs().xtal_32p_pad() };
24 (GPIO16) => { RTC_IO::regs().xtal_32n_pad() };
25 (GPIO17) => { RTC_IO::regs().pad_dac1() };
26 (GPIO18) => { RTC_IO::regs().pad_dac2() };
27 (GPIO19) => { RTC_IO::regs().rtc_pad19() };
28 (GPIO20) => { RTC_IO::regs().rtc_pad20() };
29 (GPIO21) => { RTC_IO::regs().rtc_pad21() };
30}
31
32#[rustfmt::skip]
33macro_rules! hold_field {
34 ($reg:ident, GPIO0) => { $reg.touch_pad0() };
35 ($reg:ident, GPIO1) => { $reg.touch_pad1() };
36 ($reg:ident, GPIO2) => { $reg.touch_pad2() };
37 ($reg:ident, GPIO3) => { $reg.touch_pad3() };
38 ($reg:ident, GPIO4) => { $reg.touch_pad4() };
39 ($reg:ident, GPIO5) => { $reg.touch_pad5() };
40 ($reg:ident, GPIO6) => { $reg.touch_pad6() };
41 ($reg:ident, GPIO7) => { $reg.touch_pad7() };
42 ($reg:ident, GPIO8) => { $reg.touch_pad8() };
43 ($reg:ident, GPIO9) => { $reg.touch_pad9() };
44 ($reg:ident, GPIO10) => { $reg.touch_pad10() };
45 ($reg:ident, GPIO11) => { $reg.touch_pad11() };
46 ($reg:ident, GPIO12) => { $reg.touch_pad12() };
47 ($reg:ident, GPIO13) => { $reg.touch_pad13() };
48 ($reg:ident, GPIO14) => { $reg.touch_pad14() };
49 ($reg:ident, GPIO15) => { $reg.x32p() };
50 ($reg:ident, GPIO16) => { $reg.x32n() };
51 ($reg:ident, GPIO17) => { $reg.pdac1() };
52 ($reg:ident, GPIO18) => { $reg.pdac2() };
53 ($reg:ident, GPIO19) => { $reg.pad19() };
54 ($reg:ident, GPIO20) => { $reg.pad20() };
55 ($reg:ident, GPIO21) => { $reg.pad21() };
56}
57
58for_each_lp_function!(
60 (LP_GPIOn $(
61 (($_lp:ident, LP_GPIOn, $n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt)
62 ),*) => {
63 macro_rules! with_pin_reg {
64 ($pin:expr, |$reg:ident| $code:expr) => {{
65 match $pin {
66 $(
67 $n => {
68 let $reg = pin_reg!($gpio);
69 $code
70 }
71 )*
72 _ => unreachable!(),
73 }
74 }};
75 }
76 };
77);
78
79for_each_lp_function! {
80 (($_lp:ident, LP_GPIOn, $n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => {
81 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
82 impl LpPin for crate::peripherals::$gpio<'_> {
83 fn lp_number(&self) -> u8 {
84 $n
85 }
86 }
87 };
88
89 (LP_GPIOn $( (($_lp:ident, LP_GPIOn, $n:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) ),*) => {
92 pub(crate) fn pad_hold(lp: u8, enable: bool) {
93 LPWR::regs().pad_hold().modify(|_, w| {
94 match lp {
95 $( $n => hold_field!(w, $gpio).bit(enable), )*
96 _ => unreachable!(),
97 }
98 });
99 }
100
101 pub(crate) fn is_pad_held(lp: u8) -> bool {
103 let r = LPWR::regs().pad_hold().read();
104 match lp {
105 $( $n => hold_field!(r, $gpio).bit_is_set(), )*
106 _ => unreachable!(),
107 }
108 }
109
110 #[cfg(sleep_driver_supported)]
112 const ALL_PADS: u32 = 0 $( | 1 << $n )*;
113 };
114}
115
116fn digital_hold_bit(gpio: u8) -> Option<u8> {
121 gpio.checked_sub(21)
122}
123
124pub(crate) fn digital_pad_hold(gpio: u8, enable: bool) {
126 let Some(bit) = digital_hold_bit(gpio) else {
127 return;
128 };
129
130 let mask = 1 << bit;
131 LPWR::regs().dig_pad_hold().modify(|r, w| unsafe {
132 let bits = r.dig_pad_hold().bits();
133 w.dig_pad_hold()
134 .bits(if enable { bits | mask } else { bits & !mask })
135 });
136}
137
138pub(crate) fn is_digital_pad_held(gpio: u8) -> bool {
140 let Some(bit) = digital_hold_bit(gpio) else {
141 return false;
142 };
143
144 LPWR::regs().dig_pad_hold().read().dig_pad_hold().bits() & (1 << bit) != 0
145}
146
147pub(crate) fn set_config(lp: u8, input_enable: bool, mux: bool, func: LpFunction) {
148 enable_iomux_clk_gate();
149 with_pin_reg!(lp, |reg| reg.modify(|_, w| unsafe {
150 w.fun_ie().bit(input_enable);
151 w.mux_sel().bit(mux);
152 w.fun_sel().bits(func as u8)
153 }));
154}
155
156pub(crate) fn apply_wakeup(lp: u8, wakeup: bool, level: Level) {
157 RTC_IO::regs().pin(lp as usize).modify(|_, w| unsafe {
158 w.wakeup_enable().bit(wakeup);
159 w.int_type().bits(crate::gpio::lp_io::wake_trigger(level))
160 });
161}
162
163#[cfg(sleep_driver_supported)]
165pub(crate) fn wakeup_status() -> u32 {
166 let status = RTC_IO::regs().rtc_gpio_status().read();
167 cfg_select! {
168 esp32s2 => status.gpio_status_int().bits(),
169 esp32s3 => status.int().bits(),
170 }
171}
172
173#[cfg(sleep_driver_supported)]
176pub(crate) fn wakeup_enabled_mask() -> u32 {
177 let mut mask = 0;
178 let mut pads = ALL_PADS;
179 while pads != 0 {
180 let lp = pads.trailing_zeros();
181 pads &= !(1 << lp);
182
183 if RTC_IO::regs()
184 .pin(lp as usize)
185 .read()
186 .wakeup_enable()
187 .bit_is_set()
188 {
189 mask |= 1 << lp;
190 }
191 }
192 mask
193}
194
195#[cfg(sleep_driver_supported)]
197pub(crate) fn clear_wakeup_status() {
198 RTC_IO::regs().rtc_gpio_status_w1tc().write(|w| unsafe {
199 cfg_select! {
200 esp32s2 => w.gpio_status_int_w1tc().bits(ALL_PADS),
201 esp32s3 => w.rtc_gpio_status_int_w1tc().bits(ALL_PADS),
202 }
203 });
204}
205
206for_each_analog_function! {
207 (($_ch:ident, ADCn_CHm, $_n:literal, $_m:literal), $gpio:ident) => {
208 impl crate::peripherals::$gpio<'_> {
209 #[cfg(feature = "unstable")]
210 pub(crate) fn set_analog_impl(&self) {
211 use crate::gpio::{LpPin, Pin};
212
213 enable_iomux_clk_gate();
214
215 output_enable(self.lp_number(), false);
216 set_open_drain_output(self.number(), false);
217
218 pin_reg!($gpio).modify(|_, w| {
219 w.fun_ie().clear_bit();
220 w.mux_sel().set_bit();
221 unsafe { w.fun_sel().bits(LpFunction::LP_GPIO as u8) };
222 w.rue().bit(false);
223 w.rde().bit(false)
224 });
225 }
226 }
227 };
228}
229
230pub(crate) fn init_pin(lp: u8, input_enable: bool) -> u8 {
231 set_config(lp, input_enable, true, LpFunction::LP_GPIO);
232 lp
233}
234
235pub(crate) fn output_enable(lp: u8, enable: bool) {
236 if enable {
237 RTC_IO::regs()
238 .rtc_gpio_enable_w1ts()
239 .write(|w| unsafe { w.rtc_gpio_enable_w1ts().bits(1 << lp) });
240 } else {
241 RTC_IO::regs()
242 .enable_w1tc()
243 .write(|w| unsafe { w.enable_w1tc().bits(1 << lp) });
244 }
245}
246
247pub(crate) fn input_enable(lp: u8, enable: bool) {
248 with_pin_reg!(lp, |reg| reg.modify(|_, w| w.fun_ie().bit(enable)));
249}
250
251pub(crate) fn pullup_enable(lp: u8, enable: bool) {
252 with_pin_reg!(lp, |reg| reg.modify(|_, w| w.rue().bit(enable)));
253}
254
255pub(crate) fn pulldown_enable(lp: u8, enable: bool) {
256 with_pin_reg!(lp, |reg| reg.modify(|_, w| w.rde().bit(enable)));
257}
258
259pub(crate) fn set_open_drain_output(gpio: u8, enable: bool) {
262 GPIO::regs()
263 .pin(gpio as usize)
264 .modify(|_, w| w.pad_driver().bit(enable));
265}
266
267#[cfg(lp_i2c_master_driver_supported)]
268pub(crate) fn reset_pin(lp: u8) {
269 output_enable(lp, false);
270 set_open_drain_output(lp, false);
272
273 enable_iomux_clk_gate();
276 with_pin_reg!(lp, |reg| reg.reset());
277}
278
279fn enable_iomux_clk_gate() {
280 cfg_select! {
281 esp32s2 => {
282 SENS::regs()
283 .sar_io_mux_conf()
284 .modify(|_, w| w.iomux_clk_gate_en().set_bit());
285 }
286 esp32s3 => {
287 SENS::regs()
288 .sar_peri_clk_gate_conf()
289 .modify(|_, w| w.iomux_clk_en().set_bit());
290 }
291 }
292}