atsamd_hal/peripherals/eic/d11/
pin.rs

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