Skip to content
This repository was archived by the owner on Aug 9, 2022. It is now read-only.

Commit bc79010

Browse files
authored
Merge pull request #42 from arjanmels/feature-gpio-rtc
Extended (RTC) GPIO functionality
2 parents 1d57619 + 6ea2ce2 commit bc79010

File tree

2 files changed

+740
-139
lines changed

2 files changed

+740
-139
lines changed

examples/gpio.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use core::{fmt::Write, panic::PanicInfo};
5+
6+
use esp32_hal::{
7+
clock_control::sleep,
8+
dport::Split,
9+
dprintln,
10+
gpio::{Event, Floating, InputPin, OutputPin, Pin, Pull, RTCInputPin, RTCOutputPin},
11+
interrupt::{Interrupt, InterruptLevel},
12+
prelude::*,
13+
serial::{config::Config, Serial},
14+
target,
15+
timer::Timer,
16+
Core,
17+
};
18+
19+
static SERIAL: CriticalSectionSpinLockMutex<
20+
Option<
21+
esp32_hal::serial::Serial<
22+
esp32::UART0,
23+
esp32_hal::gpio::Gpio1<esp32_hal::gpio::Unknown>,
24+
esp32_hal::gpio::Gpio3<esp32_hal::gpio::Unknown>,
25+
>,
26+
>,
27+
> = CriticalSectionSpinLockMutex::new(None);
28+
29+
static GPIO: CriticalSectionSpinLockMutex<
30+
Option<esp32_hal::gpio::Gpio26<esp32_hal::gpio::RTCInput<Floating>>>,
31+
> = CriticalSectionSpinLockMutex::new(None);
32+
33+
#[entry]
34+
fn main() -> ! {
35+
let dp = target::Peripherals::take().unwrap();
36+
37+
let (mut dport, dport_clock_control) = dp.DPORT.split();
38+
39+
let clkcntrl = esp32_hal::clock_control::ClockControl::new(
40+
dp.RTCCNTL,
41+
dp.APB_CTRL,
42+
dport_clock_control,
43+
esp32_hal::clock_control::XTAL_FREQUENCY_AUTO,
44+
)
45+
.unwrap();
46+
47+
let (clkcntrl_config, mut watchdog_rtc) = clkcntrl.freeze().unwrap();
48+
let (_, _, _, mut watchdog0) = Timer::new(dp.TIMG0, clkcntrl_config);
49+
let (_, _, _, mut watchdog1) = Timer::new(dp.TIMG1, clkcntrl_config);
50+
51+
watchdog_rtc.disable();
52+
watchdog0.disable();
53+
watchdog1.disable();
54+
55+
let gpios = dp.GPIO.split();
56+
57+
let mut gpio = gpios.gpio26.into_floating_rtc_input();
58+
gpio.internal_pull_up(true);
59+
gpio.enable_hold(false);
60+
gpio.enable_input(false);
61+
gpio.rtc_enable_input(true);
62+
63+
gpio.listen_with_options(Event::LowLevel, true, false, true, false, false);
64+
65+
// setup serial controller
66+
let mut serial: Serial<_, _, _> = Serial::new(
67+
dp.UART0,
68+
esp32_hal::serial::Pins {
69+
tx: gpios.gpio1,
70+
rx: gpios.gpio3,
71+
cts: None,
72+
rts: None,
73+
},
74+
Config::default().baudrate(115_200.Hz()),
75+
clkcntrl_config,
76+
&mut dport,
77+
)
78+
.unwrap();
79+
80+
writeln!(serial, "\n\nESP32 Started\n\n").unwrap();
81+
82+
(&SERIAL).lock(|val| *val = Some(serial));
83+
(&GPIO).lock(|val| *val = Some(gpio));
84+
85+
interrupt::enable(Interrupt::GPIO_INTR).unwrap();
86+
87+
// Even though the interrupt is called GPIO_NMI is can be routed to any interrupt level.
88+
// Using NMI level (7) is in principle a risk for deadlocks because the
89+
// CriticalSectionSpinLockMutex does not disable the NMI. Therefore using level 5 instead.
90+
91+
// Because the level 5 interrupt clears the interrupt, the regular level 1 handler
92+
// will not be called.
93+
// Comment out the next line to test the level 1 handler
94+
interrupt::enable_with_priority(Core::PRO, Interrupt::GPIO_NMI, InterruptLevel(5)).unwrap();
95+
96+
let mut x = 0;
97+
loop {
98+
x = x + 1;
99+
(&SERIAL, &GPIO).lock(|serial, gpio| {
100+
let serial = serial.as_mut().unwrap();
101+
let gpio = gpio.as_mut().unwrap();
102+
writeln!(
103+
serial,
104+
"Loop: {} {} {} {}",
105+
x,
106+
gpio.is_high().unwrap(),
107+
gpio.is_input_high(),
108+
gpio.rtc_is_input_high()
109+
)
110+
.unwrap();
111+
});
112+
113+
sleep(500.ms());
114+
}
115+
}
116+
117+
fn handle_gpio_interrupt() {
118+
(&GPIO, &SERIAL).lock(|gpio, serial| {
119+
let gpio = gpio.as_mut().unwrap();
120+
let serial = serial.as_mut().unwrap();
121+
122+
if gpio.is_interrupt_set() || gpio.is_non_maskable_interrupt_set() {
123+
writeln!(
124+
serial,
125+
" Interrupt level: {}, pin state: {}",
126+
xtensa_lx6::interrupt::get_level(),
127+
gpio.is_high().unwrap()
128+
)
129+
.unwrap();
130+
131+
if gpio.is_high().unwrap() {
132+
gpio.listen_with_options(Event::LowLevel, true, false, true, false, false);
133+
} else {
134+
gpio.listen_with_options(Event::HighLevel, true, false, true, false, false);
135+
};
136+
// need to change listen before clearing interrupt, otherwise will fire
137+
// immediately again.
138+
gpio.clear_interrupt();
139+
}
140+
});
141+
}
142+
143+
#[interrupt]
144+
fn GPIO_INTR() {
145+
handle_gpio_interrupt();
146+
}
147+
148+
#[interrupt]
149+
fn GPIO_NMI() {
150+
handle_gpio_interrupt();
151+
}
152+
153+
#[panic_handler]
154+
fn panic(info: &PanicInfo) -> ! {
155+
dprintln!("\n\n*** {:?}", info);
156+
loop {}
157+
}

0 commit comments

Comments
 (0)