diff --git a/embassy-stm32-examples/Cargo.toml b/embassy-stm32-examples/Cargo.toml index af809b838..14ffcc083 100644 --- a/embassy-stm32-examples/Cargo.toml +++ b/embassy-stm32-examples/Cargo.toml @@ -38,9 +38,9 @@ f479 = ["embassy-stm32/f469"] [dependencies] embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } embassy-traits = { version = "0.1.0", path = "../embassy-traits", features = ["defmt"] } -embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } +embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", features = ["defmt", "defmt-trace"] } embassy-extras = {version = "0.1.0", path = "../embassy-extras" } -stm32f4 = { version = "0.13", features = ["stm32f429"] } +stm32f4 = { version = "0.13", features = ["stm32f429", "rt"] } defmt = "0.2.0" defmt-rtt = "0.2.0" diff --git a/embassy-stm32-examples/src/bin/button_exti.rs b/embassy-stm32-examples/src/bin/button_exti.rs new file mode 100644 index 000000000..8f6799604 --- /dev/null +++ b/embassy-stm32-examples/src/bin/button_exti.rs @@ -0,0 +1,129 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::exti::{self, ExtiInput}; +use embassy_stm32::gpio::{Input, Pull}; +use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; +use example_common::*; + +use cortex_m_rt::entry; +use pac::{interrupt, NVIC}; +use stm32f4::stm32f429 as pac; + +#[embassy::task] +async fn main_task() { + let p = embassy_stm32::Peripherals::take().unwrap(); + let button = Input::new(p.PC13, Pull::Down); + let mut button = ExtiInput::new(button, p.EXTI13); + + info!("Press the USER button..."); + + loop { + button.wait_for_rising_edge().await; + info!("Pressed!"); + button.wait_for_falling_edge().await; + info!("Released!"); + } +} + +struct ZeroClock; + +impl Clock for ZeroClock { + fn now(&self) -> u64 { + 0 + } +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); + + pp.RCC.ahb1enr.modify(|_, w| { + w.gpioaen().enabled(); + w.gpioben().enabled(); + w.gpiocen().enabled(); + w.gpioden().enabled(); + w.gpioeen().enabled(); + w.gpiofen().enabled(); + w + }); + pp.RCC.apb2enr.modify(|_, w| { + w.syscfgen().enabled(); + w + }); + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + unsafe { + NVIC::unmask(interrupt::EXTI0); + NVIC::unmask(interrupt::EXTI1); + NVIC::unmask(interrupt::EXTI2); + NVIC::unmask(interrupt::EXTI3); + NVIC::unmask(interrupt::EXTI4); + NVIC::unmask(interrupt::EXTI9_5); + NVIC::unmask(interrupt::EXTI15_10); + } + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} + +// TODO for now irq handling is done by user code using the old pac, until we figure out how interrupts work in the metapac + +#[interrupt] +unsafe fn EXTI0() { + exti::on_irq() +} + +#[interrupt] +unsafe fn EXTI1() { + exti::on_irq() +} + +#[interrupt] +unsafe fn EXTI2() { + exti::on_irq() +} + +#[interrupt] +unsafe fn EXTI3() { + exti::on_irq() +} + +#[interrupt] +unsafe fn EXTI4() { + exti::on_irq() +} + +#[interrupt] +unsafe fn EXTI9_5() { + exti::on_irq() +} + +#[interrupt] +unsafe fn EXTI15_10() { + exti::on_irq() +} diff --git a/embassy-stm32/src/chip/f429.rs b/embassy-stm32/src/chip/f429.rs index 26956e01f..db68faa5a 100644 --- a/embassy-stm32/src/chip/f429.rs +++ b/embassy-stm32/src/chip/f429.rs @@ -7,4 +7,9 @@ peripherals!( PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15, // GPIO Port C PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15, + // todo more ports + + // EXTI + EXTI0, EXTI1, EXTI2, EXTI3, EXTI4, EXTI5, EXTI6, EXTI7, EXTI8, EXTI9, EXTI10, EXTI11, EXTI12, + EXTI13, EXTI14, EXTI15, ); diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 9a12f8115..d1b5eabbf 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -1,89 +1,75 @@ +use core::convert::Infallible; use core::future::Future; -use core::mem; -use cortex_m; +use core::marker::PhantomData; +use core::pin::Pin; +use core::task::{Context, Poll}; +use embassy::traits::gpio::{WaitForAnyEdge, WaitForFallingEdge, WaitForRisingEdge}; +use embassy::util::{AtomicWaker, Unborrow}; +use embassy_extras::impl_unborrow; +use embedded_hal::digital::v2::InputPin; +use futures::future::Select; +use pac::exti::{regs, vals}; -use crate::hal::gpio; +use crate::fmt::*; +use crate::gpio::{AnyPin, Input, Pin as GpioPin}; +use crate::pac; +use crate::peripherals; -#[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f410", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479", -))] -use crate::hal::syscfg::SysCfg; +// TODO hardcoding peripheral addrs until we figure out how these are handled in the metapac +const SYSCFG: pac::syscfg_f4::Syscfg = pac::syscfg_f4::Syscfg(0x40013800 as *mut _); +const EXTI: pac::exti::Exti = pac::exti::Exti(0x40013c00 as *mut _); -#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] -use crate::hal::syscfg::SYSCFG as SysCfg; +const EXTI_COUNT: usize = 16; +const NEW_AW: AtomicWaker = AtomicWaker::new(); +static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT]; -use embassy::traits::gpio::{ - WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge, -}; -use embassy::util::InterruptFuture; +// TODO for now delegate irq handling to user code until we figure out how interrupts work in the metapac +pub unsafe fn on_irq() { + let bits = EXTI.pr().read().0; -use embedded_hal::digital::v2 as digital; + // Mask all the channels that fired. + EXTI.imr().modify(|w| w.0 &= !bits); -use crate::interrupt; + // Wake the tasks + for pin in BitIter(bits) { + EXTI_WAKERS[pin as usize].wake(); + } -pub struct ExtiPin { - pin: T, - interrupt: T::Interrupt, + // Clear pending + EXTI.pr().write_value(regs::Pr(bits)); } -impl ExtiPin { - pub fn new(mut pin: T, interrupt: T::Interrupt, syscfg: &mut SysCfg) -> Self { - cortex_m::interrupt::free(|_| { - pin.make_source(syscfg); - }); +struct BitIter(u32); - Self { pin, interrupt } +impl Iterator for BitIter { + type Item = u32; + + fn next(&mut self) -> Option { + match self.0.trailing_zeros() { + 32 => None, + b => { + self.0 &= !(1 << b); + Some(b) + } + } } } -impl digital::OutputPin for ExtiPin { - type Error = T::Error; +/// EXTI input driver +pub struct ExtiInput<'d, T: GpioPin> { + pin: Input<'d, T>, +} - fn set_low(&mut self) -> Result<(), Self::Error> { - self.pin.set_low() - } +impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} - fn set_high(&mut self) -> Result<(), Self::Error> { - self.pin.set_high() +impl<'d, T: GpioPin> ExtiInput<'d, T> { + pub fn new(pin: Input<'d, T>, _ch: impl Unborrow + 'd) -> Self { + Self { pin } } } -impl digital::StatefulOutputPin for ExtiPin { - fn is_set_low(&self) -> Result { - self.pin.is_set_low() - } - - fn is_set_high(&self) -> Result { - self.pin.is_set_high() - } -} - -impl digital::ToggleableOutputPin for ExtiPin { - type Error = T::Error; - - fn toggle(&mut self) -> Result<(), Self::Error> { - self.pin.toggle() - } -} - -impl digital::InputPin for ExtiPin { - type Error = T::Error; +impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> { + type Error = Infallible; fn is_high(&self) -> Result { self.pin.is_high() @@ -94,697 +80,139 @@ impl digital::InputPin for ExtiPin { } } -impl ExtiPin { - fn wait_for_state<'a>(&'a mut self, state: bool) -> impl Future + 'a { - async move { - let fut = InterruptFuture::new(&mut self.interrupt); - let pin = &mut self.pin; - cortex_m::interrupt::free(|_| { - pin.trigger_edge(if state { - EdgeOption::Rising - } else { - EdgeOption::Falling - }); - }); - - if (state && self.pin.is_high().unwrap_or(false)) - || (!state && self.pin.is_low().unwrap_or(false)) - { - return; - } - - fut.await; - - self.pin.clear_pending_bit(); - } - } -} - -impl ExtiPin { - fn wait_for_edge<'a>(&'a mut self, state: EdgeOption) -> impl Future + 'a { - self.pin.clear_pending_bit(); - async move { - let fut = InterruptFuture::new(&mut self.interrupt); - let pin = &mut self.pin; - cortex_m::interrupt::free(|_| { - pin.trigger_edge(state); - }); - - fut.await; - - self.pin.clear_pending_bit(); - } - } -} - -impl WaitForHigh for ExtiPin { - type Future<'a> = impl Future + 'a; - - fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_state(true) - } -} - -impl WaitForLow for ExtiPin { - type Future<'a> = impl Future + 'a; - - fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_state(false) - } -} - -/* - Irq Handler Description - EXTI0_IRQn EXTI0_IRQHandler Handler for pins connected to line 0 - EXTI1_IRQn EXTI1_IRQHandler Handler for pins connected to line 1 - EXTI2_IRQn EXTI2_IRQHandler Handler for pins connected to line 2 - EXTI3_IRQn EXTI3_IRQHandler Handler for pins connected to line 3 - EXTI4_IRQn EXTI4_IRQHandler Handler for pins connected to line 4 - EXTI9_5_IRQn EXTI9_5_IRQHandler Handler for pins connected to line 5 to 9 - EXTI15_10_IRQn EXTI15_10_IRQHandler Handler for pins connected to line 10 to 15 -*/ - -impl WaitForRisingEdge for ExtiPin { - type Future<'a> = impl Future + 'a; +impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> { + type Future<'a> = ExtiInputFuture<'a>; fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_edge(EdgeOption::Rising) + ExtiInputFuture::new( + self.pin.pin.pin(), + self.pin.pin.port(), + vals::Tr::ENABLED, + vals::Tr::DISABLED, + ) } } -impl WaitForFallingEdge for ExtiPin { - type Future<'a> = impl Future + 'a; +impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> { + type Future<'a> = ExtiInputFuture<'a>; fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_edge(EdgeOption::Falling) + ExtiInputFuture::new( + self.pin.pin.pin(), + self.pin.pin.port(), + vals::Tr::DISABLED, + vals::Tr::ENABLED, + ) } } -impl WaitForAnyEdge for ExtiPin { - type Future<'a> = impl Future + 'a; +impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> { + type Future<'a> = ExtiInputFuture<'a>; fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_edge(EdgeOption::RisingFalling) + ExtiInputFuture::new( + self.pin.pin.pin(), + self.pin.pin.port(), + vals::Tr::ENABLED, + vals::Tr::ENABLED, + ) } } -mod private { - pub trait Sealed {} +pub struct ExtiInputFuture<'a> { + pin: u8, + phantom: PhantomData<&'a mut AnyPin>, } -#[derive(Copy, Clone)] -pub enum EdgeOption { - Rising, - Falling, - RisingFalling, +impl<'a> ExtiInputFuture<'a> { + fn new(pin: u8, port: u8, rising: vals::Tr, falling: vals::Tr) -> Self { + cortex_m::interrupt::free(|_| unsafe { + let pin = pin as usize; + SYSCFG.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); + EXTI.rtsr().modify(|w| w.set_tr(pin, rising)); + EXTI.ftsr().modify(|w| w.set_tr(pin, falling)); + EXTI.pr().write(|w| w.set_pr(pin, true)); // clear pending bit + EXTI.imr().modify(|w| w.set_mr(pin, vals::Mr::UNMASKED)); + }); + + Self { + pin, + phantom: PhantomData, + } + } } -pub trait WithInterrupt: private::Sealed { - type Interrupt: interrupt::Interrupt; +impl<'a> Drop for ExtiInputFuture<'a> { + fn drop(&mut self) { + cortex_m::interrupt::free(|_| unsafe { + let pin = self.pin as _; + EXTI.imr().modify(|w| w.set_mr(pin, vals::Mr::MASKED)); + }); + } } -pub trait Instance: WithInterrupt { - fn make_source(&mut self, syscfg: &mut SysCfg); - fn clear_pending_bit(&mut self); - fn trigger_edge(&mut self, edge: EdgeOption); +impl<'a> Future for ExtiInputFuture<'a> { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + EXTI_WAKERS[self.pin as usize].register(cx.waker()); + + if unsafe { EXTI.imr().read().mr(self.pin as _) == vals::Mr::MASKED } { + Poll::Ready(()) + } else { + Poll::Pending + } + } } -macro_rules! exti { - ($set:ident, [ - $($INT:ident => $pin:ident,)+ - ]) => { - $( - impl private::Sealed for gpio::$set::$pin {} - impl WithInterrupt for gpio::$set::$pin { - type Interrupt = interrupt::$INT; +pub(crate) mod sealed { + pub trait Channel {} +} + +pub trait Channel: sealed::Channel + Sized { + fn number(&self) -> usize; + fn degrade(self) -> AnyChannel { + AnyChannel { + number: self.number() as u8, + } + } +} + +pub struct AnyChannel { + number: u8, +} +impl_unborrow!(AnyChannel); +impl sealed::Channel for AnyChannel {} +impl Channel for AnyChannel { + fn number(&self) -> usize { + self.number as usize + } +} + +macro_rules! impl_exti { + ($type:ident, $number:expr) => { + impl sealed::Channel for peripherals::$type {} + impl Channel for peripherals::$type { + fn number(&self) -> usize { + $number as usize } - - #[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f410", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479", - ))] - impl Instance for gpio::$set::$pin> { - fn make_source(&mut self, syscfg: &mut SysCfg) { - use crate::hal::gpio::ExtiPin; - self.make_interrupt_source(syscfg); - } - - fn clear_pending_bit(&mut self) { - use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg}; - - self.clear_interrupt_pending_bit(); - } - - fn trigger_edge(&mut self, edge: EdgeOption) { - use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg}; - use crate::pac::EXTI; - let mut exti: EXTI = unsafe { mem::transmute(()) }; - let edge = match edge { - EdgeOption::Falling => Edge::FALLING, - EdgeOption::Rising => Edge::RISING, - EdgeOption::RisingFalling => Edge::RISING_FALLING, - }; - self.trigger_on_edge(&mut exti, edge); - self.enable_interrupt(&mut exti); - } - } - - #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] - impl Instance for gpio::$set::$pin { - fn make_source(&mut self, syscfg: &mut SysCfg) {} - - fn clear_pending_bit(&mut self) { - use crate::hal::{ - exti::{Exti, ExtiLine, GpioLine, TriggerEdge}, - syscfg::SYSCFG, - }; - - Exti::unpend(GpioLine::from_raw_line(self.pin_number()).unwrap()); - } - - fn trigger_edge(&mut self, edge: EdgeOption) { - use crate::hal::{ - exti::{Exti, ExtiLine, GpioLine, TriggerEdge}, - syscfg::SYSCFG, - }; - - use crate::pac::EXTI; - - let edge = match edge { - EdgeOption::Falling => TriggerEdge::Falling, - EdgeOption::Rising => TriggerEdge::Rising, - EdgeOption::RisingFalling => TriggerEdge::Both, - }; - - let exti: EXTI = unsafe { mem::transmute(()) }; - let mut exti = Exti::new(exti); - let port = self.port(); - let mut syscfg: SYSCFG = unsafe { mem::transmute(()) }; - let line = GpioLine::from_raw_line(self.pin_number()).unwrap(); - exti.listen_gpio(&mut syscfg, port, line, edge); - } - } - )+ + } }; } -#[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f410", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpioa, [ - EXTI0 => PA0, - EXTI1 => PA1, - EXTI2 => PA2, - EXTI3 => PA3, - EXTI4 => PA4, - EXTI9_5 => PA5, - EXTI9_5 => PA6, - EXTI9_5 => PA7, - EXTI9_5 => PA8, - EXTI9_5 => PA9, - EXTI15_10 => PA10, - EXTI15_10 => PA11, - EXTI15_10 => PA12, - EXTI15_10 => PA13, - EXTI15_10 => PA14, - EXTI15_10 => PA15, -]); - -#[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f410", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpiob, [ - EXTI0 => PB0, - EXTI1 => PB1, - EXTI2 => PB2, - EXTI3 => PB3, - EXTI4 => PB4, - EXTI9_5 => PB5, - EXTI9_5 => PB6, - EXTI9_5 => PB7, - EXTI9_5 => PB8, - EXTI9_5 => PB9, - EXTI15_10 => PB10, - EXTI15_10 => PB11, - EXTI15_10 => PB12, - EXTI15_10 => PB13, - EXTI15_10 => PB14, - EXTI15_10 => PB15, -]); - -#[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f410", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpioc, [ - EXTI0 => PC0, - EXTI1 => PC1, - EXTI2 => PC2, - EXTI3 => PC3, - EXTI4 => PC4, - EXTI9_5 => PC5, - EXTI9_5 => PC6, - EXTI9_5 => PC7, - EXTI9_5 => PC8, - EXTI9_5 => PC9, - EXTI15_10 => PC10, - EXTI15_10 => PC11, - EXTI15_10 => PC12, - EXTI15_10 => PC13, - EXTI15_10 => PC14, - EXTI15_10 => PC15, -]); - -#[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpiod, [ - EXTI0 => PD0, - EXTI1 => PD1, - EXTI2 => PD2, - EXTI3 => PD3, - EXTI4 => PD4, - EXTI9_5 => PD5, - EXTI9_5 => PD6, - EXTI9_5 => PD7, - EXTI9_5 => PD8, - EXTI9_5 => PD9, - EXTI15_10 => PD10, - EXTI15_10 => PD11, - EXTI15_10 => PD12, - EXTI15_10 => PD13, - EXTI15_10 => PD14, - EXTI15_10 => PD15, -]); - -#[cfg(any( - feature = "stm32f401", - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpioe, [ - EXTI0 => PE0, - EXTI1 => PE1, - EXTI2 => PE2, - EXTI3 => PE3, - EXTI4 => PE4, - EXTI9_5 => PE5, - EXTI9_5 => PE6, - EXTI9_5 => PE7, - EXTI9_5 => PE8, - EXTI9_5 => PE9, - EXTI15_10 => PE10, - EXTI15_10 => PE11, - EXTI15_10 => PE12, - EXTI15_10 => PE13, - EXTI15_10 => PE14, - EXTI15_10 => PE15, -]); - -#[cfg(any( - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpiof, [ - EXTI0 => PF0, - EXTI1 => PF1, - EXTI2 => PF2, - EXTI3 => PF3, - EXTI4 => PF4, - EXTI9_5 => PF5, - EXTI9_5 => PF6, - EXTI9_5 => PF7, - EXTI9_5 => PF8, - EXTI9_5 => PF9, - EXTI15_10 => PF10, - EXTI15_10 => PF11, - EXTI15_10 => PF12, - EXTI15_10 => PF13, - EXTI15_10 => PF14, - EXTI15_10 => PF15, -]); - -#[cfg(any( - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpiog, [ - EXTI0 => PG0, - EXTI1 => PG1, - EXTI2 => PG2, - EXTI3 => PG3, - EXTI4 => PG4, - EXTI9_5 => PG5, - EXTI9_5 => PG6, - EXTI9_5 => PG7, - EXTI9_5 => PG8, - EXTI9_5 => PG9, - EXTI15_10 => PG10, - EXTI15_10 => PG11, - EXTI15_10 => PG12, - EXTI15_10 => PG13, - EXTI15_10 => PG14, - EXTI15_10 => PG15, -]); - -#[cfg(any( - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f410", - feature = "stm32f411", - feature = "stm32f412", - feature = "stm32f413", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f423", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f446", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpioh, [ - EXTI0 => PH0, - EXTI1 => PH1, - EXTI2 => PH2, - EXTI3 => PH3, - EXTI4 => PH4, - EXTI9_5 => PH5, - EXTI9_5 => PH6, - EXTI9_5 => PH7, - EXTI9_5 => PH8, - EXTI9_5 => PH9, - EXTI15_10 => PH10, - EXTI15_10 => PH11, - EXTI15_10 => PH12, - EXTI15_10 => PH13, - EXTI15_10 => PH14, - EXTI15_10 => PH15, -]); - -#[cfg(any(feature = "stm32f401"))] -exti!(gpioh, [ - EXTI0 => PH0, - EXTI1 => PH1, -]); - -#[cfg(any( - feature = "stm32f405", - feature = "stm32f407", - feature = "stm32f415", - feature = "stm32f417", - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpioi, [ - EXTI0 => PI0, - EXTI1 => PI1, - EXTI2 => PI2, - EXTI3 => PI3, - EXTI4 => PI4, - EXTI9_5 => PI5, - EXTI9_5 => PI6, - EXTI9_5 => PI7, - EXTI9_5 => PI8, - EXTI9_5 => PI9, - EXTI15_10 => PI10, - EXTI15_10 => PI11, - EXTI15_10 => PI12, - EXTI15_10 => PI13, - EXTI15_10 => PI14, - EXTI15_10 => PI15, -]); - -#[cfg(any( - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpioj, [ - EXTI0 => PJ0, - EXTI1 => PJ1, - EXTI2 => PJ2, - EXTI3 => PJ3, - EXTI4 => PJ4, - EXTI9_5 => PJ5, - EXTI9_5 => PJ6, - EXTI9_5 => PJ7, - EXTI9_5 => PJ8, - EXTI9_5 => PJ9, - EXTI15_10 => PJ10, - EXTI15_10 => PJ11, - EXTI15_10 => PJ12, - EXTI15_10 => PJ13, - EXTI15_10 => PJ14, - EXTI15_10 => PJ15, -]); - -#[cfg(any( - feature = "stm32f427", - feature = "stm32f429", - feature = "stm32f437", - feature = "stm32f439", - feature = "stm32f469", - feature = "stm32f479" -))] -exti!(gpiok, [ - EXTI0 => PK0, - EXTI1 => PK1, - EXTI2 => PK2, - EXTI3 => PK3, - EXTI4 => PK4, - EXTI9_5 => PK5, - EXTI9_5 => PK6, - EXTI9_5 => PK7, -]); - -#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] -exti!(gpioa, [ - EXTI0_1 => PA0, - EXTI0_1 => PA1, - EXTI2_3 => PA2, - EXTI2_3 => PA3, - EXTI4_15 => PA4, - EXTI4_15 => PA5, - EXTI4_15 => PA6, - EXTI4_15 => PA7, - EXTI4_15 => PA8, - EXTI4_15 => PA9, - EXTI4_15 => PA10, - EXTI4_15 => PA11, - EXTI4_15 => PA12, - EXTI4_15 => PA13, - EXTI4_15 => PA14, - EXTI4_15 => PA15, -]); - -#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] -exti!(gpiob, [ - EXTI0_1 => PB0, - EXTI0_1 => PB1, - EXTI2_3 => PB2, - EXTI2_3 => PB3, - EXTI4_15 => PB4, - EXTI4_15 => PB5, - EXTI4_15 => PB6, - EXTI4_15 => PB7, - EXTI4_15 => PB8, - EXTI4_15 => PB9, - EXTI4_15 => PB10, - EXTI4_15 => PB11, - EXTI4_15 => PB12, - EXTI4_15 => PB13, - EXTI4_15 => PB14, - EXTI4_15 => PB15, -]); - -#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] -exti!(gpioc, [ - EXTI0_1 => PC0, - EXTI0_1 => PC1, - EXTI2_3 => PC2, - EXTI2_3 => PC3, - EXTI4_15 => PC4, - EXTI4_15 => PC5, - EXTI4_15 => PC6, - EXTI4_15 => PC7, - EXTI4_15 => PC8, - EXTI4_15 => PC9, - EXTI4_15 => PC10, - EXTI4_15 => PC11, - EXTI4_15 => PC12, - EXTI4_15 => PC13, - EXTI4_15 => PC14, - EXTI4_15 => PC15, -]); - -#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] -exti!(gpiod, [ - EXTI0_1 => PD0, - EXTI0_1 => PD1, - EXTI2_3 => PD2, - EXTI2_3 => PD3, - EXTI4_15 => PD4, - EXTI4_15 => PD5, - EXTI4_15 => PD6, - EXTI4_15 => PD7, - EXTI4_15 => PD8, - EXTI4_15 => PD9, - EXTI4_15 => PD10, - EXTI4_15 => PD11, - EXTI4_15 => PD12, - EXTI4_15 => PD13, - EXTI4_15 => PD14, - EXTI4_15 => PD15, -]); - -#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] -exti!(gpioe, [ - EXTI0_1 => PE0, - EXTI0_1 => PE1, - EXTI2_3 => PE2, - EXTI2_3 => PE3, - EXTI4_15 => PE4, - EXTI4_15 => PE5, - EXTI4_15 => PE6, - EXTI4_15 => PE7, - EXTI4_15 => PE8, - EXTI4_15 => PE9, - EXTI4_15 => PE10, - EXTI4_15 => PE11, - EXTI4_15 => PE12, - EXTI4_15 => PE13, - EXTI4_15 => PE14, - EXTI4_15 => PE15, -]); - -#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] -exti!(gpioh, [ - EXTI0_1 => PH0, - EXTI0_1 => PH1, - EXTI4_15 => PH9, - EXTI4_15 => PH10, -]); +impl_exti!(EXTI0, 0); +impl_exti!(EXTI1, 1); +impl_exti!(EXTI2, 2); +impl_exti!(EXTI3, 3); +impl_exti!(EXTI4, 4); +impl_exti!(EXTI5, 5); +impl_exti!(EXTI6, 6); +impl_exti!(EXTI7, 7); +impl_exti!(EXTI8, 8); +impl_exti!(EXTI9, 9); +impl_exti!(EXTI10, 10); +impl_exti!(EXTI11, 11); +impl_exti!(EXTI12, 12); +impl_exti!(EXTI13, 13); +impl_exti!(EXTI14, 14); +impl_exti!(EXTI15, 15); diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index f963400a7..e0e6cc477 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -1,8 +1,6 @@ use core::convert::Infallible; -use core::hint::unreachable_unchecked; use core::marker::PhantomData; - -use embassy::util::PeripheralBorrow; +use embassy::util::Unborrow; use embassy_extras::{impl_unborrow, unborrow}; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use gpio::vals; @@ -10,13 +8,6 @@ use gpio::vals; use crate::pac::gpio_v2 as gpio; use crate::peripherals; -/// A GPIO port with up to 16 pins. -#[derive(Debug, Eq, PartialEq)] -pub enum Port { - PortA, - PortB, -} - /// Pull setting for an input. #[derive(Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -33,7 +24,7 @@ pub struct Input<'d, T: Pin> { } impl<'d, T: Pin> Input<'d, T> { - pub fn new(pin: impl PeripheralBorrow + 'd, pull: Pull) -> Self { + pub fn new(pin: impl Unborrow + 'd, pull: Pull) -> Self { unborrow!(pin); cortex_m::interrupt::free(|_| unsafe { @@ -94,7 +85,7 @@ pub struct Output<'d, T: Pin> { } impl<'d, T: Pin> Output<'d, T> { - pub fn new(pin: impl PeripheralBorrow + 'd, initial_output: Level) -> Self { + pub fn new(pin: impl Unborrow + 'd, initial_output: Level) -> Self { unborrow!(pin); match initial_output { @@ -173,6 +164,7 @@ pub(crate) mod sealed { #[inline] fn block(&self) -> gpio::Gpio { + // TODO hardcoding peripheral addrs until we figure out how these are handled in the metapac let p = 0x4002_0000 + (self._port() as u32) * 0x400; gpio::Gpio(p as *mut u8) } @@ -181,9 +173,8 @@ pub(crate) mod sealed { #[inline] fn set_high(&self) { unsafe { - self.block() - .bsrr() - .write(|w| w.set_bs(self._pin() as _, true)); + let n = self._pin() as _; + self.block().bsrr().write(|w| w.set_bs(n, true)); } } @@ -191,9 +182,8 @@ pub(crate) mod sealed { #[inline] fn set_low(&self) { unsafe { - self.block() - .bsrr() - .write(|w| w.set_br(self._pin() as _, true)); + let n = self._pin() as _; + self.block().bsrr().write(|w| w.set_br(n, true)); } } } @@ -202,6 +192,8 @@ pub(crate) mod sealed { } pub trait Pin: sealed::Pin + Sized { + type ExtiChannel: crate::exti::Channel; + /// Number of the pin within the port (0..31) #[inline] fn pin(&self) -> u8 { @@ -210,12 +202,8 @@ pub trait Pin: sealed::Pin + Sized { /// Port of the pin #[inline] - fn port(&self) -> Port { - match self.pin_port() / 16 { - 0 => Port::PortA, - 1 => Port::PortB, - _ => unsafe { unreachable_unchecked() }, - } + fn port(&self) -> u8 { + self._port() } #[inline] @@ -245,7 +233,9 @@ impl AnyPin { } impl_unborrow!(AnyPin); -impl Pin for AnyPin {} +impl Pin for AnyPin { + type ExtiChannel = crate::exti::AnyChannel; +} impl sealed::Pin for AnyPin { #[inline] fn pin_port(&self) -> u8 { @@ -288,31 +278,20 @@ impl OptionalPin for T { } } -// Uninhabited enum, so it's actually impossible to create a DummyPin value. -#[doc(hidden)] -pub enum DummyPin {} -impl Pin for DummyPin {} -impl sealed::Pin for DummyPin { - #[inline] - fn pin_port(&self) -> u8 { - unreachable!() - } -} - #[derive(Clone, Copy, Debug)] pub struct NoPin; impl_unborrow!(NoPin); impl sealed::OptionalPin for NoPin {} impl OptionalPin for NoPin { - type Pin = DummyPin; + type Pin = AnyPin; #[inline] - fn pin(&self) -> Option<&DummyPin> { + fn pin(&self) -> Option<&AnyPin> { None } #[inline] - fn pin_mut(&mut self) -> Option<&mut DummyPin> { + fn pin_mut(&mut self) -> Option<&mut AnyPin> { None } } @@ -320,8 +299,10 @@ impl OptionalPin for NoPin { // ==================== macro_rules! impl_pin { - ($type:ident, $port_num:expr, $pin_num:expr) => { - impl Pin for peripherals::$type {} + ($type:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { + impl Pin for peripherals::$type { + type ExtiChannel = peripherals::$exti_ch; + } impl sealed::Pin for peripherals::$type { #[inline] fn pin_port(&self) -> u8 { @@ -331,51 +312,51 @@ macro_rules! impl_pin { }; } -impl_pin!(PA0, 0, 0); -impl_pin!(PA1, 0, 1); -impl_pin!(PA2, 0, 2); -impl_pin!(PA3, 0, 3); -impl_pin!(PA4, 0, 4); -impl_pin!(PA5, 0, 5); -impl_pin!(PA6, 0, 6); -impl_pin!(PA7, 0, 7); -impl_pin!(PA8, 0, 8); -impl_pin!(PA9, 0, 9); -impl_pin!(PA10, 0, 10); -impl_pin!(PA11, 0, 11); -impl_pin!(PA12, 0, 12); -impl_pin!(PA13, 0, 13); -impl_pin!(PA14, 0, 14); -impl_pin!(PA15, 0, 15); -impl_pin!(PB0, 1, 0); -impl_pin!(PB1, 1, 1); -impl_pin!(PB2, 1, 2); -impl_pin!(PB3, 1, 3); -impl_pin!(PB4, 1, 4); -impl_pin!(PB5, 1, 5); -impl_pin!(PB6, 1, 6); -impl_pin!(PB7, 1, 7); -impl_pin!(PB8, 1, 8); -impl_pin!(PB9, 1, 9); -impl_pin!(PB10, 1, 10); -impl_pin!(PB11, 1, 11); -impl_pin!(PB12, 1, 12); -impl_pin!(PB13, 1, 13); -impl_pin!(PB14, 1, 14); -impl_pin!(PB15, 1, 15); -impl_pin!(PC0, 2, 0); -impl_pin!(PC1, 2, 1); -impl_pin!(PC2, 2, 2); -impl_pin!(PC3, 2, 3); -impl_pin!(PC4, 2, 4); -impl_pin!(PC5, 2, 5); -impl_pin!(PC6, 2, 6); -impl_pin!(PC7, 2, 7); -impl_pin!(PC8, 2, 8); -impl_pin!(PC9, 2, 9); -impl_pin!(PC10, 2, 10); -impl_pin!(PC11, 2, 11); -impl_pin!(PC12, 2, 12); -impl_pin!(PC13, 2, 13); -impl_pin!(PC14, 2, 14); -impl_pin!(PC15, 2, 15); +impl_pin!(PA0, 0, 0, EXTI0); +impl_pin!(PA1, 0, 1, EXTI1); +impl_pin!(PA2, 0, 2, EXTI2); +impl_pin!(PA3, 0, 3, EXTI3); +impl_pin!(PA4, 0, 4, EXTI4); +impl_pin!(PA5, 0, 5, EXTI5); +impl_pin!(PA6, 0, 6, EXTI6); +impl_pin!(PA7, 0, 7, EXTI7); +impl_pin!(PA8, 0, 8, EXTI8); +impl_pin!(PA9, 0, 9, EXTI9); +impl_pin!(PA10, 0, 10, EXTI10); +impl_pin!(PA11, 0, 11, EXTI11); +impl_pin!(PA12, 0, 12, EXTI12); +impl_pin!(PA13, 0, 13, EXTI13); +impl_pin!(PA14, 0, 14, EXTI14); +impl_pin!(PA15, 0, 15, EXTI15); +impl_pin!(PB0, 1, 0, EXTI0); +impl_pin!(PB1, 1, 1, EXTI1); +impl_pin!(PB2, 1, 2, EXTI2); +impl_pin!(PB3, 1, 3, EXTI3); +impl_pin!(PB4, 1, 4, EXTI4); +impl_pin!(PB5, 1, 5, EXTI5); +impl_pin!(PB6, 1, 6, EXTI6); +impl_pin!(PB7, 1, 7, EXTI7); +impl_pin!(PB8, 1, 8, EXTI8); +impl_pin!(PB9, 1, 9, EXTI9); +impl_pin!(PB10, 1, 10, EXTI10); +impl_pin!(PB11, 1, 11, EXTI11); +impl_pin!(PB12, 1, 12, EXTI12); +impl_pin!(PB13, 1, 13, EXTI13); +impl_pin!(PB14, 1, 14, EXTI14); +impl_pin!(PB15, 1, 15, EXTI15); +impl_pin!(PC0, 2, 0, EXTI0); +impl_pin!(PC1, 2, 1, EXTI1); +impl_pin!(PC2, 2, 2, EXTI2); +impl_pin!(PC3, 2, 3, EXTI3); +impl_pin!(PC4, 2, 4, EXTI4); +impl_pin!(PC5, 2, 5, EXTI5); +impl_pin!(PC6, 2, 6, EXTI6); +impl_pin!(PC7, 2, 7, EXTI7); +impl_pin!(PC8, 2, 8, EXTI8); +impl_pin!(PC9, 2, 9, EXTI9); +impl_pin!(PC10, 2, 10, EXTI10); +impl_pin!(PC11, 2, 11, EXTI11); +impl_pin!(PC12, 2, 12, EXTI12); +impl_pin!(PC13, 2, 13, EXTI13); +impl_pin!(PC14, 2, 14, EXTI14); +impl_pin!(PC15, 2, 15, EXTI15); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 58a846229..da266f75d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -28,8 +28,9 @@ pub mod fmt; mod chip; pub use chip::{peripherals, Peripherals}; +pub mod exti; pub mod gpio; -//pub mod exti; +//pub mod rtc; //pub mod interrupt; pub(crate) use stm32_metapac as pac;