Skip to content

Commit 7223611

Browse files
committed
Pin::interrupt
1 parent 84dd4e9 commit 7223611

File tree

5 files changed

+135
-108
lines changed

5 files changed

+135
-108
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Changed
1111

12+
- Add `Pin::interrupt()` helper method
1213
- Add restriction for setting pins in alternate mode (`IntoAF`), add docs
1314
- Explicit order for PINS, more smart aliases for peripherals
1415
- Add `AFn` type aliases for `Alternate<n>`

examples/stopwatch-with-ssd1306-and-interrupts.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,18 @@ fn main() -> ! {
9595
timer.start(1.secs()).unwrap();
9696
timer.listen(Event::Update);
9797

98+
let btn_int_num = board_btn.interrupt(); // hal::pac::Interrupt::EXTI15_10
99+
98100
free(|cs| {
99101
TIMER_TIM2.borrow(cs).replace(Some(timer));
100102
BUTTON.borrow(cs).replace(Some(board_btn));
101103
});
102104

103105
// Enable interrupts
104106
pac::NVIC::unpend(hal::pac::Interrupt::TIM2);
105-
pac::NVIC::unpend(hal::pac::Interrupt::EXTI15_10);
107+
pac::NVIC::unpend(btn_int_num);
106108
unsafe {
107-
pac::NVIC::unmask(hal::pac::Interrupt::EXTI15_10);
109+
pac::NVIC::unmask(btn_int_num);
108110
};
109111

110112
let mut delay = Timer::syst(cp.SYST, &clocks).delay();

src/gpio.rs

Lines changed: 4 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@
5656
5757
use core::marker::PhantomData;
5858

59-
use crate::pac::EXTI;
60-
use crate::syscfg::SysCfg;
61-
6259
mod alt;
6360
pub(crate) use alt::{Const, PinA, SetAlternate};
6461
mod convert;
@@ -67,6 +64,8 @@ mod partially_erased;
6764
pub use partially_erased::{PEPin, PartiallyErasedPin};
6865
mod erased;
6966
pub use erased::{EPin, ErasedPin};
67+
mod exti;
68+
pub use exti::ExtiPin;
7069
mod dynamic;
7170
pub use dynamic::{Dynamic, DynamicPin};
7271
mod hal_02;
@@ -150,6 +149,8 @@ mod marker {
150149
pub trait IntoAf<const A: u8> {}
151150
}
152151

152+
impl<MODE> marker::Interruptable for Output<MODE> {}
153+
impl marker::Interruptable for Input {}
153154
impl marker::Readable for Input {}
154155
impl marker::Readable for Output<OpenDrain> {}
155156
impl marker::Active for Input {}
@@ -215,109 +216,6 @@ af!(
215216
15: AF15
216217
);
217218

218-
use marker::Interruptable;
219-
impl<MODE> Interruptable for Output<MODE> {}
220-
impl Interruptable for Input {}
221-
222-
/// External Interrupt Pin
223-
pub trait ExtiPin {
224-
fn make_interrupt_source(&mut self, syscfg: &mut SysCfg);
225-
fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
226-
fn enable_interrupt(&mut self, exti: &mut EXTI);
227-
fn disable_interrupt(&mut self, exti: &mut EXTI);
228-
fn clear_interrupt_pending_bit(&mut self);
229-
fn check_interrupt(&self) -> bool;
230-
}
231-
232-
impl<PIN> ExtiPin for PIN
233-
where
234-
PIN: PinExt,
235-
PIN::Mode: Interruptable,
236-
{
237-
/// Make corresponding EXTI line sensitive to this pin
238-
#[inline(always)]
239-
fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) {
240-
let i = self.pin_id();
241-
let port = self.port_id() as u32;
242-
let offset = 4 * (i % 4);
243-
match i {
244-
0..=3 => {
245-
syscfg.exticr1.modify(|r, w| unsafe {
246-
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
247-
});
248-
}
249-
4..=7 => {
250-
syscfg.exticr2.modify(|r, w| unsafe {
251-
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
252-
});
253-
}
254-
8..=11 => {
255-
syscfg.exticr3.modify(|r, w| unsafe {
256-
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
257-
});
258-
}
259-
12..=15 => {
260-
syscfg.exticr4.modify(|r, w| unsafe {
261-
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
262-
});
263-
}
264-
_ => unreachable!(),
265-
}
266-
}
267-
268-
/// Generate interrupt on rising edge, falling edge or both
269-
#[inline(always)]
270-
fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
271-
let i = self.pin_id();
272-
match edge {
273-
Edge::Rising => {
274-
exti.rtsr
275-
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
276-
exti.ftsr
277-
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
278-
}
279-
Edge::Falling => {
280-
exti.ftsr
281-
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
282-
exti.rtsr
283-
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
284-
}
285-
Edge::RisingFalling => {
286-
exti.rtsr
287-
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
288-
exti.ftsr
289-
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
290-
}
291-
}
292-
}
293-
294-
/// Enable external interrupts from this pin.
295-
#[inline(always)]
296-
fn enable_interrupt(&mut self, exti: &mut EXTI) {
297-
exti.imr
298-
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
299-
}
300-
301-
/// Disable external interrupts from this pin
302-
#[inline(always)]
303-
fn disable_interrupt(&mut self, exti: &mut EXTI) {
304-
exti.imr
305-
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
306-
}
307-
308-
/// Clear the interrupt pending bit for this pin
309-
#[inline(always)]
310-
fn clear_interrupt_pending_bit(&mut self) {
311-
unsafe { (*EXTI::ptr()).pr.write(|w| w.bits(1 << self.pin_id())) };
312-
}
313-
314-
/// Reads the interrupt pending bit for this pin
315-
#[inline(always)]
316-
fn check_interrupt(&self) -> bool {
317-
unsafe { ((*EXTI::ptr()).pr.read().bits() & (1 << self.pin_id())) != 0 }
318-
}
319-
}
320-
321219
/// Generic pin type
322220
///
323221
/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section).

