diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-08-19 22:17:17 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-08-19 22:17:17 +0200 |
| commit | ec51880e28d48269ae1ce8b037305f4f7f182c84 (patch) | |
| tree | b9283065cbaf692c17dddba587a862003dc266ce | |
| parent | dd62790f3630335b905743627a9d2e3c40cb6e4f (diff) | |
stm32/exti: unify all versions into single impl
| -rw-r--r-- | embassy-stm32/src/exti.rs | 270 | ||||
| -rw-r--r-- | embassy-stm32/src/exti/mod.rs | 116 | ||||
| -rw-r--r-- | embassy-stm32/src/exti/v1.rs | 171 | ||||
| -rw-r--r-- | embassy-stm32/src/exti/v2.rs | 184 | ||||
| -rw-r--r-- | examples/stm32wb55/src/bin/button_exti.rs | 36 |
5 files changed, 306 insertions, 471 deletions
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs new file mode 100644 index 000000000..659daa377 --- /dev/null +++ b/embassy-stm32/src/exti.rs | |||
| @@ -0,0 +1,270 @@ | |||
| 1 | use core::convert::Infallible; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::pin::Pin; | ||
| 5 | use core::task::{Context, Poll}; | ||
| 6 | use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge}; | ||
| 7 | use embassy::util::{AtomicWaker, Unborrow}; | ||
| 8 | use embassy_hal_common::unsafe_impl_unborrow; | ||
| 9 | use embedded_hal::digital::v2::InputPin; | ||
| 10 | |||
| 11 | use crate::gpio::{AnyPin, Input, Pin as GpioPin}; | ||
| 12 | use crate::interrupt; | ||
| 13 | use crate::pac; | ||
| 14 | use crate::pac::{EXTI, SYSCFG}; | ||
| 15 | use crate::peripherals; | ||
| 16 | |||
| 17 | const EXTI_COUNT: usize = 16; | ||
| 18 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||
| 19 | static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT]; | ||
| 20 | |||
| 21 | #[cfg(exti_w)] | ||
| 22 | fn cpu_regs() -> pac::exti::Cpu { | ||
| 23 | EXTI.cpu(crate::pac::CORE_INDEX) | ||
| 24 | } | ||
| 25 | |||
| 26 | #[cfg(not(exti_w))] | ||
| 27 | fn cpu_regs() -> pac::exti::Exti { | ||
| 28 | EXTI | ||
| 29 | } | ||
| 30 | |||
| 31 | pub unsafe fn on_irq() { | ||
| 32 | let bits = EXTI.pr(0).read(); | ||
| 33 | |||
| 34 | // Mask all the channels that fired. | ||
| 35 | cpu_regs().imr(0).modify(|w| w.0 &= !bits.0); | ||
| 36 | |||
| 37 | // Wake the tasks | ||
| 38 | for pin in BitIter(bits.0) { | ||
| 39 | EXTI_WAKERS[pin as usize].wake(); | ||
| 40 | } | ||
| 41 | |||
| 42 | // Clear pending | ||
| 43 | EXTI.pr(0).write_value(bits); | ||
| 44 | } | ||
| 45 | |||
| 46 | struct BitIter(u32); | ||
| 47 | |||
| 48 | impl Iterator for BitIter { | ||
| 49 | type Item = u32; | ||
| 50 | |||
| 51 | fn next(&mut self) -> Option<Self::Item> { | ||
| 52 | match self.0.trailing_zeros() { | ||
| 53 | 32 => None, | ||
| 54 | b => { | ||
| 55 | self.0 &= !(1 << b); | ||
| 56 | Some(b) | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | /// EXTI input driver | ||
| 63 | pub struct ExtiInput<'d, T: GpioPin> { | ||
| 64 | pin: Input<'d, T>, | ||
| 65 | } | ||
| 66 | |||
| 67 | impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} | ||
| 68 | |||
| 69 | impl<'d, T: GpioPin> ExtiInput<'d, T> { | ||
| 70 | pub fn new(pin: Input<'d, T>, _ch: impl Unborrow<Target = T::ExtiChannel> + 'd) -> Self { | ||
| 71 | Self { pin } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> { | ||
| 76 | type Error = Infallible; | ||
| 77 | |||
| 78 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 79 | self.pin.is_high() | ||
| 80 | } | ||
| 81 | |||
| 82 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 83 | self.pin.is_low() | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> { | ||
| 88 | type Future<'a> = ExtiInputFuture<'a>; | ||
| 89 | |||
| 90 | fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||
| 91 | ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), true, false) | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> { | ||
| 96 | type Future<'a> = ExtiInputFuture<'a>; | ||
| 97 | |||
| 98 | fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||
| 99 | ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), false, true) | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> { | ||
| 104 | type Future<'a> = ExtiInputFuture<'a>; | ||
| 105 | |||
| 106 | fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||
| 107 | ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), true, true) | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | pub struct ExtiInputFuture<'a> { | ||
| 112 | pin: u8, | ||
| 113 | phantom: PhantomData<&'a mut AnyPin>, | ||
| 114 | } | ||
| 115 | |||
| 116 | impl<'a> ExtiInputFuture<'a> { | ||
| 117 | fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { | ||
| 118 | cortex_m::interrupt::free(|_| unsafe { | ||
| 119 | let pin = pin as usize; | ||
| 120 | SYSCFG.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); | ||
| 121 | EXTI.rtsr(0).modify(|w| w.set_line(pin, rising)); | ||
| 122 | EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); | ||
| 123 | EXTI.pr(0).write(|w| w.set_line(pin, true)); // clear pending bit | ||
| 124 | cpu_regs().imr(0).modify(|w| w.set_line(pin, true)); | ||
| 125 | }); | ||
| 126 | |||
| 127 | Self { | ||
| 128 | pin, | ||
| 129 | phantom: PhantomData, | ||
| 130 | } | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | impl<'a> Drop for ExtiInputFuture<'a> { | ||
| 135 | fn drop(&mut self) { | ||
| 136 | cortex_m::interrupt::free(|_| unsafe { | ||
| 137 | let pin = self.pin as _; | ||
| 138 | cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); | ||
| 139 | }); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | impl<'a> Future for ExtiInputFuture<'a> { | ||
| 144 | type Output = (); | ||
| 145 | |||
| 146 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 147 | EXTI_WAKERS[self.pin as usize].register(cx.waker()); | ||
| 148 | |||
| 149 | let imr = unsafe { cpu_regs().imr(0).read() }; | ||
| 150 | if !imr.line(self.pin as _) { | ||
| 151 | Poll::Ready(()) | ||
| 152 | } else { | ||
| 153 | Poll::Pending | ||
| 154 | } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | macro_rules! foreach_exti_irq { | ||
| 159 | ($action:ident) => { | ||
| 160 | crate::pac::interrupts!( | ||
| 161 | (EXTI0) => { $action!(EXTI0); }; | ||
| 162 | (EXTI1) => { $action!(EXTI1); }; | ||
| 163 | (EXTI2) => { $action!(EXTI2); }; | ||
| 164 | (EXTI3) => { $action!(EXTI3); }; | ||
| 165 | (EXTI4) => { $action!(EXTI4); }; | ||
| 166 | (EXTI5) => { $action!(EXTI5); }; | ||
| 167 | (EXTI6) => { $action!(EXTI6); }; | ||
| 168 | (EXTI7) => { $action!(EXTI7); }; | ||
| 169 | (EXTI8) => { $action!(EXTI8); }; | ||
| 170 | (EXTI9) => { $action!(EXTI9); }; | ||
| 171 | (EXTI10) => { $action!(EXTI10); }; | ||
| 172 | (EXTI11) => { $action!(EXTI11); }; | ||
| 173 | (EXTI12) => { $action!(EXTI12); }; | ||
| 174 | (EXTI13) => { $action!(EXTI13); }; | ||
| 175 | (EXTI14) => { $action!(EXTI14); }; | ||
| 176 | (EXTI15) => { $action!(EXTI15); }; | ||
| 177 | |||
| 178 | // plus the weird ones | ||
| 179 | (EXTI0_1) => { $action!( EXTI0_1 ); }; | ||
| 180 | (EXTI15_10) => { $action!(EXTI15_10); }; | ||
| 181 | (EXTI15_4) => { $action!(EXTI15_4); }; | ||
| 182 | (EXTI1_0) => { $action!(EXTI1_0); }; | ||
| 183 | (EXTI2_3) => { $action!(EXTI2_3); }; | ||
| 184 | (EXTI2_TSC) => { $action!(EXTI2_TSC); }; | ||
| 185 | (EXTI3_2) => { $action!(EXTI3_2); }; | ||
| 186 | (EXTI4_15) => { $action!(EXTI4_15); }; | ||
| 187 | (EXTI9_5) => { $action!(EXTI9_5); }; | ||
| 188 | ); | ||
| 189 | }; | ||
| 190 | } | ||
| 191 | |||
| 192 | macro_rules! impl_irq { | ||
| 193 | ($e:ident) => { | ||
| 194 | #[interrupt] | ||
| 195 | unsafe fn $e() { | ||
| 196 | on_irq() | ||
| 197 | } | ||
| 198 | }; | ||
| 199 | } | ||
| 200 | |||
| 201 | foreach_exti_irq!(impl_irq); | ||
| 202 | |||
| 203 | pub(crate) mod sealed { | ||
| 204 | pub trait Channel {} | ||
| 205 | } | ||
| 206 | |||
| 207 | pub trait Channel: sealed::Channel + Sized { | ||
| 208 | fn number(&self) -> usize; | ||
| 209 | fn degrade(self) -> AnyChannel { | ||
| 210 | AnyChannel { | ||
| 211 | number: self.number() as u8, | ||
| 212 | } | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | pub struct AnyChannel { | ||
| 217 | number: u8, | ||
| 218 | } | ||
| 219 | unsafe_impl_unborrow!(AnyChannel); | ||
| 220 | impl sealed::Channel for AnyChannel {} | ||
| 221 | impl Channel for AnyChannel { | ||
| 222 | fn number(&self) -> usize { | ||
| 223 | self.number as usize | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | macro_rules! impl_exti { | ||
| 228 | ($type:ident, $number:expr) => { | ||
| 229 | impl sealed::Channel for peripherals::$type {} | ||
| 230 | impl Channel for peripherals::$type { | ||
| 231 | fn number(&self) -> usize { | ||
| 232 | $number as usize | ||
| 233 | } | ||
| 234 | } | ||
| 235 | }; | ||
| 236 | } | ||
| 237 | |||
| 238 | impl_exti!(EXTI0, 0); | ||
| 239 | impl_exti!(EXTI1, 1); | ||
| 240 | impl_exti!(EXTI2, 2); | ||
| 241 | impl_exti!(EXTI3, 3); | ||
| 242 | impl_exti!(EXTI4, 4); | ||
| 243 | impl_exti!(EXTI5, 5); | ||
| 244 | impl_exti!(EXTI6, 6); | ||
| 245 | impl_exti!(EXTI7, 7); | ||
| 246 | impl_exti!(EXTI8, 8); | ||
| 247 | impl_exti!(EXTI9, 9); | ||
| 248 | impl_exti!(EXTI10, 10); | ||
| 249 | impl_exti!(EXTI11, 11); | ||
| 250 | impl_exti!(EXTI12, 12); | ||
| 251 | impl_exti!(EXTI13, 13); | ||
| 252 | impl_exti!(EXTI14, 14); | ||
| 253 | impl_exti!(EXTI15, 15); | ||
| 254 | |||
| 255 | macro_rules! enable_irq { | ||
| 256 | ($e:ident) => { | ||
| 257 | crate::interrupt::$e::steal().enable(); | ||
| 258 | }; | ||
| 259 | } | ||
| 260 | |||
| 261 | /// safety: must be called only once | ||
| 262 | pub(crate) unsafe fn init() { | ||
| 263 | use embassy::interrupt::Interrupt; | ||
| 264 | use embassy::interrupt::InterruptExt; | ||
| 265 | |||
| 266 | foreach_exti_irq!(enable_irq); | ||
| 267 | |||
| 268 | #[cfg(not(any(rcc_wb, rcc_wl5)))] | ||
| 269 | <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable(); | ||
| 270 | } | ||
diff --git a/embassy-stm32/src/exti/mod.rs b/embassy-stm32/src/exti/mod.rs deleted file mode 100644 index 3f43e0bc7..000000000 --- a/embassy-stm32/src/exti/mod.rs +++ /dev/null | |||
| @@ -1,116 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | macro_rules! foreach_exti_irq { | ||
| 4 | ($action:ident) => { | ||
| 5 | crate::pac::interrupts!( | ||
| 6 | (EXTI0) => { $action!(EXTI0); }; | ||
| 7 | (EXTI1) => { $action!(EXTI1); }; | ||
| 8 | (EXTI2) => { $action!(EXTI2); }; | ||
| 9 | (EXTI3) => { $action!(EXTI3); }; | ||
| 10 | (EXTI4) => { $action!(EXTI4); }; | ||
| 11 | (EXTI5) => { $action!(EXTI5); }; | ||
| 12 | (EXTI6) => { $action!(EXTI6); }; | ||
| 13 | (EXTI7) => { $action!(EXTI7); }; | ||
| 14 | (EXTI8) => { $action!(EXTI8); }; | ||
| 15 | (EXTI9) => { $action!(EXTI9); }; | ||
| 16 | (EXTI10) => { $action!(EXTI10); }; | ||
| 17 | (EXTI11) => { $action!(EXTI11); }; | ||
| 18 | (EXTI12) => { $action!(EXTI12); }; | ||
| 19 | (EXTI13) => { $action!(EXTI13); }; | ||
| 20 | (EXTI14) => { $action!(EXTI14); }; | ||
| 21 | (EXTI15) => { $action!(EXTI15); }; | ||
| 22 | |||
| 23 | // plus the weird ones | ||
| 24 | (EXTI0_1) => { $action!( EXTI0_1 ); }; | ||
| 25 | (EXTI15_10) => { $action!(EXTI15_10); }; | ||
| 26 | (EXTI15_4) => { $action!(EXTI15_4); }; | ||
| 27 | (EXTI1_0) => { $action!(EXTI1_0); }; | ||
| 28 | (EXTI2_3) => { $action!(EXTI2_3); }; | ||
| 29 | (EXTI2_TSC) => { $action!(EXTI2_TSC); }; | ||
| 30 | (EXTI3_2) => { $action!(EXTI3_2); }; | ||
| 31 | (EXTI4_15) => { $action!(EXTI4_15); }; | ||
| 32 | (EXTI9_5) => { $action!(EXTI9_5); }; | ||
| 33 | ); | ||
| 34 | }; | ||
| 35 | } | ||
| 36 | |||
| 37 | #[cfg_attr(exti_v1, path = "v1.rs")] | ||
| 38 | #[cfg_attr(exti_h7, path = "v1.rs")] | ||
| 39 | #[cfg_attr(exti_wb55, path = "v2.rs")] | ||
| 40 | #[cfg_attr(exti_wl5x, path = "v2.rs")] | ||
| 41 | mod _version; | ||
| 42 | |||
| 43 | #[allow(unused)] | ||
| 44 | pub use _version::*; | ||
| 45 | |||
| 46 | use crate::peripherals; | ||
| 47 | use embassy_hal_common::unsafe_impl_unborrow; | ||
| 48 | |||
| 49 | pub(crate) mod sealed { | ||
| 50 | pub trait Channel {} | ||
| 51 | } | ||
| 52 | |||
| 53 | pub trait Channel: sealed::Channel + Sized { | ||
| 54 | fn number(&self) -> usize; | ||
| 55 | fn degrade(self) -> AnyChannel { | ||
| 56 | AnyChannel { | ||
| 57 | number: self.number() as u8, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | pub struct AnyChannel { | ||
| 63 | number: u8, | ||
| 64 | } | ||
| 65 | unsafe_impl_unborrow!(AnyChannel); | ||
| 66 | impl sealed::Channel for AnyChannel {} | ||
| 67 | impl Channel for AnyChannel { | ||
| 68 | fn number(&self) -> usize { | ||
| 69 | self.number as usize | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | macro_rules! impl_exti { | ||
| 74 | ($type:ident, $number:expr) => { | ||
| 75 | impl sealed::Channel for peripherals::$type {} | ||
| 76 | impl Channel for peripherals::$type { | ||
| 77 | fn number(&self) -> usize { | ||
| 78 | $number as usize | ||
| 79 | } | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | } | ||
| 83 | |||
| 84 | impl_exti!(EXTI0, 0); | ||
| 85 | impl_exti!(EXTI1, 1); | ||
| 86 | impl_exti!(EXTI2, 2); | ||
| 87 | impl_exti!(EXTI3, 3); | ||
| 88 | impl_exti!(EXTI4, 4); | ||
| 89 | impl_exti!(EXTI5, 5); | ||
| 90 | impl_exti!(EXTI6, 6); | ||
| 91 | impl_exti!(EXTI7, 7); | ||
| 92 | impl_exti!(EXTI8, 8); | ||
| 93 | impl_exti!(EXTI9, 9); | ||
| 94 | impl_exti!(EXTI10, 10); | ||
| 95 | impl_exti!(EXTI11, 11); | ||
| 96 | impl_exti!(EXTI12, 12); | ||
| 97 | impl_exti!(EXTI13, 13); | ||
| 98 | impl_exti!(EXTI14, 14); | ||
| 99 | impl_exti!(EXTI15, 15); | ||
| 100 | |||
| 101 | macro_rules! enable_irq { | ||
| 102 | ($e:ident) => { | ||
| 103 | crate::interrupt::$e::steal().enable(); | ||
| 104 | }; | ||
| 105 | } | ||
| 106 | |||
| 107 | /// safety: must be called only once | ||
| 108 | pub(crate) unsafe fn init() { | ||
| 109 | use embassy::interrupt::Interrupt; | ||
| 110 | use embassy::interrupt::InterruptExt; | ||
| 111 | |||
| 112 | foreach_exti_irq!(enable_irq); | ||
| 113 | |||
| 114 | #[cfg(not(any(rcc_wb55, rcc_wl5x)))] | ||
| 115 | <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable(); | ||
| 116 | } | ||
diff --git a/embassy-stm32/src/exti/v1.rs b/embassy-stm32/src/exti/v1.rs deleted file mode 100644 index caf457605..000000000 --- a/embassy-stm32/src/exti/v1.rs +++ /dev/null | |||
| @@ -1,171 +0,0 @@ | |||
| 1 | use core::convert::Infallible; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::pin::Pin; | ||
| 5 | use core::task::{Context, Poll}; | ||
| 6 | use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge}; | ||
| 7 | use embassy::util::{AtomicWaker, Unborrow}; | ||
| 8 | use embedded_hal::digital::v2::InputPin; | ||
| 9 | use pac::exti::{regs, vals}; | ||
| 10 | |||
| 11 | use crate::gpio::{AnyPin, Input, Pin as GpioPin}; | ||
| 12 | use crate::pac; | ||
| 13 | use crate::pac::{EXTI, SYSCFG}; | ||
| 14 | |||
| 15 | const EXTI_COUNT: usize = 16; | ||
| 16 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||
| 17 | static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT]; | ||
| 18 | |||
| 19 | pub unsafe fn on_irq() { | ||
| 20 | let bits = EXTI.pr().read().0; | ||
| 21 | |||
| 22 | // Mask all the channels that fired. | ||
| 23 | EXTI.imr().modify(|w| w.0 &= !bits); | ||
| 24 | |||
| 25 | // Wake the tasks | ||
| 26 | for pin in BitIter(bits) { | ||
| 27 | EXTI_WAKERS[pin as usize].wake(); | ||
| 28 | } | ||
| 29 | |||
| 30 | // Clear pending | ||
| 31 | EXTI.pr().write_value(regs::Pr(bits)); | ||
| 32 | } | ||
| 33 | |||
| 34 | struct BitIter(u32); | ||
| 35 | |||
| 36 | impl Iterator for BitIter { | ||
| 37 | type Item = u32; | ||
| 38 | |||
| 39 | fn next(&mut self) -> Option<Self::Item> { | ||
| 40 | match self.0.trailing_zeros() { | ||
| 41 | 32 => None, | ||
| 42 | b => { | ||
| 43 | self.0 &= !(1 << b); | ||
| 44 | Some(b) | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | /// EXTI input driver | ||
| 51 | pub struct ExtiInput<'d, T: GpioPin> { | ||
| 52 | pin: Input<'d, T>, | ||
| 53 | } | ||
| 54 | |||
| 55 | impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} | ||
| 56 | |||
| 57 | impl<'d, T: GpioPin> ExtiInput<'d, T> { | ||
| 58 | pub fn new(pin: Input<'d, T>, _ch: impl Unborrow<Target = T::ExtiChannel> + 'd) -> Self { | ||
| 59 | Self { pin } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> { | ||
| 64 | type Error = Infallible; | ||
| 65 | |||
| 66 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 67 | self.pin.is_high() | ||
| 68 | } | ||
| 69 | |||
| 70 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 71 | self.pin.is_low() | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> { | ||
| 76 | type Future<'a> = ExtiInputFuture<'a>; | ||
| 77 | |||
| 78 | fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||
| 79 | ExtiInputFuture::new( | ||
| 80 | self.pin.pin.pin(), | ||
| 81 | self.pin.pin.port(), | ||
| 82 | vals::Tr::ENABLED, | ||
| 83 | vals::Tr::DISABLED, | ||
| 84 | ) | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> { | ||
| 89 | type Future<'a> = ExtiInputFuture<'a>; | ||
| 90 | |||
| 91 | fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||
| 92 | ExtiInputFuture::new( | ||
| 93 | self.pin.pin.pin(), | ||
| 94 | self.pin.pin.port(), | ||
| 95 | vals::Tr::DISABLED, | ||
| 96 | vals::Tr::ENABLED, | ||
| 97 | ) | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> { | ||
| 102 | type Future<'a> = ExtiInputFuture<'a>; | ||
| 103 | |||
| 104 | fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||
| 105 | ExtiInputFuture::new( | ||
| 106 | self.pin.pin.pin(), | ||
| 107 | self.pin.pin.port(), | ||
| 108 | vals::Tr::ENABLED, | ||
| 109 | vals::Tr::ENABLED, | ||
| 110 | ) | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | pub struct ExtiInputFuture<'a> { | ||
| 115 | pin: u8, | ||
| 116 | phantom: PhantomData<&'a mut AnyPin>, | ||
| 117 | } | ||
| 118 | |||
| 119 | impl<'a> ExtiInputFuture<'a> { | ||
| 120 | fn new(pin: u8, port: u8, rising: vals::Tr, falling: vals::Tr) -> Self { | ||
| 121 | cortex_m::interrupt::free(|_| unsafe { | ||
| 122 | let pin = pin as usize; | ||
| 123 | SYSCFG.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); | ||
| 124 | EXTI.rtsr().modify(|w| w.set_tr(pin, rising)); | ||
| 125 | EXTI.ftsr().modify(|w| w.set_tr(pin, falling)); | ||
| 126 | EXTI.pr().write(|w| w.set_pr(pin, true)); // clear pending bit | ||
| 127 | EXTI.imr().modify(|w| w.set_mr(pin, vals::Mr::UNMASKED)); | ||
| 128 | }); | ||
| 129 | |||
| 130 | Self { | ||
| 131 | pin, | ||
| 132 | phantom: PhantomData, | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | impl<'a> Drop for ExtiInputFuture<'a> { | ||
| 138 | fn drop(&mut self) { | ||
| 139 | cortex_m::interrupt::free(|_| unsafe { | ||
| 140 | let pin = self.pin as _; | ||
| 141 | EXTI.imr().modify(|w| w.set_mr(pin, vals::Mr::MASKED)); | ||
| 142 | }); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | impl<'a> Future for ExtiInputFuture<'a> { | ||
| 147 | type Output = (); | ||
| 148 | |||
| 149 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 150 | EXTI_WAKERS[self.pin as usize].register(cx.waker()); | ||
| 151 | |||
| 152 | if unsafe { EXTI.imr().read().mr(self.pin as _) == vals::Mr::MASKED } { | ||
| 153 | Poll::Ready(()) | ||
| 154 | } else { | ||
| 155 | Poll::Pending | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | use crate::interrupt; | ||
| 161 | |||
| 162 | macro_rules! impl_irq { | ||
| 163 | ($e:ident) => { | ||
| 164 | #[interrupt] | ||
| 165 | unsafe fn $e() { | ||
| 166 | on_irq() | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | foreach_exti_irq!(impl_irq); | ||
diff --git a/embassy-stm32/src/exti/v2.rs b/embassy-stm32/src/exti/v2.rs deleted file mode 100644 index 2e62331fe..000000000 --- a/embassy-stm32/src/exti/v2.rs +++ /dev/null | |||
| @@ -1,184 +0,0 @@ | |||
| 1 | use core::convert::Infallible; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::pin::Pin; | ||
| 5 | use core::task::{Context, Poll}; | ||
| 6 | use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge}; | ||
| 7 | use embassy::util::{AtomicWaker, Unborrow}; | ||
| 8 | use embedded_hal::digital::v2::InputPin; | ||
| 9 | use pac::exti::{regs, vals}; | ||
| 10 | |||
| 11 | use crate::gpio::{AnyPin, Input, Pin as GpioPin}; | ||
| 12 | use crate::pac; | ||
| 13 | use crate::pac::CORE_INDEX; | ||
| 14 | use crate::pac::{EXTI, SYSCFG}; | ||
| 15 | |||
| 16 | const EXTI_COUNT: usize = 16; | ||
| 17 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||
| 18 | static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT]; | ||
| 19 | |||
| 20 | pub 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 | |||
| 37 | struct BitIter(u32); | ||
| 38 | |||
| 39 | impl 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 | ||
| 54 | pub struct ExtiInput<'d, T: GpioPin> { | ||
| 55 | pin: Input<'d, T>, | ||
| 56 | } | ||
| 57 | |||
| 58 | impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} | ||
| 59 | |||
| 60 | impl<'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 | |||
| 66 | impl<'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 | |||
| 78 | impl<'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 | |||
| 91 | impl<'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 | |||
| 104 | impl<'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 | |||
| 117 | pub struct ExtiInputFuture<'a> { | ||
| 118 | pin: u8, | ||
| 119 | phantom: PhantomData<&'a mut AnyPin>, | ||
| 120 | } | ||
| 121 | |||
| 122 | impl<'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 | |||
| 142 | impl<'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 | |||
| 153 | impl<'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 | |||
| 173 | use crate::interrupt; | ||
| 174 | |||
| 175 | macro_rules! impl_irq { | ||
| 176 | ($e:ident) => { | ||
| 177 | #[interrupt] | ||
| 178 | unsafe fn $e() { | ||
| 179 | on_irq() | ||
| 180 | } | ||
| 181 | }; | ||
| 182 | } | ||
| 183 | |||
| 184 | foreach_exti_irq!(impl_irq); | ||
diff --git a/examples/stm32wb55/src/bin/button_exti.rs b/examples/stm32wb55/src/bin/button_exti.rs new file mode 100644 index 000000000..92a310c7a --- /dev/null +++ b/examples/stm32wb55/src/bin/button_exti.rs | |||
| @@ -0,0 +1,36 @@ | |||
| 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"] | ||
| 8 | mod example_common; | ||
| 9 | use embassy::executor::Spawner; | ||
| 10 | use embassy_stm32::dbgmcu::Dbgmcu; | ||
| 11 | use embassy_stm32::exti::ExtiInput; | ||
| 12 | use embassy_stm32::gpio::{Input, Pull}; | ||
| 13 | use embassy_stm32::Peripherals; | ||
| 14 | use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; | ||
| 15 | use example_common::*; | ||
| 16 | |||
| 17 | #[embassy::main] | ||
| 18 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | unsafe { | ||
| 22 | Dbgmcu::enable_all(); | ||
| 23 | } | ||
| 24 | |||
| 25 | let button = Input::new(p.PC4, Pull::Up); | ||
| 26 | let mut button = ExtiInput::new(button, p.EXTI4); | ||
| 27 | |||
| 28 | info!("Press the USER button..."); | ||
| 29 | |||
| 30 | loop { | ||
| 31 | button.wait_for_falling_edge().await; | ||
| 32 | info!("Pressed!"); | ||
| 33 | button.wait_for_rising_edge().await; | ||
| 34 | info!("Released!"); | ||
| 35 | } | ||
| 36 | } | ||
