aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/exti.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/exti.rs')
-rw-r--r--embassy-stm32/src/exti.rs165
1 files changed, 105 insertions, 60 deletions
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 9fce78f95..458174b5d 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -5,13 +5,16 @@ use core::marker::PhantomData;
5use core::pin::Pin; 5use core::pin::Pin;
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::{impl_peripheral, PeripheralType}; 8use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use futures_util::FutureExt;
10 11
11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; 12use crate::gpio::{AnyPin, ExtiPin, Input, Level, Pin as GpioPin, PinNumber, Pull};
12use crate::pac::exti::regs::Lines; 13use crate::interrupt::Interrupt as InterruptEnum;
14use crate::interrupt::typelevel::{Binding, Handler, Interrupt as InterruptType};
13use crate::pac::EXTI; 15use crate::pac::EXTI;
14use crate::{interrupt, pac, peripherals, Peri}; 16use crate::pac::exti::regs::Lines;
17use crate::{Peri, pac};
15 18
16const EXTI_COUNT: usize = 16; 19const EXTI_COUNT: usize = 16;
17static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; 20static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT];
@@ -31,11 +34,11 @@ fn cpu_regs() -> pac::exti::Exti {
31 EXTI 34 EXTI
32} 35}
33 36
34#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] 37#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50, exti_n6)))]
35fn exticr_regs() -> pac::syscfg::Syscfg { 38fn exticr_regs() -> pac::syscfg::Syscfg {
36 pac::SYSCFG 39 pac::SYSCFG
37} 40}
38#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 41#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
39fn exticr_regs() -> pac::exti::Exti { 42fn exticr_regs() -> pac::exti::Exti {
40 EXTI 43 EXTI
41} 44}
@@ -45,9 +48,9 @@ fn exticr_regs() -> pac::afio::Afio {
45} 48}
46 49
47unsafe fn on_irq() { 50unsafe fn on_irq() {
48 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 51 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
49 let bits = EXTI.pr(0).read().0; 52 let bits = EXTI.pr(0).read().0;
50 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 53 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
51 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; 54 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
52 55
53 // We don't handle or change any EXTI lines above 16. 56 // We don't handle or change any EXTI lines above 16.
@@ -62,16 +65,16 @@ unsafe fn on_irq() {
62 } 65 }
63 66
64 // Clear pending 67 // Clear pending
65 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 68 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
66 EXTI.pr(0).write_value(Lines(bits)); 69 EXTI.pr(0).write_value(Lines(bits));
67 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 70 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
68 { 71 {
69 EXTI.rpr(0).write_value(Lines(bits)); 72 EXTI.rpr(0).write_value(Lines(bits));
70 EXTI.fpr(0).write_value(Lines(bits)); 73 EXTI.fpr(0).write_value(Lines(bits));
71 } 74 }
72 75
73 #[cfg(feature = "low-power")] 76 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq(); 77 crate::low_power::Executor::on_wakeup_irq_or_event();
75} 78}
76 79
77struct BitIter(u32); 80struct BitIter(u32);
@@ -105,10 +108,17 @@ impl<'d> Unpin for ExtiInput<'d> {}
105 108
106impl<'d> ExtiInput<'d> { 109impl<'d> ExtiInput<'d> {
107 /// Create an EXTI input. 110 /// Create an EXTI input.
108 pub fn new<T: GpioPin>(pin: Peri<'d, T>, ch: Peri<'d, T::ExtiChannel>, pull: Pull) -> Self { 111 ///
109 // Needed if using AnyPin+AnyChannel. 112 /// The Binding must bind the Channel's IRQ to [InterruptHandler].
110 assert_eq!(pin.pin(), ch.number()); 113 pub fn new<T: ExtiPin + GpioPin>(
111 114 pin: Peri<'d, T>,
115 _ch: Peri<'d, T::ExtiChannel>,
116 pull: Pull,
117 _irq: impl Binding<
118 <<T as ExtiPin>::ExtiChannel as Channel>::IRQ,
119 InterruptHandler<<<T as ExtiPin>::ExtiChannel as Channel>::IRQ>,
120 >,
121 ) -> Self {
112 Self { 122 Self {
113 pin: Input::new(pin, pull), 123 pin: Input::new(pin, pull),
114 } 124 }
@@ -133,7 +143,7 @@ impl<'d> ExtiInput<'d> {
133 /// 143 ///
134 /// This returns immediately if the pin is already high. 144 /// This returns immediately if the pin is already high.
135 pub async fn wait_for_high(&mut self) { 145 pub async fn wait_for_high(&mut self) {
136 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); 146 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, true);
137 if self.is_high() { 147 if self.is_high() {
138 return; 148 return;
139 } 149 }
@@ -144,7 +154,7 @@ impl<'d> ExtiInput<'d> {
144 /// 154 ///
145 /// This returns immediately if the pin is already low. 155 /// This returns immediately if the pin is already low.
146 pub async fn wait_for_low(&mut self) { 156 pub async fn wait_for_low(&mut self) {
147 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); 157 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, true);
148 if self.is_low() { 158 if self.is_low() {
149 return; 159 return;
150 } 160 }
@@ -155,19 +165,40 @@ impl<'d> ExtiInput<'d> {
155 /// 165 ///
156 /// If the pin is already high, it will wait for it to go low then back high. 166 /// If the pin is already high, it will wait for it to go low then back high.
157 pub async fn wait_for_rising_edge(&mut self) { 167 pub async fn wait_for_rising_edge(&mut self) {
158 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await 168 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, true).await
169 }
170
171 /// Asynchronously wait until the pin sees a rising edge.
172 ///
173 /// If the pin is already high, it will wait for it to go low then back high.
174 pub fn poll_for_rising_edge<'a>(&mut self, cx: &mut Context<'a>) {
175 let _ =
176 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, false).poll_unpin(cx);
159 } 177 }
160 178
161 /// Asynchronously wait until the pin sees a falling edge. 179 /// Asynchronously wait until the pin sees a falling edge.
162 /// 180 ///
163 /// If the pin is already low, it will wait for it to go high then back low. 181 /// If the pin is already low, it will wait for it to go high then back low.
164 pub async fn wait_for_falling_edge(&mut self) { 182 pub async fn wait_for_falling_edge(&mut self) {
165 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await 183 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, true).await
184 }
185
186 /// Asynchronously wait until the pin sees a falling edge.
187 ///
188 /// If the pin is already low, it will wait for it to go high then back low.
189 pub fn poll_for_falling_edge<'a>(&mut self, cx: &mut Context<'a>) {
190 let _ =
191 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, false).poll_unpin(cx);
166 } 192 }
167 193
168 /// Asynchronously wait until the pin sees any edge (either rising or falling). 194 /// Asynchronously wait until the pin sees any edge (either rising or falling).
169 pub async fn wait_for_any_edge(&mut self) { 195 pub async fn wait_for_any_edge(&mut self) {
170 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await 196 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true, true).await
197 }
198
199 /// Asynchronously wait until the pin sees any edge (either rising or falling).
200 pub fn poll_for_any_edge<'a>(&mut self, cx: &mut Context<'a>) {
201 let _ = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true, false).poll_unpin(cx);
171 } 202 }
172} 203}
173 204
@@ -226,12 +257,13 @@ impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> {
226 257
227#[must_use = "futures do nothing unless you `.await` or poll them"] 258#[must_use = "futures do nothing unless you `.await` or poll them"]
228struct ExtiInputFuture<'a> { 259struct ExtiInputFuture<'a> {
229 pin: u8, 260 pin: PinNumber,
261 drop: bool,
230 phantom: PhantomData<&'a mut AnyPin>, 262 phantom: PhantomData<&'a mut AnyPin>,
231} 263}
232 264
233impl<'a> ExtiInputFuture<'a> { 265impl<'a> ExtiInputFuture<'a> {
234 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { 266 fn new(pin: PinNumber, port: PinNumber, rising: bool, falling: bool, drop: bool) -> Self {
235 critical_section::with(|_| { 267 critical_section::with(|_| {
236 let pin = pin as usize; 268 let pin = pin as usize;
237 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); 269 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
@@ -239,9 +271,9 @@ impl<'a> ExtiInputFuture<'a> {
239 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); 271 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
240 272
241 // clear pending bit 273 // clear pending bit
242 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 274 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
243 EXTI.pr(0).write(|w| w.set_line(pin, true)); 275 EXTI.pr(0).write(|w| w.set_line(pin, true));
244 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 276 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
245 { 277 {
246 EXTI.rpr(0).write(|w| w.set_line(pin, true)); 278 EXTI.rpr(0).write(|w| w.set_line(pin, true));
247 EXTI.fpr(0).write(|w| w.set_line(pin, true)); 279 EXTI.fpr(0).write(|w| w.set_line(pin, true));
@@ -252,6 +284,7 @@ impl<'a> ExtiInputFuture<'a> {
252 284
253 Self { 285 Self {
254 pin, 286 pin,
287 drop,
255 phantom: PhantomData, 288 phantom: PhantomData,
256 } 289 }
257 } 290 }
@@ -259,10 +292,12 @@ impl<'a> ExtiInputFuture<'a> {
259 292
260impl<'a> Drop for ExtiInputFuture<'a> { 293impl<'a> Drop for ExtiInputFuture<'a> {
261 fn drop(&mut self) { 294 fn drop(&mut self) {
262 critical_section::with(|_| { 295 if self.drop {
263 let pin = self.pin as _; 296 critical_section::with(|_| {
264 cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); 297 let pin = self.pin as _;
265 }); 298 cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
299 });
300 }
266 } 301 }
267} 302}
268 303
@@ -302,7 +337,7 @@ macro_rules! foreach_exti_irq {
302 (EXTI15) => { $action!(EXTI15); }; 337 (EXTI15) => { $action!(EXTI15); };
303 338
304 // plus the weird ones 339 // plus the weird ones
305 (EXTI0_1) => { $action!( EXTI0_1 ); }; 340 (EXTI0_1) => { $action!(EXTI0_1); };
306 (EXTI15_10) => { $action!(EXTI15_10); }; 341 (EXTI15_10) => { $action!(EXTI15_10); };
307 (EXTI15_4) => { $action!(EXTI15_4); }; 342 (EXTI15_4) => { $action!(EXTI15_4); };
308 (EXTI1_0) => { $action!(EXTI1_0); }; 343 (EXTI1_0) => { $action!(EXTI1_0); };
@@ -315,57 +350,67 @@ macro_rules! foreach_exti_irq {
315 }; 350 };
316} 351}
317 352
318macro_rules! impl_irq { 353///EXTI interrupt handler. All EXTI interrupt vectors should be bound to this handler.
319 ($e:ident) => { 354///
320 #[allow(non_snake_case)] 355/// It is generic over the [Interrupt](InterruptType) rather
321 #[cfg(feature = "rt")] 356/// than the [Channel] because it should not be bound multiple
322 #[interrupt] 357/// times to the same vector on chips which multiplex multiple EXTI interrupts into one vector.
323 unsafe fn $e() { 358//
324 on_irq() 359// It technically doesn't need to be generic at all, except to satisfy the generic argument
325 } 360// of [Handler]. All EXTI interrupts eventually land in the same on_irq() function.
326 }; 361pub struct InterruptHandler<T: crate::interrupt::typelevel::Interrupt> {
362 _phantom: PhantomData<T>,
327} 363}
328 364
329foreach_exti_irq!(impl_irq); 365impl<T: InterruptType> Handler<T> for InterruptHandler<T> {
366 unsafe fn on_interrupt() {
367 on_irq()
368 }
369}
330 370
331trait SealedChannel {} 371trait SealedChannel {}
332 372
333/// EXTI channel trait. 373/// EXTI channel trait.
334#[allow(private_bounds)] 374#[allow(private_bounds)]
335pub trait Channel: PeripheralType + SealedChannel + Sized { 375pub trait Channel: PeripheralType + SealedChannel + Sized {
336 /// Get the EXTI channel number. 376 /// EXTI channel number.
337 fn number(&self) -> u8; 377 fn number(&self) -> PinNumber;
378 /// [Enum-level Interrupt](InterruptEnum), which may be the same for multiple channels.
379 fn irq(&self) -> InterruptEnum;
380 /// [Type-level Interrupt](InterruptType), which may be the same for multiple channels.
381 type IRQ: InterruptType;
338} 382}
339 383
340/// Type-erased EXTI channel. 384//Doc isn't hidden in order to surface the explanation to users, even though it's completely inoperable, not just deprecated.
385//Entire type along with doc can probably be removed after deprecation has appeared in a release once.
386/// Deprecated type-erased EXTI channel.
341/// 387///
342/// This represents ownership over any EXTI channel, known at runtime. 388/// Support for AnyChannel was removed in order to support manually bindable EXTI interrupts via bind_interrupts; [ExtiInput::new()]
389/// must know the required IRQ at compile time, and therefore cannot support type-erased channels.
390#[deprecated = "type-erased EXTI channels are no longer supported, in order to support manually bindable EXTI interrupts (more info: https://github.com/embassy-rs/embassy/pull/4922)"]
343pub struct AnyChannel { 391pub struct AnyChannel {
344 number: u8, 392 #[allow(unused)]
345} 393 number: PinNumber,
346
347impl_peripheral!(AnyChannel);
348impl SealedChannel for AnyChannel {}
349impl Channel for AnyChannel {
350 fn number(&self) -> u8 {
351 self.number
352 }
353} 394}
354 395
355macro_rules! impl_exti { 396macro_rules! impl_exti {
356 ($type:ident, $number:expr) => { 397 ($type:ident, $number:expr) => {
357 impl SealedChannel for peripherals::$type {} 398 impl SealedChannel for crate::peripherals::$type {}
358 impl Channel for peripherals::$type { 399 impl Channel for crate::peripherals::$type {
359 fn number(&self) -> u8 { 400 fn number(&self) -> PinNumber {
360 $number 401 $number
361 } 402 }
403 fn irq(&self) -> InterruptEnum {
404 crate::_generated::peripheral_interrupts::EXTI::$type::IRQ
405 }
406 type IRQ = crate::_generated::peripheral_interrupts::EXTI::$type;
362 } 407 }
363 408
364 impl From<peripherals::$type> for AnyChannel { 409 //Still here to surface deprecation messages to the user - remove when removing AnyChannel
365 fn from(val: peripherals::$type) -> Self { 410 #[allow(deprecated)]
366 Self { 411 impl From<crate::peripherals::$type> for AnyChannel {
367 number: val.number() as u8, 412 fn from(_val: crate::peripherals::$type) -> Self {
368 } 413 Self { number: $number }
369 } 414 }
370 } 415 }
371 }; 416 };