From 316be179af500fdf31606f085adf77c6879a396d Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 24 May 2023 17:29:56 -0500 Subject: [PATCH 1/2] stm32: move to bind_interrupts disable lora functionality for now --- ci.sh | 3 +- embassy-stm32/src/dcmi.rs | 98 +- embassy-stm32/src/eth/mod.rs | 2 +- embassy-stm32/src/eth/v1/mod.rs | 53 +- embassy-stm32/src/eth/v2/mod.rs | 53 +- embassy-stm32/src/i2c/v1.rs | 13 +- embassy-stm32/src/i2c/v2.rs | 49 +- embassy-stm32/src/interrupt.rs | 4 - embassy-stm32/src/lib.rs | 36 +- embassy-stm32/src/sdmmc/mod.rs | 91 +- embassy-stm32/src/time_driver.rs | 3 +- embassy-stm32/src/tl_mbox/mod.rs | 58 +- embassy-stm32/src/usart/buffered.rs | 157 +-- embassy-stm32/src/usart/mod.rs | 164 +-- embassy-stm32/src/usb/usb.rs | 180 ++-- embassy-stm32/src/usb_otg/usb.rs | 963 +++++++++--------- examples/stm32f1/src/bin/usb_serial.rs | 9 +- examples/stm32f3/src/bin/usart_dma.rs | 9 +- examples/stm32f3/src/bin/usb_serial.rs | 9 +- examples/stm32f4/src/bin/i2c.rs | 9 +- examples/stm32f4/src/bin/sdmmc.rs | 10 +- examples/stm32f4/src/bin/usart.rs | 9 +- examples/stm32f4/src/bin/usart_buffered.rs | 9 +- examples/stm32f4/src/bin/usart_dma.rs | 9 +- examples/stm32f4/src/bin/usb_ethernet.rs | 9 +- examples/stm32f4/src/bin/usb_serial.rs | 9 +- examples/stm32f7/src/bin/eth.rs | 9 +- examples/stm32f7/src/bin/sdmmc.rs | 10 +- examples/stm32f7/src/bin/usart_dma.rs | 9 +- examples/stm32f7/src/bin/usb_serial.rs | 9 +- examples/stm32h5/src/bin/eth.rs | 9 +- examples/stm32h5/src/bin/i2c.rs | 9 +- examples/stm32h5/src/bin/usart.rs | 9 +- examples/stm32h5/src/bin/usart_dma.rs | 9 +- examples/stm32h5/src/bin/usart_split.rs | 9 +- examples/stm32h5/src/bin/usb_serial.rs | 9 +- examples/stm32h7/src/bin/camera.rs | 14 +- examples/stm32h7/src/bin/eth.rs | 9 +- examples/stm32h7/src/bin/eth_client.rs | 9 +- examples/stm32h7/src/bin/i2c.rs | 9 +- examples/stm32h7/src/bin/sdmmc.rs | 10 +- examples/stm32h7/src/bin/usart.rs | 9 +- examples/stm32h7/src/bin/usart_dma.rs | 9 +- examples/stm32h7/src/bin/usart_split.rs | 9 +- examples/stm32h7/src/bin/usb_serial.rs | 9 +- examples/stm32l0/src/bin/usart_dma.rs | 9 +- examples/stm32l0/src/bin/usart_irq.rs | 9 +- examples/stm32l4/src/bin/i2c.rs | 9 +- .../stm32l4/src/bin/i2c_blocking_async.rs | 9 +- examples/stm32l4/src/bin/i2c_dma.rs | 9 +- examples/stm32l4/src/bin/usart.rs | 9 +- examples/stm32l4/src/bin/usart_dma.rs | 9 +- examples/stm32l4/src/bin/usb_serial.rs | 9 +- examples/stm32l5/src/bin/usb_ethernet.rs | 9 +- examples/stm32l5/src/bin/usb_hid_mouse.rs | 9 +- examples/stm32l5/src/bin/usb_serial.rs | 9 +- examples/stm32u5/src/bin/usb_serial.rs | 9 +- examples/stm32wb/src/bin/tl_mbox.rs | 12 +- examples/stm32wb/src/bin/tl_mbox_tx_rx.rs | 12 +- tests/stm32/src/bin/sdmmc.rs | 23 +- tests/stm32/src/bin/usart.rs | 52 +- tests/stm32/src/bin/usart_dma.rs | 85 +- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 79 +- 63 files changed, 1395 insertions(+), 1172 deletions(-) delete mode 100644 embassy-stm32/src/interrupt.rs diff --git a/ci.sh b/ci.sh index d2bf4df9..106689d0 100755 --- a/ci.sh +++ b/ci.sh @@ -112,7 +112,6 @@ cargo batch \ --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ - --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 --out-dir out/examples/boot/nrf --bin b \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns --out-dir out/examples/boot/nrf --bin b \ --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/boot/rp --bin b \ @@ -143,6 +142,8 @@ cargo batch \ $BUILD_EXTRA +# --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ + function run_elf { echo Running target=$1 elf=$2 STATUSCODE=$( diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index c19be86c..5f3fc6a9 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -1,4 +1,5 @@ use core::future::poll_fn; +use core::marker::PhantomData; use core::task::Poll; use embassy_hal_common::{into_ref, PeripheralRef}; @@ -8,7 +9,31 @@ use crate::dma::Transfer; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::interrupt::{Interrupt, InterruptExt}; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let ris = crate::pac::DCMI.ris().read(); + if ris.err_ris() { + trace!("DCMI IRQ: Error."); + crate::pac::DCMI.ier().modify(|ier| ier.set_err_ie(false)); + } + if ris.ovr_ris() { + trace!("DCMI IRQ: Overrun."); + crate::pac::DCMI.ier().modify(|ier| ier.set_ovr_ie(false)); + } + if ris.frame_ris() { + trace!("DCMI IRQ: Frame captured."); + crate::pac::DCMI.ier().modify(|ier| ier.set_frame_ie(false)); + } + STATE.waker.wake(); + } +} /// The level on the VSync pin when the data is not valid on the parallel interface. #[derive(Clone, Copy, PartialEq)] @@ -94,7 +119,7 @@ where pub fn new_8bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -108,17 +133,17 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7); config_pins!(v_sync, h_sync, pixclk); - Self::new_inner(peri, dma, irq, config, false, 0b00) + Self::new_inner(peri, dma, config, false, 0b00) } pub fn new_10bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -134,17 +159,17 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); config_pins!(v_sync, h_sync, pixclk); - Self::new_inner(peri, dma, irq, config, false, 0b01) + Self::new_inner(peri, dma, config, false, 0b01) } pub fn new_12bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -162,17 +187,17 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); config_pins!(v_sync, h_sync, pixclk); - Self::new_inner(peri, dma, irq, config, false, 0b10) + Self::new_inner(peri, dma, config, false, 0b10) } pub fn new_14bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -192,17 +217,17 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); config_pins!(v_sync, h_sync, pixclk); - Self::new_inner(peri, dma, irq, config, false, 0b11) + Self::new_inner(peri, dma, config, false, 0b11) } pub fn new_es_8bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -214,17 +239,17 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7); config_pins!(pixclk); - Self::new_inner(peri, dma, irq, config, true, 0b00) + Self::new_inner(peri, dma, config, true, 0b00) } pub fn new_es_10bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -238,17 +263,17 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); config_pins!(pixclk); - Self::new_inner(peri, dma, irq, config, true, 0b01) + Self::new_inner(peri, dma, config, true, 0b01) } pub fn new_es_12bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -264,17 +289,17 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); config_pins!(pixclk); - Self::new_inner(peri, dma, irq, config, true, 0b10) + Self::new_inner(peri, dma, config, true, 0b10) } pub fn new_es_14bit( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, d0: impl Peripheral

> + 'd, d1: impl Peripheral

> + 'd, d2: impl Peripheral

> + 'd, @@ -292,17 +317,16 @@ where pixclk: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(peri, dma, irq); + into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); config_pins!(pixclk); - Self::new_inner(peri, dma, irq, config, true, 0b11) + Self::new_inner(peri, dma, config, true, 0b11) } fn new_inner( peri: PeripheralRef<'d, T>, dma: PeripheralRef<'d, Dma>, - irq: PeripheralRef<'d, T::Interrupt>, config: Config, use_embedded_synchronization: bool, edm: u8, @@ -322,30 +346,12 @@ where }); } - irq.set_handler(Self::on_interrupt); - irq.unpend(); - irq.enable(); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); Self { inner: peri, dma } } - unsafe fn on_interrupt(_: *mut ()) { - let ris = crate::pac::DCMI.ris().read(); - if ris.err_ris() { - trace!("DCMI IRQ: Error."); - crate::pac::DCMI.ier().modify(|ier| ier.set_err_ie(false)); - } - if ris.ovr_ris() { - trace!("DCMI IRQ: Overrun."); - crate::pac::DCMI.ier().modify(|ier| ier.set_ovr_ie(false)); - } - if ris.frame_ris() { - trace!("DCMI IRQ: Frame captured."); - crate::pac::DCMI.ier().modify(|ier| ier.set_frame_ie(false)); - } - STATE.waker.wake(); - } - unsafe fn toggle(enable: bool) { crate::pac::DCMI.cr().modify(|r| { r.set_enable(enable); diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index e1d7a09b..4989e17c 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -11,7 +11,7 @@ use core::task::Context; use embassy_net_driver::{Capabilities, LinkState}; use embassy_sync::waitqueue::AtomicWaker; -pub use self::_version::*; +pub use self::_version::{InterruptHandler, *}; #[allow(unused)] const MTU: usize = 1514; diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 9c0f4d66..8ef2c358 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -5,7 +5,7 @@ mod tx_desc; use core::sync::atomic::{fence, Ordering}; -use embassy_cortex_m::interrupt::InterruptExt; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_hal_common::{into_ref, PeripheralRef}; use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; @@ -19,7 +19,30 @@ use crate::pac::AFIO; #[cfg(any(eth_v1b, eth_v1c))] use crate::pac::SYSCFG; use crate::pac::{ETH, RCC}; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler {} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + WAKER.wake(); + + // TODO: Check and clear more flags + unsafe { + let dma = ETH.ethernet_dma(); + + dma.dmasr().modify(|w| { + w.set_ts(true); + w.set_rs(true); + w.set_nis(true); + }); + // Delay two peripheral's clock + dma.dmasr().read(); + dma.dmasr().read(); + } + } +} pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, @@ -77,7 +100,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { pub fn new( queue: &'d mut PacketQueue, peri: impl Peripheral

+ 'd, - interrupt: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding + 'd, ref_clk: impl Peripheral

> + 'd, mdio: impl Peripheral

> + 'd, mdc: impl Peripheral

> + 'd, @@ -91,7 +114,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { mac_addr: [u8; 6], phy_addr: u8, ) -> Self { - into_ref!(peri, interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); + into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); unsafe { // Enable the necessary Clocks @@ -244,30 +267,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { P::phy_reset(&mut this); P::phy_init(&mut this); - interrupt.set_handler(Self::on_interrupt); - interrupt.enable(); + interrupt::ETH::steal().unpend(); + interrupt::ETH::steal().enable(); this } } - - fn on_interrupt(_cx: *mut ()) { - WAKER.wake(); - - // TODO: Check and clear more flags - unsafe { - let dma = ETH.ethernet_dma(); - - dma.dmasr().modify(|w| { - w.set_ts(true); - w.set_rs(true); - w.set_nis(true); - }); - // Delay two peripheral's clock - dma.dmasr().read(); - dma.dmasr().read(); - } - } } unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index d49b1f76..b56c3e8a 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -2,7 +2,7 @@ mod descriptors; use core::sync::atomic::{fence, Ordering}; -use embassy_cortex_m::interrupt::InterruptExt; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_hal_common::{into_ref, PeripheralRef}; pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; @@ -10,7 +10,30 @@ use super::*; use crate::gpio::sealed::{AFType, Pin as _}; use crate::gpio::{AnyPin, Speed}; use crate::pac::ETH; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler {} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + WAKER.wake(); + + // TODO: Check and clear more flags + unsafe { + let dma = ETH.ethernet_dma(); + + dma.dmacsr().modify(|w| { + w.set_ti(true); + w.set_ri(true); + w.set_nis(true); + }); + // Delay two peripheral's clock + dma.dmacsr().read(); + dma.dmacsr().read(); + } + } +} const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet @@ -41,7 +64,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { pub fn new( queue: &'d mut PacketQueue, peri: impl Peripheral

+ 'd, - interrupt: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding + 'd, ref_clk: impl Peripheral

> + 'd, mdio: impl Peripheral

> + 'd, mdc: impl Peripheral

> + 'd, @@ -55,7 +78,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { mac_addr: [u8; 6], phy_addr: u8, ) -> Self { - into_ref!(peri, interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); + into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); unsafe { // Enable the necessary Clocks @@ -215,30 +238,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { P::phy_reset(&mut this); P::phy_init(&mut this); - interrupt.set_handler(Self::on_interrupt); - interrupt.enable(); + interrupt::ETH::steal().unpend(); + interrupt::ETH::steal().enable(); this } } - - fn on_interrupt(_cx: *mut ()) { - WAKER.wake(); - - // TODO: Check and clear more flags - unsafe { - let dma = ETH.ethernet_dma(); - - dma.dmacsr().modify(|w| { - w.set_ti(true); - w.set_ri(true); - w.set_nis(true); - }); - // Delay two peripheral's clock - dma.dmacsr().read(); - dma.dmacsr().read(); - } - } } unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 4b47f0eb..b9be2e58 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -9,7 +9,16 @@ use crate::gpio::Pull; use crate::i2c::{Error, Instance, SclPin, SdaPin}; use crate::pac::i2c; use crate::time::Hertz; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() {} +} #[non_exhaustive] #[derive(Copy, Clone)] @@ -48,7 +57,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { _peri: impl Peripheral

