aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-08-19 22:17:17 +0200
committerDario Nieuwenhuis <[email protected]>2021-08-19 22:17:17 +0200
commitec51880e28d48269ae1ce8b037305f4f7f182c84 (patch)
treeb9283065cbaf692c17dddba587a862003dc266ce
parentdd62790f3630335b905743627a9d2e3c40cb6e4f (diff)
stm32/exti: unify all versions into single impl
-rw-r--r--embassy-stm32/src/exti.rs270
-rw-r--r--embassy-stm32/src/exti/mod.rs116
-rw-r--r--embassy-stm32/src/exti/v1.rs171
-rw-r--r--embassy-stm32/src/exti/v2.rs184
-rw-r--r--examples/stm32wb55/src/bin/button_exti.rs36
5 files changed, 306 insertions, 471 deletions
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
new file mode 100644
index 000000000..659daa377
--- /dev/null
+++ b/embassy-stm32/src/exti.rs
@@ -0,0 +1,270 @@
1use core::convert::Infallible;
2use core::future::Future;
3use core::marker::PhantomData;
4use core::pin::Pin;
5use core::task::{Context, Poll};
6use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge};
7use embassy::util::{AtomicWaker, Unborrow};
8use embassy_hal_common::unsafe_impl_unborrow;
9use embedded_hal::digital::v2::InputPin;
10
11use crate::gpio::{AnyPin, Input, Pin as GpioPin};
12use crate::interrupt;
13use crate::pac;
14use crate::pac::{EXTI, SYSCFG};
15use crate::peripherals;
16
17const EXTI_COUNT: usize = 16;
18const NEW_AW: AtomicWaker = AtomicWaker::new();
19static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT];
20
21#[cfg(exti_w)]
22fn cpu_regs() -> pac::exti::Cpu {
23 EXTI.cpu(crate::pac::CORE_INDEX)
24}
25
26#[cfg(not(exti_w))]
27fn cpu_regs() -> pac::exti::Exti {
28 EXTI
29}
30
31pub unsafe fn on_irq() {
32 let bits = EXTI.pr(0).read();
33
34 // Mask all the channels that fired.
35 cpu_regs().imr(0).modify(|w| w.0 &= !bits.0);
36
37 // Wake the tasks
38 for pin in BitIter(bits.0) {
39 EXTI_WAKERS[pin as usize].wake();
40 }
41
42 // Clear pending
43 EXTI.pr(0).write_value(bits);
44}
45
46struct BitIter(u32);
47
48impl Iterator for BitIter {
49 type Item = u32;
50
51 fn next(&mut self) -> Option<Self::Item> {
52 match self.0.trailing_zeros() {
53 32 => None,
54 b => {
55 self.0 &= !(1 << b);
56 Some(b)
57 }
58 }
59 }
60}
61
62/// EXTI input driver
63pub struct ExtiInput<'d, T: GpioPin> {
64 pin: Input<'d, T>,
65}
66
67impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
68
69impl<'d, T: GpioPin> ExtiInput<'d, T> {
70 pub fn new(pin: Input<'d, T>, _ch: impl Unborrow<Target = T::ExtiChannel> + 'd) -> Self {
71 Self { pin }
72 }
73}
74
75impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> {
76 type Error = Infallible;
77
78 fn is_high(&self) -> Result<bool, Self::Error> {
79 self.pin.is_high()
80 }
81
82 fn is_low(&self) -> Result<bool, Self::Error> {
83 self.pin.is_low()
84 }
85}
86
87impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> {
88 type Future<'a> = ExtiInputFuture<'a>;
89
90 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> {
91 ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), true, false)
92 }
93}
94
95impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> {
96 type Future<'a> = ExtiInputFuture<'a>;
97
98 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> {
99 ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), false, true)
100 }
101}
102
103impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> {
104 type Future<'a> = ExtiInputFuture<'a>;
105
106 fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
107 ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), true, true)
108 }
109}
110
111pub struct ExtiInputFuture<'a> {
112 pin: u8,
113 phantom: PhantomData<&'a mut AnyPin>,
114}
115
116impl<'a> ExtiInputFuture<'a> {
117 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
118 cortex_m::interrupt::free(|_| unsafe {
119 let pin = pin as usize;
120 SYSCFG.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
121 EXTI.rtsr(0).modify(|w| w.set_line(pin, rising));
122 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
123 EXTI.pr(0).write(|w| w.set_line(pin, true)); // clear pending bit
124 cpu_regs().imr(0).modify(|w| w.set_line(pin, true));
125 });
126
127 Self {
128 pin,
129 phantom: PhantomData,
130 }
131 }
132}
133
134impl<'a> Drop for ExtiInputFuture<'a> {
135 fn drop(&mut self) {
136 cortex_m::interrupt::free(|_| unsafe {
137 let pin = self.pin as _;
138 cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
139 });
140 }
141}
142
143impl<'a> Future for ExtiInputFuture<'a> {
144 type Output = ();
145
146 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
147 EXTI_WAKERS[self.pin as usize].register(cx.waker());
148
149 let imr = unsafe { cpu_regs().imr(0).read() };
150 if !imr.line(self.pin as _) {
151 Poll::Ready(())
152 } else {
153 Poll::Pending
154 }
155 }
156}
157
158macro_rules! foreach_exti_irq {
159 ($action:ident) => {
160 crate::pac::interrupts!(
161 (EXTI0) => { $action!(EXTI0); };
162 (EXTI1) => { $action!(EXTI1); };
163 (EXTI2) => { $action!(EXTI2); };
164 (EXTI3) => { $action!(EXTI3); };
165 (EXTI4) => { $action!(EXTI4); };
166 (EXTI5) => { $action!(EXTI5); };
167 (EXTI6) => { $action!(EXTI6); };
168 (EXTI7) => { $action!(EXTI7); };
169 (EXTI8) => { $action!(EXTI8); };
170 (EXTI9) => { $action!(EXTI9); };
171 (EXTI10) => { $action!(EXTI10); };
172 (EXTI11) => { $action!(EXTI11); };
173 (EXTI12) => { $action!(EXTI12); };
174 (EXTI13) => { $action!(EXTI13); };
175 (EXTI14) => { $action!(EXTI14); };
176 (EXTI15) => { $action!(EXTI15); };
177
178 // plus the weird ones
179 (EXTI0_1) => { $action!( EXTI0_1 ); };
180 (EXTI15_10) => { $action!(EXTI15_10); };
181 (EXTI15_4) => { $action!(EXTI15_4); };
182 (EXTI1_0) => { $action!(EXTI1_0); };
183 (EXTI2_3) => { $action!(EXTI2_3); };
184 (EXTI2_TSC) => { $action!(EXTI2_TSC); };
185 (EXTI3_2) => { $action!(EXTI3_2); };
186 (EXTI4_15) => { $action!(EXTI4_15); };
187 (EXTI9_5) => { $action!(EXTI9_5); };
188 );
189 };
190}
191
192macro_rules! impl_irq {
193 ($e:ident) => {
194 #[interrupt]
195 unsafe fn $e() {
196 on_irq()
197 }
198 };
199}
200
201foreach_exti_irq!(impl_irq);
202
203pub(crate) mod sealed {
204 pub trait Channel {}
205}
206
207pub trait Channel: sealed::Channel + Sized {
208 fn number(&self) -> usize;
209 fn degrade(self) -> AnyChannel {
210 AnyChannel {
211 number: self.number() as u8,
212 }
213 }
214}
215
216pub struct AnyChannel {
217 number: u8,
218}
219unsafe_impl_unborrow!(AnyChannel);
220impl sealed::Channel for AnyChannel {}
221impl Channel for AnyChannel {
222 fn number(&self) -> usize {
223 self.number as usize
224 }
225}
226
227macro_rules! impl_exti {
228 ($type:ident, $number:expr) => {
229 impl sealed::Channel for peripherals::$type {}
230 impl Channel for peripherals::$type {
231 fn number(&self) -> usize {
232 $number as usize
233 }
234 }
235 };
236}
237
238impl_exti!(EXTI0, 0);
239impl_exti!(EXTI1, 1);
240impl_exti!(EXTI2, 2);
241impl_exti!(EXTI3, 3);
242impl_exti!(EXTI4, 4);
243impl_exti!(EXTI5, 5);
244impl_exti!(EXTI6, 6);
245impl_exti!(EXTI7, 7);
246impl_exti!(EXTI8, 8);
247impl_exti!(EXTI9, 9);
248impl_exti!(EXTI10, 10);
249impl_exti!(EXTI11, 11);
250impl_exti!(EXTI12, 12);
251impl_exti!(EXTI13, 13);
252impl_exti!(EXTI14, 14);
253impl_exti!(EXTI15, 15);
254
255macro_rules! enable_irq {
256 ($e:ident) => {
257 crate::interrupt::$e::steal().enable();
258 };
259}
260
261/// safety: must be called only once
262pub(crate) unsafe fn init() {
263 use embassy::interrupt::Interrupt;
264 use embassy::interrupt::InterruptExt;
265
266 foreach_exti_irq!(enable_irq);
267
268 #[cfg(not(any(rcc_wb, rcc_wl5)))]
269 <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable();
270}
diff --git a/embassy-stm32/src/exti/mod.rs b/embassy-stm32/src/exti/mod.rs
deleted file mode 100644
index 3f43e0bc7..000000000
--- a/embassy-stm32/src/exti/mod.rs
+++ /dev/null
@@ -1,116 +0,0 @@
1#![macro_use]
2
3macro_rules! foreach_exti_irq {
4 ($action:ident) => {
5 crate::pac::interrupts!(
6 (EXTI0) => { $action!(EXTI0); };
7 (EXTI1) => { $action!(EXTI1); };
8 (EXTI2) => { $action!(EXTI2); };
9 (EXTI3) => { $action!(EXTI3); };
10 (EXTI4) => { $action!(EXTI4); };
11 (EXTI5) => { $action!(EXTI5); };
12 (EXTI6) => { $action!(EXTI6); };
13 (EXTI7) => { $action!(EXTI7); };
14 (EXTI8) => { $action!(EXTI8); };
15 (EXTI9) => { $action!(EXTI9); };
16 (EXTI10) => { $action!(EXTI10); };
17 (EXTI11) => { $action!(EXTI11); };
18 (EXTI12) => { $action!(EXTI12); };
19 (EXTI13) => { $action!(EXTI13); };
20 (EXTI14) => { $action!(EXTI14); };
21 (EXTI15) => { $action!(EXTI15); };
22
23 // plus the weird ones
24 (EXTI0_1) => { $action!( EXTI0_1 ); };
25 (EXTI15_10) => { $action!(EXTI15_10); };
26 (EXTI15_4) => { $action!(EXTI15_4); };
27 (EXTI1_0) => { $action!(EXTI1_0); };
28 (EXTI2_3) => { $action!(EXTI2_3); };
29 (EXTI2_TSC) => { $action!(EXTI2_TSC); };
30 (EXTI3_2) => { $action!(EXTI3_2); };
31 (EXTI4_15) => { $action!(EXTI4_15); };
32 (EXTI9_5) => { $action!(EXTI9_5); };
33 );
34 };
35}
36
37#[cfg_attr(exti_v1, path = "v1.rs")]
38#[cfg_attr(exti_h7, path = "v1.rs")]
39#[cfg_attr(exti_wb55, path = "v2.rs")]
40#[cfg_attr(exti_wl5x, path = "v2.rs")]
41mod _version;
42
43#[allow(unused)]
44pub use _version::*;
45
46use crate::peripherals;
47use embassy_hal_common::unsafe_impl_unborrow;
48
49pub(crate) mod sealed {
50 pub trait Channel {}
51}
52
53pub trait Channel: sealed::Channel + Sized {
54 fn number(&self) -> usize;
55 fn degrade(self) -> AnyChannel {
56 AnyChannel {
57 number: self.number() as u8,
58 }
59 }
60}
61
62pub struct AnyChannel {
63 number: u8,
64}
65unsafe_impl_unborrow!(AnyChannel);
66impl sealed::Channel for AnyChannel {}
67impl Channel for AnyChannel {
68 fn number(&self) -> usize {
69 self.number as usize
70 }
71}
72
73macro_rules! impl_exti {
74 ($type:ident, $number:expr) => {
75 impl sealed::Channel for peripherals::$type {}
76 impl Channel for peripherals::$type {
77 fn number(&self) -> usize {
78 $number as usize
79 }
80 }
81 };
82}
83
84impl_exti!(EXTI0, 0);
85impl_exti!(EXTI1, 1);
86impl_exti!(EXTI2, 2);
87impl_exti!(EXTI3, 3);
88impl_exti!(EXTI4, 4);
89impl_exti!(EXTI5, 5);
90impl_exti!(EXTI6, 6);
91impl_exti!(EXTI7, 7);
92impl_exti!(EXTI8, 8);
93impl_exti!(EXTI9, 9);
94impl_exti!(EXTI10, 10);
95impl_exti!(EXTI11, 11);
96impl_exti!(EXTI12, 12);
97impl_exti!(EXTI13, 13);
98impl_exti!(EXTI14, 14);
99impl_exti!(EXTI15, 15);
100
101macro_rules! enable_irq {
102 ($e:ident) => {
103 crate::interrupt::$e::steal().enable();
104 };
105}
106
107/// safety: must be called only once
108pub(crate) unsafe fn init() {
109 use embassy::interrupt::Interrupt;
110 use embassy::interrupt::InterruptExt;
111
112 foreach_exti_irq!(enable_irq);
113
114 #[cfg(not(any(rcc_wb55, rcc_wl5x)))]
115 <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable();
116}
diff --git a/embassy-stm32/src/exti/v1.rs b/embassy-stm32/src/exti/v1.rs
deleted file mode 100644
index caf457605..000000000
--- a/embassy-stm32/src/exti/v1.rs
+++ /dev/null
@@ -1,171 +0,0 @@
1use core::convert::Infallible;
2use core::future::Future;
3use core::marker::PhantomData;
4use core::pin::Pin;
5use core::task::{Context, Poll};
6use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge};
7use embassy::util::{AtomicWaker, Unborrow};
8use embedded_hal::digital::v2::InputPin;
9use pac::exti::{regs, vals};
10
11use crate::gpio::{AnyPin, Input, Pin as GpioPin};
12use crate::pac;
13use crate::pac::{EXTI, SYSCFG};
14
15const EXTI_COUNT: usize = 16;
16const NEW_AW: AtomicWaker = AtomicWaker::new();
17static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT];
18
19pub unsafe fn on_irq() {
20 let bits = EXTI.pr().read().0;
21
22 // Mask all the channels that fired.
23 EXTI.imr().modify(|w| w.0 &= !bits);
24
25 // Wake the tasks
26 for pin in BitIter(bits) {
27 EXTI_WAKERS[pin as usize].wake();
28 }
29
30 // Clear pending
31 EXTI.pr().write_value(regs::Pr(bits));
32}
33
34struct BitIter(u32);
35
36impl Iterator for BitIter {
37 type Item = u32;
38
39 fn next(&mut self) -> Option<Self::Item> {
40 match self.0.trailing_zeros() {
41 32 => None,
42 b => {
43 self.0 &= !(1 << b);
44 Some(b)
45 }
46 }
47 }
48}
49
50/// EXTI input driver
51pub struct ExtiInput<'d, T: GpioPin> {
52 pin: Input<'d, T>,
53}
54
55impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
56
57impl<'d, T: GpioPin> ExtiInput<'d, T> {
58 pub fn new(pin: Input<'d, T>, _ch: impl Unborrow<Target = T::ExtiChannel> + 'd) -> Self {
59 Self { pin }
60 }
61}
62
63impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> {
64 type Error = Infallible;
65
66 fn is_high(&self) -> Result<bool, Self::Error> {
67 self.pin.is_high()
68 }
69
70 fn is_low(&self) -> Result<bool, Self::Error> {
71 self.pin.is_low()
72 }
73}
74
75impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> {
76 type Future<'a> = ExtiInputFuture<'a>;
77
78 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> {
79 ExtiInputFuture::new(
80 self.pin.pin.pin(),
81 self.pin.pin.port(),
82 vals::Tr::ENABLED,
83 vals::Tr::DISABLED,
84 )
85 }
86}
87
88impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> {
89 type Future<'a> = ExtiInputFuture<'a>;
90
91 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> {
92 ExtiInputFuture::new(
93 self.pin.pin.pin(),
94 self.pin.pin.port(),
95 vals::Tr::DISABLED,
96 vals::Tr::ENABLED,
97 )
98 }
99}
100
101impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> {
102 type Future<'a> = ExtiInputFuture<'a>;
103
104 fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
105 ExtiInputFuture::new(
106 self.pin.pin.pin(),
107 self.pin.pin.port(),
108 vals::Tr::ENABLED,
109 vals::Tr::ENABLED,
110 )
111 }
112}
113
114pub struct ExtiInputFuture<'a> {
115 pin: u8,
116 phantom: PhantomData<&'a mut AnyPin>,
117}
118
119impl<'a> ExtiInputFuture<'a> {
120 fn new(pin: u8, port: u8, rising: vals::Tr, falling: vals::Tr) -> Self {
121 cortex_m::interrupt::free(|_| unsafe {
122 let pin = pin as usize;
123 SYSCFG.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
124 EXTI.rtsr().modify(|w| w.set_tr(pin, rising));
125 EXTI.ftsr().modify(|w| w.set_tr(pin, falling));
126 EXTI.pr().write(|w| w.set_pr(pin, true)); // clear pending bit
127 EXTI.imr().modify(|w| w.set_mr(pin, vals::Mr::UNMASKED));
128 });
129
130 Self {
131 pin,
132 phantom: PhantomData,
133 }
134 }
135}
136
137impl<'a> Drop for ExtiInputFuture<'a> {
138 fn drop(&mut self) {
139 cortex_m::interrupt::free(|_| unsafe {
140 let pin = self.pin as _;
141 EXTI.imr().modify(|w| w.set_mr(pin, vals::Mr::MASKED));
142 });
143 }
144}
145
146impl<'a> Future for ExtiInputFuture<'a> {
147 type Output = ();
148
149 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
150 EXTI_WAKERS[self.pin as usize].register(cx.waker());
151
152 if unsafe { EXTI.imr().read().mr(self.pin as _) == vals::Mr::MASKED } {
153 Poll::Ready(())
154 } else {
155 Poll::Pending
156 }
157 }
158}
159
160use crate::interrupt;
161
162macro_rules! impl_irq {
163 ($e:ident) => {
164 #[interrupt]
165 unsafe fn $e() {
166 on_irq()
167 }
168 };
169}
170
171foreach_exti_irq!(impl_irq);
diff --git a/embassy-stm32/src/exti/v2.rs b/embassy-stm32/src/exti/v2.rs
deleted file mode 100644
index 2e62331fe..000000000
--- a/embassy-stm32/src/exti/v2.rs
+++ /dev/null
@@ -1,184 +0,0 @@
1use core::convert::Infallible;
2use core::future::Future;
3use core::marker::PhantomData;
4use core::pin::Pin;
5use core::task::{Context, Poll};
6use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge};
7use embassy::util::{AtomicWaker, Unborrow};
8use embedded_hal::digital::v2::InputPin;
9use pac::exti::{regs, vals};
10
11use crate::gpio::{AnyPin, Input, Pin as GpioPin};
12use crate::pac;
13use crate::pac::CORE_INDEX;
14use crate::pac::{EXTI, SYSCFG};
15
16const EXTI_COUNT: usize = 16;
17const NEW_AW: AtomicWaker = AtomicWaker::new();
18static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT];
19
20pub unsafe fn on_irq() {
21 let bits = EXTI.pr(0).read().0;
22
23 // Mask all the channels that fired.
24 EXTI.cpu(CORE_INDEX)
25 .imr(CORE_INDEX)
26 .modify(|w| w.0 &= !bits);
27
28 // Wake the tasks
29 for pin in BitIter(bits) {
30 EXTI_WAKERS[pin as usize].wake();
31 }
32
33 // Clear pending
34 EXTI.pr(0).write_value(regs::Pr(bits));
35}
36
37struct BitIter(u32);
38
39impl Iterator for BitIter {
40 type Item = u32;
41
42 fn next(&mut self) -> Option<Self::Item> {
43 match self.0.trailing_zeros() {
44 32 => None,
45 b => {
46 self.0 &= !(1 << b);
47 Some(b)
48 }
49 }
50 }
51}
52
53/// EXTI input driver
54pub struct ExtiInput<'d, T: GpioPin> {
55 pin: Input<'d, T>,
56}
57
58impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
59
60impl<'d, T: GpioPin> ExtiInput<'d, T> {
61 pub fn new(pin: Input<'d, T>, _ch: impl Unborrow<Target = T::ExtiChannel> + 'd) -> Self {
62 Self { pin }
63 }
64}
65
66impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> {
67 type Error = Infallible;
68
69 fn is_high(&self) -> Result<bool, Self::Error> {
70 self.pin.is_high()
71 }
72
73 fn is_low(&self) -> Result<bool, Self::Error> {
74 self.pin.is_low()
75 }
76}
77
78impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> {
79 type Future<'a> = ExtiInputFuture<'a>;
80
81 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> {
82 ExtiInputFuture::new(
83 self.pin.pin.pin(),
84 self.pin.pin.port(),
85 vals::Rt::ENABLED,
86 vals::Ft::DISABLED,
87 )
88 }
89}
90
91impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> {
92 type Future<'a> = ExtiInputFuture<'a>;
93
94 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> {
95 ExtiInputFuture::new(
96 self.pin.pin.pin(),
97 self.pin.pin.port(),
98 vals::Rt::DISABLED,
99 vals::Ft::ENABLED,
100 )
101 }
102}
103
104impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> {
105 type Future<'a> = ExtiInputFuture<'a>;
106
107 fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
108 ExtiInputFuture::new(
109 self.pin.pin.pin(),
110 self.pin.pin.port(),
111 vals::Rt::ENABLED,
112 vals::Ft::ENABLED,
113 )
114 }
115}
116
117pub struct ExtiInputFuture<'a> {
118 pin: u8,
119 phantom: PhantomData<&'a mut AnyPin>,
120}
121
122impl<'a> ExtiInputFuture<'a> {
123 fn new(pin: u8, port: u8, rising: vals::Rt, falling: vals::Ft) -> Self {
124 cortex_m::interrupt::free(|_| unsafe {
125 let pin = pin as usize;
126 SYSCFG.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
127 EXTI.rtsr(CORE_INDEX).modify(|w| w.set_rt(pin, rising));
128 EXTI.ftsr(CORE_INDEX).modify(|w| w.set_ft(pin, falling));
129 EXTI.pr(CORE_INDEX).write(|w| w.set_pif(pin, true)); // clear pending bit
130 EXTI.cpu(CORE_INDEX)
131 .imr(CORE_INDEX)
132 .modify(|w| w.set_im(pin, vals::Mr::UNMASKED));
133 });
134
135 Self {
136 pin,
137 phantom: PhantomData,
138 }
139 }
140}
141
142impl<'a> Drop for ExtiInputFuture<'a> {
143 fn drop(&mut self) {
144 cortex_m::interrupt::free(|_| unsafe {
145 let pin = self.pin as _;
146 EXTI.cpu(CORE_INDEX)
147 .imr(CORE_INDEX)
148 .modify(|w| w.set_im(pin, vals::Mr::MASKED));
149 });
150 }
151}
152
153impl<'a> Future for ExtiInputFuture<'a> {
154 type Output = ();
155
156 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
157 EXTI_WAKERS[self.pin as usize].register(cx.waker());
158
159 if unsafe {
160 EXTI.cpu(CORE_INDEX)
161 .imr(CORE_INDEX)
162 .read()
163 .im(self.pin as _)
164 == vals::Mr::MASKED
165 } {
166 Poll::Ready(())
167 } else {
168 Poll::Pending
169 }
170 }
171}
172
173use crate::interrupt;
174
175macro_rules! impl_irq {
176 ($e:ident) => {
177 #[interrupt]
178 unsafe fn $e() {
179 on_irq()
180 }
181 };
182}
183
184foreach_exti_irq!(impl_irq);
diff --git a/examples/stm32wb55/src/bin/button_exti.rs b/examples/stm32wb55/src/bin/button_exti.rs
new file mode 100644
index 000000000..92a310c7a
--- /dev/null
+++ b/examples/stm32wb55/src/bin/button_exti.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(type_alias_impl_trait)]
5#![allow(incomplete_features)]
6
7#[path = "../example_common.rs"]
8mod example_common;
9use embassy::executor::Spawner;
10use embassy_stm32::dbgmcu::Dbgmcu;
11use embassy_stm32::exti::ExtiInput;
12use embassy_stm32::gpio::{Input, Pull};
13use embassy_stm32::Peripherals;
14use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
15use example_common::*;
16
17#[embassy::main]
18async fn main(_spawner: Spawner, p: Peripherals) {
19 info!("Hello World!");
20
21 unsafe {
22 Dbgmcu::enable_all();
23 }
24
25 let button = Input::new(p.PC4, Pull::Up);
26 let mut button = ExtiInput::new(button, p.EXTI4);
27
28 info!("Press the USER button...");
29
30 loop {
31 button.wait_for_falling_edge().await;
32 info!("Pressed!");
33 button.wait_for_rising_edge().await;
34 info!("Released!");
35 }
36}