Skip to content

Commit 9510815

Browse files
authored
gpio: add EXTI support (#21)
Add EXTI support to GPIO module. This is taken directly from the implementation in [stm32h7xx-hal](https://github.com/stm32-rs/stm32h7xx-hal).
1 parent 526ceba commit 9510815

File tree

2 files changed

+166
-1
lines changed

2 files changed

+166
-1
lines changed

src/gpio.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
//! ownership reasons, you can use the closure based `with_<mode>` functions to temporarily change the pin type, do
4545
//! some output or input, and then have it change back once done.
4646
47+
mod exti;
4748
mod gpio_def;
4849

4950
use core::{fmt, marker::PhantomData};
@@ -52,6 +53,7 @@ pub use embedded_hal::digital::PinState;
5253

5354
use crate::rcc::ResetEnable;
5455

56+
pub use exti::ExtiPin;
5557
pub use gpio_def::*;
5658

5759
/// A filler pin type
@@ -152,7 +154,6 @@ pub type Debugger = Alternate<0, PushPull>;
152154

153155
mod marker {
154156
/// Marker trait that show if `ExtiPin` can be implemented
155-
#[allow(dead_code)] // TODO: Remove when EXTI is implemented
156157
pub trait Interruptable {}
157158
/// Marker trait for readable pin modes
158159
pub trait Readable {}

src/gpio/exti.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use super::{marker, Edge, Pin, PinExt};
2+
use crate::pac::{Interrupt, EXTI};
3+
4+
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
5+
/// NVIC interrupt number of interrupt from this pin
6+
///
7+
/// Used to unmask / enable the interrupt with [`cortex_m::peripheral::NVIC::unmask()`].
8+
/// This is also useful for all other [`cortex_m::peripheral::NVIC`] functions.
9+
pub const fn interrupt(&self) -> Interrupt {
10+
match N {
11+
0 => Interrupt::EXTI0,
12+
1 => Interrupt::EXTI1,
13+
2 => Interrupt::EXTI2,
14+
3 => Interrupt::EXTI3,
15+
4 => Interrupt::EXTI4,
16+
5 => Interrupt::EXTI5,
17+
6 => Interrupt::EXTI6,
18+
7 => Interrupt::EXTI7,
19+
8 => Interrupt::EXTI8,
20+
9 => Interrupt::EXTI9,
21+
10 => Interrupt::EXTI10,
22+
11 => Interrupt::EXTI11,
23+
12 => Interrupt::EXTI12,
24+
13 => Interrupt::EXTI13,
25+
14 => Interrupt::EXTI14,
26+
15 => Interrupt::EXTI15,
27+
_ => panic!("Unsupported pin number"),
28+
}
29+
}
30+
}
31+
32+
/// External Interrupt Pin
33+
pub trait ExtiPin {
34+
fn make_interrupt_source(&mut self, exti: &mut EXTI);
35+
fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
36+
fn enable_event(&mut self, exti: &mut EXTI);
37+
fn disable_event(&mut self, exti: &mut EXTI);
38+
fn enable_interrupt(&mut self, exti: &mut EXTI);
39+
fn disable_interrupt(&mut self, exti: &mut EXTI);
40+
fn clear_interrupt_pending_bit(&mut self, edge: Edge);
41+
fn check_interrupt(&self, edge: Edge) -> bool;
42+
}
43+
44+
impl<PIN> ExtiPin for PIN
45+
where
46+
PIN: PinExt,
47+
PIN::Mode: marker::Interruptable,
48+
{
49+
/// Make corresponding EXTI line sensitive to this pin
50+
#[inline(always)]
51+
fn make_interrupt_source(&mut self, exti: &mut EXTI) {
52+
let i = self.pin_id();
53+
let port = self.port_id() as u32;
54+
let offset = 8 * (i % 4);
55+
match i {
56+
0..=3 => {
57+
exti.exticr1().modify(|r, w| unsafe {
58+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
59+
});
60+
}
61+
4..=7 => {
62+
exti.exticr2().modify(|r, w| unsafe {
63+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
64+
});
65+
}
66+
8..=11 => {
67+
exti.exticr3().modify(|r, w| unsafe {
68+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
69+
});
70+
}
71+
12..=15 => {
72+
exti.exticr4().modify(|r, w| unsafe {
73+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
74+
});
75+
}
76+
_ => unreachable!(),
77+
}
78+
}
79+
80+
/// Generate interrupt on rising edge, falling edge or both
81+
#[inline(always)]
82+
fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
83+
let i = self.pin_id();
84+
match edge {
85+
Edge::Rising => {
86+
exti.rtsr1()
87+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
88+
exti.ftsr1()
89+
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
90+
}
91+
Edge::Falling => {
92+
exti.ftsr1()
93+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
94+
exti.rtsr1()
95+
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
96+
}
97+
Edge::RisingFalling => {
98+
exti.rtsr1()
99+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
100+
exti.ftsr1()
101+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
102+
}
103+
}
104+
}
105+
106+
/// Enable external interrupts from this pin.
107+
#[inline(always)]
108+
fn enable_event(&mut self, exti: &mut EXTI) {
109+
exti.emr1()
110+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
111+
}
112+
113+
/// Disable external interrupts from this pin
114+
#[inline(always)]
115+
fn disable_event(&mut self, exti: &mut EXTI) {
116+
exti.emr1()
117+
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
118+
}
119+
120+
/// Enable external interrupts from this pin.
121+
#[inline(always)]
122+
fn enable_interrupt(&mut self, exti: &mut EXTI) {
123+
exti.imr1()
124+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
125+
}
126+
127+
/// Disable external interrupts from this pin
128+
#[inline(always)]
129+
fn disable_interrupt(&mut self, exti: &mut EXTI) {
130+
exti.imr1()
131+
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
132+
}
133+
134+
/// Clear the interrupt pending bit for this pin
135+
#[inline(always)]
136+
fn clear_interrupt_pending_bit(&mut self, edge: Edge) {
137+
unsafe {
138+
let exti = &(*EXTI::ptr());
139+
140+
let mask = 1 << self.pin_id();
141+
match edge {
142+
Edge::Rising => exti.rpr1().write(|w| w.bits(mask)),
143+
Edge::Falling => exti.fpr1().write(|w| w.bits(mask)),
144+
_ => panic!("Must choose a rising or falling edge"),
145+
}
146+
}
147+
}
148+
149+
/// Reads the interrupt pending bit for this pin
150+
#[inline(always)]
151+
fn check_interrupt(&self, edge: Edge) -> bool {
152+
unsafe {
153+
let exti = &(*EXTI::ptr());
154+
155+
let bits = match edge {
156+
Edge::Rising => exti.rpr1().read().bits(),
157+
Edge::Falling => exti.fpr1().read().bits(),
158+
_ => panic!("Must choose a rising or falling edge"),
159+
};
160+
161+
bits & (1 << self.pin_id()) != 0
162+
}
163+
}
164+
}

0 commit comments

Comments
 (0)