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 two generic interrupt
7
+ //! handlers:
8
+ //!
9
+ //! - [on_interrupt_for_async_gpio_port_a]
10
+ //! - [on_interrupt_for_async_gpio_port_b]
11
+ //!
12
+ //! Those should be called in the interrupt handlers which handle GPIO interrupts for port A
13
+ //! and/or port B.
9
14
//!
10
15
//! # Example
11
16
//!
@@ -22,59 +27,80 @@ use crate::InterruptConfig;
22
27
23
28
use super :: {
24
29
pin, DynGroup , DynPin , DynPinId , InputConfig , InterruptEdge , InvalidPinTypeError , Pin , PinId ,
25
- NUM_GPIO_PINS , NUM_PINS_PORT_A ,
30
+ NUM_PINS_PORT_A , NUM_PINS_PORT_B ,
26
31
} ;
27
32
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 ] ;
31
-
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
- }
33
+ static WAKERS_FOR_PORT_A : [ AtomicWaker ; NUM_PINS_PORT_A ] =
34
+ [ const { AtomicWaker :: new ( ) } ; NUM_PINS_PORT_A ] ;
35
+ static WAKERS_FOR_PORT_B : [ AtomicWaker ; NUM_PINS_PORT_B ] =
36
+ [ const { AtomicWaker :: new ( ) } ; NUM_PINS_PORT_B ] ;
37
+ static EDGE_DETECTION_PORT_A : [ AtomicBool ; NUM_PINS_PORT_A ] =
38
+ [ const { AtomicBool :: new ( false ) } ; NUM_PINS_PORT_A ] ;
39
+ static EDGE_DETECTION_PORT_B : [ AtomicBool ; NUM_PINS_PORT_B ] =
40
+ [ const { AtomicBool :: new ( false ) } ; NUM_PINS_PORT_B ] ;
39
41
40
- /// Generic interrupt handler for GPIO interrupts to support the async functionalities.
42
+ /// Generic interrupt handler for GPIO interrupts on PORT A to support the async functionalities.
43
+ ///
44
+ /// This function should be called in all interrupt hanflers which handle any PORT A GPIO
45
+ /// interrupts.
41
46
///
42
47
/// This handler will wake the correspoding wakers for the pins which triggered an interrupt
43
48
/// as well as updating the static edge detection structures. This allows the pin future to
44
49
/// complete async operations. The user should call this function in ALL interrupt handlers
45
50
/// which handle any GPIO interrupts.
46
51
#[ inline]
47
- pub fn on_interrupt_for_asynch_gpio ( ) {
52
+ pub fn on_interrupt_for_async_gpio_port_a ( ) {
48
53
let periphs = unsafe { pac:: Peripherals :: steal ( ) } ;
49
54
50
55
handle_interrupt_for_gpio_and_port (
51
56
periphs. porta . irq_enb ( ) . read ( ) . bits ( ) ,
52
57
periphs. porta . edge_status ( ) . read ( ) . bits ( ) ,
53
- 0 ,
58
+ & WAKERS_FOR_PORT_A ,
59
+ & EDGE_DETECTION_PORT_A ,
54
60
) ;
61
+ }
62
+
63
+ /// Generic interrupt handler for GPIO interrupts on PORT B to support the async functionalities.
64
+ ///
65
+ /// This function should be called in all interrupt hanflers which handle any PORT B GPIO
66
+ /// interrupts.
67
+ ///
68
+ /// This handler will wake the correspoding wakers for the pins which triggered an interrupt
69
+ /// as well as updating the static edge detection structures. This allows the pin future to
70
+ /// complete async operations. The user should call this function in ALL interrupt handlers
71
+ /// which handle any GPIO interrupts.
72
+ #[ inline]
73
+ pub fn on_interrupt_for_async_gpio_port_b ( ) {
74
+ let periphs = unsafe { pac:: Peripherals :: steal ( ) } ;
75
+
55
76
handle_interrupt_for_gpio_and_port (
56
77
periphs. portb . irq_enb ( ) . read ( ) . bits ( ) ,
57
78
periphs. portb . edge_status ( ) . read ( ) . bits ( ) ,
58
- NUM_PINS_PORT_A ,
79
+ & WAKERS_FOR_PORT_B ,
80
+ & EDGE_DETECTION_PORT_B ,
59
81
) ;
60
82
}
61
83
62
84
// Uses the enabled interrupt register and the persistent edge status to capture all GPIO events.
63
85
#[ inline]
64
- fn handle_interrupt_for_gpio_and_port ( mut irq_enb : u32 , edge_status : u32 , pin_base_offset : usize ) {
86
+ fn handle_interrupt_for_gpio_and_port (
87
+ mut irq_enb : u32 ,
88
+ edge_status : u32 ,
89
+ wakers : & ' static [ AtomicWaker ] ,
90
+ edge_detection : & ' static [ AtomicBool ] ,
91
+ ) {
65
92
while irq_enb != 0 {
66
93
let bit_pos = irq_enb. trailing_zeros ( ) as usize ;
67
94
let bit_mask = 1 << bit_pos;
68
95
69
- WAKERS [ pin_base_offset + bit_pos] . wake ( ) ;
96
+ wakers [ bit_pos] . wake ( ) ;
70
97
71
98
if edge_status & bit_mask != 0 {
72
- EDGE_DETECTION [ pin_base_offset + bit_pos]
73
- . store ( true , core:: sync:: atomic:: Ordering :: Relaxed ) ;
74
- }
99
+ edge_detection[ bit_pos] . store ( true , core:: sync:: atomic:: Ordering :: Relaxed ) ;
75
100
76
- // Clear the processed bit
77
- irq_enb &= !bit_mask;
101
+ // Clear the processed bit
102
+ irq_enb &= !bit_mask;
103
+ }
78
104
}
79
105
}
80
106
@@ -85,6 +111,8 @@ fn handle_interrupt_for_gpio_and_port(mut irq_enb: u32, edge_status: u32, pin_ba
85
111
/// struture is granted to allow writing custom async structures.
86
112
pub struct InputPinFuture {
87
113
pin_id : DynPinId ,
114
+ waker_group : & ' static [ AtomicWaker ] ,
115
+ edge_detection_group : & ' static [ AtomicBool ] ,
88
116
}
89
117
90
118
impl InputPinFuture {
@@ -102,6 +130,15 @@ impl InputPinFuture {
102
130
Self :: new_with_dyn_pin ( pin, irq, edge, & mut periphs. sysconfig , & mut periphs. irqsel )
103
131
}
104
132
133
+ pub fn pin_group_to_waker_and_edge_detection_group (
134
+ group : DynGroup ,
135
+ ) -> ( & ' static [ AtomicWaker ] , & ' static [ AtomicBool ] ) {
136
+ match group {
137
+ DynGroup :: A => ( WAKERS_FOR_PORT_A . as_ref ( ) , EDGE_DETECTION_PORT_A . as_ref ( ) ) ,
138
+ DynGroup :: B => ( WAKERS_FOR_PORT_B . as_ref ( ) , EDGE_DETECTION_PORT_B . as_ref ( ) ) ,
139
+ }
140
+ }
141
+
105
142
pub fn new_with_dyn_pin (
106
143
pin : & mut DynPin ,
107
144
irq : pac:: Interrupt ,
@@ -113,7 +150,9 @@ impl InputPinFuture {
113
150
return Err ( InvalidPinTypeError ( pin. mode ( ) ) ) ;
114
151
}
115
152
116
- EDGE_DETECTION [ pin_id_to_offset ( pin. id ( ) ) ]
153
+ let ( waker_group, edge_detection_group) =
154
+ Self :: pin_group_to_waker_and_edge_detection_group ( pin. id ( ) . group ) ;
155
+ edge_detection_group[ pin. id ( ) . num as usize ]
117
156
. store ( false , core:: sync:: atomic:: Ordering :: Relaxed ) ;
118
157
pin. configure_edge_interrupt (
119
158
edge,
@@ -122,7 +161,11 @@ impl InputPinFuture {
122
161
Some ( irq_sel) ,
123
162
)
124
163
. unwrap ( ) ;
125
- Ok ( Self { pin_id : pin. id ( ) } )
164
+ Ok ( Self {
165
+ pin_id : pin. id ( ) ,
166
+ waker_group,
167
+ edge_detection_group,
168
+ } )
126
169
}
127
170
128
171
/// # Safety
@@ -146,15 +189,21 @@ impl InputPinFuture {
146
189
sys_cfg : & mut Sysconfig ,
147
190
irq_sel : & mut Irqsel ,
148
191
) -> Self {
149
- EDGE_DETECTION [ pin_id_to_offset ( pin. id ( ) ) ]
192
+ let ( waker_group, edge_detection_group) =
193
+ Self :: pin_group_to_waker_and_edge_detection_group ( pin. id ( ) . group ) ;
194
+ edge_detection_group[ pin. id ( ) . num as usize ]
150
195
. store ( false , core:: sync:: atomic:: Ordering :: Relaxed ) ;
151
196
pin. configure_edge_interrupt (
152
197
edge,
153
198
InterruptConfig :: new ( irq, true , true ) ,
154
199
Some ( sys_cfg) ,
155
200
Some ( irq_sel) ,
156
201
) ;
157
- Self { pin_id : pin. id ( ) }
202
+ Self {
203
+ pin_id : pin. id ( ) ,
204
+ edge_detection_group,
205
+ waker_group,
206
+ }
158
207
}
159
208
}
160
209
@@ -181,9 +230,9 @@ impl Future for InputPinFuture {
181
230
self : core:: pin:: Pin < & mut Self > ,
182
231
cx : & mut core:: task:: Context < ' _ > ,
183
232
) -> 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 ) {
233
+ let idx = self . pin_id . num as usize ;
234
+ self . waker_group [ idx] . register ( cx. waker ( ) ) ;
235
+ if self . edge_detection_group [ idx] . swap ( false , core:: sync:: atomic:: Ordering :: Relaxed ) {
187
236
return core:: task:: Poll :: Ready ( ( ) ) ;
188
237
}
189
238
core:: task:: Poll :: Pending
@@ -200,8 +249,8 @@ impl InputDynPinAsync {
200
249
/// passed as well and is used to route and enable the interrupt.
201
250
///
202
251
/// 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.
252
+ /// generic [on_interrupt_for_async_gpio_port_a] or [on_interrupt_for_async_gpio_port_b]
253
+ /// function must be called inside that function for the asynchronous functionality to work.
205
254
pub fn new ( pin : DynPin , irq : pac:: Interrupt ) -> Result < Self , InvalidPinTypeError > {
206
255
if !pin. is_input_pin ( ) {
207
256
return Err ( InvalidPinTypeError ( pin. mode ( ) ) ) ;
@@ -335,8 +384,8 @@ impl<I: PinId, C: InputConfig> InputPinAsync<I, C> {
335
384
/// passed as well and is used to route and enable the interrupt.
336
385
///
337
386
/// 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.
387
+ /// generic [on_interrupt_for_async_gpio_port_a] or [on_interrupt_for_async_gpio_port_b]
388
+ /// function must be called inside that function for the asynchronous functionality to work.
340
389
pub fn new ( pin : Pin < I , pin:: Input < C > > , irq : pac:: Interrupt ) -> Self {
341
390
Self { pin, irq }
342
391
}
0 commit comments