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