3
3
//! This module provides the [InputPinAsync] and [InputDynPinAsync] which both implement
4
4
//! the [embedded_hal_async::digital::Wait] trait. These types allow for asynchronous waiting
5
5
//! on GPIO pins. Please note that this module does not specify/declare the interrupt handlers
6
- //! which must be provided for async support to work. However, it provides one generic
7
- //! [handler][on_interrupt_for_asynch_gpio] which should be called in ALL user interrupt handlers
8
- //! which handle GPIO interrupts.
6
+ //! which must be provided for async support to work. However, it provides the
7
+ //! [on_interrupt_for_async_gpio_for_port] generic interrupt handler. This should be called in all
8
+ //! IRQ functions which handle any GPIO interrupts with the corresponding [Port] argument .
9
9
//!
10
10
//! # Example
11
11
//!
@@ -21,60 +21,66 @@ use va108xx::{self as pac, Irqsel, Sysconfig};
21
21
use crate :: InterruptConfig ;
22
22
23
23
use super :: {
24
- pin, DynGroup , DynPin , DynPinId , InputConfig , InterruptEdge , InvalidPinTypeError , Pin , PinId ,
25
- NUM_GPIO_PINS , NUM_PINS_PORT_A ,
24
+ pin, DynPin , DynPinId , InputConfig , InterruptEdge , InvalidPinTypeError , Pin , PinId , Port ,
25
+ NUM_PINS_PORT_A , NUM_PINS_PORT_B ,
26
26
} ;
27
27
28
- static WAKERS : [ AtomicWaker ; NUM_GPIO_PINS ] = [ const { AtomicWaker :: new ( ) } ; NUM_GPIO_PINS ] ;
29
- static EDGE_DETECTION : [ AtomicBool ; NUM_GPIO_PINS ] =
30
- [ const { AtomicBool :: new ( false ) } ; NUM_GPIO_PINS ] ;
28
+ static WAKERS_FOR_PORT_A : [ AtomicWaker ; NUM_PINS_PORT_A ] =
29
+ [ const { AtomicWaker :: new ( ) } ; NUM_PINS_PORT_A ] ;
30
+ static WAKERS_FOR_PORT_B : [ AtomicWaker ; NUM_PINS_PORT_B ] =
31
+ [ const { AtomicWaker :: new ( ) } ; NUM_PINS_PORT_B ] ;
32
+ static EDGE_DETECTION_PORT_A : [ AtomicBool ; NUM_PINS_PORT_A ] =
33
+ [ const { AtomicBool :: new ( false ) } ; NUM_PINS_PORT_A ] ;
34
+ static EDGE_DETECTION_PORT_B : [ AtomicBool ; NUM_PINS_PORT_B ] =
35
+ [ const { AtomicBool :: new ( false ) } ; NUM_PINS_PORT_B ] ;
31
36
32
- #[ inline]
33
- fn pin_id_to_offset ( dyn_pin_id : DynPinId ) -> usize {
34
- match dyn_pin_id. group {
35
- DynGroup :: A => dyn_pin_id. num as usize ,
36
- DynGroup :: B => NUM_PINS_PORT_A + dyn_pin_id. num as usize ,
37
- }
38
- }
39
-
40
- /// Generic interrupt handler for GPIO interrupts to support the async functionalities.
37
+ /// Generic interrupt handler for GPIO interrupts on a specific port to support async functionalities
41
38
///
42
- /// This handler will wake the correspoding wakers for the pins which triggered an interrupt
43
- /// as well as updating the static edge detection structures. This allows the pin future to
44
- /// complete async operations. The user should call this function in ALL interrupt handlers
45
- /// which handle any GPIO interrupts.
46
- # [ inline ]
47
- pub fn on_interrupt_for_asynch_gpio ( ) {
39
+ /// This function should be called in all interrupt handlers which handle any GPIO interrupts
40
+ /// matching the [Port] argument.
41
+ /// The handler will wake the corresponding wakers for the pins that triggered an interrupts
42
+ /// as well as update the static edge detection structures. This allows the pin future tocomplete
43
+ /// complete async operations.
44
+ pub fn on_interrupt_for_async_gpio_for_port ( port : Port ) {
48
45
let periphs = unsafe { pac:: Peripherals :: steal ( ) } ;
49
46
50
- handle_interrupt_for_gpio_and_port (
51
- periphs. porta . irq_enb ( ) . read ( ) . bits ( ) ,
52
- periphs. porta . edge_status ( ) . read ( ) . bits ( ) ,
53
- 0 ,
54
- ) ;
55
- handle_interrupt_for_gpio_and_port (
56
- periphs. portb . irq_enb ( ) . read ( ) . bits ( ) ,
57
- periphs. portb . edge_status ( ) . read ( ) . bits ( ) ,
58
- NUM_PINS_PORT_A ,
59
- ) ;
47
+ let ( irq_enb, edge_status, wakers, edge_detection) = match port {
48
+ Port :: A => (
49
+ periphs. porta . irq_enb ( ) . read ( ) . bits ( ) ,
50
+ periphs. porta . edge_status ( ) . read ( ) . bits ( ) ,
51
+ WAKERS_FOR_PORT_A . as_ref ( ) ,
52
+ EDGE_DETECTION_PORT_A . as_ref ( ) ,
53
+ ) ,
54
+ Port :: B => (
55
+ periphs. portb . irq_enb ( ) . read ( ) . bits ( ) ,
56
+ periphs. portb . edge_status ( ) . read ( ) . bits ( ) ,
57
+ WAKERS_FOR_PORT_B . as_ref ( ) ,
58
+ EDGE_DETECTION_PORT_B . as_ref ( ) ,
59
+ ) ,
60
+ } ;
61
+
62
+ on_interrupt_for_port ( irq_enb, edge_status, wakers, edge_detection) ;
60
63
}
61
64
62
- // Uses the enabled interrupt register and the persistent edge status to capture all GPIO events.
63
65
#[ inline]
64
- fn handle_interrupt_for_gpio_and_port ( mut irq_enb : u32 , edge_status : u32 , pin_base_offset : usize ) {
66
+ fn on_interrupt_for_port (
67
+ mut irq_enb : u32 ,
68
+ edge_status : u32 ,
69
+ wakers : & ' static [ AtomicWaker ] ,
70
+ edge_detection : & ' static [ AtomicBool ] ,
71
+ ) {
65
72
while irq_enb != 0 {
66
73
let bit_pos = irq_enb. trailing_zeros ( ) as usize ;
67
74
let bit_mask = 1 << bit_pos;
68
75
69
- WAKERS [ pin_base_offset + bit_pos] . wake ( ) ;
76
+ wakers [ bit_pos] . wake ( ) ;
70
77
71
78
if edge_status & bit_mask != 0 {
72
- EDGE_DETECTION [ pin_base_offset + bit_pos]
73
- . store ( true , core:: sync:: atomic:: Ordering :: Relaxed ) ;
74
- }
79
+ edge_detection[ bit_pos] . store ( true , core:: sync:: atomic:: Ordering :: Relaxed ) ;
75
80
76
- // Clear the processed bit
77
- irq_enb &= !bit_mask;
81
+ // Clear the processed bit
82
+ irq_enb &= !bit_mask;
83
+ }
78
84
}
79
85
}
80
86
@@ -85,6 +91,8 @@ fn handle_interrupt_for_gpio_and_port(mut irq_enb: u32, edge_status: u32, pin_ba
85
91
/// struture is granted to allow writing custom async structures.
86
92
pub struct InputPinFuture {
87
93
pin_id : DynPinId ,
94
+ waker_group : & ' static [ AtomicWaker ] ,
95
+ edge_detection_group : & ' static [ AtomicBool ] ,
88
96
}
89
97
90
98
impl InputPinFuture {
@@ -102,6 +110,16 @@ impl InputPinFuture {
102
110
Self :: new_with_dyn_pin ( pin, irq, edge, & mut periphs. sysconfig , & mut periphs. irqsel )
103
111
}
104
112
113
+ #[ inline]
114
+ pub fn pin_group_to_waker_and_edge_detection_group (
115
+ group : Port ,
116
+ ) -> ( & ' static [ AtomicWaker ] , & ' static [ AtomicBool ] ) {
117
+ match group {
118
+ Port :: A => ( WAKERS_FOR_PORT_A . as_ref ( ) , EDGE_DETECTION_PORT_A . as_ref ( ) ) ,
119
+ Port :: B => ( WAKERS_FOR_PORT_B . as_ref ( ) , EDGE_DETECTION_PORT_B . as_ref ( ) ) ,
120
+ }
121
+ }
122
+
105
123
pub fn new_with_dyn_pin (
106
124
pin : & mut DynPin ,
107
125
irq : pac:: Interrupt ,
@@ -113,7 +131,9 @@ impl InputPinFuture {
113
131
return Err ( InvalidPinTypeError ( pin. mode ( ) ) ) ;
114
132
}
115
133
116
- EDGE_DETECTION [ pin_id_to_offset ( pin. id ( ) ) ]
134
+ let ( waker_group, edge_detection_group) =
135
+ Self :: pin_group_to_waker_and_edge_detection_group ( pin. id ( ) . group ) ;
136
+ edge_detection_group[ pin. id ( ) . num as usize ]
117
137
. store ( false , core:: sync:: atomic:: Ordering :: Relaxed ) ;
118
138
pin. configure_edge_interrupt (
119
139
edge,
@@ -122,7 +142,11 @@ impl InputPinFuture {
122
142
Some ( irq_sel) ,
123
143
)
124
144
. unwrap ( ) ;
125
- Ok ( Self { pin_id : pin. id ( ) } )
145
+ Ok ( Self {
146
+ pin_id : pin. id ( ) ,
147
+ waker_group,
148
+ edge_detection_group,
149
+ } )
126
150
}
127
151
128
152
/// # Safety
@@ -146,22 +170,28 @@ impl InputPinFuture {
146
170
sys_cfg : & mut Sysconfig ,
147
171
irq_sel : & mut Irqsel ,
148
172
) -> Self {
149
- EDGE_DETECTION [ pin_id_to_offset ( pin. id ( ) ) ]
173
+ let ( waker_group, edge_detection_group) =
174
+ Self :: pin_group_to_waker_and_edge_detection_group ( pin. id ( ) . group ) ;
175
+ edge_detection_group[ pin. id ( ) . num as usize ]
150
176
. store ( false , core:: sync:: atomic:: Ordering :: Relaxed ) ;
151
177
pin. configure_edge_interrupt (
152
178
edge,
153
179
InterruptConfig :: new ( irq, true , true ) ,
154
180
Some ( sys_cfg) ,
155
181
Some ( irq_sel) ,
156
182
) ;
157
- Self { pin_id : pin. id ( ) }
183
+ Self {
184
+ pin_id : pin. id ( ) ,
185
+ edge_detection_group,
186
+ waker_group,
187
+ }
158
188
}
159
189
}
160
190
161
191
impl Drop for InputPinFuture {
162
192
fn drop ( & mut self ) {
163
193
let periphs = unsafe { pac:: Peripherals :: steal ( ) } ;
164
- if self . pin_id . group == DynGroup :: A {
194
+ if self . pin_id . group == Port :: A {
165
195
periphs
166
196
. porta
167
197
. irq_enb ( )
@@ -181,9 +211,9 @@ impl Future for InputPinFuture {
181
211
self : core:: pin:: Pin < & mut Self > ,
182
212
cx : & mut core:: task:: Context < ' _ > ,
183
213
) -> core:: task:: Poll < Self :: Output > {
184
- let idx = pin_id_to_offset ( self . pin_id ) ;
185
- WAKERS [ idx] . register ( cx. waker ( ) ) ;
186
- if EDGE_DETECTION [ idx] . swap ( false , core:: sync:: atomic:: Ordering :: Relaxed ) {
214
+ let idx = self . pin_id . num as usize ;
215
+ self . waker_group [ idx] . register ( cx. waker ( ) ) ;
216
+ if self . edge_detection_group [ idx] . swap ( false , core:: sync:: atomic:: Ordering :: Relaxed ) {
187
217
return core:: task:: Poll :: Ready ( ( ) ) ;
188
218
}
189
219
core:: task:: Poll :: Pending
@@ -200,8 +230,8 @@ impl InputDynPinAsync {
200
230
/// passed as well and is used to route and enable the interrupt.
201
231
///
202
232
/// Please note that the interrupt handler itself must be provided by the user and the
203
- /// generic [on_interrupt_for_asynch_gpio ] function must be called inside that function for
204
- /// the asynchronous functionality to work.
233
+ /// generic [on_interrupt_for_async_gpio_for_port ] function must be called inside that function
234
+ /// for the asynchronous functionality to work.
205
235
pub fn new ( pin : DynPin , irq : pac:: Interrupt ) -> Result < Self , InvalidPinTypeError > {
206
236
if !pin. is_input_pin ( ) {
207
237
return Err ( InvalidPinTypeError ( pin. mode ( ) ) ) ;
@@ -335,8 +365,8 @@ impl<I: PinId, C: InputConfig> InputPinAsync<I, C> {
335
365
/// passed as well and is used to route and enable the interrupt.
336
366
///
337
367
/// Please note that the interrupt handler itself must be provided by the user and the
338
- /// generic [on_interrupt_for_asynch_gpio ] function must be called inside that function for
339
- /// the asynchronous functionality to work.
368
+ /// generic [on_interrupt_for_async_gpio_for_port ] function must be called inside that function
369
+ /// for the asynchronous functionality to work.
340
370
pub fn new ( pin : Pin < I , pin:: Input < C > > , irq : pac:: Interrupt ) -> Self {
341
371
Self { pin, irq }
342
372
}
0 commit comments