sam3_hal/pio/
filter.rs

1//! PIO line filtering
2//!
3//! PIO lines can be filtered in three ways:
4//! 1. No filtering
5//! 2. Programmable glitch filtering
6//! 3. Debouncing
7//!
8//! It's difficult to communincate the exact nature of the debouncer and glitch filter through just
9//! text, so please refer to the appropriate documentation for your chip for information on this
10//! functionality:
11//! - SAM3A, SAM3X: [manual][ax], pages 624-626
12//! - SAM3N: [manual][n], pages 382-384
13//! - SAM3S1, SAM3S2, SAM3S4: [manual][s124], pages 473-475
14//! - SAM3S8, SAM3SD8: [manual][sd8], pages 482-484
15//! - SAM3U: [manual][u], pages 500-502
16//!
17//! [ax]: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf
18//! [n]: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11011-32-bit-Cortex-M3-Microcontroller-SAM3N_Datasheet.pdf
19//! [s124]: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6500-32-bit-Cortex-M3-Microcontroller-SAM3S4-SAM3S2-SAM3S1_Datasheet.pdf
20//! [sd8]: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11090-32-bit%20Cortex-M3-Microcontroller-SAM-3S8-SD8_Datasheet.pdf
21//! [u]: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6430-32-bit-Cortex-M3-Microcontroller-SAM3U4-SAM3U2-SAM3U1_Datasheet.pdf
22//!
23//! Note that for SAM3A, SAM3U, and SAM3X the slow clock is referred to as the (divided) system
24//! clock.
25
26use crate::{
27    pio::{
28        interrupt::InterruptCfg,
29        peripheral::PioControlCfg,
30        pin::{MultiDriverCfg, PadResistorCfg, Pin, PinId, Unconfigured},
31        PioRegisters,
32    },
33    structure::*,
34};
35use core::marker::PhantomData;
36
37#[allow(clippy::module_name_repetitions)]
38/// Marker trait for input filter configuration options.
39pub trait InputFilterCfg {}
40
41impl InputFilterCfg for Unconfigured {}
42
43#[allow(clippy::module_name_repetitions)]
44/// Disable the glitch input filter on an I/O line.
45pub struct InputFilterDisabled;
46
47impl InputFilterCfg for InputFilterDisabled {}
48
49#[allow(clippy::module_name_repetitions)]
50/// Enable the glitch input filter on an I/O line.
51pub struct InputFilterEnabled<Flck: InputFilterClockCfg> {
52    _flck: PhantomData<Flck>,
53}
54
55impl<Flck: InputFilterClockCfg> InputFilterCfg for InputFilterEnabled<Flck> {}
56
57/// # Input filter configuration
58///
59/// For further details, refer to module-level documentation for links to the relevant device
60/// manuals.
61pub trait ConfigureInputFilter {
62    type Disabled: ConfigureInputFilter;
63    type Enabled: ConfigureInputFilter;
64
65    /// Disable the input filter for this pin.
66    fn disable_input_filter(self) -> Self::Disabled;
67    /// Disable the input filter without waiting for the status register to update.
68    ///
69    /// # Safety
70    ///
71    /// This function returns a type showing that this pin has its input filter disabled, but the
72    /// trigger won't be disabled until the corresponding bit in `PIO_IFSR` is cleared.
73    unsafe fn disable_input_filter_unchecked(self) -> Self::Disabled;
74    /// Enable the input filter for this pin.
75    fn enable_input_filter(self) -> Self::Enabled;
76    /// Enable the input filter without waiting for the status register to update.
77    ///
78    /// # Safety
79    ///
80    /// This function returns a type showing that this pin has its input filter enabled, but the
81    /// trigger won't be enabled until the corresponding bit in `PIO_IFSR` is set.
82    unsafe fn enable_input_filter_unchecked(self) -> Self::Enabled;
83}
84
85#[allow(clippy::module_name_repetitions)]
86/// Marker trait for input filter clock configuration options.
87pub trait InputFilterClockCfg {}
88
89impl InputFilterClockCfg for Unconfigured {}
90
91#[allow(clippy::module_name_repetitions)]
92/// Set an I/O line's input filter to use the system clock glitch filter.
93pub struct SlowClock;
94
95impl InputFilterClockCfg for SlowClock {}
96
97#[allow(clippy::module_name_repetitions)]
98/// Set an I/O line's input filter to use the debouncing filter.
99pub struct Debouncing;
100
101impl InputFilterClockCfg for Debouncing {}
102
103/// # Input filter clock configuration
104///
105/// For further details, refer to the module-level documentation for links to the relevant device
106/// manuals.
107pub trait ConfigureInputFilterClock {
108    type Debouncing: ConfigureInputFilterClock;
109    type SlowClock: ConfigureInputFilterClock;
110
111    /// Select the debouncing filter clock for this pin.
112    fn debouncing_filter(self) -> Self::Debouncing;
113    /// Select the debouncing filter clock without waiting for the status register to update.
114    ///
115    /// # Safety
116    ///
117    /// This function returns a type showing that this pin has the debouncing clock selected, but
118    /// the clock isn't actually selected until the corresponding bit in `
119    #[cfg_attr(
120        any(feature = "sam3a", feature = "sam3u", feature = "sam3x"),
121        doc = "PIO_IFDGSR"
122    )]
123    #[cfg_attr(
124        any(feature = "sam3n", feature = "sam3s", feature = "sam3s8"),
125        doc = "PIO_IFSCSR"
126    )]
127    /// ` is cleared.
128    unsafe fn debouncing_filter_unchecked(self) -> Self::Debouncing;
129    /// Select the slow clock filter clock for this pin.
130    fn slow_clock_filter(self) -> Self::SlowClock;
131    /// Select the slow clock filter clock without waiting for the status register to update.
132    ///
133    /// # Safety
134    ///
135    /// This function returns a type showing that this pin has the slow clock selected, but the
136    /// clock isn't actually selected until the corresponding bit in `
137    #[cfg_attr(
138        any(feature = "sam3a", feature = "sam3u", feature = "sam3x"),
139        doc = "PIO_IFDGSR"
140    )]
141    #[cfg_attr(
142        any(feature = "sam3n", feature = "sam3s", feature = "sam3s8"),
143        doc = "PIO_IFSCSR"
144    )]
145    /// ` is set.
146    unsafe fn slow_clock_filter_unchecked(self) -> Self::SlowClock;
147}
148
149impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilter
150    for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, Unconfigured>
151where
152    Pio: PioRegisters,
153    Pid: PinId<Controller = Pio>,
154    Mdvr: MultiDriverCfg,
155    Pioc: PioControlCfg,
156    Padr: PadResistorCfg,
157    Irpt: InterruptCfg,
158{
159    type Disabled = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterDisabled>;
160    type Enabled = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Unconfigured>>;
161
162    fn disable_input_filter(self) -> Self::Disabled {
163        unsafe {
164            let pioreg = &*Pio::PTR;
165            if pioreg._ifsr().read().bits() & Pid::MASK != 0 {
166                let _ = self.disable_input_filter_unchecked();
167                while pioreg._ifsr().read().bits() & Pid::MASK != 0 {}
168            }
169            Pin::new()
170        }
171    }
172
173    unsafe fn disable_input_filter_unchecked(self) -> Self::Disabled {
174        let pioreg = &*Pio::PTR;
175        pioreg._ifdr().write_with_zero(|w| w.bits(Pid::MASK));
176        Pin::new()
177    }
178
179    fn enable_input_filter(self) -> Self::Enabled {
180        unsafe {
181            let pioreg = &*Pio::PTR;
182            if pioreg._ifsr().read().bits() & Pid::MASK == 0 {
183                let _ = self.enable_input_filter_unchecked();
184                while pioreg._ifsr().read().bits() & Pid::MASK == 0 {}
185            }
186            Pin::new()
187        }
188    }
189
190    unsafe fn enable_input_filter_unchecked(self) -> Self::Enabled {
191        let pioreg = &*Pio::PTR;
192        pioreg._ifer().write_with_zero(|w| w.bits(Pid::MASK));
193        Pin::new()
194    }
195}
196
197impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilter
198    for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterDisabled>
199where
200    Pio: PioRegisters,
201    Pid: PinId<Controller = Pio>,
202    Mdvr: MultiDriverCfg,
203    Pioc: PioControlCfg,
204    Padr: PadResistorCfg,
205    Irpt: InterruptCfg,
206{
207    type Disabled = Self;
208    type Enabled = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Unconfigured>>;
209
210    fn disable_input_filter(self) -> Self::Disabled {
211        self
212    }
213
214    unsafe fn disable_input_filter_unchecked(self) -> Self::Disabled {
215        self
216    }
217
218    fn enable_input_filter(self) -> Self::Enabled {
219        unsafe {
220            let pioreg = &*Pio::PTR;
221            let _ = self.enable_input_filter_unchecked();
222            while pioreg._ifsr().read().bits() & Pid::MASK == 0 {}
223            Pin::new()
224        }
225    }
226
227    unsafe fn enable_input_filter_unchecked(self) -> Self::Enabled {
228        let pioreg = &*Pio::PTR;
229        pioreg._ifer().write_with_zero(|w| w.bits(Pid::MASK));
230        Pin::new()
231    }
232}
233
234impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt, Flck> ConfigureInputFilter
235    for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Flck>>
236where
237    Pio: PioRegisters,
238    Pid: PinId<Controller = Pio>,
239    Mdvr: MultiDriverCfg,
240    Pioc: PioControlCfg,
241    Padr: PadResistorCfg,
242    Irpt: InterruptCfg,
243    Flck: InputFilterClockCfg,
244{
245    type Disabled = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterDisabled>;
246    type Enabled = Self;
247
248    fn disable_input_filter(self) -> Self::Disabled {
249        unsafe {
250            let pioreg = &*Pio::PTR;
251            let _ = self.disable_input_filter_unchecked();
252            while pioreg._ifsr().read().bits() & Pid::MASK != 0 {}
253            Pin::new()
254        }
255    }
256
257    unsafe fn disable_input_filter_unchecked(self) -> Self::Disabled {
258        let pioreg = &*Pio::PTR;
259        pioreg._ifdr().write_with_zero(|w| w.bits(Pid::MASK));
260        Pin::new()
261    }
262
263    fn enable_input_filter(self) -> Self::Enabled {
264        self
265    }
266
267    unsafe fn enable_input_filter_unchecked(self) -> Self::Enabled {
268        self
269    }
270}
271
272#[cfg(any(feature = "sam3a", feature = "sam3u", feature = "sam3x"))]
273const _: () = {
274    impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilterClock
275        for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Unconfigured>>
276    where
277        Pio: PioRegisters,
278        Pid: PinId<Controller = Pio>,
279        Mdvr: MultiDriverCfg,
280        Pioc: PioControlCfg,
281        Padr: PadResistorCfg,
282        Irpt: InterruptCfg,
283    {
284        type Debouncing = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Debouncing>>;
285        type SlowClock = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<SlowClock>>;
286
287        fn debouncing_filter(self) -> Self::Debouncing {
288            unsafe {
289                let pioreg = &*Pio::PTR;
290                if pioreg._ifdgsr().read().bits() & Pid::MASK != 0 {
291                    let _ = self.debouncing_filter_unchecked();
292                    while pioreg._ifdgsr().read().bits() & Pid::MASK != 0 {}
293                }
294                Pin::new()
295            }
296        }
297
298        unsafe fn debouncing_filter_unchecked(self) -> Self::Debouncing {
299            let pioreg = &*Pio::PTR;
300            pioreg._difsr().write_with_zero(|w| w.bits(Pid::MASK));
301            Pin::new()
302        }
303
304        fn slow_clock_filter(self) -> Self::SlowClock {
305            unsafe {
306                let pioreg = &*Pio::PTR;
307                if pioreg._ifdgsr().read().bits() & Pid::MASK == 0 {
308                    let _ = self.slow_clock_filter_unchecked();
309                    while pioreg._ifdgsr().read().bits() & Pid::MASK == 0 {}
310                }
311                Pin::new()
312            }
313        }
314
315        unsafe fn slow_clock_filter_unchecked(self) -> Self::SlowClock {
316            let pioreg = &*Pio::PTR;
317            pioreg._scifsr().write_with_zero(|w| w.bits(Pid::MASK));
318            Pin::new()
319        }
320    }
321
322    impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilterClock
323        for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Debouncing>>
324    where
325        Pio: PioRegisters,
326        Pid: PinId<Controller = Pio>,
327        Mdvr: MultiDriverCfg,
328        Pioc: PioControlCfg,
329        Padr: PadResistorCfg,
330        Irpt: InterruptCfg,
331    {
332        type Debouncing = Self;
333        type SlowClock = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<SlowClock>>;
334
335        fn debouncing_filter(self) -> Self::Debouncing {
336            self
337        }
338
339        unsafe fn debouncing_filter_unchecked(self) -> Self::Debouncing {
340            self
341        }
342
343        fn slow_clock_filter(self) -> Self::SlowClock {
344            unsafe {
345                let pioreg = &*Pio::PTR;
346                let _ = self.slow_clock_filter_unchecked();
347                while pioreg._ifdgsr().read().bits() & Pid::MASK == 0 {}
348                Pin::new()
349            }
350        }
351
352        unsafe fn slow_clock_filter_unchecked(self) -> Self::SlowClock {
353            let pioreg = &*Pio::PTR;
354            pioreg._scifsr().write_with_zero(|w| w.bits(Pid::MASK));
355            Pin::new()
356        }
357    }
358
359    impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilterClock
360        for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<SlowClock>>
361    where
362        Pio: PioRegisters,
363        Pid: PinId<Controller = Pio>,
364        Mdvr: MultiDriverCfg,
365        Pioc: PioControlCfg,
366        Padr: PadResistorCfg,
367        Irpt: InterruptCfg,
368    {
369        type Debouncing = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Debouncing>>;
370        type SlowClock = Self;
371
372        fn debouncing_filter(self) -> Self::Debouncing {
373            unsafe {
374                let pioreg = &*Pio::PTR;
375                let _ = self.debouncing_filter_unchecked();
376                while pioreg._ifdgsr().read().bits() & Pid::MASK != 0 {}
377                Pin::new()
378            }
379        }
380
381        unsafe fn debouncing_filter_unchecked(self) -> Self::Debouncing {
382            let pioreg = &*Pio::PTR;
383            pioreg._difsr().write_with_zero(|w| w.bits(Pid::MASK));
384            Pin::new()
385        }
386
387        fn slow_clock_filter(self) -> Self::SlowClock {
388            self
389        }
390
391        unsafe fn slow_clock_filter_unchecked(self) -> Self::SlowClock {
392            self
393        }
394    }
395};
396
397#[cfg(any(feature = "sam3n", feature = "sam3s", feature = "sam3s8"))]
398const _: () = {
399    impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilterClock
400        for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Unconfigured>>
401    where
402        Pio: PioRegisters,
403        Pid: PinId<Controller = Pio>,
404        Mdvr: MultiDriverCfg,
405        Pioc: PioControlCfg,
406        Padr: PadResistorCfg,
407        Irpt: InterruptCfg,
408    {
409        type Debouncing = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Debouncing>>;
410        type SlowClock = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<SlowClock>>;
411
412        fn debouncing_filter(self) -> Self::Debouncing {
413            unsafe {
414                let pioreg = &*Pio::PTR;
415                if pioreg._ifscsr().read().bits() & Pid::MASK != 0 {
416                    let _ = self.debouncing_filter_unchecked();
417                    while pioreg._ifscsr().read().bits() & Pid::MASK != 0 {}
418                }
419                Pin::new()
420            }
421        }
422
423        unsafe fn debouncing_filter_unchecked(self) -> Self::Debouncing {
424            let pioreg = &*Pio::PTR;
425            pioreg._ifscdr().write_with_zero(|w| w.bits(Pid::MASK));
426            Pin::new()
427        }
428
429        fn slow_clock_filter(self) -> Self::SlowClock {
430            unsafe {
431                let pioreg = &*Pio::PTR;
432                if pioreg._ifscsr().read().bits() & Pid::MASK == 0 {
433                    let _ = self.slow_clock_filter_unchecked();
434                    while pioreg._ifscsr().read().bits() & Pid::MASK == 0 {}
435                }
436                Pin::new()
437            }
438        }
439
440        unsafe fn slow_clock_filter_unchecked(self) -> Self::SlowClock {
441            let pioreg = &*Pio::PTR;
442            pioreg._ifscer().write_with_zero(|w| w.bits(Pid::MASK));
443            Pin::new()
444        }
445    }
446
447    impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilterClock
448        for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Debouncing>>
449    where
450        Pio: PioRegisters,
451        Pid: PinId<Controller = Pio>,
452        Mdvr: MultiDriverCfg,
453        Pioc: PioControlCfg,
454        Padr: PadResistorCfg,
455        Irpt: InterruptCfg,
456    {
457        type Debouncing = Self;
458        type SlowClock = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<SlowClock>>;
459
460        fn debouncing_filter(self) -> Self::Debouncing {
461            self
462        }
463
464        unsafe fn debouncing_filter_unchecked(self) -> Self::Debouncing {
465            self
466        }
467
468        fn slow_clock_filter(self) -> Self::SlowClock {
469            unsafe {
470                let pioreg = &*Pio::PTR;
471                let _ = self.slow_clock_filter_unchecked();
472                while pioreg._ifscsr().read().bits() & Pid::MASK == 0 {}
473                Pin::new()
474            }
475        }
476
477        unsafe fn slow_clock_filter_unchecked(self) -> Self::SlowClock {
478            let pioreg = &*Pio::PTR;
479            pioreg._ifscer().write_with_zero(|w| w.bits(Pid::MASK));
480            Pin::new()
481        }
482    }
483
484    impl<Pio, Pid, Mdvr, Pioc, Padr, Irpt> ConfigureInputFilterClock
485        for Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<SlowClock>>
486    where
487        Pio: PioRegisters,
488        Pid: PinId<Controller = Pio>,
489        Mdvr: MultiDriverCfg,
490        Pioc: PioControlCfg,
491        Padr: PadResistorCfg,
492        Irpt: InterruptCfg,
493    {
494        type Debouncing = Pin<Pio, Pid, Mdvr, Pioc, Padr, Irpt, InputFilterEnabled<Debouncing>>;
495        type SlowClock = Self;
496
497        fn debouncing_filter(self) -> Self::Debouncing {
498            unsafe {
499                let pioreg = &*Pio::PTR;
500                let _ = self.debouncing_filter_unchecked();
501                while pioreg._ifscsr().read().bits() & Pid::MASK != 0 {}
502                Pin::new()
503            }
504        }
505
506        unsafe fn debouncing_filter_unchecked(self) -> Self::Debouncing {
507            let pioreg = &*Pio::PTR;
508            pioreg._ifscdr().write_with_zero(|w| w.bits(Pid::MASK));
509            Pin::new()
510        }
511
512        fn slow_clock_filter(self) -> Self::SlowClock {
513            self
514        }
515
516        unsafe fn slow_clock_filter_unchecked(self) -> Self::SlowClock {
517            self
518        }
519    }
520};