Skip to content

Commit 94e0ecd

Browse files
committed
zephyr: device: gpio: Implementing wait for low
The api allows for either waiting for high or low. This somewhat works, but seems to lock up after a few times. Signed-off-by: David Brown <[email protected]>
1 parent f156c85 commit 94e0ecd

File tree

2 files changed

+30
-22
lines changed

2 files changed

+30
-22
lines changed

tests/drivers/gpio-async/src/lib.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
extern crate alloc;
77

8-
use embassy_time::{Duration, Timer};
98
use zephyr::{embassy::Executor, raw::{GPIO_INPUT, GPIO_OUTPUT_ACTIVE, GPIO_PULL_DOWN}};
109

1110
use embassy_executor::Spawner;
@@ -41,21 +40,10 @@ async fn main(spawner: Spawner) {
4140
row0.configure(&mut gpio_token, GPIO_INPUT | GPIO_PULL_DOWN);
4241
}
4342

44-
let mut last = false;
45-
4643
loop {
47-
let current = unsafe { row0.get(&mut gpio_token) };
48-
// info!("Current: {:?}", current);
49-
if current != last {
50-
if current {
51-
info!("Pressed");
52-
} else {
53-
info!("Released: Waiting for high");
54-
unsafe { row0.wait_for_high(&mut gpio_token).await };
55-
}
56-
last = current;
57-
}
58-
59-
Timer::after(Duration::from_millis(25)).await;
44+
unsafe { row0.wait_for_high(&mut gpio_token).await };
45+
info!("Pressed");
46+
unsafe { row0.wait_for_low(&mut gpio_token).await };
47+
info!("Released");
6048
}
6149
}

zephyr/src/device/gpio.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ mod async_io {
2020
//! the largest number currently used, although this might change with 64-bit targest in the
2121
//! future.
2222
23-
use core::{cell::UnsafeCell, future::Future, mem, sync::atomic::Ordering, task::{Poll, Waker}};
23+
use core::{cell::UnsafeCell, ffi::c_int, future::Future, mem, sync::atomic::Ordering, task::{Poll, Waker}};
2424

2525
use embassy_sync::waitqueue::AtomicWaker;
2626
use portable_atomic::AtomicBool;
27-
use zephyr_sys::{device, gpio_add_callback, gpio_callback, gpio_init_callback, gpio_pin_get, gpio_pin_interrupt_configure, gpio_pin_interrupt_configure_dt, gpio_port_pins_t, GPIO_INT_LEVEL_HIGH, ZR_GPIO_INT_MODE_DISABLE_ONLY};
27+
use zephyr_sys::{device, gpio_add_callback, gpio_callback, gpio_init_callback, gpio_pin_get, gpio_pin_interrupt_configure, gpio_pin_interrupt_configure_dt, gpio_port_pins_t, GPIO_INT_LEVEL_HIGH, GPIO_INT_LEVEL_LOW, ZR_GPIO_INT_MODE_DISABLE_ONLY};
28+
29+
use crate::printkln;
2830

2931
use super::{GpioPin, GpioToken};
3032

@@ -135,19 +137,31 @@ mod async_io {
135137
/// more than one GPIO.
136138
///
137139
pub unsafe fn wait_for_high(&mut self, _token: &mut GpioToken) -> impl Future<Output = ()> + use<'_> {
138-
GpioWait::new(self)
140+
GpioWait::new(self, 1)
141+
}
142+
143+
/// Asynchronously wait for a gpio pin to become low.
144+
///
145+
/// # Safety
146+
///
147+
/// The `_token` enforces single use of gpios. Note that this makes it impossible to wait
148+
/// for more than one GPIO.
149+
pub unsafe fn wait_for_low(&mut self, _token: &mut GpioToken) -> impl Future<Output = ()> + use<'_> {
150+
GpioWait::new(self, 0)
139151
}
140152
}
141153

142154
/// A future that waits for a gpio to become high.
143155
pub struct GpioWait<'a> {
144156
pin: &'a mut GpioPin,
157+
level: u8,
145158
}
146159

147160
impl<'a> GpioWait<'a> {
148-
fn new(pin: &'a mut GpioPin) -> Self {
161+
fn new(pin: &'a mut GpioPin, level: u8) -> Self {
149162
Self {
150163
pin,
164+
level,
151165
}
152166
}
153167
}
@@ -160,10 +174,16 @@ mod async_io {
160174

161175
self.pin.data.register(self.pin.pin.pin, cx.waker());
162176

177+
let mode = match self.level {
178+
0 => GPIO_INT_LEVEL_LOW,
179+
1 => GPIO_INT_LEVEL_HIGH,
180+
_ => unreachable!(),
181+
};
182+
163183
unsafe {
164-
gpio_pin_interrupt_configure_dt(&self.pin.pin, GPIO_INT_LEVEL_HIGH);
184+
gpio_pin_interrupt_configure_dt(&self.pin.pin, mode);
165185

166-
if gpio_pin_get(self.pin.pin.port, self.pin.pin.pin) == 1 {
186+
if gpio_pin_get(self.pin.pin.port, self.pin.pin.pin) == self.level as c_int {
167187
// TODO: Need to match with level.
168188
// Zephyr doesn't have a way to determine if a given interrupt is pending, so the
169189
// best we can do is just read the pin. This doesn't work for edges though.

0 commit comments

Comments
 (0)