src/gpio/convert.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl<const P: char, const N: u8, MODE: PinMode + marker::NotAlt, const A: u8, Ot
1111
From<Pin<P, N, MODE>> for Pin<P, N, Alternate<A, Otype>>
1212
where
1313
Alternate<A, Otype>: PinMode,
14+
Self: marker::IntoAf<A>,
1415
{
1516
#[inline(always)]
1617
fn from(f: Pin<P, N, MODE>) -> Self {
@@ -20,6 +21,8 @@ where
2021

2122
impl<const P: char, const N: u8, const A: u8, const B: u8> From<Pin<P, N, Alternate<B, PushPull>>>
2223
for Pin<P, N, Alternate<A, OpenDrain>>
24+
where
25+
Self: marker::IntoAf<A>,
2326
{
2427
#[inline(always)]
2528
fn from(f: Pin<P, N, Alternate<B, PushPull>>) -> Self {

src/gpio/exti.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use super::{marker, Edge, Pin, PinExt};
2+
use crate::{
3+
pac::{Interrupt, EXTI},
4+
syscfg::SysCfg,
5+
};
6+
7+
impl<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
27+
pub trait ExtiPin {
28+
fn make_interrupt_source(&mut self, syscfg: &mut SysCfg);
29+
fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
30+
fn enable_interrupt(&mut self, exti: &mut EXTI);
31+
fn disable_interrupt(&mut self, exti: &mut EXTI);
32+
fn clear_interrupt_pending_bit(&mut self);
33+
fn check_interrupt(&self) -> bool;
34+
}
35+
36+
impl<PIN> ExtiPin for PIN
37+
where
38+
PIN: PinExt,
39+
PIN::Mode: marker::Interruptable,
40+
{
41+
/// Make corresponding EXTI line sensitive to this pin
42+
#[inline(always)]
43+
fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) {
44+
let i = self.pin_id();
45+
let port = self.port_id() as u32;
46+
let offset = 4 * (i % 4);
47+
match i {
48+
0..=3 => {
49+
syscfg.exticr1.modify(|r, w| unsafe {
50+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
51+
});
52+
}
53+
4..=7 => {
54+
syscfg.exticr2.modify(|r, w| unsafe {
55+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
56+
});
57+
}
58+
8..=11 => {
59+
syscfg.exticr3.modify(|r, w| unsafe {
60+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
61+
});
62+
}
63+
12..=15 => {
64+
syscfg.exticr4.modify(|r, w| unsafe {
65+
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
66+
});
67+
}
68+
_ => unreachable!(),
69+
}
70+
}
71+
72+
/// Generate interrupt on rising edge, falling edge or both
73+
#[inline(always)]
74+
fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
75+
let i = self.pin_id();
76+
match edge {
77+
Edge::Rising => {
78+
exti.rtsr
79+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
80+
exti.ftsr
81+
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
82+
}
83+
Edge::Falling => {
84+
exti.ftsr
85+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
86+
exti.rtsr
87+
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
88+
}
89+
Edge::RisingFalling => {
90+
exti.rtsr
91+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
92+
exti.ftsr
93+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
94+
}
95+
}
96+
}
97+
98+
/// Enable external interrupts from this pin.
99+
#[inline(always)]
100+
fn enable_interrupt(&mut self, exti: &mut EXTI) {
101+
exti.imr
102+
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
103+
}
104+
105+
/// Disable external interrupts from this pin
106+
#[inline(always)]
107+
fn disable_interrupt(&mut self, exti: &mut EXTI) {
108+
exti.imr
109+
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
110+
}
111+
112+
/// Clear the interrupt pending bit for this pin
113+
#[inline(always)]
114+
fn clear_interrupt_pending_bit(&mut self) {
115+
unsafe { (*EXTI::ptr()).pr.write(|w| w.bits(1 << self.pin_id())) };
116+
}
117+
118+
/// Reads the interrupt pending bit for this pin
119+
#[inline(always)]
120+
fn check_interrupt(&self) -> bool {
121+
unsafe { ((*EXTI::ptr()).pr.read().bits() & (1 << self.pin_id())) != 0 }
122+
}
123+
}

0 commit comments

Comments
 (0)