lpc8xx_hal/pinint/
interrupt.rs

1use core::marker::PhantomData;
2
3use super::traits::Trait;
4
5use crate::{init_state::Enabled, pac, pins, syscon};
6
7/// API for controlling pin interrupts
8pub struct Interrupt<I, P, State> {
9    interrupt: PhantomData<I>,
10    _pin: PhantomData<P>,
11    state: PhantomData<State>,
12}
13
14impl<I, P, State> Interrupt<I, P, State> {
15    pub(super) fn new() -> Self {
16        Self {
17            interrupt: PhantomData,
18            _pin: PhantomData,
19            state: PhantomData,
20        }
21    }
22}
23
24impl<I, OldPin, State> Interrupt<I, OldPin, State>
25where
26    I: Trait,
27{
28    /// Select a pin as the source of this interrupt
29    ///
30    /// Please be aware that this method allows you to do things that might or
31    /// might not be valid things to do:
32    ///
33    /// - You can select any pin, regardless of its current state.
34    /// - You can select the same pin for multiple interrupts.
35    ///
36    /// The documentation isn't totally clear about whether these are allowed,
37    /// and no research has been done to verify it one way or the other. Please
38    /// be careful, and make sure to [open an issue], if you discover that this
39    /// API allows you to do something that is not correct.
40    ///
41    /// Please also be aware that the interrupt handler for various pin
42    /// interrupts is reused for other purposes.
43    ///
44    /// [open an issue]: https://github.com/lpc-rs/lpc8xx-hal/issues
45    pub fn select<P>(
46        self,
47        interrupt_pin: &P,
48        _: &mut syscon::Handle,
49    ) -> Interrupt<I, P, State>
50    where
51        P: pins::Trait,
52    {
53        // Sound, as this `Interrupt` instance is the only one accessing this
54        // register, and the mutable reference to the SYSCON handle guarantees
55        // that safe concurrent PAC-level access to the register is not
56        // possible.
57        let syscon = unsafe { &*pac::SYSCON::ptr() };
58
59        syscon.pintsel[I::INDEX].write(|w|
60            // Sound, as any value with `0 <= value <= 63` is valid to write to
61            // the register.
62            unsafe { w.intpin().bits(32 * interrupt_pin.port() as u8 + interrupt_pin.id())});
63
64        Interrupt {
65            interrupt: self.interrupt,
66            _pin: PhantomData,
67            state: self.state,
68        }
69    }
70}
71
72impl<I, P> Interrupt<I, P, Enabled>
73where
74    I: Trait,
75    P: pins::Trait,
76{
77    /// Returns whether a rising edge has been detected and clears the flag
78    ///
79    /// This method will work regardless of whether rising edge interrupts have
80    /// been enabled or not.
81    ///
82    /// You must call this handle while handling a rising edge interrupt.
83    /// Otherwise, the interrupt will be fired again immediately, after the
84    /// interrupt handler exits.
85    pub fn clear_rising_edge_flag(&mut self) -> bool {
86        // This is sound, as we're only doing an atomic read and write, both to // a single bit that no other `Interrupt` instance is writing to.
87        let pint = unsafe { &*pac::PINT::ptr() };
88
89        let is_set = pint.rise.read().rdet().bits() & I::MASK != 0;
90
91        // Clear flag
92        pint.rise.write(|w|
93            // Sound, as long as `Trait` is only implemented for valid
94            // interrupts.
95            unsafe { w.rdet().bits(I::MASK) });
96
97        is_set
98    }
99
100    /// Fire interrupt on rising edge
101    pub fn enable_rising_edge(&mut self) {
102        // This is sound, as we're only doing an atomic write to a single bit
103        // that no other `Interrupt` instance is writing to.
104        let pint = unsafe { &*pac::PINT::ptr() };
105
106        pint.sienr.write(|w|
107            // Sound, as long as `Trait` is only implemented for valid
108            // interrupts.
109            unsafe { w.setenrl().bits(I::MASK) });
110    }
111
112    /// Don't fire interrupt on rising edge
113    pub fn disable_rising_edge(&mut self) {
114        // This is sound, as we're only doing an atomic write to a single bit
115        // that no other `Interrupt` instance is writing to.
116        let pint = unsafe { &*pac::PINT::ptr() };
117
118        pint.cienr.write(|w|
119            // Sound, as long as `Trait` is only implemented for valid
120            // interrupts.
121            unsafe { w.cenrl().bits(I::MASK) });
122    }
123
124    /// Returns whether a falling edge has been detected and clears the flag
125    ///
126    /// This method will work regardless of whether falling edge interrupts have
127    /// been enabled or not.
128    ///
129    /// You must call this handle while handling a falling edge interrupt.
130    /// Otherwise, the interrupt will be fired again immediately, after the
131    /// interrupt handler exits.
132    pub fn clear_falling_edge_flag(&mut self) -> bool {
133        // This is sound, as we're only doing an atomic read and write, both to // a single bit that no other `Interrupt` instance is writing to.
134        let pint = unsafe { &*pac::PINT::ptr() };
135
136        let is_set = pint.fall.read().fdet().bits() & I::MASK != 0;
137
138        // Clear flag
139        pint.fall.write(|w|
140            // Sound, as long as `Trait` is only implemented for valid
141            // interrupts.
142            unsafe { w.fdet().bits(I::MASK) });
143
144        is_set
145    }
146
147    /// Fire interrupt on falling edge
148    pub fn enable_falling_edge(&mut self) {
149        // This is sound, as we're only doing an atomic write to a single bit
150        // that no other `Interrupt` instance is writing to.
151        let pint = unsafe { &*pac::PINT::ptr() };
152
153        pint.sienf.write(|w|
154            // Sound, as long as `Trait` is only implemented for valid
155            // interrupts.
156            unsafe { w.setenaf().bits(I::MASK) });
157    }
158
159    /// Don't fire interrupt on falling edge
160    pub fn disable_falling_edge(&mut self) {
161        // This is sound, as we're only doing an atomic write to a single bit
162        // that no other `Interrupt` instance is writing to.
163        let pint = unsafe { &*pac::PINT::ptr() };
164
165        pint.cienf.write(|w|
166            // Sound, as long as `Trait` is only implemented for valid
167            // interrupts.
168            unsafe { w.cenaf().bits(I::MASK) });
169    }
170}