stm32f4xx/
exti.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5use cortexm4f::support::atomic;
6use enum_primitive::cast::FromPrimitive;
7use enum_primitive::enum_from_primitive;
8use kernel::platform::chip::ClockInterface;
9use kernel::utilities::cells::OptionalCell;
10use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
11use kernel::utilities::registers::{register_bitfields, ReadWrite};
12use kernel::utilities::StaticRef;
13
14use crate::gpio;
15use crate::syscfg;
16
17/// External interrupt/event controller
18#[repr(C)]
19struct ExtiRegisters {
20    /// Interrupt mask register (EXTI_IMR)
21    imr: ReadWrite<u32, IMR::Register>,
22    /// Event mask register (EXTI_EMR)
23    emr: ReadWrite<u32, EMR::Register>,
24    /// Rising Trigger selection register (EXTI_RTSR)
25    rtsr: ReadWrite<u32, RTSR::Register>,
26    /// Falling Trigger selection register (EXTI_FTSR)
27    ftsr: ReadWrite<u32, FTSR::Register>,
28    /// Software interrupt event register (EXTI_SWIER)
29    swier: ReadWrite<u32, SWIER::Register>,
30    /// Pending register (EXTI_PR)
31    pr: ReadWrite<u32, PR::Register>,
32}
33
34register_bitfields![u32,
35    IMR [
36        /// Interrupt Mask on line 0
37        MR0 OFFSET(0) NUMBITS(1) [],
38        /// Interrupt Mask on line 1
39        MR1 OFFSET(1) NUMBITS(1) [],
40        /// Interrupt Mask on line 2
41        MR2 OFFSET(2) NUMBITS(1) [],
42        /// Interrupt Mask on line 3
43        MR3 OFFSET(3) NUMBITS(1) [],
44        /// Interrupt Mask on line 4
45        MR4 OFFSET(4) NUMBITS(1) [],
46        /// Interrupt Mask on line 5
47        MR5 OFFSET(5) NUMBITS(1) [],
48        /// Interrupt Mask on line 6
49        MR6 OFFSET(6) NUMBITS(1) [],
50        /// Interrupt Mask on line 7
51        MR7 OFFSET(7) NUMBITS(1) [],
52        /// Interrupt Mask on line 8
53        MR8 OFFSET(8) NUMBITS(1) [],
54        /// Interrupt Mask on line 9
55        MR9 OFFSET(9) NUMBITS(1) [],
56        /// Interrupt Mask on line 10
57        MR10 OFFSET(10) NUMBITS(1) [],
58        /// Interrupt Mask on line 11
59        MR11 OFFSET(11) NUMBITS(1) [],
60        /// Interrupt Mask on line 12
61        MR12 OFFSET(12) NUMBITS(1) [],
62        /// Interrupt Mask on line 13
63        MR13 OFFSET(13) NUMBITS(1) [],
64        /// Interrupt Mask on line 14
65        MR14 OFFSET(14) NUMBITS(1) [],
66        /// Interrupt Mask on line 15
67        MR15 OFFSET(15) NUMBITS(1) [],
68        /// Interrupt Mask on line 16
69        MR16 OFFSET(16) NUMBITS(1) [],
70        /// Interrupt Mask on line 17
71        MR17 OFFSET(17) NUMBITS(1) [],
72        /// Interrupt Mask on line 18
73        MR18 OFFSET(18) NUMBITS(1) [],
74        /// Interrupt Mask on line 19
75        MR19 OFFSET(19) NUMBITS(1) [],
76        /// Interrupt Mask on line 20
77        MR20 OFFSET(20) NUMBITS(1) [],
78        /// Interrupt Mask on line 21
79        MR21 OFFSET(21) NUMBITS(1) [],
80        /// Interrupt Mask on line 22
81        MR22 OFFSET(22) NUMBITS(1) []
82    ],
83    EMR [
84        /// Event Mask on line 0
85        MR0 OFFSET(0) NUMBITS(1) [],
86        /// Event Mask on line 1
87        MR1 OFFSET(1) NUMBITS(1) [],
88        /// Event Mask on line 2
89        MR2 OFFSET(2) NUMBITS(1) [],
90        /// Event Mask on line 3
91        MR3 OFFSET(3) NUMBITS(1) [],
92        /// Event Mask on line 4
93        MR4 OFFSET(4) NUMBITS(1) [],
94        /// Event Mask on line 5
95        MR5 OFFSET(5) NUMBITS(1) [],
96        /// Event Mask on line 6
97        MR6 OFFSET(6) NUMBITS(1) [],
98        /// Event Mask on line 7
99        MR7 OFFSET(7) NUMBITS(1) [],
100        /// Event Mask on line 8
101        MR8 OFFSET(8) NUMBITS(1) [],
102        /// Event Mask on line 9
103        MR9 OFFSET(9) NUMBITS(1) [],
104        /// Event Mask on line 10
105        MR10 OFFSET(10) NUMBITS(1) [],
106        /// Event Mask on line 11
107        MR11 OFFSET(11) NUMBITS(1) [],
108        /// Event Mask on line 12
109        MR12 OFFSET(12) NUMBITS(1) [],
110        /// Event Mask on line 13
111        MR13 OFFSET(13) NUMBITS(1) [],
112        /// Event Mask on line 14
113        MR14 OFFSET(14) NUMBITS(1) [],
114        /// Event Mask on line 15
115        MR15 OFFSET(15) NUMBITS(1) [],
116        /// Event Mask on line 16
117        MR16 OFFSET(16) NUMBITS(1) [],
118        /// Event Mask on line 17
119        MR17 OFFSET(17) NUMBITS(1) [],
120        /// Event Mask on line 18
121        MR18 OFFSET(18) NUMBITS(1) [],
122        /// Event Mask on line 19
123        MR19 OFFSET(19) NUMBITS(1) [],
124        /// Event Mask on line 20
125        MR20 OFFSET(20) NUMBITS(1) [],
126        /// Event Mask on line 21
127        MR21 OFFSET(21) NUMBITS(1) [],
128        /// Event Mask on line 22
129        MR22 OFFSET(22) NUMBITS(1) []
130    ],
131    RTSR [
132        /// Rising trigger event configuration of line 0
133        TR0 OFFSET(0) NUMBITS(1) [],
134        /// Rising trigger event configuration of line 1
135        TR1 OFFSET(1) NUMBITS(1) [],
136        /// Rising trigger event configuration of line 2
137        TR2 OFFSET(2) NUMBITS(1) [],
138        /// Rising trigger event configuration of line 3
139        TR3 OFFSET(3) NUMBITS(1) [],
140        /// Rising trigger event configuration of line 4
141        TR4 OFFSET(4) NUMBITS(1) [],
142        /// Rising trigger event configuration of line 5
143        TR5 OFFSET(5) NUMBITS(1) [],
144        /// Rising trigger event configuration of line 6
145        TR6 OFFSET(6) NUMBITS(1) [],
146        /// Rising trigger event configuration of line 7
147        TR7 OFFSET(7) NUMBITS(1) [],
148        /// Rising trigger event configuration of line 8
149        TR8 OFFSET(8) NUMBITS(1) [],
150        /// Rising trigger event configuration of line 9
151        TR9 OFFSET(9) NUMBITS(1) [],
152        /// Rising trigger event configuration of line 10
153        TR10 OFFSET(10) NUMBITS(1) [],
154        /// Rising trigger event configuration of line 11
155        TR11 OFFSET(11) NUMBITS(1) [],
156        /// Rising trigger event configuration of line 12
157        TR12 OFFSET(12) NUMBITS(1) [],
158        /// Rising trigger event configuration of line 13
159        TR13 OFFSET(13) NUMBITS(1) [],
160        /// Rising trigger event configuration of line 14
161        TR14 OFFSET(14) NUMBITS(1) [],
162        /// Rising trigger event configuration of line 15
163        TR15 OFFSET(15) NUMBITS(1) [],
164        /// Rising trigger event configuration of line 16
165        TR16 OFFSET(16) NUMBITS(1) [],
166        /// Rising trigger event configuration of line 17
167        TR17 OFFSET(17) NUMBITS(1) [],
168        /// Rising trigger event configuration of line 18
169        TR18 OFFSET(18) NUMBITS(1) [],
170        /// Rising trigger event configuration of line 19
171        TR19 OFFSET(19) NUMBITS(1) [],
172        /// Rising trigger event configuration of line 20
173        TR20 OFFSET(20) NUMBITS(1) [],
174        /// Rising trigger event configuration of line 21
175        TR21 OFFSET(21) NUMBITS(1) [],
176        /// Rising trigger event configuration of line 22
177        TR22 OFFSET(22) NUMBITS(1) []
178    ],
179    FTSR [
180        /// Falling trigger event configuration of line 0
181        TR0 OFFSET(0) NUMBITS(1) [],
182        /// Falling trigger event configuration of line 1
183        TR1 OFFSET(1) NUMBITS(1) [],
184        /// Falling trigger event configuration of line 2
185        TR2 OFFSET(2) NUMBITS(1) [],
186        /// Falling trigger event configuration of line 3
187        TR3 OFFSET(3) NUMBITS(1) [],
188        /// Falling trigger event configuration of line 4
189        TR4 OFFSET(4) NUMBITS(1) [],
190        /// Falling trigger event configuration of line 5
191        TR5 OFFSET(5) NUMBITS(1) [],
192        /// Falling trigger event configuration of line 6
193        TR6 OFFSET(6) NUMBITS(1) [],
194        /// Falling trigger event configuration of line 7
195        TR7 OFFSET(7) NUMBITS(1) [],
196        /// Falling trigger event configuration of line 8
197        TR8 OFFSET(8) NUMBITS(1) [],
198        /// Falling trigger event configuration of line 9
199        TR9 OFFSET(9) NUMBITS(1) [],
200        /// Falling trigger event configuration of line 10
201        TR10 OFFSET(10) NUMBITS(1) [],
202        /// Falling trigger event configuration of line 11
203        TR11 OFFSET(11) NUMBITS(1) [],
204        /// Falling trigger event configuration of line 12
205        TR12 OFFSET(12) NUMBITS(1) [],
206        /// Falling trigger event configuration of line 13
207        TR13 OFFSET(13) NUMBITS(1) [],
208        /// Falling trigger event configuration of line 14
209        TR14 OFFSET(14) NUMBITS(1) [],
210        /// Falling trigger event configuration of line 15
211        TR15 OFFSET(15) NUMBITS(1) [],
212        /// Falling trigger event configuration of line 16
213        TR16 OFFSET(16) NUMBITS(1) [],
214        /// Falling trigger event configuration of line 17
215        TR17 OFFSET(17) NUMBITS(1) [],
216        /// Falling trigger event configuration of line 18
217        TR18 OFFSET(18) NUMBITS(1) [],
218        /// Falling trigger event configuration of line 19
219        TR19 OFFSET(19) NUMBITS(1) [],
220        /// Falling trigger event configuration of line 20
221        TR20 OFFSET(20) NUMBITS(1) [],
222        /// Falling trigger event configuration of line 21
223        TR21 OFFSET(21) NUMBITS(1) [],
224        /// Falling trigger event configuration of line 22
225        TR22 OFFSET(22) NUMBITS(1) []
226    ],
227    SWIER [
228        /// Software Interrupt on line 0
229        SWIER0 OFFSET(0) NUMBITS(1) [],
230        /// Software Interrupt on line 1
231        SWIER1 OFFSET(1) NUMBITS(1) [],
232        /// Software Interrupt on line 2
233        SWIER2 OFFSET(2) NUMBITS(1) [],
234        /// Software Interrupt on line 3
235        SWIER3 OFFSET(3) NUMBITS(1) [],
236        /// Software Interrupt on line 4
237        SWIER4 OFFSET(4) NUMBITS(1) [],
238        /// Software Interrupt on line 5
239        SWIER5 OFFSET(5) NUMBITS(1) [],
240        /// Software Interrupt on line 6
241        SWIER6 OFFSET(6) NUMBITS(1) [],
242        /// Software Interrupt on line 7
243        SWIER7 OFFSET(7) NUMBITS(1) [],
244        /// Software Interrupt on line 8
245        SWIER8 OFFSET(8) NUMBITS(1) [],
246        /// Software Interrupt on line 9
247        SWIER9 OFFSET(9) NUMBITS(1) [],
248        /// Software Interrupt on line 10
249        SWIER10 OFFSET(10) NUMBITS(1) [],
250        /// Software Interrupt on line 11
251        SWIER11 OFFSET(11) NUMBITS(1) [],
252        /// Software Interrupt on line 12
253        SWIER12 OFFSET(12) NUMBITS(1) [],
254        /// Software Interrupt on line 13
255        SWIER13 OFFSET(13) NUMBITS(1) [],
256        /// Software Interrupt on line 14
257        SWIER14 OFFSET(14) NUMBITS(1) [],
258        /// Software Interrupt on line 15
259        SWIER15 OFFSET(15) NUMBITS(1) [],
260        /// Software Interrupt on line 16
261        SWIER16 OFFSET(16) NUMBITS(1) [],
262        /// Software Interrupt on line 17
263        SWIER17 OFFSET(17) NUMBITS(1) [],
264        /// Software Interrupt on line 18
265        SWIER18 OFFSET(18) NUMBITS(1) [],
266        /// Software Interrupt on line 19
267        SWIER19 OFFSET(19) NUMBITS(1) [],
268        /// Software Interrupt on line 20
269        SWIER20 OFFSET(20) NUMBITS(1) [],
270        /// Software Interrupt on line 21
271        SWIER21 OFFSET(21) NUMBITS(1) [],
272        /// Software Interrupt on line 22
273        SWIER22 OFFSET(22) NUMBITS(1) []
274    ],
275    PR [
276        /// Pending bit 0
277        PR0 OFFSET(0) NUMBITS(1) [],
278        /// Pending bit 1
279        PR1 OFFSET(1) NUMBITS(1) [],
280        /// Pending bit 2
281        PR2 OFFSET(2) NUMBITS(1) [],
282        /// Pending bit 3
283        PR3 OFFSET(3) NUMBITS(1) [],
284        /// Pending bit 4
285        PR4 OFFSET(4) NUMBITS(1) [],
286        /// Pending bit 5
287        PR5 OFFSET(5) NUMBITS(1) [],
288        /// Pending bit 6
289        PR6 OFFSET(6) NUMBITS(1) [],
290        /// Pending bit 7
291        PR7 OFFSET(7) NUMBITS(1) [],
292        /// Pending bit 8
293        PR8 OFFSET(8) NUMBITS(1) [],
294        /// Pending bit 9
295        PR9 OFFSET(9) NUMBITS(1) [],
296        /// Pending bit 10
297        PR10 OFFSET(10) NUMBITS(1) [],
298        /// Pending bit 11
299        PR11 OFFSET(11) NUMBITS(1) [],
300        /// Pending bit 12
301        PR12 OFFSET(12) NUMBITS(1) [],
302        /// Pending bit 13
303        PR13 OFFSET(13) NUMBITS(1) [],
304        /// Pending bit 14
305        PR14 OFFSET(14) NUMBITS(1) [],
306        /// Pending bit 15
307        PR15 OFFSET(15) NUMBITS(1) [],
308        /// Pending bit 16
309        PR16 OFFSET(16) NUMBITS(1) [],
310        /// Pending bit 17
311        PR17 OFFSET(17) NUMBITS(1) [],
312        /// Pending bit 18
313        PR18 OFFSET(18) NUMBITS(1) [],
314        /// Pending bit 19
315        PR19 OFFSET(19) NUMBITS(1) [],
316        /// Pending bit 20
317        PR20 OFFSET(20) NUMBITS(1) [],
318        /// Pending bit 21
319        PR21 OFFSET(21) NUMBITS(1) [],
320        /// Pending bit 22
321        PR22 OFFSET(22) NUMBITS(1) []
322    ]
323];
324
325const EXTI_BASE: StaticRef<ExtiRegisters> =
326    unsafe { StaticRef::new(0x40013C00 as *const ExtiRegisters) };
327
328/// EXTI block has 23 lines going into NVIC. This arrangement is described here
329/// [^1].
330///
331/// The 23 lines going into NVIC, are mapped to the following NVIC IRQs. Note
332/// there is *no* one-to-one mapping between the 23 lines to NVIC IRQs. The 23
333/// lines going into NVIC translates to 14 IRQs on NVIC.
334///
335///  - `EXTI0` (6)
336///  - `EXTI1` (7)
337///  - `EXTI2` (8)
338///  - `EXTI3` (9)
339///  - `EXTI4` (10)
340///  - `EXTI9_5` (23)
341///  - `EXTI15_10` (40)
342///
343///  - `EXTI16` -> `PVD` (1)
344///  - `EXTI17` -> `RTC_Alarm` (41)
345///  - `EXTI18` -> `OTG_FS_WKUP` (42)
346///  - `EXTI19` -> `<UNKNOWN>`
347///  - `EXTI20` -> `OTG_FS` (67)
348///  - `EXTI21` -> `TAMP_STAMP` (2)
349///  - `EXTI22` -> `RTC_WKUP` (3)
350///
351/// The EXTI_PR (pending) register when set, generates a level-triggered
352/// interrupt on the NVIC. This means, that its the responsibility of the IRQ
353/// handler to clear the interrupt source (pending bit), in order to prevent
354/// multiple interrupts from occurring.
355///
356/// `EXTI_EVENTS` is modeled to capture information from `EXTI_PR` register. In
357/// the top half IRQ handler, prior to clearing the pending bit, we set the
358/// corresponding bit in `EXTI_EVENTS`. Once the bit is set, in `EXTI_EVENTS`,
359/// we clear the pending bit and exit the ISR.
360///
361/// [^1]: Section 10.2.2, EXTI block diagram, page 243 of reference manual.
362#[no_mangle]
363#[used]
364pub static mut EXTI_EVENTS: u32 = 0;
365
366enum_from_primitive! {
367    #[repr(u8)]
368    #[derive(Copy, Clone)]
369    pub enum LineId {
370        Exti0 = 0,
371        Exti1 = 1,
372        Exti2 = 2,
373        Exti3 = 3,
374        Exti4 = 4,
375        Exti5 = 5,
376        Exti6 = 6,
377        Exti7 = 7,
378        Exti8 = 8,
379        Exti9 = 9,
380        Exti10 = 10,
381        Exti11 = 11,
382        Exti12 = 12,
383        Exti13 = 13,
384        Exti14 = 14,
385        Exti15 = 15,
386    }
387}
388
389// `line_gpiopin_map` is used to call `handle_interrupt()` on the pin.
390pub struct Exti<'a> {
391    registers: StaticRef<ExtiRegisters>,
392    clock: ExtiClock<'a>,
393    line_gpiopin_map: [OptionalCell<&'static gpio::Pin<'static>>; 16],
394    syscfg: &'a syscfg::Syscfg<'a>,
395}
396
397impl<'a> Exti<'a> {
398    pub const fn new(syscfg: &'a syscfg::Syscfg<'a>) -> Self {
399        Self {
400            registers: EXTI_BASE,
401            clock: ExtiClock(syscfg),
402            line_gpiopin_map: [
403                OptionalCell::empty(),
404                OptionalCell::empty(),
405                OptionalCell::empty(),
406                OptionalCell::empty(),
407                OptionalCell::empty(),
408                OptionalCell::empty(),
409                OptionalCell::empty(),
410                OptionalCell::empty(),
411                OptionalCell::empty(),
412                OptionalCell::empty(),
413                OptionalCell::empty(),
414                OptionalCell::empty(),
415                OptionalCell::empty(),
416                OptionalCell::empty(),
417                OptionalCell::empty(),
418                OptionalCell::empty(),
419            ],
420            syscfg,
421        }
422    }
423
424    pub fn is_enabled_clock(&self) -> bool {
425        self.clock.is_enabled()
426    }
427
428    pub fn enable_clock(&self) {
429        self.clock.enable();
430    }
431
432    pub fn disable_clock(&self) {
433        self.clock.disable();
434    }
435
436    pub fn associate_line_gpiopin(&self, lineid: LineId, pin: &'static gpio::Pin<'static>) {
437        self.line_gpiopin_map[usize::from(lineid as u8)].set(pin);
438        self.syscfg.configure_interrupt(pin.get_pinid());
439        pin.set_exti_lineid(lineid);
440
441        // By default, all interrupts are masked. But, this will ensure that it
442        // is really the case.
443        self.mask_interrupt(lineid);
444    }
445
446    pub fn mask_interrupt(&self, lineid: LineId) {
447        match lineid {
448            LineId::Exti0 => self.registers.imr.modify(IMR::MR0::CLEAR),
449            LineId::Exti1 => self.registers.imr.modify(IMR::MR1::CLEAR),
450            LineId::Exti2 => self.registers.imr.modify(IMR::MR2::CLEAR),
451            LineId::Exti3 => self.registers.imr.modify(IMR::MR3::CLEAR),
452            LineId::Exti4 => self.registers.imr.modify(IMR::MR4::CLEAR),
453            LineId::Exti5 => self.registers.imr.modify(IMR::MR5::CLEAR),
454            LineId::Exti6 => self.registers.imr.modify(IMR::MR6::CLEAR),
455            LineId::Exti7 => self.registers.imr.modify(IMR::MR7::CLEAR),
456            LineId::Exti8 => self.registers.imr.modify(IMR::MR8::CLEAR),
457            LineId::Exti9 => self.registers.imr.modify(IMR::MR9::CLEAR),
458            LineId::Exti10 => self.registers.imr.modify(IMR::MR10::CLEAR),
459            LineId::Exti11 => self.registers.imr.modify(IMR::MR11::CLEAR),
460            LineId::Exti12 => self.registers.imr.modify(IMR::MR12::CLEAR),
461            LineId::Exti13 => self.registers.imr.modify(IMR::MR13::CLEAR),
462            LineId::Exti14 => self.registers.imr.modify(IMR::MR14::CLEAR),
463            LineId::Exti15 => self.registers.imr.modify(IMR::MR15::CLEAR),
464        }
465    }
466
467    pub fn unmask_interrupt(&self, lineid: LineId) {
468        match lineid {
469            LineId::Exti0 => self.registers.imr.modify(IMR::MR0::SET),
470            LineId::Exti1 => self.registers.imr.modify(IMR::MR1::SET),
471            LineId::Exti2 => self.registers.imr.modify(IMR::MR2::SET),
472            LineId::Exti3 => self.registers.imr.modify(IMR::MR3::SET),
473            LineId::Exti4 => self.registers.imr.modify(IMR::MR4::SET),
474            LineId::Exti5 => self.registers.imr.modify(IMR::MR5::SET),
475            LineId::Exti6 => self.registers.imr.modify(IMR::MR6::SET),
476            LineId::Exti7 => self.registers.imr.modify(IMR::MR7::SET),
477            LineId::Exti8 => self.registers.imr.modify(IMR::MR8::SET),
478            LineId::Exti9 => self.registers.imr.modify(IMR::MR9::SET),
479            LineId::Exti10 => self.registers.imr.modify(IMR::MR10::SET),
480            LineId::Exti11 => self.registers.imr.modify(IMR::MR11::SET),
481            LineId::Exti12 => self.registers.imr.modify(IMR::MR12::SET),
482            LineId::Exti13 => self.registers.imr.modify(IMR::MR13::SET),
483            LineId::Exti14 => self.registers.imr.modify(IMR::MR14::SET),
484            LineId::Exti15 => self.registers.imr.modify(IMR::MR15::SET),
485        }
486    }
487
488    // Pending clear happens by writing 1
489    pub fn clear_pending(&self, lineid: LineId) {
490        match lineid {
491            LineId::Exti0 => self.registers.pr.write(PR::PR0::SET),
492            LineId::Exti1 => self.registers.pr.write(PR::PR1::SET),
493            LineId::Exti2 => self.registers.pr.write(PR::PR2::SET),
494            LineId::Exti3 => self.registers.pr.write(PR::PR3::SET),
495            LineId::Exti4 => self.registers.pr.write(PR::PR4::SET),
496            LineId::Exti5 => self.registers.pr.write(PR::PR5::SET),
497            LineId::Exti6 => self.registers.pr.write(PR::PR6::SET),
498            LineId::Exti7 => self.registers.pr.write(PR::PR7::SET),
499            LineId::Exti8 => self.registers.pr.write(PR::PR8::SET),
500            LineId::Exti9 => self.registers.pr.write(PR::PR9::SET),
501            LineId::Exti10 => self.registers.pr.write(PR::PR10::SET),
502            LineId::Exti11 => self.registers.pr.write(PR::PR11::SET),
503            LineId::Exti12 => self.registers.pr.write(PR::PR12::SET),
504            LineId::Exti13 => self.registers.pr.write(PR::PR13::SET),
505            LineId::Exti14 => self.registers.pr.write(PR::PR14::SET),
506            LineId::Exti15 => self.registers.pr.write(PR::PR15::SET),
507        }
508    }
509
510    pub fn is_pending(&self, lineid: LineId) -> bool {
511        let val = match lineid {
512            LineId::Exti0 => self.registers.pr.read(PR::PR0),
513            LineId::Exti1 => self.registers.pr.read(PR::PR1),
514            LineId::Exti2 => self.registers.pr.read(PR::PR2),
515            LineId::Exti3 => self.registers.pr.read(PR::PR3),
516            LineId::Exti4 => self.registers.pr.read(PR::PR4),
517            LineId::Exti5 => self.registers.pr.read(PR::PR5),
518            LineId::Exti6 => self.registers.pr.read(PR::PR6),
519            LineId::Exti7 => self.registers.pr.read(PR::PR7),
520            LineId::Exti8 => self.registers.pr.read(PR::PR8),
521            LineId::Exti9 => self.registers.pr.read(PR::PR9),
522            LineId::Exti10 => self.registers.pr.read(PR::PR10),
523            LineId::Exti11 => self.registers.pr.read(PR::PR11),
524            LineId::Exti12 => self.registers.pr.read(PR::PR12),
525            LineId::Exti13 => self.registers.pr.read(PR::PR13),
526            LineId::Exti14 => self.registers.pr.read(PR::PR14),
527            LineId::Exti15 => self.registers.pr.read(PR::PR15),
528        };
529        val > 0
530    }
531
532    pub fn select_rising_trigger(&self, lineid: LineId) {
533        match lineid {
534            LineId::Exti0 => self.registers.rtsr.modify(RTSR::TR0::SET),
535            LineId::Exti1 => self.registers.rtsr.modify(RTSR::TR1::SET),
536            LineId::Exti2 => self.registers.rtsr.modify(RTSR::TR2::SET),
537            LineId::Exti3 => self.registers.rtsr.modify(RTSR::TR3::SET),
538            LineId::Exti4 => self.registers.rtsr.modify(RTSR::TR4::SET),
539            LineId::Exti5 => self.registers.rtsr.modify(RTSR::TR5::SET),
540            LineId::Exti6 => self.registers.rtsr.modify(RTSR::TR6::SET),
541            LineId::Exti7 => self.registers.rtsr.modify(RTSR::TR7::SET),
542            LineId::Exti8 => self.registers.rtsr.modify(RTSR::TR8::SET),
543            LineId::Exti9 => self.registers.rtsr.modify(RTSR::TR9::SET),
544            LineId::Exti10 => self.registers.rtsr.modify(RTSR::TR10::SET),
545            LineId::Exti11 => self.registers.rtsr.modify(RTSR::TR11::SET),
546            LineId::Exti12 => self.registers.rtsr.modify(RTSR::TR12::SET),
547            LineId::Exti13 => self.registers.rtsr.modify(RTSR::TR13::SET),
548            LineId::Exti14 => self.registers.rtsr.modify(RTSR::TR14::SET),
549            LineId::Exti15 => self.registers.rtsr.modify(RTSR::TR15::SET),
550        }
551    }
552
553    pub fn deselect_rising_trigger(&self, lineid: LineId) {
554        match lineid {
555            LineId::Exti0 => self.registers.rtsr.modify(RTSR::TR0::CLEAR),
556            LineId::Exti1 => self.registers.rtsr.modify(RTSR::TR1::CLEAR),
557            LineId::Exti2 => self.registers.rtsr.modify(RTSR::TR2::CLEAR),
558            LineId::Exti3 => self.registers.rtsr.modify(RTSR::TR3::CLEAR),
559            LineId::Exti4 => self.registers.rtsr.modify(RTSR::TR4::CLEAR),
560            LineId::Exti5 => self.registers.rtsr.modify(RTSR::TR5::CLEAR),
561            LineId::Exti6 => self.registers.rtsr.modify(RTSR::TR6::CLEAR),
562            LineId::Exti7 => self.registers.rtsr.modify(RTSR::TR7::CLEAR),
563            LineId::Exti8 => self.registers.rtsr.modify(RTSR::TR8::CLEAR),
564            LineId::Exti9 => self.registers.rtsr.modify(RTSR::TR9::CLEAR),
565            LineId::Exti10 => self.registers.rtsr.modify(RTSR::TR10::CLEAR),
566            LineId::Exti11 => self.registers.rtsr.modify(RTSR::TR11::CLEAR),
567            LineId::Exti12 => self.registers.rtsr.modify(RTSR::TR12::CLEAR),
568            LineId::Exti13 => self.registers.rtsr.modify(RTSR::TR13::CLEAR),
569            LineId::Exti14 => self.registers.rtsr.modify(RTSR::TR14::CLEAR),
570            LineId::Exti15 => self.registers.rtsr.modify(RTSR::TR15::CLEAR),
571        }
572    }
573
574    pub fn select_falling_trigger(&self, lineid: LineId) {
575        match lineid {
576            LineId::Exti0 => self.registers.ftsr.modify(FTSR::TR0::SET),
577            LineId::Exti1 => self.registers.ftsr.modify(FTSR::TR1::SET),
578            LineId::Exti2 => self.registers.ftsr.modify(FTSR::TR2::SET),
579            LineId::Exti3 => self.registers.ftsr.modify(FTSR::TR3::SET),
580            LineId::Exti4 => self.registers.ftsr.modify(FTSR::TR4::SET),
581            LineId::Exti5 => self.registers.ftsr.modify(FTSR::TR5::SET),
582            LineId::Exti6 => self.registers.ftsr.modify(FTSR::TR6::SET),
583            LineId::Exti7 => self.registers.ftsr.modify(FTSR::TR7::SET),
584            LineId::Exti8 => self.registers.ftsr.modify(FTSR::TR8::SET),
585            LineId::Exti9 => self.registers.ftsr.modify(FTSR::TR9::SET),
586            LineId::Exti10 => self.registers.ftsr.modify(FTSR::TR10::SET),
587            LineId::Exti11 => self.registers.ftsr.modify(FTSR::TR11::SET),
588            LineId::Exti12 => self.registers.ftsr.modify(FTSR::TR12::SET),
589            LineId::Exti13 => self.registers.ftsr.modify(FTSR::TR13::SET),
590            LineId::Exti14 => self.registers.ftsr.modify(FTSR::TR14::SET),
591            LineId::Exti15 => self.registers.ftsr.modify(FTSR::TR15::SET),
592        }
593    }
594
595    pub fn deselect_falling_trigger(&self, lineid: LineId) {
596        match lineid {
597            LineId::Exti0 => self.registers.ftsr.modify(FTSR::TR0::CLEAR),
598            LineId::Exti1 => self.registers.ftsr.modify(FTSR::TR1::CLEAR),
599            LineId::Exti2 => self.registers.ftsr.modify(FTSR::TR2::CLEAR),
600            LineId::Exti3 => self.registers.ftsr.modify(FTSR::TR3::CLEAR),
601            LineId::Exti4 => self.registers.ftsr.modify(FTSR::TR4::CLEAR),
602            LineId::Exti5 => self.registers.ftsr.modify(FTSR::TR5::CLEAR),
603            LineId::Exti6 => self.registers.ftsr.modify(FTSR::TR6::CLEAR),
604            LineId::Exti7 => self.registers.ftsr.modify(FTSR::TR7::CLEAR),
605            LineId::Exti8 => self.registers.ftsr.modify(FTSR::TR8::CLEAR),
606            LineId::Exti9 => self.registers.ftsr.modify(FTSR::TR9::CLEAR),
607            LineId::Exti10 => self.registers.ftsr.modify(FTSR::TR10::CLEAR),
608            LineId::Exti11 => self.registers.ftsr.modify(FTSR::TR11::CLEAR),
609            LineId::Exti12 => self.registers.ftsr.modify(FTSR::TR12::CLEAR),
610            LineId::Exti13 => self.registers.ftsr.modify(FTSR::TR13::CLEAR),
611            LineId::Exti14 => self.registers.ftsr.modify(FTSR::TR14::CLEAR),
612            LineId::Exti15 => self.registers.ftsr.modify(FTSR::TR15::CLEAR),
613        }
614    }
615
616    pub fn handle_interrupt(&self) {
617        let mut exti_pr: u32 = 0;
618
619        // Read the `EXTI_PR` register and toggle the appropriate bits in
620        // `exti_pr`. Once that is done, write the value of `exti_pr` back. We
621        // can have a situation where memory value of `EXTI_PR` could have
622        // changed due to an external interrupt. `EXTI_PR` is a read/clear write
623        // 1 register (`rc_w1`). So, we only clear bits whose value has been
624        // transferred to `exti_pr`.
625        unsafe {
626            atomic(|| {
627                exti_pr = self.registers.pr.get();
628                self.registers.pr.set(exti_pr);
629            });
630        }
631
632        // ignore the "reserved" EXTI bits. Use bits [22:0]. See `EXTI_PR` for
633        // details.
634        exti_pr |= 0x007fffff;
635
636        let mut flagged_bit = 0;
637
638        // stay in loop until we have processed all the flagged event bits
639        while exti_pr != 0 {
640            if (exti_pr & 0b1) != 0 {
641                if let Some(d) = LineId::from_u8(flagged_bit) {
642                    self.line_gpiopin_map[usize::from(d as u8)].map(|pin| pin.handle_interrupt());
643                }
644            }
645            // move to next bit
646            flagged_bit += 1;
647            exti_pr >>= 1;
648        }
649    }
650}
651
652/// Exti peripheral is clocked using PCLK2. However, PCLK2 does not seem to be
653/// gated. The configuration registers for Exti is in Syscfg, so we need to
654/// enable clock to Syscfg, when using Exti.
655struct ExtiClock<'a>(&'a syscfg::Syscfg<'a>);
656
657impl ClockInterface for ExtiClock<'_> {
658    fn is_enabled(&self) -> bool {
659        self.0.is_enabled_clock()
660    }
661
662    fn enable(&self) {
663        self.0.enable_clock();
664    }
665
666    fn disable(&self) {
667        self.0.disable_clock();
668    }
669}