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