aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2021-08-17 14:25:18 +0200
committerUlf Lilleengen <[email protected]>2021-08-17 16:22:47 +0200
commit4df63f5379206ebb5d09d5017e19498f0a1713af (patch)
treebfc39f01fe74a3068e50e189375ef6afef846ead
parent61409e2fb6798a8474d32df581e1cabfa04ec565 (diff)
Add per-core EXTI support
* Generate a core index put into the PAC for the peripherals to use as index into registers. * Add EXTI v2 which uses CORE_INDEX to index exti registers
-rw-r--r--embassy-stm32/src/exti/v2.rs183
-rw-r--r--examples/stm32wl55/src/bin/button_exti.rs34
-rw-r--r--stm32-metapac-gen/src/lib.rs18
3 files changed, 230 insertions, 5 deletions
diff --git a/embassy-stm32/src/exti/v2.rs b/embassy-stm32/src/exti/v2.rs
index 8b1378917..2e62331fe 100644
--- a/embassy-stm32/src/exti/v2.rs
+++ b/embassy-stm32/src/exti/v2.rs
@@ -1 +1,184 @@
1use core::convert::Infallible;
2use core::future::Future;
3use core::marker::PhantomData;
4use core::pin::Pin;
5use core::task::{Context, Poll};
6use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge};
7use embassy::util::{AtomicWaker, Unborrow};
8use embedded_hal::digital::v2::InputPin;
9use pac::exti::{regs, vals};
1 10
11use crate::gpio::{AnyPin, Input, Pin as GpioPin};
12use crate::pac;
13use crate::pac::CORE_INDEX;
14use crate::pac::{EXTI, SYSCFG};
15
16const EXTI_COUNT: usize = 16;
17const NEW_AW: AtomicWaker = AtomicWaker::new();
18static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT];
19
20pub unsafe fn on_irq() {
21 let bits = EXTI.pr(0).read().0;
22
23 // Mask all the channels that fired.
24 EXTI.cpu(CORE_INDEX)
25 .imr(CORE_INDEX)
26 .modify(|w| w.0 &= !bits);
27
28 // Wake the tasks
29 for pin in BitIter(bits) {
30 EXTI_WAKERS[pin as usize].wake();
31 }
32
33 // Clear pending
34 EXTI.pr(0).write_value(regs::Pr(bits));
35}
36
37struct BitIter(u32);
38
39impl Iterator for BitIter {
40 type Item = u32;
41
42 fn next(&mut self) -> Option<Self::Item> {
43 match self.0.trailing_zeros() {
44 32 => None,
45 b => {
46 self.0 &= !(1 << b);
47 Some(b)
48 }
49 }
50 }
51}
52
53/// EXTI input driver
54pub struct ExtiInput<'d, T: GpioPin> {
55 pin: Input<'d, T>,
56}
57
58impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
59
60impl<'d, T: GpioPin> ExtiInput<'d, T> {
61 pub fn new(pin: Input<'d, T>, _ch: impl Unborrow<Target = T::ExtiChannel> + 'd) -> Self {
62 Self { pin }
63 }
64}
65
66impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> {
67 type Error = Infallible;
68
69 fn is_high(&self) -> Result<bool, Self::Error> {
70 self.pin.is_high()
71 }
72
73 fn is_low(&self) -> Result<bool, Self::Error> {
74 self.pin.is_low()
75 }
76}
77
78impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> {
79 type Future<'a> = ExtiInputFuture<'a>;
80
81 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> {
82 ExtiInputFuture::new(
83 self.pin.pin.pin(),
84 self.pin.pin.port(),
85 vals::Rt::ENABLED,
86 vals::Ft::DISABLED,
87 )
88 }
89}
90
91impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> {
92 type Future<'a> = ExtiInputFuture<'a>;
93
94 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> {
95 ExtiInputFuture::new(
96 self.pin.pin.pin(),
97 self.pin.pin.port(),
98 vals::Rt::DISABLED,
99 vals::Ft::ENABLED,
100 )
101 }
102}
103
104impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> {
105 type Future<'a> = ExtiInputFuture<'a>;
106
107 fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
108 ExtiInputFuture::new(
109 self.pin.pin.pin(),
110 self.pin.pin.port(),
111 vals::Rt::ENABLED,
112 vals::Ft::ENABLED,
113 )
114 }
115}
116
117pub struct ExtiInputFuture<'a> {
118 pin: u8,
119 phantom: PhantomData<&'a mut AnyPin>,
120}
121
122impl<'a> ExtiInputFuture<'a> {
123 fn new(pin: u8, port: u8, rising: vals::Rt, falling: vals::Ft) -> Self {
124 cortex_m::interrupt::free(|_| unsafe {
125 let pin = pin as usize;
126 SYSCFG.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
127 EXTI.rtsr(CORE_INDEX).modify(|w| w.set_rt(pin, rising));
128 EXTI.ftsr(CORE_INDEX).modify(|w| w.set_ft(pin, falling));
129 EXTI.pr(CORE_INDEX).write(|w| w.set_pif(pin, true)); // clear pending bit
130 EXTI.cpu(CORE_INDEX)
131 .imr(CORE_INDEX)
132 .modify(|w| w.set_im(pin, vals::Mr::UNMASKED));
133 });
134
135 Self {
136 pin,
137 phantom: PhantomData,
138 }
139 }
140}
141
142impl<'a> Drop for ExtiInputFuture<'a> {
143 fn drop(&mut self) {
144 cortex_m::interrupt::free(|_| unsafe {
145 let pin = self.pin as _;
146 EXTI.cpu(CORE_INDEX)
147 .imr(CORE_INDEX)
148 .modify(|w| w.set_im(pin, vals::Mr::MASKED));
149 });
150 }
151}
152
153impl<'a> Future for ExtiInputFuture<'a> {
154 type Output = ();
155
156 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
157 EXTI_WAKERS[self.pin as usize].register(cx.waker());
158
159 if unsafe {
160 EXTI.cpu(CORE_INDEX)
161 .imr(CORE_INDEX)
162 .read()
163 .im(self.pin as _)
164 == vals::Mr::MASKED
165 } {
166 Poll::Ready(())
167 } else {
168 Poll::Pending
169 }
170 }
171}
172
173use crate::interrupt;
174
175macro_rules! impl_irq {
176 ($e:ident) => {
177 #[interrupt]
178 unsafe fn $e() {
179 on_irq()
180 }
181 };
182}
183
184foreach_exti_irq!(impl_irq);
diff --git a/examples/stm32wl55/src/bin/button_exti.rs b/examples/stm32wl55/src/bin/button_exti.rs
new file mode 100644
index 000000000..2f6e55115
--- /dev/null
+++ b/examples/stm32wl55/src/bin/button_exti.rs
@@ -0,0 +1,34 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(type_alias_impl_trait)]
5#![allow(incomplete_features)]
6
7#[path = "../example_common.rs"]
8mod example_common;
9use embassy::executor::Spawner;
10use embassy_stm32::dbgmcu::Dbgmcu;
11use embassy_stm32::exti::ExtiInput;
12use embassy_stm32::gpio::{Input, Pull};
13use embassy_stm32::Peripherals;
14use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
15use example_common::*;
16
17#[embassy::main]
18async fn main(_spawner: Spawner, p: Peripherals) {
19 info!("Hello World!");
20
21 unsafe { Dbgmcu::enable_all() };
22
23 let button = Input::new(p.PA0, Pull::Up);
24 let mut button = ExtiInput::new(button, p.EXTI0);
25
26 info!("Press the USER button...");
27
28 loop {
29 button.wait_for_falling_edge().await;
30 info!("Pressed!");
31 button.wait_for_rising_edge().await;
32 info!("Released!");
33 }
34}
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs
index ae401bb67..b1980d84e 100644
--- a/stm32-metapac-gen/src/lib.rs
+++ b/stm32-metapac-gen/src/lib.rs
@@ -231,21 +231,23 @@ pub fn gen(options: Options) {
231 let chip: Chip = serde_yaml::from_slice(&chip).unwrap(); 231 let chip: Chip = serde_yaml::from_slice(&chip).unwrap();
232 232
233 println!("looking for core {:?}", core_name); 233 println!("looking for core {:?}", core_name);
234 let core: Option<&Core> = if let Some(core_name) = core_name { 234 let core: Option<(&Core, usize)> = if let Some(core_name) = core_name {
235 let core_name = core_name.to_ascii_lowercase(); 235 let core_name = core_name.to_ascii_lowercase();
236 let mut c = None; 236 let mut c = None;
237 for core in chip.cores.iter() { 237 let mut idx = 0;
238 for (i, core) in chip.cores.iter().enumerate() {
238 if core.name == core_name { 239 if core.name == core_name {
239 c = Some(core); 240 c = Some(core);
241 idx = i;
240 break; 242 break;
241 } 243 }
242 } 244 }
243 c 245 c.map(|c| (c, idx))
244 } else { 246 } else {
245 Some(&chip.cores[0]) 247 Some((&chip.cores[0], 0))
246 }; 248 };
247 249
248 let core = core.unwrap(); 250 let (core, core_index) = core.unwrap();
249 let core_name = &core.name; 251 let core_name = &core.name;
250 252
251 let mut ir = ir::IR::new(); 253 let mut ir = ir::IR::new();
@@ -584,6 +586,12 @@ pub fn gen(options: Options) {
584 ) 586 )
585 .unwrap(); 587 .unwrap();
586 } 588 }
589 write!(
590 &mut extra,
591 "pub const CORE_INDEX: usize = {};\n",
592 core_index
593 )
594 .unwrap();
587 595
588 // Cleanups! 596 // Cleanups!
589 transform::sort::Sort {}.run(&mut ir).unwrap(); 597 transform::sort::Sort {}.run(&mut ir).unwrap();