@@ -22,28 +22,29 @@ mod async_io {
22
22
23
23
use core:: {
24
24
cell:: UnsafeCell ,
25
- ffi:: c_int,
26
25
future:: Future ,
27
26
mem,
28
27
sync:: atomic:: Ordering ,
29
28
task:: { Poll , Waker } ,
30
29
} ;
31
30
32
31
use embassy_sync:: waitqueue:: AtomicWaker ;
33
- use portable_atomic:: AtomicBool ;
34
32
use zephyr_sys:: {
35
- device, gpio_add_callback, gpio_callback, gpio_init_callback, gpio_pin_get ,
36
- gpio_pin_interrupt_configure , gpio_pin_interrupt_configure_dt, gpio_port_pins_t,
37
- GPIO_INT_LEVEL_HIGH , GPIO_INT_LEVEL_LOW , ZR_GPIO_INT_MODE_DISABLE_ONLY ,
33
+ device, gpio_add_callback, gpio_callback, gpio_init_callback, gpio_pin_interrupt_configure ,
34
+ gpio_pin_interrupt_configure_dt, gpio_port_pins_t, GPIO_INT_LEVEL_HIGH , GPIO_INT_LEVEL_LOW ,
35
+ ZR_GPIO_INT_MODE_DISABLE_ONLY ,
38
36
} ;
39
37
40
- use crate :: printkln ;
38
+ use crate :: sync :: atomic :: { AtomicBool , AtomicU32 } ;
41
39
42
40
use super :: { GpioPin , GpioToken } ;
43
41
44
42
pub ( crate ) struct GpioStatic {
45
43
/// The wakers for each of the gpios.
46
44
wakers : [ AtomicWaker ; 32 ] ,
45
+ /// Indicates when an interrupt has fired. Used to definitively indicate the event has
46
+ /// happened, so we can wake.
47
+ fired : AtomicU32 ,
47
48
/// Have we been initialized?
48
49
installed : AtomicBool ,
49
50
/// The data for the callback itself.
@@ -56,6 +57,7 @@ mod async_io {
56
57
pub ( crate ) const fn new ( ) -> Self {
57
58
Self {
58
59
wakers : [ const { AtomicWaker :: new ( ) } ; 32 ] ,
60
+ fired : AtomicU32 :: new ( 0 ) ,
59
61
installed : AtomicBool :: new ( false ) ,
60
62
// SAFETY: `installed` will tell us this need to be installed.
61
63
callback : unsafe { mem:: zeroed ( ) } ,
@@ -116,8 +118,6 @@ mod async_io {
116
118
. cast :: < Self > ( )
117
119
} ;
118
120
119
- // printkln!("CB called: pins: {pins:#x}");
120
-
121
121
// For each pin we are informed of.
122
122
while pins > 0 {
123
123
let pin = pins. trailing_zeros ( ) ;
@@ -134,13 +134,23 @@ mod async_io {
134
134
gpio_pin_interrupt_configure ( port, pin as u8 , ZR_GPIO_INT_MODE_DISABLE_ONLY ) ;
135
135
136
136
// Remove the callback bit. Unclear if this is actually useful.
137
- // (*cb).pin_mask &= !(1 << pin);
137
+ ( * cb) . pin_mask &= !( 1 << pin) ;
138
+
139
+ // Indicate that we have fired.
140
+ // AcqRel is sufficient for ordering across a single atomic.
141
+ ( * data) . fired . fetch_or ( 1 << pin, Ordering :: AcqRel ) ;
138
142
139
143
// After the interrupt is off, wake the handler.
140
144
( * data) . wakers [ pin as usize ] . wake ( ) ;
141
145
}
142
146
}
143
147
}
148
+
149
+ /// Check if we have fired for a given pin. Clears the status.
150
+ pub ( crate ) fn has_fired ( & self , pin : u8 ) -> bool {
151
+ let value = self . fired . fetch_and ( !( 1 << pin) , Ordering :: AcqRel ) ;
152
+ value & ( 1 << pin) != 0
153
+ }
144
154
}
145
155
146
156
impl GpioPin {
@@ -193,6 +203,12 @@ mod async_io {
193
203
) -> core:: task:: Poll < Self :: Output > {
194
204
self . pin . data . fast_install ( self . pin . pin . port ) ;
195
205
206
+ // Early detection of the event. Also clears.
207
+ // This should be non-racy as long as only one task at a time waits on the gpio.
208
+ if self . pin . data . has_fired ( self . pin . pin . pin ) {
209
+ return Poll :: Ready ( ( ) ) ;
210
+ }
211
+
196
212
self . pin . data . register ( self . pin . pin . pin , cx. waker ( ) ) ;
197
213
198
214
let mode = match self . level {
@@ -204,10 +220,9 @@ mod async_io {
204
220
unsafe {
205
221
gpio_pin_interrupt_configure_dt ( & self . pin . pin , mode) ;
206
222
207
- if gpio_pin_get ( self . pin . pin . port , self . pin . pin . pin ) == self . level as c_int {
208
- // TODO: Need to match with level.
209
- // Zephyr doesn't have a way to determine if a given interrupt is pending, so the
210
- // best we can do is just read the pin. This doesn't work for edges though.
223
+ // Before sleeping, check if it fired, to avoid having to pend if it already
224
+ // happened.
225
+ if self . pin . data . has_fired ( self . pin . pin . pin ) {
211
226
return Poll :: Ready ( ( ) ) ;
212
227
}
213
228
}
0 commit comments