alt_stm32f30x_hal/
exti.rs

1//! External interrupts
2
3use crate::gpio;
4use crate::syscfg::Syscfg;
5
6use crate::pac::{self, EXTI};
7
8/// Extension trait that contsrins the `EXTI` peripheral
9pub trait ExtiExt {
10    /// Constrains the `EXTI` peripheral so it plays nicely with the other
11    /// abstractions
12    fn constrain(self) -> ExternalInterrupts;
13}
14
15/// External interrupts configuration
16pub struct Exti<E: ExternalInterrupt> {
17    ei: E,
18}
19
20/// Interrupt bound to pin
21pub struct BoundInterrupt<GP, E> {
22    pin: GP,
23    ei: E,
24}
25
26impl<GP, E> BoundInterrupt<GP, E>
27    where GP: gpio::GPIOPin,
28          E: ExternalInterrupt
29{
30    /// Clears pending status on external interrupt
31    pub fn unpend(&mut self) {
32        let mask: bool = true;
33        let exti = unsafe { &(*EXTI::ptr()) };
34        let offset: u8 = self.ei.index();
35
36        exti.pr1.modify(|r, w| unsafe {
37                    w.bits((r.bits() & !((mask as u32) << offset))
38                           | (((true & mask) as u32) << offset))
39                });
40    }
41
42    /// Disconnect pin from external interrupt
43    pub fn free(self, syscfg: &mut Syscfg) -> (GP, E) {
44        let exti = unsafe { &(*EXTI::ptr()) };
45
46        // Disable external interrupt on rise
47        let offset = self.pin.index() as u32;
48        exti.imr1
49            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1 << offset)) });
50        exti.emr1
51            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1 << offset)) });
52        exti.rtsr1
53            .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1 << offset)) });
54
55        // Clear pin group
56        let group_bits_to_clear = !bits_of_gpio_group(&self.pin.group());
57        match self.ei.enumeration() {
58            ExtIn::EXTI0 => {
59                syscfg.exticr1().modify(|_, w| unsafe {
60                                    w.exti0().bits(group_bits_to_clear)
61                                });
62            }
63            ExtIn::EXTI1 => {
64                syscfg.exticr1().modify(|_, w| unsafe {
65                                    w.exti1().bits(group_bits_to_clear)
66                                });
67            }
68            ExtIn::EXTI2 => {
69                syscfg.exticr1().modify(|_, w| unsafe {
70                                    w.exti2().bits(group_bits_to_clear)
71                                });
72            }
73            ExtIn::EXTI3 => {
74                syscfg.exticr1().modify(|_, w| unsafe {
75                                    w.exti3().bits(group_bits_to_clear)
76                                });
77            }
78            ExtIn::EXTI4 => {
79                syscfg.exticr2().modify(|_, w| unsafe {
80                                    w.exti4().bits(group_bits_to_clear)
81                                });
82            }
83            ExtIn::EXTI13 => {
84                syscfg.exticr4().modify(|_, w| unsafe {
85                                    w.exti13().bits(group_bits_to_clear)
86                                });
87            }
88        }
89
90        (self.pin, self.ei)
91    }
92}
93
94impl<E: ExternalInterrupt> Exti<E> {
95    /// Bind interrupt to input pin. Returns bound interrput that can be used to
96    /// unpend.
97    pub fn bind<GP>(self, pin: GP, syscfg: &mut Syscfg) -> BoundInterrupt<GP, E>
98        where GP: gpio::GPIOPin + hal::digital::v2::InputPin
99    {
100        let exti = unsafe { &(*EXTI::ptr()) };
101
102        let group_bits = bits_of_gpio_group(&pin.group());
103
104        // Setup pin group
105        match self.ei.enumeration() {
106            ExtIn::EXTI0 => {
107                syscfg.exticr1()
108                      .modify(|_, w| unsafe { w.exti0().bits(group_bits) });
109            }
110            ExtIn::EXTI1 => {
111                syscfg.exticr1()
112                      .modify(|_, w| unsafe { w.exti1().bits(group_bits) });
113            }
114            ExtIn::EXTI2 => {
115                syscfg.exticr1()
116                      .modify(|_, w| unsafe { w.exti2().bits(group_bits) });
117            }
118            ExtIn::EXTI3 => {
119                syscfg.exticr1()
120                      .modify(|_, w| unsafe { w.exti3().bits(group_bits) });
121            }
122            ExtIn::EXTI4 => {
123                syscfg.exticr2()
124                      .modify(|_, w| unsafe { w.exti4().bits(group_bits) });
125            }
126            ExtIn::EXTI13 => {
127                syscfg.exticr4()
128                      .modify(|_, w| unsafe { w.exti13().bits(group_bits) });
129            }
130        }
131
132        let offset = pin.index() as u32;
133        // Enable external interrupt on rise
134        exti.imr1.modify(|r, w| unsafe {
135                     w.bits((r.bits() & !(0b1 << offset)) | (1 << offset))
136                 });
137        exti.emr1.modify(|r, w| unsafe {
138                     w.bits((r.bits() & !(0b1 << offset)) | (1 << offset))
139                 });
140        exti.rtsr1.modify(|r, w| unsafe {
141                      w.bits((r.bits() & !(0b1 << offset)) | (1 << offset))
142                  });
143
144        BoundInterrupt { pin: pin,
145                         ei: self.ei }
146    }
147}
148
149#[doc(hidden)]
150pub trait ExternalInterrupt: private::Sealed {
151    #[doc(hidden)]
152    fn interrupt(&self) -> pac::Interrupt;
153    #[doc(hidden)]
154    fn enumeration(&self) -> ExtIn;
155    #[doc(hidden)]
156    fn index(&self) -> u8;
157}
158
159// XXX: re do this, without enum
160#[doc(hidden)]
161pub enum ExtIn {
162    /// 0,
163    EXTI0,
164    /// 1,
165    EXTI1,
166    /// 2,
167    EXTI2,
168    /// 3,
169    EXTI3,
170    /// 4,
171    EXTI4,
172    /// 13 (15_10),
173    EXTI13,
174}
175
176macro_rules! gen_exti {
177    ([$(($name:ident, $exti:ident, $i: expr),)+]) => {
178        #[doc(hidden)]
179        mod private {
180            #[doc(hidden)]
181            pub trait Sealed {}
182            $(
183                impl Sealed for super::$name {}
184            )+
185        }
186
187
188        $(
189            /// $name external interrupt
190            pub struct $name {
191                _0: (),
192            }
193            impl ExternalInterrupt for $name {
194                fn interrupt(&self) -> pac::Interrupt {
195                    pac::Interrupt::$exti
196                }
197
198                fn enumeration(&self) -> ExtIn {
199                    ExtIn::$name
200                }
201
202                fn index(&self) -> u8 {
203                    $i
204                }
205            }
206        )+
207
208        /// All external interrupts
209        #[allow(non_snake_case)]
210        pub struct ExternalInterrupts {
211            $(
212                /// $name interrupt
213                pub $name: Exti<$name>,
214            )+
215        }
216
217        impl ExtiExt for EXTI {
218            fn constrain(self) -> ExternalInterrupts {
219                (
220                    ExternalInterrupts {
221                        $(
222                            $name: Exti { ei: $name { _0: () }} ,
223                        )+
224                    }
225                )
226            }
227        }
228    }
229}
230
231// TODO: fix this, EXTIx should be only connectable to PAx, PBx, etc.
232gen_exti!([(EXTI0, EXTI0, 0),
233           (EXTI1, EXTI1, 1),
234           (EXTI2, EXTI2_TSC, 2),
235           (EXTI3, EXTI3, 2),
236           (EXTI4, EXTI4, 4),
237           (EXTI13, EXTI15_10, 13),]);
238
239fn bits_of_gpio_group(group: &gpio::Group) -> u8 {
240    match group {
241        gpio::Group::A => 0b0000,
242        gpio::Group::B => 0b0001,
243        gpio::Group::C => 0b0010,
244        gpio::Group::D => 0b0011,
245        gpio::Group::E => 0b0100,
246        gpio::Group::F => 0b0101,
247        gpio::Group::G => 0b0110,
248    }
249}