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}