atsamd_hal/peripherals/eic/d11/
pin.rs

1use atsamd_hal_macros::hal_cfg;
2
3use core::convert::Infallible;
4use crate::ehal_02::digital::v2::InputPin as InputPin_02;
5use crate::ehal::digital::{ErrorType, InputPin};
6use crate::eic::*;
7use crate::gpio::{
8    self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt,
9};
10
11/// The pad macro defines the given EIC pin and implements EicPin for the
12/// given pins. The EicPin implementation will configure the pin for the
13/// appropriate function and return the pin wrapped in the EIC type.
14macro_rules! ei {
15    (
16        $PadType:ident [ $num:expr ] {
17            $(
18                $(#[$attr:meta])*
19                $PinType:ident,
20            )+
21        }
22    ) => {
23        crate::paste::item! {
24            $(
25                $(#[$attr])*
26                impl<M: PinMode> EicPin for Pin<gpio::$PinType, M> {
27                    type Floating = ExtInt<Pin<gpio::$PinType, FloatingInterrupt>, Self::ChId>;
28                    type PullUp = ExtInt<Pin<gpio::$PinType, PullUpInterrupt>, Self::ChId>;
29                    type PullDown = ExtInt<Pin<gpio::$PinType, PullDownInterrupt>, Self::ChId>;
30
31                    type ChId = [<Ch $num>];
32
33                    fn into_floating_ei(self, chan: Channel<Self::ChId>) -> Self::Floating {
34                        Self::Floating::new(self.into_floating_interrupt(), chan)
35                    }
36
37                    fn into_pull_up_ei(self, chan: Channel<Self::ChId>) -> Self::PullUp {
38                    Self::PullUp::new(self.into_pull_up_interrupt(), chan)
39                    }
40
41                    fn into_pull_down_ei(self, chan: Channel<Self::ChId>) -> Self::PullDown {
42                        Self::PullDown::new(self.into_pull_down_interrupt(), chan)
43                    }
44                }
45            )+
46        }
47    };
48}
49
50impl<P, Id, F> ExtInt<P, Id, F>
51where
52    P: EicPin,
53    Id: ChId,
54{
55    /// Configure the eic with options for this external interrupt
56    pub fn enable_event(&mut self) {
57        self.chan
58            .eic
59            .evctrl()
60            .modify(|r, w| unsafe { w.bits(r.bits() | (1 << P::ChId::ID)) });
61    }
62
63    pub fn enable_interrupt(&mut self) {
64        self.chan
65            .eic
66            .intenset()
67            .write(|w| unsafe { w.bits(1 << P::ChId::ID) });
68    }
69
70    pub fn enable_interrupt_wake(&mut self) {
71        self.chan
72            .eic
73            .wakeup()
74            .modify(|r, w| unsafe { w.bits(r.bits() | (1 << P::ChId::ID)) })
75    }
76
77    pub fn disable_interrupt(&mut self) {
78        self.chan
79            .eic
80            .intenclr()
81            .write(|w| unsafe { w.bits(1 << P::ChId::ID) });
82    }
83
84    pub fn is_interrupt(&mut self) -> bool {
85        self.chan.eic.intflag().read().bits() & (1 << P::ChId::ID) != 0
86    }
87
88    pub fn clear_interrupt(&mut self) {
89        self.chan
90            .eic
91            .intflag()
92            .write(|w| unsafe { w.bits(1 << P::ChId::ID) });
93    }
94
95    pub fn sense(&mut self, sense: Sense) {
96        // Which of the two config blocks this eic config is in
97        let offset = (P::ChId::ID >> 3) & 0b0001;
98        let config = &self.chan.eic.config(offset);
99
100        config.modify(|_, w| unsafe {
101            // Which of the eight eic configs in this config block
102            match P::ChId::ID & 0b111 {
103                0b000 => w.sense0().bits(sense as u8),
104                0b001 => w.sense1().bits(sense as u8),
105                0b010 => w.sense2().bits(sense as u8),
106                0b011 => w.sense3().bits(sense as u8),
107                0b100 => w.sense4().bits(sense as u8),
108                0b101 => w.sense5().bits(sense as u8),
109                0b110 => w.sense6().bits(sense as u8),
110                0b111 => w.sense7().bits(sense as u8),
111                _ => unreachable!(),
112            }
113        });
114    }
115
116    pub fn filter(&mut self, filter: bool) {
117        // Which of the two config blocks this eic config is in
118        let offset = (P::ChId::ID >> 3) & 0b0001;
119        let config = &self.chan.eic.config(offset);
120
121        config.modify(|_, w| {
122            // Which of the eight eic configs in this config block
123            match P::ChId::ID & 0b111 {
124                0b000 => w.filten0().bit(filter),
125                0b001 => w.filten1().bit(filter),
126                0b010 => w.filten2().bit(filter),
127                0b011 => w.filten3().bit(filter),
128                0b100 => w.filten4().bit(filter),
129                0b101 => w.filten5().bit(filter),
130                0b110 => w.filten6().bit(filter),
131                0b111 => w.filten7().bit(filter),
132                _ => unreachable!(),
133            }
134        });
135    }
136}
137
138impl<P, C, Id, F> InputPin_02 for ExtInt<P, Id, F>
139where
140    P: EicPin + AnyPin<Mode = Interrupt<C>>,
141    Id: ChId,
142    C: InterruptConfig,
143{
144    type Error = Infallible;
145    #[inline]
146    fn is_high(&self) -> Result<bool, Self::Error> {
147        self.pin.is_high()
148    }
149    #[inline]
150    fn is_low(&self) -> Result<bool, Self::Error> {
151        self.pin.is_low()
152    }
153}
154
155impl<P, Id, F> InputPin for ExtInt<P, Id, F>
156where Self: ErrorType,
157    P: EicPin,
158    Id: ChId,
159{
160    #[inline]
161    fn is_high(&mut self) -> Result<bool, Self::Error> {
162        Ok(self.pin._is_high())
163    }
164
165    #[inline]
166    fn is_low(&mut self) -> Result<bool, Self::Error> {
167        Ok(self.pin._is_low())
168    }
169}
170
171impl<P, Id, F> ErrorType for ExtInt<P, Id, F>
172where
173    P: EicPin,
174    Id: ChId,
175{
176    type Error = Infallible;
177}
178
179#[cfg(feature = "async")]
180mod async_impls {
181    use embedded_hal_async::digital::Wait;
182
183    use super::super::async_api::WAKERS;
184    use super::*;
185
186    impl<P, Id> ExtInt<P, Id, EicFuture>
187    where
188        P: EicPin,
189        Id: ChId,
190        Self: InputPin<Error = Infallible>,
191    {
192        pub async fn wait(&mut self, sense: Sense) {
193            use core::{future::poll_fn, task::Poll};
194            self.disable_interrupt();
195
196            match sense {
197                Sense::High => {
198                    if self.is_high().unwrap() {
199                        return;
200                    }
201                }
202                Sense::Low => {
203                    if self.is_low().unwrap() {
204                        return;
205                    }
206                }
207                _ => (),
208            }
209
210            self.enable_interrupt_wake();
211            self.sense(sense);
212            poll_fn(|cx| {
213                if self.is_interrupt() {
214                    self.clear_interrupt();
215                    self.disable_interrupt();
216                    self.sense(Sense::None);
217                    return Poll::Ready(());
218                }
219
220                WAKERS[P::ChId::ID].register(cx.waker());
221                self.enable_interrupt();
222
223                if self.is_interrupt() {
224                    self.clear_interrupt();
225                    self.disable_interrupt();
226                    self.sense(Sense::None);
227                    return Poll::Ready(());
228                }
229
230                Poll::Pending
231            })
232            .await;
233        }
234    }
235
236    impl<P, Id> Wait for ExtInt<P, Id, EicFuture>
237    where
238        P: EicPin,
239        Id: ChId,
240        Self: InputPin<Error = Infallible>,
241    {
242        async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
243            self.wait(Sense::High).await;
244            Ok(())
245        }
246
247        async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
248            self.wait(Sense::Low).await;
249            Ok(())
250        }
251
252        async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
253            self.wait(Sense::Rise).await;
254            Ok(())
255        }
256
257        async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
258            self.wait(Sense::Fall).await;
259            Ok(())
260        }
261
262        async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
263            self.wait(Sense::Both).await;
264            Ok(())
265        }
266    }
267}
268
269// The SAMD11 and SAMD21 devices have different ExtInt designations. Just for
270// clarity's sake, the `ei!()` invocations below have been split into SAMD11-
271// and SAMD21-specific declarations.
272
273// SAMD11
274#[hal_cfg("eic-d11")]
275mod impls {
276    use super::*;
277
278    ei!(ExtInt[1] {
279        #[hal_cfg("pa15")]
280        PA15,
281    });
282
283    ei!(ExtInt[2] {
284        #[hal_cfg("pa02")]
285        PA02,
286    });
287
288    ei!(ExtInt[3] {
289        #[hal_cfg("pa31")]
290        PA31,
291    });
292
293    ei!(ExtInt[4] {
294        #[hal_cfg("pa04")]
295        PA04,
296        #[hal_cfg("pa24")]
297        PA24,
298    });
299
300    ei!(ExtInt[5] {
301        #[hal_cfg("pa05")]
302        PA05,
303        #[hal_cfg("pa25")]
304        PA25,
305    });
306
307    ei!(ExtInt[6] {
308        #[hal_cfg("pa08")]
309        PA08,
310    });
311
312    ei!(ExtInt[7] {
313        #[hal_cfg("pa09")]
314        PA09,
315    });
316}
317
318// SAMD21
319#[hal_cfg("eic-d21")]
320mod impls {
321    use super::*;
322
323    ei!(ExtInt[0] {
324        #[hal_cfg("pa00")]
325        PA00,
326        #[hal_cfg("pa16")]
327        PA16,
328        #[hal_cfg("pb00")]
329        PB00,
330        #[hal_cfg("pb16")]
331        PB16,
332    });
333
334    ei!(ExtInt[1] {
335        #[hal_cfg("pa01")]
336        PA01,
337        #[hal_cfg("pa17")]
338        PA17,
339        #[hal_cfg("pb01")]
340        PB01,
341        #[hal_cfg("pb17")]
342        PB17,
343    });
344
345    ei!(ExtInt[2] {
346        #[hal_cfg("pa02")]
347        PA02,
348        #[hal_cfg("pa18")]
349        PA18,
350        #[hal_cfg("pb02")]
351        PB02,
352    });
353
354    ei!(ExtInt[3] {
355        #[hal_cfg("pa03")]
356        PA03,
357        #[hal_cfg("pa19")]
358        PA19,
359        #[hal_cfg("pb03")]
360        PB03,
361    });
362
363    ei!(ExtInt[4] {
364        #[hal_cfg("pa04")]
365        PA04,
366        #[hal_cfg("pa20")]
367        PA20,
368        #[hal_cfg("pb04")]
369        PB04,
370    });
371
372    ei!(ExtInt[5] {
373        #[hal_cfg("pa05")]
374        PA05,
375        #[hal_cfg("pa21")]
376        PA21,
377        #[hal_cfg("pb05")]
378        PB05,
379    });
380
381    ei!(ExtInt[6] {
382        #[hal_cfg("pa06")]
383        PA06,
384        #[hal_cfg("pa22")]
385        PA22,
386        #[hal_cfg("pb06")]
387        PB06,
388        #[hal_cfg("pb22")]
389        PB22,
390    });
391
392    ei!(ExtInt[7] {
393        #[hal_cfg("pa07")]
394        PA07,
395        #[hal_cfg("pa23")]
396        PA23,
397        #[hal_cfg("pb07")]
398        PB07,
399        #[hal_cfg("pb23")]
400        PB23,
401    });
402
403    ei!(ExtInt[8] {
404        #[hal_cfg("pa28")]
405        PA28,
406        #[hal_cfg("pb08")]
407        PB08,
408    });
409
410    ei!(ExtInt[9] {
411        #[hal_cfg("pa09")]
412        PA09,
413        #[hal_cfg("pb09")]
414        PB09,
415    });
416
417    ei!(ExtInt[10] {
418        #[hal_cfg("pa10")]
419        PA10,
420        #[hal_cfg("pa30")]
421        PA30,
422        #[hal_cfg("pb10")]
423        PB10,
424    });
425
426    ei!(ExtInt[11] {
427        #[hal_cfg("pa11")]
428        PA11,
429        #[hal_cfg("pa31")]
430        PA31,
431        #[hal_cfg("pb11")]
432        PB11,
433    });
434
435    ei!(ExtInt[12] {
436        #[hal_cfg("pa12")]
437        PA12,
438        #[hal_cfg("pa24")]
439        PA24,
440        #[hal_cfg("pb12")]
441        PB12,
442    });
443
444    ei!(ExtInt[13] {
445        #[hal_cfg("pa13")]
446        PA13,
447        #[hal_cfg("pa25")]
448        PA25,
449        #[hal_cfg("pb13")]
450        PB13,
451    });
452
453    ei!(ExtInt[14] {
454        #[hal_cfg("pa14")]
455        PA14,
456        #[hal_cfg("pb14")]
457        PB14,
458        #[hal_cfg("pb30")]
459        PB30,
460    });
461
462    ei!(ExtInt[15] {
463        #[hal_cfg("pa15")]
464        PA15,
465        #[hal_cfg("pa27")]
466        PA27,
467        #[hal_cfg("pb15")]
468        PB15,
469        #[hal_cfg("pb31")]
470        PB31,
471    });
472}