diff options
| author | Ulf Lilleengen <[email protected]> | 2021-08-17 14:25:18 +0200 |
|---|---|---|
| committer | Ulf Lilleengen <[email protected]> | 2021-08-17 16:22:47 +0200 |
| commit | 4df63f5379206ebb5d09d5017e19498f0a1713af (patch) | |
| tree | bfc39f01fe74a3068e50e189375ef6afef846ead | |
| parent | 61409e2fb6798a8474d32df581e1cabfa04ec565 (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.rs | 183 | ||||
| -rw-r--r-- | examples/stm32wl55/src/bin/button_exti.rs | 34 | ||||
| -rw-r--r-- | stm32-metapac-gen/src/lib.rs | 18 |
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 @@ | |||
| 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}; | ||
| 1 | 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/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"] | ||
| 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 { 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(); |
