stm32f4xx_hal/gpio/
exti.rs

1use super::{marker, Edge, Pin, PinExt};
2use crate::{
3    pac::{Interrupt, EXTI},
4    syscfg::SysCfg,
5};
6
7impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
8    /// NVIC interrupt number of interrupt from this pin
9    ///
10    /// Used to unmask / enable the interrupt with [`cortex_m::peripheral::NVIC::unmask()`].
11    /// This is also useful for all other [`cortex_m::peripheral::NVIC`] functions.
12    pub const fn interrupt(&self) -> Interrupt {
13        match N {
14            0 => Interrupt::EXTI0,
15            1 => Interrupt::EXTI1,
16            2 => Interrupt::EXTI2,
17            3 => Interrupt::EXTI3,
18            4 => Interrupt::EXTI4,
19            5..=9 => Interrupt::EXTI9_5,
20            10..=15 => Interrupt::EXTI15_10,
21            _ => panic!("Unsupported pin number"),
22        }
23    }
24}
25
26/// External Interrupt Pin
27pub trait ExtiPin {
28    /// Make corresponding EXTI line sensitive to this pin
29    fn make_interrupt_source(&mut self, syscfg: &mut SysCfg);
30
31    /// Generate interrupt on rising edge, falling edge or both
32    fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
33
34    /// Enable external interrupts from this pin.
35    fn enable_interrupt(&mut self, exti: &mut EXTI);
36
37    /// Disable external interrupts from this pin
38    fn disable_interrupt(&mut self, exti: &mut EXTI);
39
40    /// Clear the interrupt pending bit for this pin
41    fn clear_interrupt_pending_bit(&mut self);
42
43    /// Reads the interrupt pending bit for this pin
44    fn check_interrupt(&self) -> bool;
45}
46
47impl<PIN> ExtiPin for PIN
48where
49    PIN: PinExt,
50    PIN::Mode: marker::Interruptible,
51{
52    #[inline(always)]
53    fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) {
54        let i = self.pin_id();
55        let port = self.port_id() as u32;
56        let offset = 4 * (i % 4);
57        match i {
58            0..=3 => {
59                syscfg.exticr1().modify(|r, w| unsafe {
60                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
61                });
62            }
63            4..=7 => {
64                syscfg.exticr2().modify(|r, w| unsafe {
65                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
66                });
67            }
68            8..=11 => {
69                syscfg.exticr3().modify(|r, w| unsafe {
70                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
71                });
72            }
73            12..=15 => {
74                syscfg.exticr4().modify(|r, w| unsafe {
75                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
76                });
77            }
78            _ => unreachable!(),
79        }
80    }
81
82    #[inline(always)]
83    fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
84        let i = self.pin_id();
85        match edge {
86            Edge::Rising => {
87                exti.rtsr()
88                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
89                exti.ftsr()
90                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
91            }
92            Edge::Falling => {
93                exti.ftsr()
94                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
95                exti.rtsr()
96                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
97            }
98            Edge::RisingFalling => {
99                exti.rtsr()
100                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
101                exti.ftsr()
102                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
103            }
104        }
105    }
106
107    #[inline(always)]
108    fn enable_interrupt(&mut self, exti: &mut EXTI) {
109        exti.imr()
110            .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
111    }
112
113    #[inline(always)]
114    fn disable_interrupt(&mut self, exti: &mut EXTI) {
115        exti.imr()
116            .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
117    }
118
119    #[inline(always)]
120    fn clear_interrupt_pending_bit(&mut self) {
121        unsafe { (*EXTI::ptr()).pr().write(|w| w.bits(1 << self.pin_id())) };
122    }
123
124    #[inline(always)]
125    fn check_interrupt(&self) -> bool {
126        unsafe { ((*EXTI::ptr()).pr().read().bits() & (1 << self.pin_id())) != 0 }
127    }
128}