1use core::convert::Infallible;
3use core::future::Future;
4use core::marker::PhantomData;
5use core::pin::Pin;
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{impl_peripheral, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
10
11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull};
12use crate::pac::exti::regs::Lines;
13use crate::pac::EXTI;
14use crate::{interrupt, pac, peripherals, Peri};
15
16const EXTI_COUNT: usize = 16;
17static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT];
18
19#[cfg(all(exti_w, feature = "_core-cm0p"))]
20fn cpu_regs() -> pac::exti::Cpu {
21 EXTI.cpu(1)
22}
23
24#[cfg(all(exti_w, not(feature = "_core-cm0p")))]
25fn cpu_regs() -> pac::exti::Cpu {
26 EXTI.cpu(0)
27}
28
29#[cfg(not(exti_w))]
30fn cpu_regs() -> pac::exti::Exti {
31 EXTI
32}
33
34#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))]
35fn exticr_regs() -> pac::syscfg::Syscfg {
36 pac::SYSCFG
37}
38#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
39fn exticr_regs() -> pac::exti::Exti {
40 EXTI
41}
42#[cfg(gpio_v1)]
43fn exticr_regs() -> pac::afio::Afio {
44 pac::AFIO
45}
46
47unsafe fn on_irq() {
48 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
49 let bits = EXTI.pr(0).read().0;
50 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
51 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
52
53 let bits = bits & 0x0000FFFF;
55
56 cpu_regs().imr(0).modify(|w| w.0 &= !bits);
58
59 for pin in BitIter(bits) {
61 EXTI_WAKERS[pin as usize].wake();
62 }
63
64 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
66 EXTI.pr(0).write_value(Lines(bits));
67 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
68 {
69 EXTI.rpr(0).write_value(Lines(bits));
70 EXTI.fpr(0).write_value(Lines(bits));
71 }
72
73 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq();
75}
76
77struct BitIter(u32);
78
79impl Iterator for BitIter {
80 type Item = u32;
81
82 fn next(&mut self) -> Option<Self::Item> {
83 match self.0.trailing_zeros() {
84 32 => None,
85 b => {
86 self.0 &= !(1 << b);
87 Some(b)
88 }
89 }
90 }
91}
92
93pub struct ExtiInput<'d> {
101 pin: Input<'d>,
102}
103
104impl<'d> Unpin for ExtiInput<'d> {}
105
106impl<'d> ExtiInput<'d> {
107 pub fn new<T: GpioPin>(pin: Peri<'d, T>, ch: Peri<'d, T::ExtiChannel>, pull: Pull) -> Self {
109 assert_eq!(pin.pin(), ch.number());
111
112 Self {
113 pin: Input::new(pin, pull),
114 }
115 }
116
117 pub fn is_high(&self) -> bool {
119 self.pin.is_high()
120 }
121
122 pub fn is_low(&self) -> bool {
124 self.pin.is_low()
125 }
126
127 pub fn get_level(&self) -> Level {
129 self.pin.get_level()
130 }
131
132 pub async fn wait_for_high(&mut self) {
136 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
137 if self.is_high() {
138 return;
139 }
140 fut.await
141 }
142
143 pub async fn wait_for_low(&mut self) {
147 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
148 if self.is_low() {
149 return;
150 }
151 fut.await
152 }
153
154 pub async fn wait_for_rising_edge(&mut self) {
158 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
159 }
160
161 pub async fn wait_for_falling_edge(&mut self) {
165 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
166 }
167
168 pub async fn wait_for_any_edge(&mut self) {
170 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
171 }
172}
173
174impl<'d> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d> {
175 type Error = Infallible;
176
177 fn is_high(&self) -> Result<bool, Self::Error> {
178 Ok(self.is_high())
179 }
180
181 fn is_low(&self) -> Result<bool, Self::Error> {
182 Ok(self.is_low())
183 }
184}
185
186impl<'d> embedded_hal_1::digital::ErrorType for ExtiInput<'d> {
187 type Error = Infallible;
188}
189
190impl<'d> embedded_hal_1::digital::InputPin for ExtiInput<'d> {
191 fn is_high(&mut self) -> Result<bool, Self::Error> {
192 Ok((*self).is_high())
193 }
194
195 fn is_low(&mut self) -> Result<bool, Self::Error> {
196 Ok((*self).is_low())
197 }
198}
199
200impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> {
201 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
202 self.wait_for_high().await;
203 Ok(())
204 }
205
206 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
207 self.wait_for_low().await;
208 Ok(())
209 }
210
211 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
212 self.wait_for_rising_edge().await;
213 Ok(())
214 }
215
216 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
217 self.wait_for_falling_edge().await;
218 Ok(())
219 }
220
221 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
222 self.wait_for_any_edge().await;
223 Ok(())
224 }
225}
226
227#[must_use = "futures do nothing unless you `.await` or poll them"]
228struct ExtiInputFuture<'a> {
229 pin: u8,
230 phantom: PhantomData<&'a mut AnyPin>,
231}
232
233impl<'a> ExtiInputFuture<'a> {
234 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
235 critical_section::with(|_| {
236 let pin = pin as usize;
237 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
238 EXTI.rtsr(0).modify(|w| w.set_line(pin, rising));
239 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
240
241 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
243 EXTI.pr(0).write(|w| w.set_line(pin, true));
244 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
245 {
246 EXTI.rpr(0).write(|w| w.set_line(pin, true));
247 EXTI.fpr(0).write(|w| w.set_line(pin, true));
248 }
249
250 cpu_regs().imr(0).modify(|w| w.set_line(pin, true));
251 });
252
253 Self {
254 pin,
255 phantom: PhantomData,
256 }
257 }
258}
259
260impl<'a> Drop for ExtiInputFuture<'a> {
261 fn drop(&mut self) {
262 critical_section::with(|_| {
263 let pin = self.pin as _;
264 cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
265 });
266 }
267}
268
269impl<'a> Future for ExtiInputFuture<'a> {
270 type Output = ();
271
272 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
273 EXTI_WAKERS[self.pin as usize].register(cx.waker());
274
275 let imr = cpu_regs().imr(0).read();
276 if !imr.line(self.pin as _) {
277 Poll::Ready(())
278 } else {
279 Poll::Pending
280 }
281 }
282}
283
284macro_rules! foreach_exti_irq {
285 ($action:ident) => {
286 foreach_interrupt!(
287 (EXTI0) => { $action!(EXTI0); };
288 (EXTI1) => { $action!(EXTI1); };
289 (EXTI2) => { $action!(EXTI2); };
290 (EXTI3) => { $action!(EXTI3); };
291 (EXTI4) => { $action!(EXTI4); };
292 (EXTI5) => { $action!(EXTI5); };
293 (EXTI6) => { $action!(EXTI6); };
294 (EXTI7) => { $action!(EXTI7); };
295 (EXTI8) => { $action!(EXTI8); };
296 (EXTI9) => { $action!(EXTI9); };
297 (EXTI10) => { $action!(EXTI10); };
298 (EXTI11) => { $action!(EXTI11); };
299 (EXTI12) => { $action!(EXTI12); };
300 (EXTI13) => { $action!(EXTI13); };
301 (EXTI14) => { $action!(EXTI14); };
302 (EXTI15) => { $action!(EXTI15); };
303
304 (EXTI0_1) => { $action!( EXTI0_1 ); };
306 (EXTI15_10) => { $action!(EXTI15_10); };
307 (EXTI15_4) => { $action!(EXTI15_4); };
308 (EXTI1_0) => { $action!(EXTI1_0); };
309 (EXTI2_3) => { $action!(EXTI2_3); };
310 (EXTI2_TSC) => { $action!(EXTI2_TSC); };
311 (EXTI3_2) => { $action!(EXTI3_2); };
312 (EXTI4_15) => { $action!(EXTI4_15); };
313 (EXTI9_5) => { $action!(EXTI9_5); };
314 );
315 };
316}
317
318macro_rules! impl_irq {
319 ($e:ident) => {
320 #[allow(non_snake_case)]
321 #[cfg(feature = "rt")]
322 #[interrupt]
323 unsafe fn $e() {
324 on_irq()
325 }
326 };
327}
328
329foreach_exti_irq!(impl_irq);
330
331trait SealedChannel {}
332
333#[allow(private_bounds)]
335pub trait Channel: PeripheralType + SealedChannel + Sized {
336 fn number(&self) -> u8;
338}
339
340pub struct AnyChannel {
344 number: u8,
345}
346
347impl_peripheral!(AnyChannel);
348impl SealedChannel for AnyChannel {}
349impl Channel for AnyChannel {
350 fn number(&self) -> u8 {
351 self.number
352 }
353}
354
355macro_rules! impl_exti {
356 ($type:ident, $number:expr) => {
357 impl SealedChannel for peripherals::$type {}
358 impl Channel for peripherals::$type {
359 fn number(&self) -> u8 {
360 $number
361 }
362 }
363
364 impl From<peripherals::$type> for AnyChannel {
365 fn from(val: peripherals::$type) -> Self {
366 Self {
367 number: val.number() as u8,
368 }
369 }
370 }
371 };
372}
373
374impl_exti!(EXTI0, 0);
375impl_exti!(EXTI1, 1);
376impl_exti!(EXTI2, 2);
377impl_exti!(EXTI3, 3);
378impl_exti!(EXTI4, 4);
379impl_exti!(EXTI5, 5);
380impl_exti!(EXTI6, 6);
381impl_exti!(EXTI7, 7);
382impl_exti!(EXTI8, 8);
383impl_exti!(EXTI9, 9);
384impl_exti!(EXTI10, 10);
385impl_exti!(EXTI11, 11);
386impl_exti!(EXTI12, 12);
387impl_exti!(EXTI13, 13);
388impl_exti!(EXTI14, 14);
389impl_exti!(EXTI15, 15);
390
391macro_rules! enable_irq {
392 ($e:ident) => {
393 crate::interrupt::typelevel::$e::enable();
394 };
395}
396
397pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
399 use crate::interrupt::typelevel::Interrupt;
400
401 foreach_exti_irq!(enable_irq);
402}