+ 'd, scl: impl Peripheral

> + 'd, sda: impl Peripheral

> + 'd, - _irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, freq: Hertz, diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 853bc128..642ddc18 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1,7 +1,9 @@ use core::cmp; use core::future::poll_fn; +use core::marker::PhantomData; use core::task::Poll; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_embedded_hal::SetConfig; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; @@ -11,10 +13,30 @@ use crate::dma::{NoDma, Transfer}; use crate::gpio::sealed::AFType; use crate::gpio::Pull; use crate::i2c::{Error, Instance, SclPin, SdaPin}; -use crate::interrupt::InterruptExt; use crate::pac::i2c; use crate::time::Hertz; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let regs = T::regs(); + let isr = regs.isr().read(); + + if isr.tcr() || isr.tc() { + T::state().waker.wake(); + } + // The flag can only be cleared by writting to nbytes, we won't do that here, so disable + // the interrupt + critical_section::with(|_| { + regs.cr1().modify(|w| w.set_tcie(false)); + }); + } +} #[non_exhaustive] #[derive(Copy, Clone)] @@ -56,13 +78,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { peri: impl Peripheral

+ 'd, scl: impl Peripheral

> + 'd, sda: impl Peripheral

> + 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, freq: Hertz, config: Config, ) -> Self { - into_ref!(peri, irq, scl, sda, tx_dma, rx_dma); + into_ref!(peri, scl, sda, tx_dma, rx_dma); T::enable(); T::reset(); @@ -111,9 +133,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { }); } - irq.set_handler(Self::on_interrupt); - irq.unpend(); - irq.enable(); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); Self { _peri: peri, @@ -122,20 +143,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } - unsafe fn on_interrupt(_: *mut ()) { - let regs = T::regs(); - let isr = regs.isr().read(); - - if isr.tcr() || isr.tc() { - T::state().waker.wake(); - } - // The flag can only be cleared by writting to nbytes, we won't do that here, so disable - // the interrupt - critical_section::with(|_| { - regs.cr1().modify(|w| w.set_tcie(false)); - }); - } - fn master_stop(&mut self) { unsafe { T::regs().cr2().write(|w| w.set_stop(true)); diff --git a/embassy-stm32/src/interrupt.rs b/embassy-stm32/src/interrupt.rs deleted file mode 100644 index b66e4c7e..00000000 --- a/embassy-stm32/src/interrupt.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub use critical_section::{CriticalSection, Mutex}; -pub use embassy_cortex_m::interrupt::*; - -pub use crate::_generated::interrupt::*; diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 1920e264..6722658c 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -6,7 +6,6 @@ pub mod fmt; include!(concat!(env!("OUT_DIR"), "/_macros.rs")); // Utilities -pub mod interrupt; pub mod time; mod traits; @@ -73,6 +72,41 @@ pub(crate) mod _generated { include!(concat!(env!("OUT_DIR"), "/_generated.rs")); } +pub mod interrupt { + //! Interrupt definitions and macros to bind them. + pub use cortex_m::interrupt::{CriticalSection, Mutex}; + pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; + + pub use crate::_generated::interrupt::*; + + /// Macro to bind interrupts to handlers. + /// + /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) + /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to + /// prove at compile-time that the right interrupts have been bound. + // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. + #[macro_export] + macro_rules! bind_interrupts { + ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + $vis struct $name; + + $( + #[allow(non_snake_case)] + #[no_mangle] + unsafe extern "C" fn $irq() { + $( + <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); + )* + } + + $( + unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} + )* + )* + }; + } +} + // Reexports pub use _generated::{peripherals, Peripherals}; pub use embassy_cortex_m::executor; diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index be788f1b..be03a1ba 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -2,6 +2,7 @@ use core::default::Default; use core::future::poll_fn; +use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::Poll; @@ -17,7 +18,36 @@ use crate::interrupt::{Interrupt, InterruptExt}; use crate::pac::sdmmc::Sdmmc as RegBlock; use crate::rcc::RccPeripheral; use crate::time::Hertz; -use crate::{peripherals, Peripheral}; +use crate::{interrupt, peripherals, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl InterruptHandler { + fn data_interrupts(enable: bool) { + let regs = T::regs(); + // NOTE(unsafe) Atomic write + unsafe { + regs.maskr().write(|w| { + w.set_dcrcfailie(enable); + w.set_dtimeoutie(enable); + w.set_dataendie(enable); + + #[cfg(sdmmc_v2)] + w.set_dabortie(enable); + }); + } + } +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + Self::data_interrupts(false); + T::state().wake(); + } +} /// Frequency used for SD Card initialization. Must be no higher than 400 kHz. const SD_INIT_FREQ: Hertz = Hertz(400_000); @@ -223,7 +253,6 @@ impl Default for Config { /// Sdmmc device pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma = NoDma> { _peri: PeripheralRef<'d, T>, - irq: PeripheralRef<'d, T::Interrupt>, #[allow(unused)] dma: PeripheralRef<'d, Dma>, @@ -247,7 +276,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma = NoDma> { impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, dma: impl Peripheral

+ 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, @@ -268,7 +297,6 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { Self::new_inner( sdmmc, - irq, dma, clk.map_into(), cmd.map_into(), @@ -282,7 +310,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { pub fn new_4bit( sdmmc: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, dma: impl Peripheral

+ 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, @@ -312,7 +340,6 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { Self::new_inner( sdmmc, - irq, dma, clk.map_into(), cmd.map_into(), @@ -329,7 +356,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, d0: impl Peripheral

> + 'd, @@ -349,7 +376,6 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { Self::new_inner( sdmmc, - irq, NoDma.into_ref(), clk.map_into(), cmd.map_into(), @@ -363,7 +389,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { pub fn new_4bit( sdmmc: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, d0: impl Peripheral

> + 'd, @@ -392,7 +418,6 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { Self::new_inner( sdmmc, - irq, NoDma.into_ref(), clk.map_into(), cmd.map_into(), @@ -408,7 +433,6 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { fn new_inner( sdmmc: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, clk: PeripheralRef<'d, AnyPin>, cmd: PeripheralRef<'d, AnyPin>, @@ -418,14 +442,13 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { d3: Option>, config: Config, ) -> Self { - into_ref!(sdmmc, irq, dma); + into_ref!(sdmmc, dma); T::enable(); T::reset(); - irq.set_handler(Self::on_interrupt); - irq.unpend(); - irq.enable(); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); let regs = T::regs(); unsafe { @@ -451,7 +474,6 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Self { _peri: sdmmc, - irq, dma, clk, @@ -691,7 +713,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); let transfer = self.prepare_datapath_read(&mut status, 64, 6); - Self::data_interrupts(true); + InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 let res = poll_fn(|cx| { @@ -767,7 +789,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); let transfer = self.prepare_datapath_read(&mut status, 64, 6); - Self::data_interrupts(true); + InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::card_status(0), true)?; let res = poll_fn(|cx| { @@ -849,23 +871,6 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } } - /// Enables the interrupts for data transfer - #[inline(always)] - fn data_interrupts(enable: bool) { - let regs = T::regs(); - // NOTE(unsafe) Atomic write - unsafe { - regs.maskr().write(|w| { - w.set_dcrcfailie(enable); - w.set_dtimeoutie(enable); - w.set_dataendie(enable); - - #[cfg(sdmmc_v2)] - w.set_dabortie(enable); - }); - } - } - async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { // Read the the 64-bit SCR register Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 @@ -878,7 +883,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); - Self::data_interrupts(true); + InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd51(), true)?; let res = poll_fn(|cx| { @@ -996,7 +1001,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { // Wait for the abort while Self::data_active() {} } - Self::data_interrupts(false); + InterruptHandler::::data_interrupts(false); Self::clear_interrupt_flags(); Self::stop_datapath(); } @@ -1170,7 +1175,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); let transfer = self.prepare_datapath_read(buffer, 512, 9); - Self::data_interrupts(true); + InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::read_single_block(address), true)?; let res = poll_fn(|cx| { @@ -1219,7 +1224,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Self::cmd(Cmd::write_single_block(address), true)?; let transfer = self.prepare_datapath_write(buffer, 512, 9); - Self::data_interrupts(true); + InterruptHandler::::data_interrupts(true); #[cfg(sdmmc_v2)] Self::cmd(Cmd::write_single_block(address), true)?; @@ -1279,17 +1284,11 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { pub fn clock(&self) -> Hertz { self.clock } - - #[inline(always)] - fn on_interrupt(_: *mut ()) { - Self::data_interrupts(false); - T::state().wake(); - } } impl<'d, T: Instance, Dma: SdmmcDma + 'd> Drop for Sdmmc<'d, T, Dma> { fn drop(&mut self) { - self.irq.disable(); + unsafe { T::Interrupt::steal() }.disable(); unsafe { Self::on_drop() }; critical_section::with(|_| unsafe { diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index d45c90dd..2236fde2 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -4,13 +4,14 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::{mem, ptr}; use atomic_polyfill::{AtomicU32, AtomicU8}; +use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time::driver::{AlarmHandle, Driver}; use embassy_time::TICK_HZ; use stm32_metapac::timer::regs; -use crate::interrupt::{CriticalSection, InterruptExt}; +use crate::interrupt::InterruptExt; use crate::pac::timer::vals; use crate::rcc::sealed::RccPeripheral; use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs index 3651b8ea..dc6104cc 100644 --- a/embassy-stm32/src/tl_mbox/mod.rs +++ b/embassy-stm32/src/tl_mbox/mod.rs @@ -1,7 +1,6 @@ use core::mem::MaybeUninit; use bit_field::BitField; -use embassy_cortex_m::interrupt::InterruptExt; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; @@ -12,7 +11,7 @@ use self::mm::MemoryManager; use self::shci::{shci_ble_init, ShciBleInitCmdParam}; use self::sys::Sys; use self::unsafe_linked_list::LinkedListNode; -use crate::_generated::interrupt::{IPCC_C1_RX, IPCC_C1_TX}; +use crate::interrupt; use crate::ipcc::Ipcc; mod ble; @@ -55,6 +54,19 @@ pub struct FusInfoTable { fus_info: u32, } +/// Interrupt handler. +pub struct ReceiveInterruptHandler {} + +impl interrupt::Handler for ReceiveInterruptHandler { + unsafe fn on_interrupt() {} +} + +pub struct TransmitInterruptHandler {} + +impl interrupt::Handler for TransmitInterruptHandler { + unsafe fn on_interrupt() {} +} + /// # Version /// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version /// - 4 -> 7 = branch - 0: Mass Market - x: ... @@ -285,7 +297,11 @@ pub struct TlMbox { impl TlMbox { /// initializes low-level transport between CPU1 and BLE stack on CPU2 - pub fn init(ipcc: &mut Ipcc, rx_irq: IPCC_C1_RX, tx_irq: IPCC_C1_TX) -> TlMbox { + pub fn init( + ipcc: &mut Ipcc, + _irqs: impl interrupt::Binding + + interrupt::Binding, + ) -> TlMbox { unsafe { TL_REF_TABLE = MaybeUninit::new(RefTable { device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), @@ -326,23 +342,23 @@ impl TlMbox { let _ble = Ble::new(ipcc); let _mm = MemoryManager::new(); - rx_irq.disable(); - tx_irq.disable(); - - rx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ()); - tx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ()); - - rx_irq.set_handler(|ipcc| { - let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() }; - Self::interrupt_ipcc_rx_handler(ipcc); - }); - tx_irq.set_handler(|ipcc| { - let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() }; - Self::interrupt_ipcc_tx_handler(ipcc); - }); - - rx_irq.enable(); - tx_irq.enable(); + // rx_irq.disable(); + // tx_irq.disable(); + // + // rx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ()); + // tx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ()); + // + // rx_irq.set_handler(|ipcc| { + // let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() }; + // Self::interrupt_ipcc_rx_handler(ipcc); + // }); + // tx_irq.set_handler(|ipcc| { + // let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() }; + // Self::interrupt_ipcc_tx_handler(ipcc); + // }); + // + // rx_irq.enable(); + // tx_irq.enable(); TlMbox { _sys, _ble, _mm } } @@ -374,6 +390,7 @@ impl TlMbox { TL_CHANNEL.recv().await } + #[allow(dead_code)] fn interrupt_ipcc_rx_handler(ipcc: &mut Ipcc) { if ipcc.is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) { sys::Sys::evt_handler(ipcc); @@ -384,6 +401,7 @@ impl TlMbox { } } + #[allow(dead_code)] fn interrupt_ipcc_tx_handler(ipcc: &mut Ipcc) { if ipcc.is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) { // TODO: handle this case diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 12cf8b0f..9f1da358 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -8,6 +8,78 @@ use embassy_sync::waitqueue::AtomicWaker; use super::*; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let r = T::regs(); + let state = T::buffered_state(); + + // RX + unsafe { + let sr = sr(r).read(); + clear_interrupt_flags(r, sr); + + if sr.rxne() { + if sr.pe() { + warn!("Parity error"); + } + if sr.fe() { + warn!("Framing error"); + } + if sr.ne() { + warn!("Noise error"); + } + if sr.ore() { + warn!("Overrun error"); + } + + let mut rx_writer = state.rx_buf.writer(); + let buf = rx_writer.push_slice(); + if !buf.is_empty() { + // This read also clears the error and idle interrupt flags on v1. + buf[0] = rdr(r).read_volatile(); + rx_writer.push_done(1); + } else { + // FIXME: Should we disable any further RX interrupts when the buffer becomes full. + } + + if state.rx_buf.is_full() { + state.rx_waker.wake(); + } + } + + if sr.idle() { + state.rx_waker.wake(); + }; + } + + // TX + unsafe { + if sr(r).read().txe() { + let mut tx_reader = state.tx_buf.reader(); + let buf = tx_reader.pop_slice(); + if !buf.is_empty() { + r.cr1().modify(|w| { + w.set_txeie(true); + }); + tdr(r).write_volatile(buf[0].into()); + tx_reader.pop_done(1); + state.tx_waker.wake(); + } else { + // Disable interrupt until we have something to transmit again + r.cr1().modify(|w| { + w.set_txeie(false); + }); + } + } + } + } +} + pub struct State { rx_waker: AtomicWaker, rx_buf: RingBuffer, @@ -43,7 +115,7 @@ pub struct BufferedUartRx<'d, T: BasicInstance> { impl<'d, T: BasicInstance> BufferedUart<'d, T> { pub fn new( peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, tx_buffer: &'d mut [u8], @@ -53,12 +125,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { T::enable(); T::reset(); - Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) + Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } pub fn new_with_rtscts( peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, rts: impl Peripheral

> + 'd, @@ -81,13 +153,13 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { }); } - Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) + Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } #[cfg(not(any(usart_v1, usart_v2)))] pub fn new_with_de( peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, de: impl Peripheral

> + 'd, @@ -107,19 +179,18 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { }); } - Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) + Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } fn new_inner( _peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> BufferedUart<'d, T> { - into_ref!(_peri, rx, tx, irq); + into_ref!(_peri, rx, tx); let state = T::buffered_state(); let len = tx_buffer.len(); @@ -145,9 +216,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { }); } - irq.set_handler(on_interrupt::); - irq.unpend(); - irq.enable(); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); Self { rx: BufferedUartRx { phantom: PhantomData }, @@ -336,71 +406,6 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { } } -unsafe fn on_interrupt(_: *mut ()) { - let r = T::regs(); - let state = T::buffered_state(); - - // RX - unsafe { - let sr = sr(r).read(); - clear_interrupt_flags(r, sr); - - if sr.rxne() { - if sr.pe() { - warn!("Parity error"); - } - if sr.fe() { - warn!("Framing error"); - } - if sr.ne() { - warn!("Noise error"); - } - if sr.ore() { - warn!("Overrun error"); - } - - let mut rx_writer = state.rx_buf.writer(); - let buf = rx_writer.push_slice(); - if !buf.is_empty() { - // This read also clears the error and idle interrupt flags on v1. - buf[0] = rdr(r).read_volatile(); - rx_writer.push_done(1); - } else { - // FIXME: Should we disable any further RX interrupts when the buffer becomes full. - } - - if state.rx_buf.is_full() { - state.rx_waker.wake(); - } - } - - if sr.idle() { - state.rx_waker.wake(); - }; - } - - // TX - unsafe { - if sr(r).read().txe() { - let mut tx_reader = state.tx_buf.reader(); - let buf = tx_reader.pop_slice(); - if !buf.is_empty() { - r.cr1().modify(|w| { - w.set_txeie(true); - }); - tdr(r).write_volatile(buf[0].into()); - tx_reader.pop_done(1); - state.tx_waker.wake(); - } else { - // Disable interrupt until we have something to transmit again - r.cr1().modify(|w| { - w.set_txeie(false); - }); - } - } - } -} - impl embedded_io::Error for Error { fn kind(&self) -> embedded_io::ErrorKind { embedded_io::ErrorKind::Other diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index b4373529..0f3e9412 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -5,7 +5,7 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use embassy_cortex_m::interrupt::InterruptExt; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; use futures::future::{select, Either}; @@ -18,7 +18,71 @@ use crate::pac::usart::Lpuart as Regs; use crate::pac::usart::Usart as Regs; use crate::pac::usart::{regs, vals}; use crate::time::Hertz; -use crate::{peripherals, Peripheral}; +use crate::{interrupt, peripherals, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let r = T::regs(); + let s = T::state(); + + let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; + + let mut wake = false; + let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); + if has_errors { + // clear all interrupts and DMA Rx Request + unsafe { + r.cr1().modify(|w| { + // disable RXNE interrupt + w.set_rxneie(false); + // disable parity interrupt + w.set_peie(false); + // disable idle line interrupt + w.set_idleie(false); + }); + r.cr3().modify(|w| { + // disable Error Interrupt: (Frame error, Noise error, Overrun error) + w.set_eie(false); + // disable DMA Rx Request + w.set_dmar(false); + }); + } + + wake = true; + } else { + if cr1.idleie() && sr.idle() { + // IDLE detected: no more data will come + unsafe { + r.cr1().modify(|w| { + // disable idle line detection + w.set_idleie(false); + }); + } + + wake = true; + } + + if cr1.rxneie() { + // We cannot check the RXNE flag as it is auto-cleared by the DMA controller + + // It is up to the listener to determine if this in fact was a RX event and disable the RXNE detection + + wake = true; + } + } + + if wake { + compiler_fence(Ordering::SeqCst); + + s.rx_waker.wake(); + } + } +} #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum DataBits { @@ -215,7 +279,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. pub fn new( peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, rx: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, @@ -223,12 +287,12 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { T::enable(); T::reset(); - Self::new_inner(peri, irq, rx, rx_dma, config) + Self::new_inner(peri, rx, rx_dma, config) } pub fn new_with_rts( peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, rx: impl Peripheral

> + 'd, rts: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, @@ -246,17 +310,16 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { }); } - Self::new_inner(peri, irq, rx, rx_dma, config) + Self::new_inner(peri, rx, rx_dma, config) } fn new_inner( peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(peri, irq, rx, rx_dma); + into_ref!(peri, rx, rx_dma); let r = T::regs(); @@ -266,9 +329,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { configure(r, &config, T::frequency(), T::KIND, true, false); - irq.set_handler(Self::on_interrupt); - irq.unpend(); - irq.enable(); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); // create state once! let _s = T::state(); @@ -282,63 +344,6 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } - fn on_interrupt(_: *mut ()) { - let r = T::regs(); - let s = T::state(); - - let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; - - let mut wake = false; - let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); - if has_errors { - // clear all interrupts and DMA Rx Request - unsafe { - r.cr1().modify(|w| { - // disable RXNE interrupt - w.set_rxneie(false); - // disable parity interrupt - w.set_peie(false); - // disable idle line interrupt - w.set_idleie(false); - }); - r.cr3().modify(|w| { - // disable Error Interrupt: (Frame error, Noise error, Overrun error) - w.set_eie(false); - // disable DMA Rx Request - w.set_dmar(false); - }); - } - - wake = true; - } else { - if cr1.idleie() && sr.idle() { - // IDLE detected: no more data will come - unsafe { - r.cr1().modify(|w| { - // disable idle line detection - w.set_idleie(false); - }); - } - - wake = true; - } - - if cr1.rxneie() { - // We cannot check the RXNE flag as it is auto-cleared by the DMA controller - - // It is up to the listener to determine if this in fact was a RX event and disable the RXNE detection - - wake = true; - } - } - - if wake { - compiler_fence(Ordering::SeqCst); - - s.rx_waker.wake(); - } - } - #[cfg(any(usart_v1, usart_v2))] unsafe fn check_rx_flags(&mut self) -> Result { let r = T::regs(); @@ -643,7 +648,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, @@ -651,14 +656,14 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { T::enable(); T::reset(); - Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) + Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) } pub fn new_with_rtscts( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, rts: impl Peripheral

> + 'd, cts: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, @@ -678,7 +683,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { w.set_ctse(true); }); } - Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) + Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) } #[cfg(not(any(usart_v1, usart_v2)))] @@ -686,7 +691,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, de: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, @@ -703,19 +708,18 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { w.set_dem(true); }); } - Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) + Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) } fn new_inner( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, tx: impl Peripheral

> + 'd, - irq: impl Peripheral

+ 'd, tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(peri, rx, tx, irq, tx_dma, rx_dma); + into_ref!(peri, rx, tx, tx_dma, rx_dma); let r = T::regs(); @@ -726,9 +730,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { configure(r, &config, T::frequency(), T::KIND, true, true); - irq.set_handler(UartRx::::on_interrupt); - irq.unpend(); - irq.enable(); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); // create state once! let _s = T::state(); @@ -1068,6 +1071,9 @@ mod eio { #[cfg(feature = "nightly")] pub use buffered::*; + +#[cfg(feature = "nightly")] +pub use crate::usart::buffered::InterruptHandler as BufferedInterruptHandler; #[cfg(feature = "nightly")] mod buffered; diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 56c46476..a9ff284a 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -14,12 +14,99 @@ use embassy_usb_driver::{ use super::{DmPin, DpPin, Instance}; use crate::gpio::sealed::AFType; -use crate::interrupt::InterruptExt; +use crate::interrupt::{Interrupt, InterruptExt}; use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; use crate::pac::USBRAM; use crate::rcc::sealed::RccPeripheral; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + unsafe { + let regs = T::regs(); + //let x = regs.istr().read().0; + //trace!("USB IRQ: {:08x}", x); + + let istr = regs.istr().read(); + + if istr.susp() { + //trace!("USB IRQ: susp"); + IRQ_SUSPEND.store(true, Ordering::Relaxed); + regs.cntr().modify(|w| { + w.set_fsusp(true); + w.set_lpmode(true); + }); + + // Write 0 to clear. + let mut clear = regs::Istr(!0); + clear.set_susp(false); + regs.istr().write_value(clear); + + // Wake main thread. + BUS_WAKER.wake(); + } + + if istr.wkup() { + //trace!("USB IRQ: wkup"); + IRQ_RESUME.store(true, Ordering::Relaxed); + regs.cntr().modify(|w| { + w.set_fsusp(false); + w.set_lpmode(false); + }); + + // Write 0 to clear. + let mut clear = regs::Istr(!0); + clear.set_wkup(false); + regs.istr().write_value(clear); + + // Wake main thread. + BUS_WAKER.wake(); + } + + if istr.reset() { + //trace!("USB IRQ: reset"); + IRQ_RESET.store(true, Ordering::Relaxed); + + // Write 0 to clear. + let mut clear = regs::Istr(!0); + clear.set_reset(false); + regs.istr().write_value(clear); + + // Wake main thread. + BUS_WAKER.wake(); + } + + if istr.ctr() { + let index = istr.ep_id() as usize; + let mut epr = regs.epr(index).read(); + if epr.ctr_rx() { + if index == 0 && epr.setup() { + EP0_SETUP.store(true, Ordering::Relaxed); + } + //trace!("EP {} RX, setup={}", index, epr.setup()); + EP_OUT_WAKERS[index].wake(); + } + if epr.ctr_tx() { + //trace!("EP {} TX", index); + EP_IN_WAKERS[index].wake(); + } + epr.set_dtog_rx(false); + epr.set_dtog_tx(false); + epr.set_stat_rx(Stat(0)); + epr.set_stat_tx(Stat(0)); + epr.set_ctr_rx(!epr.ctr_rx()); + epr.set_ctr_tx(!epr.ctr_tx()); + regs.epr(index).write_value(epr); + } + } + } +} const EP_COUNT: usize = 8; @@ -168,14 +255,13 @@ pub struct Driver<'d, T: Instance> { impl<'d, T: Instance> Driver<'d, T> { pub fn new( _usb: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, dp: impl Peripheral

> + 'd, dm: impl Peripheral

> + 'd, ) -> Self { - into_ref!(irq, dp, dm); - irq.set_handler(Self::on_interrupt); - irq.unpend(); - irq.enable(); + into_ref!(dp, dm); + unsafe { T::Interrupt::steal() }.unpend(); + unsafe { T::Interrupt::steal() }.enable(); let regs = T::regs(); @@ -225,86 +311,6 @@ impl<'d, T: Instance> Driver<'d, T> { } } - fn on_interrupt(_: *mut ()) { - unsafe { - let regs = T::regs(); - //let x = regs.istr().read().0; - //trace!("USB IRQ: {:08x}", x); - - let istr = regs.istr().read(); - - if istr.susp() { - //trace!("USB IRQ: susp"); - IRQ_SUSPEND.store(true, Ordering::Relaxed); - regs.cntr().modify(|w| { - w.set_fsusp(true); - w.set_lpmode(true); - }); - - // Write 0 to clear. - let mut clear = regs::Istr(!0); - clear.set_susp(false); - regs.istr().write_value(clear); - - // Wake main thread. - BUS_WAKER.wake(); - } - - if istr.wkup() { - //trace!("USB IRQ: wkup"); - IRQ_RESUME.store(true, Ordering::Relaxed); - regs.cntr().modify(|w| { - w.set_fsusp(false); - w.set_lpmode(false); - }); - - // Write 0 to clear. - let mut clear = regs::Istr(!0); - clear.set_wkup(false); - regs.istr().write_value(clear); - - // Wake main thread. - BUS_WAKER.wake(); - } - - if istr.reset() { - //trace!("USB IRQ: reset"); - IRQ_RESET.store(true, Ordering::Relaxed); - - // Write 0 to clear. - let mut clear = regs::Istr(!0); - clear.set_reset(false); - regs.istr().write_value(clear); - - // Wake main thread. - BUS_WAKER.wake(); - } - - if istr.ctr() { - let index = istr.ep_id() as usize; - let mut epr = regs.epr(index).read(); - if epr.ctr_rx() { - if index == 0 && epr.setup() { - EP0_SETUP.store(true, Ordering::Relaxed); - } - //trace!("EP {} RX, setup={}", index, epr.setup()); - EP_OUT_WAKERS[index].wake(); - } - if epr.ctr_tx() { - //trace!("EP {} TX", index); - EP_IN_WAKERS[index].wake(); - } - epr.set_dtog_rx(false); - epr.set_dtog_tx(false); - epr.set_stat_rx(Stat(0)); - epr.set_stat_tx(Stat(0)); - epr.set_ctr_rx(!epr.ctr_rx()); - epr.set_ctr_tx(!epr.ctr_tx()); - regs.epr(index).write_value(epr); - } - } - } - fn alloc_ep_mem(&mut self, len: u16) -> u16 { assert!(len as usize % USBRAM_ALIGN == 0); let addr = self.ep_mem_free; diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 96c574ca..921a73c8 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -4,7 +4,7 @@ use core::task::Poll; use atomic_polyfill::{AtomicBool, AtomicU16, Ordering}; use embassy_cortex_m::interrupt::InterruptExt; -use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_common::{into_ref, Peripheral}; use embassy_sync::waitqueue::AtomicWaker; use embassy_usb_driver::{ self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, @@ -14,490 +14,18 @@ use futures::future::poll_fn; use super::*; use crate::gpio::sealed::AFType; +use crate::interrupt; use crate::pac::otg::{regs, vals}; use crate::rcc::sealed::RccPeripheral; use crate::time::Hertz; -macro_rules! config_ulpi_pins { - ($($pin:ident),*) => { - into_ref!($($pin),*); - // NOTE(unsafe) Exclusive access to the registers - critical_section::with(|_| unsafe { - $( - $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); - #[cfg(gpio_v2)] - $pin.set_speed(crate::gpio::Speed::VeryHigh); - )* - }) - }; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, } -// From `synopsys-usb-otg` crate: -// This calculation doesn't correspond to one in a Reference Manual. -// In fact, the required number of words is higher than indicated in RM. -// The following numbers are pessimistic and were figured out empirically. -const RX_FIFO_EXTRA_SIZE_WORDS: u16 = 30; - -/// USB PHY type -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum PhyType { - /// Internal Full-Speed PHY - /// - /// Available on most High-Speed peripherals. - InternalFullSpeed, - /// Internal High-Speed PHY - /// - /// Available on a few STM32 chips. - InternalHighSpeed, - /// External ULPI High-Speed PHY - ExternalHighSpeed, -} - -impl PhyType { - pub fn internal(&self) -> bool { - match self { - PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, - PhyType::ExternalHighSpeed => false, - } - } - - pub fn high_speed(&self) -> bool { - match self { - PhyType::InternalFullSpeed => false, - PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true, - } - } - - pub fn to_dspd(&self) -> vals::Dspd { - match self { - PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, - PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, - PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED, - } - } -} - -/// Indicates that [State::ep_out_buffers] is empty. -const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; - -pub struct State { - /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. - ep0_setup_data: UnsafeCell<[u8; 8]>, - ep0_setup_ready: AtomicBool, - ep_in_wakers: [AtomicWaker; EP_COUNT], - ep_out_wakers: [AtomicWaker; EP_COUNT], - /// RX FIFO is shared so extra buffers are needed to dequeue all data without waiting on each endpoint. - /// Buffers are ready when associated [State::ep_out_size] != [EP_OUT_BUFFER_EMPTY]. - ep_out_buffers: [UnsafeCell<*mut u8>; EP_COUNT], - ep_out_size: [AtomicU16; EP_COUNT], - bus_waker: AtomicWaker, -} - -unsafe impl Send for State {} -unsafe impl Sync for State {} - -impl State { - pub const fn new() -> Self { - const NEW_AW: AtomicWaker = AtomicWaker::new(); - const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); - const NEW_SIZE: AtomicU16 = AtomicU16::new(EP_OUT_BUFFER_EMPTY); - - Self { - ep0_setup_data: UnsafeCell::new([0u8; 8]), - ep0_setup_ready: AtomicBool::new(false), - ep_in_wakers: [NEW_AW; EP_COUNT], - ep_out_wakers: [NEW_AW; EP_COUNT], - ep_out_buffers: [NEW_BUF; EP_COUNT], - ep_out_size: [NEW_SIZE; EP_COUNT], - bus_waker: NEW_AW, - } - } -} - -#[derive(Debug, Clone, Copy)] -struct EndpointData { - ep_type: EndpointType, - max_packet_size: u16, - fifo_size_words: u16, -} - -pub struct Driver<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, - irq: PeripheralRef<'d, T::Interrupt>, - ep_in: [Option; MAX_EP_COUNT], - ep_out: [Option; MAX_EP_COUNT], - ep_out_buffer: &'d mut [u8], - ep_out_buffer_offset: usize, - phy_type: PhyType, -} - -impl<'d, T: Instance> Driver<'d, T> { - /// Initializes USB OTG peripheral with internal Full-Speed PHY. - /// - /// # Arguments - /// - /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. - /// Must be large enough to fit all OUT endpoint max packet sizes. - /// Endpoint allocation will fail if it is too small. - pub fn new_fs( - _peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, - dp: impl Peripheral

> + 'd, - dm: impl Peripheral

> + 'd, - ep_out_buffer: &'d mut [u8], - ) -> Self { - into_ref!(dp, dm, irq); - - unsafe { - dp.set_as_af(dp.af_num(), AFType::OutputPushPull); - dm.set_as_af(dm.af_num(), AFType::OutputPushPull); - } - - Self { - phantom: PhantomData, - irq, - ep_in: [None; MAX_EP_COUNT], - ep_out: [None; MAX_EP_COUNT], - ep_out_buffer, - ep_out_buffer_offset: 0, - phy_type: PhyType::InternalFullSpeed, - } - } - - /// Initializes USB OTG peripheral with external High-Speed PHY. - /// - /// # Arguments - /// - /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. - /// Must be large enough to fit all OUT endpoint max packet sizes. - /// Endpoint allocation will fail if it is too small. - pub fn new_hs_ulpi( - _peri: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, - ulpi_clk: impl Peripheral

> + 'd, - ulpi_dir: impl Peripheral

> + 'd, - ulpi_nxt: impl Peripheral

> + 'd, - ulpi_stp: impl Peripheral

> + 'd, - ulpi_d0: impl Peripheral

> + 'd, - ulpi_d1: impl Peripheral

> + 'd, - ulpi_d2: impl Peripheral

> + 'd, - ulpi_d3: impl Peripheral

> + 'd, - ulpi_d4: impl Peripheral

> + 'd, - ulpi_d5: impl Peripheral

> + 'd, - ulpi_d6: impl Peripheral

> + 'd, - ulpi_d7: impl Peripheral

> + 'd, - ep_out_buffer: &'d mut [u8], - ) -> Self { - assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); - - config_ulpi_pins!( - ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6, - ulpi_d7 - ); - - into_ref!(irq); - - Self { - phantom: PhantomData, - irq, - ep_in: [None; MAX_EP_COUNT], - ep_out: [None; MAX_EP_COUNT], - ep_out_buffer, - ep_out_buffer_offset: 0, - phy_type: PhyType::ExternalHighSpeed, - } - } - - // Returns total amount of words (u32) allocated in dedicated FIFO - fn allocated_fifo_words(&self) -> u16 { - RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out) + ep_fifo_size(&self.ep_in) - } - - fn alloc_endpoint( - &mut self, - ep_type: EndpointType, - max_packet_size: u16, - interval_ms: u8, - ) -> Result, EndpointAllocError> { - trace!( - "allocating type={:?} mps={:?} interval_ms={}, dir={:?}", - ep_type, - max_packet_size, - interval_ms, - D::dir() - ); - - if D::dir() == Direction::Out { - if self.ep_out_buffer_offset + max_packet_size as usize >= self.ep_out_buffer.len() { - error!("Not enough endpoint out buffer capacity"); - return Err(EndpointAllocError); - } - }; - - let fifo_size_words = match D::dir() { - Direction::Out => (max_packet_size + 3) / 4, - // INEPTXFD requires minimum size of 16 words - Direction::In => u16::max((max_packet_size + 3) / 4, 16), - }; - - if fifo_size_words + self.allocated_fifo_words() > T::FIFO_DEPTH_WORDS { - error!("Not enough FIFO capacity"); - return Err(EndpointAllocError); - } - - let eps = match D::dir() { - Direction::Out => &mut self.ep_out, - Direction::In => &mut self.ep_in, - }; - - // Find free endpoint slot - let slot = eps.iter_mut().enumerate().find(|(i, ep)| { - if *i == 0 && ep_type != EndpointType::Control { - // reserved for control pipe - false - } else { - ep.is_none() - } - }); - - let index = match slot { - Some((index, ep)) => { - *ep = Some(EndpointData { - ep_type, - max_packet_size, - fifo_size_words, - }); - index - } - None => { - error!("No free endpoints available"); - return Err(EndpointAllocError); - } - }; - - trace!(" index={}", index); - - if D::dir() == Direction::Out { - // Buffer capacity check was done above, now allocation cannot fail - unsafe { - *T::state().ep_out_buffers[index].get() = - self.ep_out_buffer.as_mut_ptr().offset(self.ep_out_buffer_offset as _); - } - self.ep_out_buffer_offset += max_packet_size as usize; - } - - Ok(Endpoint { - _phantom: PhantomData, - info: EndpointInfo { - addr: EndpointAddress::from_parts(index, D::dir()), - ep_type, - max_packet_size, - interval_ms, - }, - }) - } -} - -impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { - type EndpointOut = Endpoint<'d, T, Out>; - type EndpointIn = Endpoint<'d, T, In>; - type ControlPipe = ControlPipe<'d, T>; - type Bus = Bus<'d, T>; - - fn alloc_endpoint_in( - &mut self, - ep_type: EndpointType, - max_packet_size: u16, - interval_ms: u8, - ) -> Result { - self.alloc_endpoint(ep_type, max_packet_size, interval_ms) - } - - fn alloc_endpoint_out( - &mut self, - ep_type: EndpointType, - max_packet_size: u16, - interval_ms: u8, - ) -> Result { - self.alloc_endpoint(ep_type, max_packet_size, interval_ms) - } - - fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { - let ep_out = self - .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) - .unwrap(); - let ep_in = self - .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) - .unwrap(); - assert_eq!(ep_out.info.addr.index(), 0); - assert_eq!(ep_in.info.addr.index(), 0); - - trace!("start"); - - ( - Bus { - phantom: PhantomData, - irq: self.irq, - ep_in: self.ep_in, - ep_out: self.ep_out, - phy_type: self.phy_type, - enabled: false, - }, - ControlPipe { - _phantom: PhantomData, - max_packet_size: control_max_packet_size, - ep_out, - ep_in, - }, - ) - } -} - -pub struct Bus<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, - irq: PeripheralRef<'d, T::Interrupt>, - ep_in: [Option; MAX_EP_COUNT], - ep_out: [Option; MAX_EP_COUNT], - phy_type: PhyType, - enabled: bool, -} - -impl<'d, T: Instance> Bus<'d, T> { - fn restore_irqs() { - // SAFETY: atomic write - unsafe { - T::regs().gintmsk().write(|w| { - w.set_usbrst(true); - w.set_enumdnem(true); - w.set_usbsuspm(true); - w.set_wuim(true); - w.set_iepint(true); - w.set_oepint(true); - w.set_rxflvlm(true); - }); - } - } -} - -impl<'d, T: Instance> Bus<'d, T> { - fn init_fifo(&mut self) { - trace!("init_fifo"); - - let r = T::regs(); - - // Configure RX fifo size. All endpoints share the same FIFO area. - let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); - trace!("configuring rx fifo size={}", rx_fifo_size_words); - - // SAFETY: register is exclusive to `Bus` with `&mut self` - unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) }; - - // Configure TX (USB in direction) fifo size for each endpoint - let mut fifo_top = rx_fifo_size_words; - for i in 0..T::ENDPOINT_COUNT { - if let Some(ep) = self.ep_in[i] { - trace!( - "configuring tx fifo ep={}, offset={}, size={}", - i, - fifo_top, - ep.fifo_size_words - ); - - let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; - - // SAFETY: register is exclusive to `Bus` with `&mut self` - unsafe { - dieptxf.write(|w| { - w.set_fd(ep.fifo_size_words); - w.set_sa(fifo_top); - }); - } - - fifo_top += ep.fifo_size_words; - } - } - - assert!( - fifo_top <= T::FIFO_DEPTH_WORDS, - "FIFO allocations exceeded maximum capacity" - ); - } - - fn configure_endpoints(&mut self) { - trace!("configure_endpoints"); - - let r = T::regs(); - - // Configure IN endpoints - for (index, ep) in self.ep_in.iter().enumerate() { - if let Some(ep) = ep { - // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW - critical_section::with(|_| unsafe { - r.diepctl(index).write(|w| { - if index == 0 { - w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); - } else { - w.set_mpsiz(ep.max_packet_size); - w.set_eptyp(to_eptyp(ep.ep_type)); - w.set_sd0pid_sevnfrm(true); - } - }); - }); - } - } - - // Configure OUT endpoints - for (index, ep) in self.ep_out.iter().enumerate() { - if let Some(ep) = ep { - // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW - critical_section::with(|_| unsafe { - r.doepctl(index).write(|w| { - if index == 0 { - w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); - } else { - w.set_mpsiz(ep.max_packet_size); - w.set_eptyp(to_eptyp(ep.ep_type)); - w.set_sd0pid_sevnfrm(true); - } - }); - - r.doeptsiz(index).modify(|w| { - w.set_xfrsiz(ep.max_packet_size as _); - if index == 0 { - w.set_rxdpid_stupcnt(1); - } else { - w.set_pktcnt(1); - } - }); - }); - } - } - - // Enable IRQs for allocated endpoints - // SAFETY: register is exclusive to `Bus` with `&mut self` - unsafe { - r.daintmsk().modify(|w| { - w.set_iepm(ep_irq_mask(&self.ep_in)); - // OUT interrupts not used, handled in RXFLVL - // w.set_oepm(ep_irq_mask(&self.ep_out)); - }); - } - } - - fn disable(&mut self) { - self.irq.disable(); - self.irq.remove_handler(); - - ::disable(); - - #[cfg(stm32l4)] - unsafe { - crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); - // Cannot disable PWR, because other peripherals might be using it - } - } - - fn on_interrupt(_: *mut ()) { +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { trace!("irq"); let r = T::regs(); let state = T::state(); @@ -641,6 +169,478 @@ impl<'d, T: Instance> Bus<'d, T> { } } +macro_rules! config_ulpi_pins { + ($($pin:ident),*) => { + into_ref!($($pin),*); + // NOTE(unsafe) Exclusive access to the registers + critical_section::with(|_| unsafe { + $( + $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); + #[cfg(gpio_v2)] + $pin.set_speed(crate::gpio::Speed::VeryHigh); + )* + }) + }; +} + +// From `synopsys-usb-otg` crate: +// This calculation doesn't correspond to one in a Reference Manual. +// In fact, the required number of words is higher than indicated in RM. +// The following numbers are pessimistic and were figured out empirically. +const RX_FIFO_EXTRA_SIZE_WORDS: u16 = 30; + +/// USB PHY type +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PhyType { + /// Internal Full-Speed PHY + /// + /// Available on most High-Speed peripherals. + InternalFullSpeed, + /// Internal High-Speed PHY + /// + /// Available on a few STM32 chips. + InternalHighSpeed, + /// External ULPI High-Speed PHY + ExternalHighSpeed, +} + +impl PhyType { + pub fn internal(&self) -> bool { + match self { + PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, + PhyType::ExternalHighSpeed => false, + } + } + + pub fn high_speed(&self) -> bool { + match self { + PhyType::InternalFullSpeed => false, + PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true, + } + } + + pub fn to_dspd(&self) -> vals::Dspd { + match self { + PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, + PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, + PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED, + } + } +} + +/// Indicates that [State::ep_out_buffers] is empty. +const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; + +pub struct State { + /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. + ep0_setup_data: UnsafeCell<[u8; 8]>, + ep0_setup_ready: AtomicBool, + ep_in_wakers: [AtomicWaker; EP_COUNT], + ep_out_wakers: [AtomicWaker; EP_COUNT], + /// RX FIFO is shared so extra buffers are needed to dequeue all data without waiting on each endpoint. + /// Buffers are ready when associated [State::ep_out_size] != [EP_OUT_BUFFER_EMPTY]. + ep_out_buffers: [UnsafeCell<*mut u8>; EP_COUNT], + ep_out_size: [AtomicU16; EP_COUNT], + bus_waker: AtomicWaker, +} + +unsafe impl Send for State {} +unsafe impl Sync for State {} + +impl State { + pub const fn new() -> Self { + const NEW_AW: AtomicWaker = AtomicWaker::new(); + const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); + const NEW_SIZE: AtomicU16 = AtomicU16::new(EP_OUT_BUFFER_EMPTY); + + Self { + ep0_setup_data: UnsafeCell::new([0u8; 8]), + ep0_setup_ready: AtomicBool::new(false), + ep_in_wakers: [NEW_AW; EP_COUNT], + ep_out_wakers: [NEW_AW; EP_COUNT], + ep_out_buffers: [NEW_BUF; EP_COUNT], + ep_out_size: [NEW_SIZE; EP_COUNT], + bus_waker: NEW_AW, + } + } +} + +#[derive(Debug, Clone, Copy)] +struct EndpointData { + ep_type: EndpointType, + max_packet_size: u16, + fifo_size_words: u16, +} + +pub struct Driver<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + ep_in: [Option; MAX_EP_COUNT], + ep_out: [Option; MAX_EP_COUNT], + ep_out_buffer: &'d mut [u8], + ep_out_buffer_offset: usize, + phy_type: PhyType, +} + +impl<'d, T: Instance> Driver<'d, T> { + /// Initializes USB OTG peripheral with internal Full-Speed PHY. + /// + /// # Arguments + /// + /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. + /// Must be large enough to fit all OUT endpoint max packet sizes. + /// Endpoint allocation will fail if it is too small. + pub fn new_fs( + _peri: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, + dp: impl Peripheral

> + 'd, + dm: impl Peripheral

> + 'd, + ep_out_buffer: &'d mut [u8], + ) -> Self { + into_ref!(dp, dm); + + unsafe { + dp.set_as_af(dp.af_num(), AFType::OutputPushPull); + dm.set_as_af(dm.af_num(), AFType::OutputPushPull); + } + + Self { + phantom: PhantomData, + ep_in: [None; MAX_EP_COUNT], + ep_out: [None; MAX_EP_COUNT], + ep_out_buffer, + ep_out_buffer_offset: 0, + phy_type: PhyType::InternalFullSpeed, + } + } + + /// Initializes USB OTG peripheral with external High-Speed PHY. + /// + /// # Arguments + /// + /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. + /// Must be large enough to fit all OUT endpoint max packet sizes. + /// Endpoint allocation will fail if it is too small. + pub fn new_hs_ulpi( + _peri: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding> + 'd, + ulpi_clk: impl Peripheral

> + 'd, + ulpi_dir: impl Peripheral

> + 'd, + ulpi_nxt: impl Peripheral

> + 'd, + ulpi_stp: impl Peripheral

> + 'd, + ulpi_d0: impl Peripheral

> + 'd, + ulpi_d1: impl Peripheral

> + 'd, + ulpi_d2: impl Peripheral

> + 'd, + ulpi_d3: impl Peripheral

> + 'd, + ulpi_d4: impl Peripheral

> + 'd, + ulpi_d5: impl Peripheral

> + 'd, + ulpi_d6: impl Peripheral

> + 'd, + ulpi_d7: impl Peripheral

> + 'd, + ep_out_buffer: &'d mut [u8], + ) -> Self { + assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); + + config_ulpi_pins!( + ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6, + ulpi_d7 + ); + + Self { + phantom: PhantomData, + ep_in: [None; MAX_EP_COUNT], + ep_out: [None; MAX_EP_COUNT], + ep_out_buffer, + ep_out_buffer_offset: 0, + phy_type: PhyType::ExternalHighSpeed, + } + } + + // Returns total amount of words (u32) allocated in dedicated FIFO + fn allocated_fifo_words(&self) -> u16 { + RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out) + ep_fifo_size(&self.ep_in) + } + + fn alloc_endpoint( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> Result, EndpointAllocError> { + trace!( + "allocating type={:?} mps={:?} interval_ms={}, dir={:?}", + ep_type, + max_packet_size, + interval_ms, + D::dir() + ); + + if D::dir() == Direction::Out { + if self.ep_out_buffer_offset + max_packet_size as usize >= self.ep_out_buffer.len() { + error!("Not enough endpoint out buffer capacity"); + return Err(EndpointAllocError); + } + }; + + let fifo_size_words = match D::dir() { + Direction::Out => (max_packet_size + 3) / 4, + // INEPTXFD requires minimum size of 16 words + Direction::In => u16::max((max_packet_size + 3) / 4, 16), + }; + + if fifo_size_words + self.allocated_fifo_words() > T::FIFO_DEPTH_WORDS { + error!("Not enough FIFO capacity"); + return Err(EndpointAllocError); + } + + let eps = match D::dir() { + Direction::Out => &mut self.ep_out, + Direction::In => &mut self.ep_in, + }; + + // Find free endpoint slot + let slot = eps.iter_mut().enumerate().find(|(i, ep)| { + if *i == 0 && ep_type != EndpointType::Control { + // reserved for control pipe + false + } else { + ep.is_none() + } + }); + + let index = match slot { + Some((index, ep)) => { + *ep = Some(EndpointData { + ep_type, + max_packet_size, + fifo_size_words, + }); + index + } + None => { + error!("No free endpoints available"); + return Err(EndpointAllocError); + } + }; + + trace!(" index={}", index); + + if D::dir() == Direction::Out { + // Buffer capacity check was done above, now allocation cannot fail + unsafe { + *T::state().ep_out_buffers[index].get() = + self.ep_out_buffer.as_mut_ptr().offset(self.ep_out_buffer_offset as _); + } + self.ep_out_buffer_offset += max_packet_size as usize; + } + + Ok(Endpoint { + _phantom: PhantomData, + info: EndpointInfo { + addr: EndpointAddress::from_parts(index, D::dir()), + ep_type, + max_packet_size, + interval_ms, + }, + }) + } +} + +impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { + type EndpointOut = Endpoint<'d, T, Out>; + type EndpointIn = Endpoint<'d, T, In>; + type ControlPipe = ControlPipe<'d, T>; + type Bus = Bus<'d, T>; + + fn alloc_endpoint_in( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> Result { + self.alloc_endpoint(ep_type, max_packet_size, interval_ms) + } + + fn alloc_endpoint_out( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> Result { + self.alloc_endpoint(ep_type, max_packet_size, interval_ms) + } + + fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { + let ep_out = self + .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) + .unwrap(); + let ep_in = self + .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) + .unwrap(); + assert_eq!(ep_out.info.addr.index(), 0); + assert_eq!(ep_in.info.addr.index(), 0); + + trace!("start"); + + ( + Bus { + phantom: PhantomData, + ep_in: self.ep_in, + ep_out: self.ep_out, + phy_type: self.phy_type, + enabled: false, + }, + ControlPipe { + _phantom: PhantomData, + max_packet_size: control_max_packet_size, + ep_out, + ep_in, + }, + ) + } +} + +pub struct Bus<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + ep_in: [Option; MAX_EP_COUNT], + ep_out: [Option; MAX_EP_COUNT], + phy_type: PhyType, + enabled: bool, +} + +impl<'d, T: Instance> Bus<'d, T> { + fn restore_irqs() { + // SAFETY: atomic write + unsafe { + T::regs().gintmsk().write(|w| { + w.set_usbrst(true); + w.set_enumdnem(true); + w.set_usbsuspm(true); + w.set_wuim(true); + w.set_iepint(true); + w.set_oepint(true); + w.set_rxflvlm(true); + }); + } + } +} + +impl<'d, T: Instance> Bus<'d, T> { + fn init_fifo(&mut self) { + trace!("init_fifo"); + + let r = T::regs(); + + // Configure RX fifo size. All endpoints share the same FIFO area. + let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); + trace!("configuring rx fifo size={}", rx_fifo_size_words); + + // SAFETY: register is exclusive to `Bus` with `&mut self` + unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) }; + + // Configure TX (USB in direction) fifo size for each endpoint + let mut fifo_top = rx_fifo_size_words; + for i in 0..T::ENDPOINT_COUNT { + if let Some(ep) = self.ep_in[i] { + trace!( + "configuring tx fifo ep={}, offset={}, size={}", + i, + fifo_top, + ep.fifo_size_words + ); + + let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; + + // SAFETY: register is exclusive to `Bus` with `&mut self` + unsafe { + dieptxf.write(|w| { + w.set_fd(ep.fifo_size_words); + w.set_sa(fifo_top); + }); + } + + fifo_top += ep.fifo_size_words; + } + } + + assert!( + fifo_top <= T::FIFO_DEPTH_WORDS, + "FIFO allocations exceeded maximum capacity" + ); + } + + fn configure_endpoints(&mut self) { + trace!("configure_endpoints"); + + let r = T::regs(); + + // Configure IN endpoints + for (index, ep) in self.ep_in.iter().enumerate() { + if let Some(ep) = ep { + // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW + critical_section::with(|_| unsafe { + r.diepctl(index).write(|w| { + if index == 0 { + w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); + } else { + w.set_mpsiz(ep.max_packet_size); + w.set_eptyp(to_eptyp(ep.ep_type)); + w.set_sd0pid_sevnfrm(true); + } + }); + }); + } + } + + // Configure OUT endpoints + for (index, ep) in self.ep_out.iter().enumerate() { + if let Some(ep) = ep { + // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW + critical_section::with(|_| unsafe { + r.doepctl(index).write(|w| { + if index == 0 { + w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); + } else { + w.set_mpsiz(ep.max_packet_size); + w.set_eptyp(to_eptyp(ep.ep_type)); + w.set_sd0pid_sevnfrm(true); + } + }); + + r.doeptsiz(index).modify(|w| { + w.set_xfrsiz(ep.max_packet_size as _); + if index == 0 { + w.set_rxdpid_stupcnt(1); + } else { + w.set_pktcnt(1); + } + }); + }); + } + } + + // Enable IRQs for allocated endpoints + // SAFETY: register is exclusive to `Bus` with `&mut self` + unsafe { + r.daintmsk().modify(|w| { + w.set_iepm(ep_irq_mask(&self.ep_in)); + // OUT interrupts not used, handled in RXFLVL + // w.set_oepm(ep_irq_mask(&self.ep_out)); + }); + } + } + + fn disable(&mut self) { + unsafe { T::Interrupt::steal() }.disable(); + + ::disable(); + + #[cfg(stm32l4)] + unsafe { + crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); + // Cannot disable PWR, because other peripherals might be using it + } + } +} + impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { async fn poll(&mut self) -> Event { poll_fn(move |cx| { @@ -902,9 +902,8 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { ::enable(); ::reset(); - self.irq.set_handler(Self::on_interrupt); - self.irq.unpend(); - self.irq.enable(); + T::Interrupt::steal().unpend(); + T::Interrupt::steal().enable(); let r = T::regs(); let core_id = r.cid().read().0; diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index 07cad84e..663099ff 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -8,13 +8,17 @@ use embassy_futures::join::join; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::{Duration, Timer}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USB_LP_CAN1_RX0 => usb::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -35,8 +39,7 @@ async fn main(_spawner: Spawner) { } // Create the driver, from the HAL. - let irq = interrupt::take!(USB_LP_CAN1_RX0); - let driver = Driver::new(p.USB, irq, p.PA12, p.PA11); + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); // Create embassy-usb Config let config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 47121acf..85f01a69 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -7,19 +7,22 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USART1 => usart::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); - let irq = interrupt::take!(USART1); - let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, irq, p.DMA1_CH4, NoDma, config); + let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index 5b4e0a91..f15f333b 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -8,13 +8,17 @@ use embassy_futures::join::join; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::time::mhz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::{Duration, Timer}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USB_LP_CAN_RX0 => usb::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -33,8 +37,7 @@ async fn main(_spawner: Spawner) { dp_pullup.set_high(); // Create the driver, from the HAL. - let irq = interrupt::take!(USB_LP_CAN_RX0); - let driver = Driver::new(p.USB, irq, p.PA12, p.PA11); + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); // Create embassy-usb Config let config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs index f8ae0890..a9295732 100644 --- a/examples/stm32f4/src/bin/i2c.rs +++ b/examples/stm32f4/src/bin/i2c.rs @@ -6,25 +6,28 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; -use embassy_stm32::interrupt; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello world!"); let p = embassy_stm32::init(Default::default()); - let irq = interrupt::take!(I2C2_EV); let mut i2c = I2c::new( p.I2C2, p.PB10, p.PB11, - irq, + Irqs, NoDma, NoDma, Hertz(100_000), diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index eeecbd32..6ec7d0fe 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -6,13 +6,17 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; use embassy_stm32::time::mhz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; use {defmt_rtt as _, panic_probe as _}; /// This is a safeguard to not overwrite any data on the SD card. /// If you don't care about SD card contents, set this to `true` to test writes. const ALLOW_WRITES: bool = false; +bind_interrupts!(struct Irqs { + SDIO => sdmmc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -21,11 +25,9 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); info!("Hello World!"); - let irq = interrupt::take!(SDIO); - let mut sdmmc = Sdmmc::new_4bit( p.SDIO, - irq, + Irqs, p.DMA2_CH3, p.PC12, p.PD2, diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 8f41bb6c..7680fe84 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs @@ -5,10 +5,14 @@ use cortex_m_rt::entry; use defmt::*; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USART3 => usart::InterruptHandler; +}); + #[entry] fn main() -> ! { info!("Hello World!"); @@ -16,8 +20,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let irq = interrupt::take!(USART3); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, NoDma, NoDma, config); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index a93f8bae..c573dc3a 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs @@ -4,11 +4,15 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::interrupt; use embassy_stm32::usart::{BufferedUart, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use embedded_io::asynch::BufRead; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USART3 => usart::BufferedInterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); @@ -16,10 +20,9 @@ async fn main(_spawner: Spawner) { let config = Config::default(); - let irq = interrupt::take!(USART3); let mut tx_buf = [0u8; 32]; let mut rx_buf = [0u8; 32]; - let mut buf_usart = BufferedUart::new(p.USART3, irq, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config); + let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config); loop { let buf = buf_usart.fill_buf().await.unwrap(); diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index 78baeaa0..3408ec37 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -7,19 +7,22 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USART3 => usart::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); - let irq = interrupt::take!(USART3); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, p.DMA1_CH3, NoDma, config); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 9131e589..c4e395f0 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -9,7 +9,7 @@ use embassy_net::{Stack, StackResources}; use embassy_stm32::rng::Rng; use embassy_stm32::time::mhz; use embassy_stm32::usb_otg::Driver; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; @@ -45,6 +45,10 @@ async fn net_task(stack: &'static Stack>) -> ! { stack.run().await } +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + #[embassy_executor::main] async fn main(spawner: Spawner) { info!("Hello World!"); @@ -56,9 +60,8 @@ async fn main(spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(OTG_FS); let ep_out_buffer = &mut singleton!([0; 256])[..]; - let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, ep_out_buffer); + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index d2b1dca4..f8f5940a 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -6,13 +6,17 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::mhz; use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use futures::future::join; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -24,9 +28,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(OTG_FS); let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer); + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index b947361a..6d286c36 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -11,7 +11,7 @@ use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::mhz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, eth, Config}; use embassy_time::{Duration, Timer}; use embedded_io::asynch::Write; use rand_core::RngCore; @@ -27,6 +27,10 @@ macro_rules! singleton { }}; } +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; +}); + type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] @@ -48,13 +52,12 @@ async fn main(spawner: Spawner) -> ! { rng.fill_bytes(&mut seed); let seed = u64::from_le_bytes(seed); - let eth_int = interrupt::take!(ETH); let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; let device = Ethernet::new( singleton!(PacketQueue::<16, 16>::new()), p.ETH, - eth_int, + Irqs, p.PA1, p.PA2, p.PC1, diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index c050a400..9d43892a 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -6,9 +6,13 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::Sdmmc; use embassy_stm32::time::mhz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + SDMMC1 => sdmmc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -18,11 +22,9 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let irq = interrupt::take!(SDMMC1); - let mut sdmmc = Sdmmc::new_4bit( p.SDMMC1, - irq, + Irqs, p.DMA2_CH3, p.PC12, p.PD2, diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index 4827c52a..4700287a 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs @@ -7,17 +7,20 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let irq = interrupt::take!(UART7); - let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, irq, p.DMA1_CH1, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index dca90d9c..763309ce 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -6,13 +6,17 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::mhz; use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use futures::future::join; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -25,9 +29,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(OTG_FS); let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer); + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index b2e252fc..fa1f225f 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -12,7 +12,7 @@ use embassy_stm32::peripherals::ETH; use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, eth, Config}; use embassy_time::{Duration, Timer}; use embedded_io::asynch::Write; use rand_core::RngCore; @@ -28,6 +28,10 @@ macro_rules! singleton { }}; } +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; +}); + type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] @@ -67,13 +71,12 @@ async fn main(spawner: Spawner) -> ! { rng.fill_bytes(&mut seed); let seed = u64::from_le_bytes(seed); - let eth_int = interrupt::take!(ETH); let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; let device = Ethernet::new( singleton!(PacketQueue::<4, 4>::new()), p.ETH, - eth_int, + Irqs, p.PA1, p.PA2, p.PC1, diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs index 6cbf58bb..8b6fe71a 100644 --- a/examples/stm32h5/src/bin/i2c.rs +++ b/examples/stm32h5/src/bin/i2c.rs @@ -5,25 +5,28 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; -use embassy_stm32::interrupt; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello world!"); let p = embassy_stm32::init(Default::default()); - let irq = interrupt::take!(I2C2_EV); let mut i2c = I2c::new( p.I2C2, p.PB10, p.PB11, - irq, + Irqs, p.GPDMA1_CH4, p.GPDMA1_CH5, Hertz(100_000), diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs index 405f18ec..0abb94ab 100644 --- a/examples/stm32h5/src/bin/usart.rs +++ b/examples/stm32h5/src/bin/usart.rs @@ -6,18 +6,21 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + #[embassy_executor::task] async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let irq = interrupt::take!(UART7); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs index 43d791aa..48264f88 100644 --- a/examples/stm32h5/src/bin/usart_dma.rs +++ b/examples/stm32h5/src/bin/usart_dma.rs @@ -8,19 +8,22 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + #[embassy_executor::task] async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let irq = interrupt::take!(UART7); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs index 16a49958..debd6f45 100644 --- a/examples/stm32h5/src/bin/usart_split.rs +++ b/examples/stm32h5/src/bin/usart_split.rs @@ -5,13 +5,17 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; use embassy_stm32::usart::{Config, Uart, UartRx}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::Channel; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + #[embassy_executor::task] async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); @@ -32,8 +36,7 @@ async fn main(spawner: Spawner) -> ! { info!("Hello World!"); let config = Config::default(); - let irq = interrupt::take!(UART7); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, p.GPDMA1_CH1, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config); unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); let (mut tx, rx) = usart.split(); diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 4f987cbd..3912327e 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -7,13 +7,17 @@ use embassy_executor::Spawner; use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{interrupt, pac, Config}; +use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use futures::future::join; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USB_DRD_FS => usb::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -48,8 +52,7 @@ async fn main(_spawner: Spawner) { } // Create the driver, from the HAL. - let irq = interrupt::take!(USB_DRD_FS); - let driver = Driver::new(p.USB, irq, p.PA12, p.PA11); + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 9c443b83..6f75a063 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -8,7 +8,7 @@ use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; use embassy_stm32::time::{khz, mhz}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; use embassy_time::{Duration, Timer}; use ov7725::*; use {defmt_rtt as _, panic_probe as _}; @@ -18,6 +18,11 @@ const HEIGHT: usize = 100; static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; +bind_interrupts!(struct Irqs { + I2C1_EV => i2c::InterruptHandler; + DCMI => dcmi::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -34,12 +39,11 @@ async fn main(_spawner: Spawner) { let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(3)); let mut led = Output::new(p.PE3, Level::High, Speed::Low); - let i2c_irq = interrupt::take!(I2C1_EV); let cam_i2c = I2c::new( p.I2C1, p.PB8, p.PB9, - i2c_irq, + Irqs, p.DMA1_CH1, p.DMA1_CH2, khz(100), @@ -55,11 +59,9 @@ async fn main(_spawner: Spawner) { defmt::info!("manufacturer: 0x{:x}, pid: 0x{:x}", manufacturer_id, camera_id); - let dcmi_irq = interrupt::take!(DCMI); let config = dcmi::Config::default(); let mut dcmi = Dcmi::new_8bit( - p.DCMI, p.DMA1_CH0, dcmi_irq, p.PC6, p.PC7, p.PE0, p.PE1, p.PE4, p.PD3, p.PE5, p.PE6, p.PB7, p.PA4, p.PA6, - config, + p.DCMI, p.DMA1_CH0, Irqs, p.PC6, p.PC7, p.PE0, p.PE1, p.PE4, p.PD3, p.PE5, p.PE6, p.PB7, p.PA4, p.PA6, config, ); defmt::info!("attempting capture"); diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 61bb7e37..dbfc90cf 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -11,7 +11,7 @@ use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::mhz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, eth, Config}; use embassy_time::{Duration, Timer}; use embedded_io::asynch::Write; use rand_core::RngCore; @@ -27,6 +27,10 @@ macro_rules! singleton { }}; } +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; +}); + type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] @@ -49,13 +53,12 @@ async fn main(spawner: Spawner) -> ! { rng.fill_bytes(&mut seed); let seed = u64::from_le_bytes(seed); - let eth_int = interrupt::take!(ETH); let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; let device = Ethernet::new( singleton!(PacketQueue::<16, 16>::new()), p.ETH, - eth_int, + Irqs, p.PA1, p.PA2, p.PC1, diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index b609fa5d..14e6b791 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -11,7 +11,7 @@ use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::mhz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, eth, Config}; use embassy_time::{Duration, Timer}; use embedded_io::asynch::Write; use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; @@ -28,6 +28,10 @@ macro_rules! singleton { }}; } +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; +}); + type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] @@ -50,13 +54,12 @@ async fn main(spawner: Spawner) -> ! { rng.fill_bytes(&mut seed); let seed = u64::from_le_bytes(seed); - let eth_int = interrupt::take!(ETH); let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; let device = Ethernet::new( singleton!(PacketQueue::<16, 16>::new()), p.ETH, - eth_int, + Irqs, p.PA1, p.PA2, p.PC1, diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs index 78e03f01..c2979c59 100644 --- a/examples/stm32h7/src/bin/i2c.rs +++ b/examples/stm32h7/src/bin/i2c.rs @@ -5,25 +5,28 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; -use embassy_stm32::interrupt; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello world!"); let p = embassy_stm32::init(Default::default()); - let irq = interrupt::take!(I2C2_EV); let mut i2c = I2c::new( p.I2C2, p.PB10, p.PB11, - irq, + Irqs, p.DMA1_CH4, p.DMA1_CH5, Hertz(100_000), diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index 26d1db01..ce91b6b1 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -6,9 +6,13 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::Sdmmc; use embassy_stm32::time::mhz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + SDMMC1 => sdmmc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); @@ -16,11 +20,9 @@ async fn main(_spawner: Spawner) -> ! { let p = embassy_stm32::init(config); info!("Hello World!"); - let irq = interrupt::take!(SDMMC1); - let mut sdmmc = Sdmmc::new_4bit( p.SDMMC1, - irq, + Irqs, p.PC12, p.PD2, p.PC8, diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index 405f18ec..0abb94ab 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs @@ -6,18 +6,21 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + #[embassy_executor::task] async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let irq = interrupt::take!(UART7); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index 6e3491e5..f1fe7fce 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs @@ -8,19 +8,22 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + #[embassy_executor::task] async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let irq = interrupt::take!(UART7); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index f97176ec..330d1ce0 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs @@ -5,13 +5,17 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::peripherals::{DMA1_CH1, UART7}; use embassy_stm32::usart::{Config, Uart, UartRx}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::Channel; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + #[embassy_executor::task] async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); @@ -32,8 +36,7 @@ async fn main(spawner: Spawner) -> ! { info!("Hello World!"); let config = Config::default(); - let irq = interrupt::take!(UART7); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, p.DMA1_CH1, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config); unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); let (mut tx, rx) = usart.split(); diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 475af116..c622f19f 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -6,13 +6,17 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::mhz; use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use futures::future::join; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -24,9 +28,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(OTG_FS); let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer); + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs index c307f857..eae8f345 100644 --- a/examples/stm32l0/src/bin/usart_dma.rs +++ b/examples/stm32l0/src/bin/usart_dma.rs @@ -4,15 +4,18 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USART1 => usart::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let irq = interrupt::take!(USART1); - let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH2, p.DMA1_CH3, Config::default()); + let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default()); usart.write(b"Hello Embassy World!\r\n").await.unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index 46534700..f2c72a10 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs @@ -4,11 +4,15 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::interrupt; use embassy_stm32::usart::{BufferedUart, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use embedded_io::asynch::{Read, Write}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USART2 => usart::BufferedInterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); @@ -20,8 +24,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.baudrate = 9600; - let irq = interrupt::take!(USART2); - let mut usart = unsafe { BufferedUart::new(p.USART2, irq, p.PA3, p.PA2, &mut TX_BUFFER, &mut RX_BUFFER, config) }; + let mut usart = unsafe { BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut TX_BUFFER, &mut RX_BUFFER, config) }; usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs index d40d6803..d0060d20 100644 --- a/examples/stm32l4/src/bin/i2c.rs +++ b/examples/stm32l4/src/bin/i2c.rs @@ -6,22 +6,25 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; use embassy_stm32::i2c::I2c; -use embassy_stm32::interrupt; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let irq = interrupt::take!(I2C2_EV); let mut i2c = I2c::new( p.I2C2, p.PB10, p.PB11, - irq, + Irqs, NoDma, NoDma, Hertz(100_000), diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs index d868cac0..eca59087 100644 --- a/examples/stm32l4/src/bin/i2c_blocking_async.rs +++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs @@ -7,23 +7,26 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; use embassy_stm32::i2c::I2c; -use embassy_stm32::interrupt; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; use embedded_hal_async::i2c::I2c as I2cTrait; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let irq = interrupt::take!(I2C2_EV); let i2c = I2c::new( p.I2C2, p.PB10, p.PB11, - irq, + Irqs, NoDma, NoDma, Hertz(100_000), diff --git a/examples/stm32l4/src/bin/i2c_dma.rs b/examples/stm32l4/src/bin/i2c_dma.rs index 7e62ee63..cf6f3da6 100644 --- a/examples/stm32l4/src/bin/i2c_dma.rs +++ b/examples/stm32l4/src/bin/i2c_dma.rs @@ -5,22 +5,25 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::i2c::I2c; -use embassy_stm32::interrupt; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let irq = interrupt::take!(I2C2_EV); let mut i2c = I2c::new( p.I2C2, p.PB10, p.PB11, - irq, + Irqs, p.DMA1_CH4, p.DMA1_CH5, Hertz(100_000), diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 7d874d9d..beb5ec55 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs @@ -4,10 +4,14 @@ use defmt::*; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART4 => usart::InterruptHandler; +}); + #[cortex_m_rt::entry] fn main() -> ! { info!("Hello World!"); @@ -15,8 +19,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let irq = interrupt::take!(UART4); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, NoDma, NoDma, config); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 452bede3..b7d4cb01 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -7,19 +7,22 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + UART4 => usart::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); - let irq = interrupt::take!(UART4); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, p.DMA1_CH3, NoDma, config); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index bdb290e6..80811a43 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -7,13 +7,17 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_stm32::rcc::*; use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use futures::future::join; use panic_probe as _; +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -25,9 +29,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(OTG_FS); let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer); + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 6c5645a4..b84e53d3 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -9,7 +9,7 @@ use embassy_net::{Stack, StackResources}; use embassy_stm32::rcc::*; use embassy_stm32::rng::Rng; use embassy_stm32::usb::Driver; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; @@ -31,6 +31,10 @@ macro_rules! singleton { const MTU: usize = 1514; +bind_interrupts!(struct Irqs { + USB_FS => usb::InterruptHandler; +}); + #[embassy_executor::task] async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { device.run().await @@ -54,8 +58,7 @@ async fn main(spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(USB_FS); - let driver = Driver::new(p.USB, irq, p.PA12, p.PA11); + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index e3bbe9d0..7e894e40 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::rcc::*; use embassy_stm32::usb::Driver; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_time::{Duration, Timer}; use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; @@ -15,6 +15,10 @@ use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USB_FS => usb::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(USB_FS); - let driver = Driver::new(p.USB, irq, p.PA12, p.PA11); + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 66ccacb7..0c719560 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -7,12 +7,16 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::rcc::*; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + USB_FS => usb::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); // Create the driver, from the HAL. - let irq = interrupt::take!(USB_FS); - let driver = Driver::new(p.USB, irq, p.PA12, p.PA11); + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); // Create embassy-usb Config let config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 4882cd2e..f36daf91 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -7,13 +7,17 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_stm32::rcc::*; use embassy_stm32::usb_otg::{Driver, Instance}; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; use futures::future::join; use panic_probe as _; +bind_interrupts!(struct Irqs { + OTG_FS => usb_otg::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -26,9 +30,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); // Create the driver, from the HAL. - let irq = interrupt::take!(OTG_FS); let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer); + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index acbc60c8..326e4be8 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs @@ -4,12 +4,17 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::interrupt; use embassy_stm32::ipcc::{Config, Ipcc}; use embassy_stm32::tl_mbox::TlMbox; +use embassy_stm32::{bind_interrupts, tl_mbox}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs{ + IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; + IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { /* @@ -42,10 +47,7 @@ async fn main(_spawner: Spawner) { let config = Config::default(); let mut ipcc = Ipcc::new(p.IPCC, config); - let rx_irq = interrupt::take!(IPCC_C1_RX); - let tx_irq = interrupt::take!(IPCC_C1_TX); - - let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq); + let mbox = TlMbox::init(&mut ipcc, Irqs); loop { let wireless_fw_info = mbox.wireless_fw_info(); diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs index 1008e1e4..7a69f26b 100644 --- a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs +++ b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs @@ -4,11 +4,16 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::interrupt; use embassy_stm32::ipcc::{Config, Ipcc}; use embassy_stm32::tl_mbox::TlMbox; +use embassy_stm32::{bind_interrupts, tl_mbox}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs{ + IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; + IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { /* @@ -41,10 +46,7 @@ async fn main(_spawner: Spawner) { let config = Config::default(); let mut ipcc = Ipcc::new(p.IPCC, config); - let rx_irq = interrupt::take!(IPCC_C1_RX); - let tx_irq = interrupt::take!(IPCC_C1_TX); - - let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq); + let mbox = TlMbox::init(&mut ipcc, Irqs); // initialize ble stack, does not return a response mbox.shci_ble_init(&mut ipcc, Default::default()); diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index c4e50cb4..7d96cf41 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -7,9 +7,13 @@ use defmt::{assert_eq, *}; use embassy_executor::Spawner; use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; use embassy_stm32::time::mhz; -use embassy_stm32::{interrupt, Config}; +use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + SDIO => sdmmc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -20,17 +24,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); #[cfg(feature = "stm32f429zi")] - let (mut sdmmc, mut irq, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) = ( - p.SDIO, - interrupt::take!(SDIO), - p.DMA2_CH3, - p.PC12, - p.PD2, - p.PC8, - p.PC9, - p.PC10, - p.PC11, - ); + let (mut sdmmc, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) = + (p.SDIO, p.DMA2_CH3, p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11); // Arbitrary block index let block_idx = 16; @@ -48,7 +43,7 @@ async fn main(_spawner: Spawner) { info!("initializing in 4-bit mode..."); let mut s = Sdmmc::new_4bit( &mut sdmmc, - &mut irq, + Irqs, &mut dma, &mut clk, &mut cmd, @@ -97,7 +92,7 @@ async fn main(_spawner: Spawner) { info!("initializing in 1-bit mode..."); let mut s = Sdmmc::new_1bit( &mut sdmmc, - &mut irq, + Irqs, &mut dma, &mut clk, &mut cmd, diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 0749f840..415c7afa 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -7,11 +7,37 @@ mod example_common; use defmt::assert_eq; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Error, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_time::{Duration, Instant}; use example_common::*; +#[cfg(any( + feature = "stm32f103c8", + feature = "stm32g491re", + feature = "stm32g071rb", + feature = "stm32h755zi", + feature = "stm32c031c6", +))] +bind_interrupts!(struct Irqs { + USART1 => usart::InterruptHandler; +}); + +#[cfg(feature = "stm32u585ai")] +bind_interrupts!(struct Irqs { + USART3 => usart::InterruptHandler; +}); + +#[cfg(feature = "stm32f429zi")] +bind_interrupts!(struct Irqs { + USART6 => usart::InterruptHandler; +}); + +#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))] +bind_interrupts!(struct Irqs { + LPUART1 => usart::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config()); @@ -20,27 +46,27 @@ async fn main(_spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. #[cfg(feature = "stm32f103c8")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); + let (mut tx, mut rx, mut usart) = (p.PA9, p.PA10, p.USART1); #[cfg(feature = "stm32g491re")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); + let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1); #[cfg(feature = "stm32g071rb")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); + let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1); #[cfg(feature = "stm32f429zi")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); + let (mut tx, mut rx, mut usart) = (p.PG14, p.PG9, p.USART6); #[cfg(feature = "stm32wb55rg")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); + let (mut tx, mut rx, mut usart) = (p.PA2, p.PA3, p.LPUART1); #[cfg(feature = "stm32h755zi")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); + let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1); #[cfg(feature = "stm32u585ai")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); + let (mut tx, mut rx, mut usart) = (p.PD8, p.PD9, p.USART3); #[cfg(feature = "stm32h563zi")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1)); + let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.LPUART1); #[cfg(feature = "stm32c031c6")] - let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); + let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1); { let config = Config::default(); - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); // We can't send too many bytes, they have to fit in the FIFO. // This is because we aren't sending+receiving at the same time. @@ -56,7 +82,7 @@ async fn main(_spawner: Spawner) { // Test error handling with with an overflow error { let config = Config::default(); - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); // Send enough bytes to fill the RX FIFOs off all USART versions. let data = [0xC0, 0xDE, 0x12, 0x23, 0x34]; @@ -90,7 +116,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.baudrate = baudrate; - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); let n = (baudrate as usize / 100).max(64); diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index 62444f0a..7f002b97 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs @@ -7,10 +7,36 @@ mod example_common; use defmt::assert_eq; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use example_common::*; +#[cfg(any( + feature = "stm32f103c8", + feature = "stm32g491re", + feature = "stm32g071rb", + feature = "stm32h755zi", + feature = "stm32c031c6", +))] +bind_interrupts!(struct Irqs { + USART1 => usart::InterruptHandler; +}); + +#[cfg(feature = "stm32u585ai")] +bind_interrupts!(struct Irqs { + USART3 => usart::InterruptHandler; +}); + +#[cfg(feature = "stm32f429zi")] +bind_interrupts!(struct Irqs { + USART6 => usart::InterruptHandler; +}); + +#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))] +bind_interrupts!(struct Irqs { + LPUART1 => usart::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config()); @@ -19,62 +45,23 @@ async fn main(_spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. #[cfg(feature = "stm32f103c8")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PA9, - p.PA10, - p.USART1, - interrupt::take!(USART1), - p.DMA1_CH4, - p.DMA1_CH5, - ); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, Irqs, p.DMA1_CH4, p.DMA1_CH5); #[cfg(feature = "stm32g491re")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32g071rb")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32f429zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PG14, - p.PG9, - p.USART6, - interrupt::take!(USART6), - p.DMA2_CH6, - p.DMA2_CH1, - ); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, Irqs, p.DMA2_CH6, p.DMA2_CH1); #[cfg(feature = "stm32wb55rg")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PA2, - p.PA3, - p.LPUART1, - interrupt::take!(LPUART1), - p.DMA1_CH1, - p.DMA1_CH2, - ); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32h755zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH0, p.DMA1_CH1); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH0, p.DMA1_CH1); #[cfg(feature = "stm32u585ai")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PD8, - p.PD9, - p.USART3, - interrupt::take!(USART3), - p.GPDMA1_CH0, - p.GPDMA1_CH1, - ); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1); #[cfg(feature = "stm32h563zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PB6, - p.PB7, - p.LPUART1, - interrupt::take!(LPUART1), - p.GPDMA1_CH0, - p.GPDMA1_CH1, - ); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.LPUART1, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1); #[cfg(feature = "stm32c031c6")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); let config = Config::default(); let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index 9d75dbe5..3a34773f 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -8,13 +8,40 @@ mod example_common; use defmt::{assert_eq, panic}; use embassy_executor::Spawner; -use embassy_stm32::interrupt; use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_time::{Duration, Timer}; use example_common::*; use rand_chacha::ChaCha8Rng; use rand_core::{RngCore, SeedableRng}; +#[cfg(any( + feature = "stm32f103c8", + feature = "stm32g491re", + feature = "stm32g071rb", + feature = "stm32h755zi", + feature = "stm32c031c6", +))] +bind_interrupts!(struct Irqs { + USART1 => usart::InterruptHandler; +}); + +#[cfg(feature = "stm32u585ai")] +bind_interrupts!(struct Irqs { + USART3 => usart::InterruptHandler; +}); + +#[cfg(feature = "stm32f429zi")] +bind_interrupts!(struct Irqs { + USART1 => usart::InterruptHandler; + USART6 => usart::InterruptHandler; +}); + +#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))] +bind_interrupts!(struct Irqs { + LPUART1 => usart::InterruptHandler; +}); + #[cfg(feature = "stm32f103c8")] mod board { pub type Uart = embassy_stm32::peripherals::USART1; @@ -74,53 +101,21 @@ async fn main(spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. #[cfg(feature = "stm32f103c8")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PA9, - p.PA10, - p.USART1, - interrupt::take!(USART1), - p.DMA1_CH4, - p.DMA1_CH5, - ); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); #[cfg(feature = "stm32g491re")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32g071rb")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32f429zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PG14, - p.PG9, - p.USART6, - interrupt::take!(USART6), - p.DMA2_CH6, - p.DMA2_CH1, - ); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); #[cfg(feature = "stm32wb55rg")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PA2, - p.PA3, - p.LPUART1, - interrupt::take!(LPUART1), - p.DMA1_CH1, - p.DMA1_CH2, - ); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2); #[cfg(feature = "stm32h755zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH0, p.DMA1_CH1); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); #[cfg(feature = "stm32u585ai")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = ( - p.PD8, - p.PD9, - p.USART3, - interrupt::take!(USART3), - p.GPDMA1_CH0, - p.GPDMA1_CH1, - ); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); #[cfg(feature = "stm32c031c6")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = - (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); + let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH1, p.DMA1_CH2); // To run this test, use the saturating_serial test utility to saturate the serial port @@ -132,7 +127,7 @@ async fn main(spawner: Spawner) { config.stop_bits = StopBits::STOP1; config.parity = Parity::ParityNone; - let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); + let usart = Uart::new(usart, rx, tx, Irqs, tx_dma, rx_dma, config); let (tx, rx) = usart.split(); static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE]; let dma_buf = unsafe { DMA_BUF.as_mut() }; From b6ba1ea53ada2f503ae89de66490957723a21866 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 24 May 2023 18:09:04 -0500 Subject: [PATCH 2/2] stm32: move lora to bind_interrupts --- ci.sh | 2 +- embassy-lora/src/iv.rs | 74 +++++++++++--------- examples/stm32wl/src/bin/lora_lorawan.rs | 12 ++-- examples/stm32wl/src/bin/lora_p2p_receive.rs | 12 ++-- examples/stm32wl/src/bin/lora_p2p_send.rs | 12 ++-- examples/stm32wl/src/bin/uart_async.rs | 15 ++-- 6 files changed, 71 insertions(+), 56 deletions(-) diff --git a/ci.sh b/ci.sh index 106689d0..2c46dcc6 100755 --- a/ci.sh +++ b/ci.sh @@ -112,6 +112,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ + --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 --out-dir out/examples/boot/nrf --bin b \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns --out-dir out/examples/boot/nrf --bin b \ --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/boot/rp --bin b \ @@ -142,7 +143,6 @@ cargo batch \ $BUILD_EXTRA -# --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ function run_elf { echo Running target=$1 elf=$2 diff --git a/embassy-lora/src/iv.rs b/embassy-lora/src/iv.rs index f8113440..d515bc36 100644 --- a/embassy-lora/src/iv.rs +++ b/embassy-lora/src/iv.rs @@ -1,7 +1,9 @@ #[cfg(feature = "stm32wl")] +use embassy_stm32::interrupt; +#[cfg(feature = "stm32wl")] use embassy_stm32::interrupt::*; #[cfg(feature = "stm32wl")] -use embassy_stm32::{pac, PeripheralRef}; +use embassy_stm32::pac; #[cfg(feature = "stm32wl")] use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; #[cfg(feature = "stm32wl")] @@ -13,47 +15,51 @@ use lora_phy::mod_params::RadioError::*; use lora_phy::mod_params::{BoardType, RadioError}; use lora_phy::mod_traits::InterfaceVariant; +/// Interrupt handler. #[cfg(feature = "stm32wl")] -static IRQ_SIGNAL: Signal = Signal::new(); +pub struct InterruptHandler {} #[cfg(feature = "stm32wl")] -/// Base for the InterfaceVariant implementation for an stm32wl/sx1262 combination -pub struct Stm32wlInterfaceVariant<'a, CTRL> { - board_type: BoardType, - irq: PeripheralRef<'a, SUBGHZ_RADIO>, - rf_switch_rx: Option, - rf_switch_tx: Option, -} - -#[cfg(feature = "stm32wl")] -impl<'a, CTRL> Stm32wlInterfaceVariant<'a, CTRL> -where - CTRL: OutputPin, -{ - /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination - pub fn new( - irq: PeripheralRef<'a, SUBGHZ_RADIO>, - rf_switch_rx: Option, - rf_switch_tx: Option, - ) -> Result { - irq.disable(); - irq.set_handler(Self::on_interrupt); - Ok(Self { - board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board - irq, - rf_switch_rx, - rf_switch_tx, - }) - } - - fn on_interrupt(_: *mut ()) { +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { unsafe { SUBGHZ_RADIO::steal() }.disable(); IRQ_SIGNAL.signal(()); } } #[cfg(feature = "stm32wl")] -impl InterfaceVariant for Stm32wlInterfaceVariant<'_, CTRL> +static IRQ_SIGNAL: Signal = Signal::new(); + +#[cfg(feature = "stm32wl")] +/// Base for the InterfaceVariant implementation for an stm32wl/sx1262 combination +pub struct Stm32wlInterfaceVariant { + board_type: BoardType, + rf_switch_rx: Option, + rf_switch_tx: Option, +} + +#[cfg(feature = "stm32wl")] +impl<'a, CTRL> Stm32wlInterfaceVariant +where + CTRL: OutputPin, +{ + /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination + pub fn new( + _irq: impl interrupt::Binding, + rf_switch_rx: Option, + rf_switch_tx: Option, + ) -> Result { + unsafe { interrupt::SUBGHZ_RADIO::steal() }.disable(); + Ok(Self { + board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board + rf_switch_rx, + rf_switch_tx, + }) + } +} + +#[cfg(feature = "stm32wl")] +impl InterfaceVariant for Stm32wlInterfaceVariant where CTRL: OutputPin, { @@ -89,7 +95,7 @@ where } async fn await_irq(&mut self) -> Result<(), RadioError> { - self.irq.enable(); + unsafe { interrupt::SUBGHZ_RADIO::steal() }.enable(); IRQ_SIGNAL.wait().await; Ok(()) } diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs index 1a271b2f..e179c5ca 100644 --- a/examples/stm32wl/src/bin/lora_lorawan.rs +++ b/examples/stm32wl/src/bin/lora_lorawan.rs @@ -7,12 +7,12 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_lora::iv::Stm32wlInterfaceVariant; +use embassy_lora::iv::{InterruptHandler, Stm32wlInterfaceVariant}; use embassy_lora::LoraTimer; use embassy_stm32::gpio::{Level, Output, Pin, Speed}; use embassy_stm32::rng::Rng; use embassy_stm32::spi::Spi; -use embassy_stm32::{interrupt, into_ref, pac, Peripheral}; +use embassy_stm32::{bind_interrupts, pac}; use embassy_time::Delay; use lora_phy::mod_params::*; use lora_phy::sx1261_2::SX1261_2; @@ -24,6 +24,10 @@ use {defmt_rtt as _, panic_probe as _}; const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region +bind_interrupts!(struct Irqs{ + SUBGHZ_RADIO => InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); @@ -35,13 +39,11 @@ async fn main(_spawner: Spawner) { let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); - let irq = interrupt::take!(SUBGHZ_RADIO); - into_ref!(irq); // Set CTRL1 and CTRL3 for high-power transmission, while CTRL2 acts as an RF switch between tx and rx let _ctrl1 = Output::new(p.PC4.degrade(), Level::Low, Speed::High); let ctrl2 = Output::new(p.PC5.degrade(), Level::High, Speed::High); let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); - let iv = Stm32wlInterfaceVariant::new(irq, None, Some(ctrl2)).unwrap(); + let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); let mut delay = Delay; diff --git a/examples/stm32wl/src/bin/lora_p2p_receive.rs b/examples/stm32wl/src/bin/lora_p2p_receive.rs index 5e80e8f6..d3f051b1 100644 --- a/examples/stm32wl/src/bin/lora_p2p_receive.rs +++ b/examples/stm32wl/src/bin/lora_p2p_receive.rs @@ -7,10 +7,10 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_lora::iv::Stm32wlInterfaceVariant; +use embassy_lora::iv::{InterruptHandler, Stm32wlInterfaceVariant}; +use embassy_stm32::bind_interrupts; use embassy_stm32::gpio::{Level, Output, Pin, Speed}; use embassy_stm32::spi::Spi; -use embassy_stm32::{interrupt, into_ref, Peripheral}; use embassy_time::{Delay, Duration, Timer}; use lora_phy::mod_params::*; use lora_phy::sx1261_2::SX1261_2; @@ -19,6 +19,10 @@ use {defmt_rtt as _, panic_probe as _}; const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region +bind_interrupts!(struct Irqs{ + SUBGHZ_RADIO => InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); @@ -27,13 +31,11 @@ async fn main(_spawner: Spawner) { let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); - let irq = interrupt::take!(SUBGHZ_RADIO); - into_ref!(irq); // Set CTRL1 and CTRL3 for high-power transmission, while CTRL2 acts as an RF switch between tx and rx let _ctrl1 = Output::new(p.PC4.degrade(), Level::Low, Speed::High); let ctrl2 = Output::new(p.PC5.degrade(), Level::High, Speed::High); let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); - let iv = Stm32wlInterfaceVariant::new(irq, None, Some(ctrl2)).unwrap(); + let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); let mut delay = Delay; diff --git a/examples/stm32wl/src/bin/lora_p2p_send.rs b/examples/stm32wl/src/bin/lora_p2p_send.rs index e22c714b..fc5205c8 100644 --- a/examples/stm32wl/src/bin/lora_p2p_send.rs +++ b/examples/stm32wl/src/bin/lora_p2p_send.rs @@ -7,10 +7,10 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_lora::iv::Stm32wlInterfaceVariant; +use embassy_lora::iv::{InterruptHandler, Stm32wlInterfaceVariant}; +use embassy_stm32::bind_interrupts; use embassy_stm32::gpio::{Level, Output, Pin, Speed}; use embassy_stm32::spi::Spi; -use embassy_stm32::{interrupt, into_ref, Peripheral}; use embassy_time::Delay; use lora_phy::mod_params::*; use lora_phy::sx1261_2::SX1261_2; @@ -19,6 +19,10 @@ use {defmt_rtt as _, panic_probe as _}; const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region +bind_interrupts!(struct Irqs{ + SUBGHZ_RADIO => InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); @@ -27,13 +31,11 @@ async fn main(_spawner: Spawner) { let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); - let irq = interrupt::take!(SUBGHZ_RADIO); - into_ref!(irq); // Set CTRL1 and CTRL3 for high-power transmission, while CTRL2 acts as an RF switch between tx and rx let _ctrl1 = Output::new(p.PC4.degrade(), Level::Low, Speed::High); let ctrl2 = Output::new(p.PC5.degrade(), Level::High, Speed::High); let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); - let iv = Stm32wlInterfaceVariant::new(irq, None, Some(ctrl2)).unwrap(); + let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); let mut delay = Delay; diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index ac8766af..07b0f9d2 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -4,10 +4,15 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::interrupt; -use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::usart::{Config, InterruptHandler, Uart}; +use embassy_stm32::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs{ + USART1 => InterruptHandler; + LPUART1 => InterruptHandler; +}); + /* Pass Incoming data from LPUART1 to USART1 Example is written for the LoRa-E5 mini v1.0, @@ -28,12 +33,10 @@ async fn main(_spawner: Spawner) { config2.baudrate = 9600; //RX/TX connected to USB/UART Bridge on LoRa-E5 mini v1.0 - let irq = interrupt::take!(USART1); - let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH3, p.DMA1_CH4, config1); + let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH3, p.DMA1_CH4, config1); //RX1/TX1 (LPUART) on LoRa-E5 mini v1.0 - let irq = interrupt::take!(LPUART1); - let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, irq, p.DMA1_CH5, p.DMA1_CH6, config2); + let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, Irqs, p.DMA1_CH5, p.DMA1_CH6, config2); unwrap!(usart1.write(b"Hello Embassy World!\r\n").await); unwrap!(usart2.write(b"Hello Embassy World!\r\n").await);