atsamd_hal/peripherals/eic/d5x/
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.
14#[allow(unused_macros)]
15macro_rules! ei {
16    (
17        $PadType:ident [ $num:expr ] {
18            $(
19                $(#[$attr:meta])*
20                $PinType:ident,
21            )+
22        }
23    ) => {
24
25        crate::paste::item! {
26            $(
27                $(#[$attr])*
28                impl<M: PinMode> EicPin for Pin<gpio::$PinType, M> {
29                    type Floating = ExtInt<Pin<gpio::$PinType, FloatingInterrupt>, Self::ChId>;
30                    type PullUp = ExtInt<Pin<gpio::$PinType, PullUpInterrupt>, Self::ChId>;
31                    type PullDown = ExtInt<Pin<gpio::$PinType, PullDownInterrupt>, Self::ChId>;
32
33                    type ChId = [<Ch $num>];
34
35                    #[cfg(feature = "async")]
36                    type InterruptSource = crate::async_hal::interrupts::[<EIC_EXTINT_ $num>];
37
38                    fn into_floating_ei(self, channel: Channel<Self::ChId>) -> Self::Floating {
39                        ExtInt::new(self.into_floating_interrupt(), channel)
40                    }
41
42                    fn into_pull_up_ei(self,channel: Channel<Self::ChId>) -> Self::PullUp {
43                        ExtInt::new(self.into_pull_up_interrupt(), channel)
44                    }
45
46                    fn into_pull_down_ei(self, channel: Channel<Self::ChId>) -> Self::PullDown {
47                        ExtInt::new(self.into_pull_down_interrupt(), channel)
48                    }
49                }
50            )+
51
52        }
53    };
54}
55
56impl<P, Id, F> ExtInt<P, Id, F>
57where
58    P: EicPin,
59    Id: ChId,
60{
61    pub fn enable_event(&mut self) {
62        self.chan
63            .eic
64            .evctrl()
65            .modify(|_, w| unsafe { w.bits(1 << P::ChId::ID) });
66    }
67
68    pub fn enable_interrupt(&mut self) {
69        self.chan
70            .eic
71            .intenset()
72            .write(|w| unsafe { w.bits(1 << P::ChId::ID) })
73    }
74
75    pub fn disable_interrupt(&mut self) {
76        self.chan
77            .eic
78            .intenclr()
79            .write(|w| unsafe { w.bits(1 << P::ChId::ID) })
80    }
81
82    pub fn is_interrupt(&mut self) -> bool {
83        let intflag = self.chan.eic.intflag().read().bits();
84        intflag & (1 << P::ChId::ID) != 0
85    }
86
87    pub fn state(&mut self) -> bool {
88        let state = self.chan.eic.pinstate().read().bits();
89        state & (1 << P::ChId::ID) != 0
90    }
91
92    pub fn clear_interrupt(&mut self) {
93        unsafe {
94            self.chan.eic.intflag().write(|w| w.bits(1 << P::ChId::ID));
95        }
96    }
97
98    pub fn sense(&mut self, sense: Sense) {
99        self.chan.with_disable(|e| {
100            // Which of the two config blocks this eic config is in
101            let offset = (P::ChId::ID >> 3) & 0b0001;
102            let config = &e.config(offset);
103
104            config.modify(|_, w| unsafe {
105                // Which of the eight eic configs in this config block
106                match P::ChId::ID & 0b111 {
107                    0b000 => w.sense0().bits(sense as u8),
108                    0b001 => w.sense1().bits(sense as u8),
109                    0b010 => w.sense2().bits(sense as u8),
110                    0b011 => w.sense3().bits(sense as u8),
111                    0b100 => w.sense4().bits(sense as u8),
112                    0b101 => w.sense5().bits(sense as u8),
113                    0b110 => w.sense6().bits(sense as u8),
114                    0b111 => w.sense7().bits(sense as u8),
115                    _ => unreachable!(),
116                }
117            });
118        });
119    }
120
121    pub fn filter(&mut self, filter: bool) {
122        self.chan.with_disable(|e| {
123            // Which of the two config blocks this eic config is in
124            let offset = (P::ChId::ID >> 3) & 0b0001;
125            let config = &e.config(offset);
126
127            config.modify(|_, w| {
128                // Which of the eight eic configs in this config block
129                match P::ChId::ID & 0b111 {
130                    0b000 => w.filten0().bit(filter),
131                    0b001 => w.filten1().bit(filter),
132                    0b010 => w.filten2().bit(filter),
133                    0b011 => w.filten3().bit(filter),
134                    0b100 => w.filten4().bit(filter),
135                    0b101 => w.filten5().bit(filter),
136                    0b110 => w.filten6().bit(filter),
137                    0b111 => w.filten7().bit(filter),
138                    _ => unreachable!(),
139                }
140            });
141        });
142    }
143
144    /// Enable debouncing for this pin, with a configuration appropriate for debouncing physical buttons.
145    pub fn debounce(&mut self) {
146        self.chan.with_disable(|e| {
147            e.dprescaler().modify(|_, w| {
148                w.tickon().set_bit()    // Use the 32k clock for debouncing.
149                .states0().set_bit()    // Require 7 0 samples to see a falling edge.
150                .states1().set_bit()    // Require 7 1 samples to see a rising edge.
151                .prescaler0().div16()
152                .prescaler1().div16()
153            });
154
155            e.debouncen()
156                .modify(|_, w| unsafe { w.bits(P::ChId::ID as u32) });
157        });
158    }
159}
160
161impl<P, C, Id, F> InputPin_02 for ExtInt<P, Id, F>
162where
163    P: EicPin + AnyPin<Mode = Interrupt<C>>,
164    C: InterruptConfig,
165    Id: ChId,
166{
167    type Error = Infallible;
168    #[inline]
169    fn is_high(&self) -> Result<bool, Self::Error> {
170        self.pin.is_high()
171    }
172    #[inline]
173    fn is_low(&self) -> Result<bool, Self::Error> {
174        self.pin.is_low()
175    }
176}
177
178impl<P, Id, F> InputPin for ExtInt<P, Id, F>
179where Self: ErrorType,
180    P: EicPin,
181    Id: ChId,
182{
183    #[inline]
184    fn is_high(&mut self) -> Result<bool, Self::Error> {
185        Ok(self.pin._is_high())
186    }
187
188    #[inline]
189    fn is_low(&mut self) -> Result<bool, Self::Error> {
190        Ok(self.pin._is_low())
191    }
192}
193
194impl<P, Id, F> ErrorType for ExtInt<P, Id, F>
195where
196    P: EicPin,
197    Id: ChId,
198{
199    type Error = Infallible;
200}
201
202#[cfg(feature = "async")]
203mod async_impls {
204    use embedded_hal_async::digital::Wait;
205
206    use crate::{
207        async_hal::interrupts::{Binding, Handler, InterruptSource},
208        eic::EicFuture,
209        typelevel::NoneT,
210    };
211
212    use super::{
213        super::async_api::{InterruptHandler, WAKERS},
214        *,
215    };
216
217    impl<P, Id> ExtInt<P, Id, NoneT>
218    where
219        P: EicPin,
220        Id: ChId,
221    {
222        /// Turn an EIC pin into a pin usable as a [`Future`](core::future::Future).
223        /// The correct interrupt source is needed.
224        pub fn into_future<I>(self, _irq: I) -> ExtInt<P, Id, EicFuture>
225        where
226            I: Binding<P::InterruptSource, InterruptHandler>,
227            InterruptHandler: Handler<P::InterruptSource>,
228        {
229            P::InterruptSource::unpend();
230            unsafe { P::InterruptSource::enable() };
231
232            ExtInt {
233                pin: self.pin,
234                chan: self.chan.change_mode(),
235            }
236        }
237    }
238
239    impl<P, Id> ExtInt<P, Id, EicFuture>
240    where
241        P: EicPin,
242        Self: InputPin<Error = Infallible>,
243        Id: ChId,
244    {
245        pub async fn wait(&mut self, sense: Sense) {
246            use core::{future::poll_fn, task::Poll};
247            self.disable_interrupt();
248
249            self.sense(sense);
250            poll_fn(|cx| {
251                if self.is_interrupt() {
252                    self.clear_interrupt();
253                    self.disable_interrupt();
254                    self.sense(Sense::None);
255                    return Poll::Ready(());
256                }
257
258                WAKERS[P::ChId::ID].register(cx.waker());
259                self.enable_interrupt();
260
261                if self.is_interrupt() {
262                    self.clear_interrupt();
263                    self.disable_interrupt();
264                    self.sense(Sense::None);
265                    return Poll::Ready(());
266                }
267
268                Poll::Pending
269            })
270            .await;
271        }
272    }
273
274    impl<P, Id> Wait for ExtInt<P, Id, EicFuture>
275    where
276        P: EicPin,
277        Self: InputPin<Error = Infallible>,
278        Id: ChId,
279    {
280        async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
281            self.wait(Sense::High).await;
282            Ok(())
283        }
284
285        async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
286            self.wait(Sense::Low).await;
287            Ok(())
288        }
289
290        async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
291            self.wait(Sense::Rise).await;
292            Ok(())
293        }
294
295        async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
296            self.wait(Sense::Fall).await;
297            Ok(())
298        }
299
300        async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
301            self.wait(Sense::Both).await;
302            Ok(())
303        }
304    }
305}
306
307ei!(ExtInt[0] {
308    #[hal_cfg("pa00")]
309    PA00,
310    #[hal_cfg("pa16")]
311    PA16,
312    #[hal_cfg("pb00")]
313    PB00,
314    #[hal_cfg("pb16")]
315    PB16,
316    #[hal_cfg("pc00")]
317    PC00,
318    #[hal_cfg("pc16")]
319    PC16,
320    #[hal_cfg("pd00")]
321    PD00,
322});
323
324ei!(ExtInt[1] {
325    #[hal_cfg("pa01")]
326    PA01,
327    #[hal_cfg("pa17")]
328    PA17,
329    #[hal_cfg("pb01")]
330    PB01,
331    #[hal_cfg("pb17")]
332    PB17,
333    #[hal_cfg("pc01")]
334    PC01,
335    #[hal_cfg("pc17")]
336    PC17,
337    #[hal_cfg("pd01")]
338    PD01,
339});
340
341ei!(ExtInt[2] {
342    #[hal_cfg("pa02")]
343    PA02,
344    #[hal_cfg("pa18")]
345    PA18,
346    #[hal_cfg("pb02")]
347    PB02,
348    #[hal_cfg("pb18")]
349    PB18,
350    #[hal_cfg("pc02")]
351    PC02,
352    #[hal_cfg("pc18")]
353    PC18,
354});
355
356ei!(ExtInt[3] {
357    #[hal_cfg("pa03")]
358    PA03,
359    #[hal_cfg("pa19")]
360    PA19,
361    #[hal_cfg("pb03")]
362    PB03,
363    #[hal_cfg("pb19")]
364    PB19,
365    #[hal_cfg("pc03")]
366    PC03,
367    #[hal_cfg("pc19")]
368    PC19,
369    #[hal_cfg("pd08")]
370    PD08,
371});
372
373ei!(ExtInt[4] {
374    #[hal_cfg("pa04")]
375    PA04,
376    #[hal_cfg("pa20")]
377    PA20,
378    #[hal_cfg("pb04")]
379    PB04,
380    #[hal_cfg("pb20")]
381    PB20,
382    #[hal_cfg("pc04")]
383    PC04,
384    #[hal_cfg("pc20")]
385    PC20,
386    #[hal_cfg("pd09")]
387    PD09,
388});
389
390ei!(ExtInt[5] {
391    #[hal_cfg("pa05")]
392    PA05,
393    #[hal_cfg("pa21")]
394    PA21,
395    #[hal_cfg("pb05")]
396    PB05,
397    #[hal_cfg("pb21")]
398    PB21,
399    #[hal_cfg("pc05")]
400    PC05,
401    #[hal_cfg("pc21")]
402    PC21,
403    #[hal_cfg("pd10")]
404    PD10,
405});
406
407ei!(ExtInt[6] {
408    #[hal_cfg("pa06")]
409    PA06,
410    #[hal_cfg("pa22")]
411    PA22,
412    #[hal_cfg("pb06")]
413    PB06,
414    #[hal_cfg("pb22")]
415    PB22,
416    #[hal_cfg("pc06")]
417    PC06,
418    #[hal_cfg("pc22")]
419    PC22,
420    #[hal_cfg("pd11")]
421    PD11,
422});
423
424ei!(ExtInt[7] {
425    #[hal_cfg("pa07")]
426    PA07,
427    #[hal_cfg("pa23")]
428    PA23,
429    #[hal_cfg("pb07")]
430    PB07,
431    #[hal_cfg("pb23")]
432    PB23,
433    #[hal_cfg("pc23")]
434    PC23,
435    #[hal_cfg("pd12")]
436    PD12,
437});
438
439ei!(ExtInt[8] {
440    #[hal_cfg("pa24")]
441    PA24,
442    #[hal_cfg("pb08")]
443    PB08,
444    #[hal_cfg("pb24")]
445    PB24,
446    #[hal_cfg("pc24")]
447    PC24,
448});
449
450ei!(ExtInt[9] {
451    #[hal_cfg("pa09")]
452    PA09,
453    #[hal_cfg("pa25")]
454    PA25,
455    #[hal_cfg("pb09")]
456    PB09,
457    #[hal_cfg("pb25")]
458    PB25,
459    #[hal_cfg("pc07")]
460    PC07,
461    #[hal_cfg("pc25")]
462    PC25,
463});
464
465ei!(ExtInt[10] {
466    #[hal_cfg("pa10")]
467    PA10,
468    #[hal_cfg("pb10")]
469    PB10,
470    #[hal_cfg("pc10")]
471    PC10,
472    #[hal_cfg("pc26")]
473    PC26,
474    #[hal_cfg("pd20")]
475    PD20,
476});
477
478ei!(ExtInt[11] {
479    #[hal_cfg("pa11")]
480    PA11,
481    #[hal_cfg("pa27")]
482    PA27,
483    #[hal_cfg("pb11")]
484    PB11,
485    #[hal_cfg("pc11")]
486    PC11,
487    #[hal_cfg("pc27")]
488    PC27,
489    #[hal_cfg("pd21")]
490    PD21,
491});
492
493ei!(ExtInt[12] {
494    #[hal_cfg("pa12")]
495    PA12,
496    #[hal_cfg("pb12")]
497    PB12,
498    #[hal_cfg("pb26")]
499    PB26,
500    #[hal_cfg("pc12")]
501    PC12,
502    #[hal_cfg("pc28")]
503    PC28,
504});
505
506ei!(ExtInt[13] {
507    #[hal_cfg("pa13")]
508    PA13,
509    #[hal_cfg("pb13")]
510    PB13,
511    #[hal_cfg("pb27")]
512    PB27,
513    #[hal_cfg("pc13")]
514    PC13,
515});
516
517ei!(ExtInt[14] {
518    #[hal_cfg("pa14")]
519    PA14,
520    #[hal_cfg("pa30")]
521    PA30,
522    #[hal_cfg("pb14")]
523    PB14,
524    #[hal_cfg("pb28")]
525    PB28,
526    #[hal_cfg("pb30")]
527    PB30,
528    #[hal_cfg("pc14")]
529    PC14,
530    #[hal_cfg("pc30")]
531    PC30,
532});
533
534ei!(ExtInt[15] {
535    #[hal_cfg("pa15")]
536    PA15,
537    #[hal_cfg("pa31")]
538    PA31,
539    #[hal_cfg("pb15")]
540    PB15,
541    #[hal_cfg("pb29")]
542    PB29,
543    #[hal_cfg("pb31")]
544    PB31,
545    #[hal_cfg("pc15")]
546    PC15,
547    #[hal_cfg("pc31")]
548    PC31,
549});