From 0dc31233f4197fdbe1ab6daba992b034ccf0e4cb Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Sun, 10 Dec 2023 16:42:07 -0500 Subject: [PATCH] Add multiple interrupt sources to single handler; Fix examples --- boards/feather_m0/Cargo.toml | 33 ++----- boards/feather_m0/examples/async_dmac.rs | 40 +++----- boards/feather_m0/examples/async_eic.rs | 57 ++++++------ boards/feather_m0/examples/async_i2c.rs | 43 ++++----- boards/feather_m0/examples/async_spi.rs | 43 ++++----- boards/feather_m0/examples/async_timer.rs | 49 +++++----- boards/feather_m0/examples/async_uart.rs | 45 ++++----- boards/feather_m0/examples/blinky_rtic.rs | 57 +++++------- boards/feather_m0/examples/dmac_embassy.rs | 74 --------------- boards/metro_m4/.cargo/config | 2 +- boards/metro_m4/Cargo.toml | 14 +-- boards/metro_m4/examples/async_dmac.rs | 95 +++++++++++++++++++ boards/metro_m4/examples/dmac_async.rs | 103 --------------------- hal/src/async_hal/interrupts.rs | 56 +++++++---- hal/src/async_hal/mod.rs | 47 ++++++---- hal/src/dmac/async_api.rs | 99 ++++++-------------- hal/src/dmac/dma_controller.rs | 62 +++---------- hal/src/sercom/mod.rs | 3 +- hal/src/sercom/spi/async_api.rs | 3 +- hal/src/thumbv6m/eic/mod.rs | 1 + hal/src/thumbv7em/eic/mod.rs | 3 + 21 files changed, 364 insertions(+), 565 deletions(-) delete mode 100644 boards/feather_m0/examples/dmac_embassy.rs create mode 100644 boards/metro_m4/examples/async_dmac.rs delete mode 100644 boards/metro_m4/examples/dmac_async.rs diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml index 46e6e4ad4b38..93e2a4a6f717 100644 --- a/boards/feather_m0/Cargo.toml +++ b/boards/feather_m0/Cargo.toml @@ -36,14 +36,9 @@ optional = true version = "0.3" optional = true -[dependencies.cortex-m-interrupt] -version = "0.2.1-git" -optional = true -git = "https://github.com/datdenkikniet/cortex-m-interrupt.git" -rev = "9baa936" - [dev-dependencies] -cortex-m-rtic = "1.1.3" +rtic = { version = "2.0.1", features = ["thumbv6-backend"] } +rtic-monotonics = { version = "1.3.0", features = ["cortex-m-systick", "systick-10khz"] } fugit = "0.3.6" cortex-m = "0.7" usbd-serial = "0.1" @@ -58,7 +53,6 @@ panic-semihosting = "0.5" defmt = "0.3" defmt-rtt = "0.3" panic-probe = "0.3" -embassy-executor = { version = "0.3.3", features = ["arch-cortex-m", "defmt", "executor-thread", "executor-interrupt", "nightly"] } [features] # ask the HAL to enable atsamd21g support @@ -76,8 +70,8 @@ max-channels = ["dma", "atsamd-hal/max-channels"] # Enable pins for the adalogger SD card reader adalogger = [] sdmmc = ["embedded-sdmmc", "atsamd-hal/sdmmc"] -rtic = ["atsamd-hal/rtic"] use_semihosting = [] +nightly = [] [profile.dev] incremental = false @@ -146,7 +140,7 @@ required-features = ["adalogger", "usb", "sdmmc", "unproven"] [[example]] name = "blinky_rtic" -required-features = ["rtic", "unproven"] +required-features = ["unproven", "nightly"] [[example]] name = "uart" @@ -158,31 +152,24 @@ required-features = ["dma"] [[example]] name = "async_dmac" -required-features = ["dma", "atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"] - -[[example]] -name = "dmac_embassy" -required-features = ["dma", "atsamd-hal/async", "cortex-m-interrupt"] +required-features = ["dma", "atsamd-hal/async", "nightly"] [[example]] name = "async_timer" -required-features = ["atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"] +required-features = ["atsamd-hal/async", "nightly"] [[example]] name = "async_eic" -required-features = ["atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"] +required-features = ["atsamd-hal/async", "nightly"] [[example]] name = "async_i2c" -required-features = ["dma", "atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"] +required-features = ["dma", "atsamd-hal/async", "nightly"] [[example]] name = "async_spi" -required-features = ["dma", "atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"] +required-features = ["dma", "atsamd-hal/async", "nightly"] [[example]] name = "async_uart" -required-features = ["dma", "atsamd-hal/async", "atsamd-hal/rtic", "cortex-m-interrupt"] - -[patch.crates-io] -cortex-m-rtic = { git = "https://github.com/rtic-rs/cortex-m-rtic.git", branch = "async-2022" } +required-features = ["dma", "atsamd-hal/async", "nightly"] \ No newline at end of file diff --git a/boards/feather_m0/examples/async_dmac.rs b/boards/feather_m0/examples/async_dmac.rs index 0f51c5137d96..7b555620bdb0 100644 --- a/boards/feather_m0/examples/async_dmac.rs +++ b/boards/feather_m0/examples/async_dmac.rs @@ -3,6 +3,7 @@ #![no_std] #![no_main] +#![feature(type_alias_impl_trait)] use defmt_rtt as _; use panic_probe as _; @@ -13,20 +14,15 @@ atsamd_hal::bind_interrupts!(struct Irqs { #[rtic::app(device = bsp::pac, dispatchers = [I2S])] mod app { - use bsp::{hal, pac}; + use bsp::hal; use feather_m0 as bsp; use hal::{ - clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, + clock::GenericClockController, dmac::{ - self, Ch0, Channel, DmaController, PriorityLevel, ReadyFuture, TriggerAction, - TriggerSource, + Ch0, Channel, DmaController, PriorityLevel, ReadyFuture, TriggerAction, TriggerSource, }, - rtc::{Count32Mode, Rtc}, }; - #[monotonic(binds = RTC, default = true)] - type Monotonic = Rtc; - #[shared] struct Shared {} @@ -36,34 +32,20 @@ mod app { } #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(cx: init::Context) -> (Shared, Local) { let mut peripherals = cx.device; let _core = cx.core; - let mut clocks = GenericClockController::with_external_32kosc( + let _clocks = GenericClockController::with_external_32kosc( peripherals.GCLK, &mut peripherals.PM, &mut peripherals.SYSCTRL, &mut peripherals.NVMCTRL, ); - enable_internal_32kosc(&mut peripherals.SYSCTRL); - let timer_clock = clocks - .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::OSC32K, false) - .unwrap(); - clocks.configure_standby(ClockGenId::GCLK2, true); - - // Setup RTC monotonic - let rtc_clock = clocks.rtc(&timer_clock).unwrap(); - let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); - // Initialize DMA Controller let dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); - // Get handle to IRQ - let dmac_irq = dmac::Interrupts::new(cortex_m_interrupt::take_nvic_interrupt!( - pac::Interrupt::DMAC, - 2 - )); + // Turn dmac into an async controller let mut dmac = dmac.into_future(crate::Irqs); // Get individual handles to DMA channels @@ -73,15 +55,15 @@ mod app { let channel = channels.0.init(PriorityLevel::LVL0); async_task::spawn().ok(); - (Shared {}, Local { channel }, init::Monotonics(rtc)) + (Shared {}, Local { channel }) } #[task(local = [channel])] async fn async_task(cx: async_task::Context) { - let async_task::LocalResources { channel } = cx.local; + let channel = cx.local.channel; - let mut source = [0xff; 50]; - let mut dest = [0x0; 50]; + let mut source = [0xff; 500]; + let mut dest = [0x0; 500]; defmt::info!( "Launching a DMA transfer.\n\tSource: {}\n\tDestination: {}", diff --git a/boards/feather_m0/examples/async_eic.rs b/boards/feather_m0/examples/async_eic.rs index 96daddda07b3..3b9c628d2605 100644 --- a/boards/feather_m0/examples/async_eic.rs +++ b/boards/feather_m0/examples/async_eic.rs @@ -5,35 +5,38 @@ use defmt_rtt as _; use panic_probe as _; +use bsp::{hal, pin_alias}; +use feather_m0 as bsp; +use hal::{ + clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, + ehal::digital::v2::ToggleableOutputPin, + eic::{ + pin::{ExtInt2, Sense}, + EIC, + }, + gpio::{pin::PA18, Pin, PullUpInterrupt}, + rtc::{Count32Mode, Rtc}, +}; + +atsamd_hal::bind_interrupts!(struct Irqs { + EIC => atsamd_hal::eic::InterruptHandler; +}); + #[rtic::app(device = bsp::pac, dispatchers = [I2S])] mod app { - use bsp::{hal, pac, pin_alias}; - use feather_m0 as bsp; - use hal::{ - clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, - ehal::digital::v2::ToggleableOutputPin, - eic::{ - pin::{ExtInt2, Sense}, - EIC, - }, - gpio::{pin::PA18, Pin, PullUpInterrupt}, - rtc::{Count32Mode, Rtc}, - }; - - #[monotonic(binds = RTC, default = true)] - type Monotonic = Rtc; + use super::*; #[shared] struct Shared {} #[local] struct Local { - extint: ExtInt2, hal::pac::Interrupt>, + extint: ExtInt2>, red_led: bsp::RedLed, } #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(cx: init::Context) -> (Shared, Local) { let mut peripherals = cx.device; let _core = cx.core; @@ -46,33 +49,25 @@ mod app { let pins = bsp::Pins::new(peripherals.PORT); let red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); - let timer_clock = clocks + let internal_clock = clocks .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::OSC32K, false) .unwrap(); clocks.configure_standby(ClockGenId::GCLK2, true); - let eic_irq = cortex_m_interrupt::take_nvic_interrupt!(pac::Interrupt::EIC, 2); - // tc4_irq.set_priority(2); - enable_internal_32kosc(&mut peripherals.SYSCTRL); - // Setup RTC monotonic - let rtc_clock = clocks.rtc(&timer_clock).unwrap(); - let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); - - // configure a clock for the EIC peripheral - let gclk0 = clocks.gclk0(); - let eic_clock = clocks.eic(&gclk0).unwrap(); + // Configure a clock for the EIC peripheral + let gclk2 = clocks.gclk2(); + let eic_clock = clocks.eic(&gclk2).unwrap(); - let mut eic = - EIC::init(&mut peripherals.PM, eic_clock, peripherals.EIC).into_future(eic_irq); + let mut eic = EIC::init(&mut peripherals.PM, eic_clock, peripherals.EIC).into_future(Irqs); let button: Pin<_, PullUpInterrupt> = pins.d10.into(); let mut extint = ExtInt2::new(button, &mut eic); extint.enable_interrupt_wake(); async_task::spawn().ok(); - (Shared {}, Local { extint, red_led }, init::Monotonics(rtc)) + (Shared {}, Local { extint, red_led }) } #[task(local = [extint, red_led])] diff --git a/boards/feather_m0/examples/async_i2c.rs b/boards/feather_m0/examples/async_i2c.rs index f193afc96d49..d7d26124dfb9 100644 --- a/boards/feather_m0/examples/async_i2c.rs +++ b/boards/feather_m0/examples/async_i2c.rs @@ -5,7 +5,19 @@ use defmt_rtt as _; use panic_probe as _; -use atsamd_hal::sercom::Sercom3; +use bsp::hal; +use feather_m0 as bsp; +use fugit::MillisDuration; +use hal::{ + clock::GenericClockController, + dmac::{Ch0, DmaController, PriorityLevel}, + prelude::*, + sercom::{ + i2c::{self, Config, I2cFutureDma}, + Sercom3, + }, +}; +use rtic_monotonics::systick::Systick; atsamd_hal::bind_interrupts!(struct Irqs { SERCOM3 => atsamd_hal::sercom::i2c::InterruptHandler; @@ -15,19 +27,6 @@ atsamd_hal::bind_interrupts!(struct Irqs { #[rtic::app(device = bsp::pac, dispatchers = [I2S])] mod app { use super::*; - use bsp::hal; - use feather_m0 as bsp; - use fugit::MillisDuration; - use hal::{ - clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, - dmac::{Ch0, DmaController, PriorityLevel}, - prelude::*, - rtc::{Count32Mode, Rtc}, - sercom::i2c::{self, Config, I2cFutureDma}, - }; - - #[monotonic(binds = RTC, default = true)] - type Monotonic = Rtc; #[shared] struct Shared {} @@ -38,7 +37,7 @@ mod app { } #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(cx: init::Context) -> (Shared, Local) { let mut peripherals = cx.device; let _core = cx.core; @@ -54,16 +53,6 @@ mod app { // Take SDA and SCL let (sda, scl) = (pins.sda, pins.scl); - enable_internal_32kosc(&mut peripherals.SYSCTRL); - let timer_clock = clocks - .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::OSC32K, false) - .unwrap(); - clocks.configure_standby(ClockGenId::GCLK2, true); - - // Setup RTC monotonic - let rtc_clock = clocks.rtc(&timer_clock).unwrap(); - let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); - // Initialize DMA Controller let dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); @@ -91,7 +80,7 @@ mod app { async_task::spawn().ok(); - (Shared {}, Local { i2c }, init::Monotonics(rtc)) + (Shared {}, Local { i2c }) } #[task(local = [i2c])] @@ -107,7 +96,7 @@ mod app { let mut buffer = [0xff; 4]; i2c.read(0x76, &mut buffer).await.unwrap(); defmt::info!("Read buffer: {:#x}", buffer); - crate::app::monotonics::delay(MillisDuration::::from_ticks(500).convert()).await; + Systick::delay(MillisDuration::::from_ticks(500).convert()).await; } } } diff --git a/boards/feather_m0/examples/async_spi.rs b/boards/feather_m0/examples/async_spi.rs index 7444f6941bdb..c3b6b8a78793 100644 --- a/boards/feather_m0/examples/async_spi.rs +++ b/boards/feather_m0/examples/async_spi.rs @@ -5,7 +5,19 @@ use defmt_rtt as _; use panic_probe as _; -use atsamd_hal::sercom::Sercom4; +use bsp::hal; +use feather_m0 as bsp; +use fugit::MillisDuration; +use hal::{ + clock::GenericClockController, + dmac::{Ch0, Ch1, DmaController, PriorityLevel}, + prelude::*, + sercom::{ + spi::{Config, SpiFutureDuplexDma}, + Sercom4, + }, +}; +use rtic_monotonics::systick::Systick; atsamd_hal::bind_interrupts!(struct Irqs { SERCOM4 => atsamd_hal::sercom::spi::InterruptHandler; @@ -15,19 +27,6 @@ atsamd_hal::bind_interrupts!(struct Irqs { #[rtic::app(device = bsp::pac, dispatchers = [I2S])] mod app { use super::*; - use bsp::hal; - use feather_m0 as bsp; - use fugit::MillisDuration; - use hal::{ - clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, - dmac::{Ch0, Ch1, DmaController, PriorityLevel}, - prelude::*, - rtc::{Count32Mode, Rtc}, - sercom::spi::{Config, SpiFutureDuplexDma}, - }; - - #[monotonic(binds = RTC, default = true)] - type Monotonic = Rtc; #[shared] struct Shared {} @@ -38,7 +37,7 @@ mod app { } #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(cx: init::Context) -> (Shared, Local) { let mut peripherals = cx.device; let _core = cx.core; @@ -54,16 +53,6 @@ mod app { // Take SPI pins let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sclk); - enable_internal_32kosc(&mut peripherals.SYSCTRL); - let timer_clock = clocks - .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::OSC32K, false) - .unwrap(); - clocks.configure_standby(ClockGenId::GCLK2, true); - - // Setup RTC monotonic - let rtc_clock = clocks.rtc(&timer_clock).unwrap(); - let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); - // Initialize DMA Controller let dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); @@ -90,7 +79,7 @@ mod app { async_task::spawn().ok(); - (Shared {}, Local { spi }, init::Monotonics(rtc)) + (Shared {}, Local { spi }) } #[task(local = [spi])] @@ -108,7 +97,7 @@ mod app { let mut buffer = [0xff; 4]; spi.read(&mut buffer).await.unwrap(); defmt::info!("Read buffer: {:#x}", buffer); - crate::app::monotonics::delay(MillisDuration::::from_ticks(500).convert()).await; + Systick::delay(MillisDuration::::from_ticks(500).convert()).await; } } } diff --git a/boards/feather_m0/examples/async_timer.rs b/boards/feather_m0/examples/async_timer.rs index 0591f99b2590..8e4ed5651a8a 100644 --- a/boards/feather_m0/examples/async_timer.rs +++ b/boards/feather_m0/examples/async_timer.rs @@ -7,34 +7,36 @@ use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; +use bsp::{hal, pin_alias}; +use feather_m0 as bsp; +use fugit::MillisDurationU32; +use hal::{ + async_hal::timer::TimerFuture, + clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, + ehal::digital::v2::ToggleableOutputPin, + pac::TC4, + thumbv6m::timer::TimerCounter, +}; + +atsamd_hal::bind_interrupts!(struct Irqs { + TC4 => atsamd_hal::async_hal::timer::InterruptHandler; +}); + #[rtic::app(device = bsp::pac, dispatchers = [I2S])] mod app { - use bsp::{hal, pac, pin_alias}; - use feather_m0 as bsp; - use hal::{ - async_hal::timer::TimerFuture, - clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, - ehal::digital::v2::ToggleableOutputPin, - pac::TC4, - rtc::{Count32Mode, Rtc}, - thumbv6m::timer::TimerCounter, - time::Milliseconds, - }; - - #[monotonic(binds = RTC, default = true)] - type Monotonic = Rtc; + use super::*; #[shared] struct Shared {} #[local] struct Local { - timer: TimerFuture, + timer: TimerFuture, red_led: bsp::RedLed, } #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(cx: init::Context) -> (Shared, Local) { let mut peripherals = cx.device; let _core = cx.core; @@ -47,28 +49,21 @@ mod app { let pins = bsp::Pins::new(peripherals.PORT); let red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); - let tc4_irq = cortex_m_interrupt::take_nvic_interrupt!(pac::Interrupt::TC4, 2); - // tc4_irq.set_priority(2); - enable_internal_32kosc(&mut peripherals.SYSCTRL); let timer_clock = clocks .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::OSC32K, false) .unwrap(); clocks.configure_standby(ClockGenId::GCLK2, true); - // Setup RTC monotonic - let rtc_clock = clocks.rtc(&timer_clock).unwrap(); - let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); - // configure a clock for the TC4 and TC5 peripherals let tc45 = &clocks.tc4_tc5(&timer_clock).unwrap(); // instantiate a timer object for the TC4 peripheral let timer = TimerCounter::tc4_(tc45, peripherals.TC4, &mut peripherals.PM); - let timer = timer.into_future(tc4_irq); + let timer = timer.into_future(Irqs); async_task::spawn().ok(); - (Shared {}, Local { timer, red_led }, init::Monotonics(rtc)) + (Shared {}, Local { timer, red_led }) } #[task(local = [timer, red_led])] @@ -77,7 +72,9 @@ mod app { let red_led = cx.local.red_led; loop { - timer.delay(Milliseconds(500)).await; + timer + .delay(MillisDurationU32::from_ticks(500).convert()) + .await; red_led.toggle().unwrap(); } } diff --git a/boards/feather_m0/examples/async_uart.rs b/boards/feather_m0/examples/async_uart.rs index 5a0cd3f2f548..ebc530b5ed67 100644 --- a/boards/feather_m0/examples/async_uart.rs +++ b/boards/feather_m0/examples/async_uart.rs @@ -5,7 +5,19 @@ use defmt_rtt as _; use panic_probe as _; -use atsamd_hal::sercom::Sercom0; +use bsp::{hal, periph_alias, pin_alias}; +use feather_m0 as bsp; +use fugit::MillisDuration; +use hal::{ + clock::GenericClockController, + dmac::{Ch0, Ch1, DmaController, PriorityLevel}, + prelude::*, + sercom::{ + uart::{Config, UartFutureRxDuplexDma, UartFutureTxDuplexDma}, + Sercom0, + }, +}; +use rtic_monotonics::systick::Systick; atsamd_hal::bind_interrupts!(struct Irqs { SERCOM0 => atsamd_hal::sercom::uart::InterruptHandler; @@ -15,21 +27,6 @@ atsamd_hal::bind_interrupts!(struct Irqs { #[rtic::app(device = bsp::pac, dispatchers = [I2S, AC])] mod app { use super::*; - use bsp::{hal, periph_alias, pin_alias}; - use feather_m0 as bsp; - use fugit::MillisDuration; - use hal::{ - clock::{enable_internal_32kosc, ClockGenId, ClockSource, GenericClockController}, - dmac::{Ch0, Ch1, DmaController, PriorityLevel}, - prelude::*, - rtc::{Count32Mode, Rtc}, - sercom::{ - uart::{Config, UartFutureRxDuplexDma, UartFutureTxDuplexDma}, - }, - }; - - #[monotonic(binds = RTC, default = true)] - type Monotonic = Rtc; #[shared] struct Shared {} @@ -41,7 +38,7 @@ mod app { } #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(cx: init::Context) -> (Shared, Local) { let mut peripherals = cx.device; let _core = cx.core; @@ -57,12 +54,6 @@ mod app { let (uart_rx, uart_tx) = (pin_alias!(pins.uart_rx), pin_alias!(pins.uart_tx)); let uart_sercom = periph_alias!(peripherals.uart_sercom); - enable_internal_32kosc(&mut peripherals.SYSCTRL); - let timer_clock = clocks - .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::OSC32K, false) - .unwrap(); - clocks.configure_standby(ClockGenId::GCLK2, true); - // Initialize DMA Controller let dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); // Turn dmac into an async controller @@ -74,10 +65,6 @@ mod app { let channel0 = channels.0.init(PriorityLevel::LVL0); let channel1 = channels.1.init(PriorityLevel::LVL0); - // Setup RTC monotonic - let rtc_clock = clocks.rtc(&timer_clock).unwrap(); - let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); - let (uart_rx, uart_tx) = bsp::uart( &mut clocks, 9600.Hz(), @@ -94,7 +81,7 @@ mod app { send_bytes::spawn().ok(); receive_bytes::spawn().ok(); - (Shared {}, Local { uart_rx, uart_tx }, init::Monotonics(rtc)) + (Shared {}, Local { uart_rx, uart_tx }) } #[task(local = [uart_tx], priority = 1)] @@ -104,7 +91,7 @@ mod app { loop { uart.write(&[0x00; 10]).await; defmt::info!("Sent 10 bytes"); - crate::app::monotonics::delay(MillisDuration::::from_ticks(500).convert()).await; + Systick::delay(MillisDuration::::from_ticks(500).convert()).await; } } diff --git a/boards/feather_m0/examples/blinky_rtic.rs b/boards/feather_m0/examples/blinky_rtic.rs index 01a0cd4648ec..c4e80d8f6dbc 100644 --- a/boards/feather_m0/examples/blinky_rtic.rs +++ b/boards/feather_m0/examples/blinky_rtic.rs @@ -1,9 +1,7 @@ -//! Uses RTIC with the RTC as time source to blink an LED. -//! -//! The idle task is sleeping the CPU, so in practice this gives similar power -//! figure as the "sleeping_timer_rtc" example. +//! Uses RTIC with systick to blink a led in an asynchronous fashion. #![no_std] #![no_main] +#![feature(type_alias_impl_trait)] use feather_m0 as bsp; @@ -11,35 +9,31 @@ use feather_m0 as bsp; use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; -use rtic; + +use bsp::{hal, pin_alias}; +use fugit::MillisDurationU32; +use hal::clock::GenericClockController; +use hal::pac::Peripherals; +use hal::prelude::*; +use rtic_monotonics::systick::Systick; #[rtic::app(device = bsp::pac, peripherals = true, dispatchers = [EVSYS])] mod app { use super::*; - use bsp::{hal, pin_alias}; - use hal::clock::{ClockGenId, ClockSource, GenericClockController}; - use hal::pac::Peripherals; - use hal::prelude::*; - use hal::rtc::{Count32Mode, Duration, Rtc}; #[local] - struct Local {} - - #[shared] - struct Shared { - // The LED could be a local resource, since it is only used in one task - // But we want to showcase shared resources and locking + struct Local { red_led: bsp::RedLed, } - #[monotonic(binds = RTC, default = true)] - type RtcMonotonic = Rtc; + #[shared] + struct Shared {} #[init] - fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(cx: init::Context) -> (Shared, Local) { let mut peripherals: Peripherals = cx.device; let pins = bsp::Pins::new(peripherals.PORT); - let mut core: rtic::export::Peripherals = cx.core; + let _core: rtic::export::Peripherals = cx.core; let mut clocks = GenericClockController::with_external_32kosc( peripherals.GCLK, &mut peripherals.PM, @@ -47,27 +41,20 @@ mod app { &mut peripherals.NVMCTRL, ); let _gclk = clocks.gclk0(); - let rtc_clock_src = clocks - .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::XOSC32K, false) - .unwrap(); - clocks.configure_standby(ClockGenId::GCLK2, true); - let rtc_clock = clocks.rtc(&rtc_clock_src).unwrap(); - let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); - let red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); - // We can use the RTC in standby for maximum power savings - core.SCB.set_sleepdeep(); + let red_led: bsp::RedLed = pin_alias!(pins.red_led).into(); // Start the blink task blink::spawn().unwrap(); - (Shared { red_led }, Local {}, init::Monotonics(rtc)) + (Shared {}, Local { red_led }) } - #[task(shared = [red_led])] - fn blink(mut cx: blink::Context) { - // If the LED were a local resource, the lock would not be necessary - cx.shared.red_led.lock(|led| led.toggle().unwrap()); - blink::spawn_after(Duration::secs(1)).ok(); + #[task(local = [red_led])] + async fn blink(cx: blink::Context) { + loop { + let _ = cx.local.red_led.toggle(); + Systick::delay(MillisDurationU32::from_ticks(1000).convert()).await; + } } } diff --git a/boards/feather_m0/examples/dmac_embassy.rs b/boards/feather_m0/examples/dmac_embassy.rs deleted file mode 100644 index eb2da7547e7c..000000000000 --- a/boards/feather_m0/examples/dmac_embassy.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! This example shows a safe API to -//! execute a memory-to-memory DMA transfer - -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -use defmt_rtt as _; -use panic_probe as _; - -atsamd_hal::bind_interrupts!(struct Irqs { - DMAC => atsamd_hal::dmac::async_api::InterruptHandler; -}); - -use bsp::hal; -use feather_m0 as bsp; -use hal::{ - async_hal::interrupts::{Interrupt, Priority, DMAC}, - clock::GenericClockController, - dmac::{DmaController, PriorityLevel, TriggerAction, TriggerSource}, -}; - -#[embassy_executor::main] -async fn main(_p: embassy_executor::Spawner) { - let mut peripherals = hal::pac::Peripherals::take().unwrap(); - - let _clocks = GenericClockController::with_external_32kosc( - peripherals.GCLK, - &mut peripherals.PM, - &mut peripherals.SYSCTRL, - &mut peripherals.NVMCTRL, - ); - - // Initialize DMA Controller - let dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); - DMAC::set_priority(Priority::P0); - - // Turn dmac into an async controller - let mut dmac = dmac.into_future(crate::Irqs); - // Get individual handles to DMA channels - let channels = dmac.split(); - - // Initialize DMA Channel 0 - let mut channel = channels.0.init(PriorityLevel::LVL0); - - let mut source = [0xff; 50]; - let mut dest = [0x0; 50]; - - defmt::info!( - "Launching a DMA transfer.\n\tSource: {}\n\tDestination: {}", - &source, - &dest - ); - - channel - .transfer_future( - &mut source, - &mut dest, - TriggerSource::DISABLE, - TriggerAction::BLOCK, - ) - .await - .unwrap(); - - defmt::info!( - "Finished DMA transfer.\n\tSource: {}\n\tDestination: {}", - &source, - &dest - ); - - loop { - core::future::pending::<()>().await; - } -} diff --git a/boards/metro_m4/.cargo/config b/boards/metro_m4/.cargo/config index 553292e3d068..324261873e35 100644 --- a/boards/metro_m4/.cargo/config +++ b/boards/metro_m4/.cargo/config @@ -9,6 +9,6 @@ rustflags = [ # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 "-C", "link-arg=--nmagic", - + "-C", "link-arg=-Tdefmt.x", # uncomment if using defmt "-C", "link-arg=-Tlink.x", ] diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index be9b7b4e8664..b6d2b90f726f 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -41,7 +41,9 @@ panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] } cortex-m-semihosting = "0.3" rtt-target = { version = "0.3.0", features = ["cortex-m"] } smart-leds = "0.3" -embassy = {version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git" } +defmt = "0.3" +defmt-rtt = "0.4" +rtic = { version = "2.0.1", features = ["thumbv7-backend"] } [dev-dependencies.ws2812-timer-delay] version = "0.3" @@ -50,9 +52,11 @@ version = "0.3" [features] # ask the HAL to enable atsamd51j support default = ["rt", "atsamd-hal/samd51j", "atsamd-hal/samd51"] +dma = ["atsamd-hal/dma"] rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"] unproven = ["atsamd-hal/unproven"] usb = ["atsamd-hal/usb", "usb-device"] +nightly = [] [profile.dev] incremental = false @@ -105,9 +109,5 @@ name = "i2c" required-features = ["atsamd-hal/dma"] [[example]] -name = "dmac_async" -required-features = [ - "atsamd-hal/dma", - "atsamd-hal/async", - "atsamd-hal/nightly" -] +name = "async_dmac" +required-features = ["dma", "atsamd-hal/async", "nightly"] diff --git a/boards/metro_m4/examples/async_dmac.rs b/boards/metro_m4/examples/async_dmac.rs new file mode 100644 index 000000000000..20a997318298 --- /dev/null +++ b/boards/metro_m4/examples/async_dmac.rs @@ -0,0 +1,95 @@ +//! This example shows a safe API to +//! execute a memory-to-memory DMA transfer + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt_rtt as _; +use panic_probe as _; + +atsamd_hal::bind_interrupts!(struct Irqs { + DMAC: [DMAC_0, DMAC_1, DMAC_2, DMAC_OTHER] => atsamd_hal::dmac::InterruptHandler; +}); + +#[rtic::app(device = bsp::pac, dispatchers = [I2S])] +mod app { + use bsp::hal; + use metro_m4 as bsp; + use hal::{ + clock::GenericClockController, + dmac::{ + Ch0, Channel, DmaController, PriorityLevel, ReadyFuture, TriggerAction, TriggerSource, + }, + }; + + #[shared] + struct Shared {} + + #[local] + struct Local { + channel: Channel, + } + + #[init] + fn init(cx: init::Context) -> (Shared, Local) { + let mut peripherals = cx.device; + let _core = cx.core; + + let _clocks = GenericClockController::with_external_32kosc( + peripherals.GCLK, + &mut peripherals.MCLK, + &mut peripherals.OSC32KCTRL, + &mut peripherals.OSCCTRL, + &mut peripherals.NVMCTRL, + ); + + // Initialize DMA Controller + let dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); + + // Turn dmac into an async controller + let mut dmac = dmac.into_future(crate::Irqs); + // Get individual handles to DMA channels + let channels = dmac.split(); + + // Initialize DMA Channel 0 + let channel = channels.0.init(PriorityLevel::LVL0); + + async_task::spawn().ok(); + (Shared {}, Local { channel }) + } + + #[task(local = [channel])] + async fn async_task(cx: async_task::Context) { + let channel = cx.local.channel; + + let mut source = [0xff; 1000]; + let mut dest = [0x0; 1000]; + + defmt::info!( + "Launching a DMA transfer.\n\tSource: {}\n\tDestination: {}", + &source, + &dest + ); + + channel + .transfer_future( + &mut source, + &mut dest, + TriggerSource::DISABLE, + TriggerAction::BLOCK, + ) + .await + .unwrap(); + + defmt::info!( + "Finished DMA transfer.\n\tSource: {}\n\tDestination: {}", + &source, + &dest + ); + + loop { + cortex_m::asm::wfi(); + } + } +} diff --git a/boards/metro_m4/examples/dmac_async.rs b/boards/metro_m4/examples/dmac_async.rs deleted file mode 100644 index 87248d66c906..000000000000 --- a/boards/metro_m4/examples/dmac_async.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! This example shows a safe API to -//! execute a memory-to-memory DMA transfer - -#![no_std] -#![no_main] - -use bsp::hal; -use cortex_m::asm; -use metro_m4 as bsp; -use panic_halt as _; - -use hal::{ - clock::GenericClockController, - pac::{CorePeripherals, Peripherals}, -}; - -use hal::dmac::{DmaController, PriorityLevel, Transfer, TriggerAction, TriggerSource}; - -#[embassy::main] -fn main(_spawner: embassy::executor::Spawner) -> ! { - let mut peripherals = Peripherals::take().unwrap(); - let core = CorePeripherals::take().unwrap(); - let _clocks = GenericClockController::with_external_32kosc( - peripherals.GCLK, - &mut peripherals.MCLK, - &mut peripherals.OSC32KCTRL, - &mut peripherals.OSCCTRL, - &mut peripherals.NVMCTRL, - ); - - let mut pm = peripherals.PM; - let dmac = peripherals.DMAC; - - // Initialize buffers - const LENGTH: usize = 50; - let buf_src: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0xff; LENGTH]).unwrap(); - let buf_dest: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - - // Initialize DMA Controller - let mut dmac = DmaController::init(dmac, &mut pm); - // Get individual handles to DMA channels - let mut channels = dmac.split(); - - // Initialize DMA Channel 0 - let chan0 = channels.0.init(PriorityLevel::LVL0); - - // Setup a DMA transfer (memory-to-memory -> incrementing source, incrementing - // destination) with a 8-bit beat size - let mut xfer = Transfer::new_from_arrays(chan0, buf_src, buf_dest, false); - xfer.begin_async(TriggerSource::DISABLE, TriggerAction::BLOCK) - .await; - - // Grab resulting buffers - let (chan0, buf_src, buf_dest) = xfer.free(); - - // Read the returned buffers - let _a = buf_src[LENGTH - 1]; - let _b = buf_dest[LENGTH - 1]; - - let const_16: &'static mut u16 = cortex_m::singleton!(: u16 = 0xADDE).unwrap(); - let buf_16: &'static mut [u16; LENGTH] = - cortex_m::singleton!(:[u16; LENGTH] = [0x0000; LENGTH]).unwrap(); - - // Setup a DMA transfer (memory-to-memory -> fixed source, incrementing - // destination) with a 16-bit beat size. - let mut xfer = Transfer::new(chan0, const_16, buf_16, false).unwrap(); - xfer.begin_async(TriggerSource::DISABLE, TriggerAction::BLOCK) - .await; - - let (chan0, const_16, buf_16) = xfer.free(); - - // Read the returned buffers - let _a = *const_16; - let _b = buf_16[LENGTH - 1]; - - // Manipulate the returned buffer for fun - for (i, item) in buf_16.iter_mut().enumerate() { - *item = i as u16; - } - - // Setup a DMA transfer (memory-to-memory -> incrementing source, fixed - // destination) with a 16-bit beat size - let mut xfer = Transfer::new(chan0, buf_16, const_16, false).unwrap(); - xfer.begin_async(TriggerSource::DISABLE, TriggerAction::BLOCK) - .await; - - let (chan0, buf_16, const_16) = xfer.free(); - - // Read the returned buffers - let _a = *const_16; // We expect the value "LENGTH - 1" to end up here - let _b = buf_16[LENGTH - 1]; - - // Move split channels back into the Channels struct - channels.0 = chan0.into(); - // Free the DmaController and return the PAC DMAC struct - let _dmac = dmac.free(channels, &mut pm); - - loop { - asm::nop(); - } -} diff --git a/hal/src/async_hal/interrupts.rs b/hal/src/async_hal/interrupts.rs index 9a56cbf7f2e7..78dcf3dfea74 100644 --- a/hal/src/async_hal/interrupts.rs +++ b/hal/src/async_hal/interrupts.rs @@ -7,16 +7,16 @@ use paste::paste; use seq_macro::seq; macro_rules! declare_interrupts { - ($($(#[$m:meta])* $irqs:ident),* $(,)?) => { + ($($(#[$cfg:meta])* $irqs:ident),* $(,)?) => { $( - $(#[$m])* + $(#[$cfg])* #[allow(non_camel_case_types)] #[doc=stringify!($irqs)] #[doc=" typelevel interrupt."] pub enum $irqs {} - $(#[$m])* + $(#[$cfg])* impl $crate::typelevel::Sealed for $irqs{} - $(#[$m])* + $(#[$cfg])* impl $crate::async_hal::interrupts::Interrupt for $irqs { const IRQ: crate::pac::Interrupt = crate::pac::Interrupt::$irqs; } @@ -24,18 +24,20 @@ macro_rules! declare_interrupts { } } -// Useful when we need to bind multiple interrupt sources to the same handler +// Useful when we need to bind multiple interrupt sources to the same handler. +// Calling the `InterruptSource` methods on the created struct will act on all +// interrupt sources at once. #[allow(unused_macros)] macro_rules! declare_multiple_interrupts { - ($(#[$m:meta])* $name:ident, $($irq:ident),+ $(,)?) => { + ($(#[$cfg:meta])* $name:ident: [ $($irq:ident),+ $(,)? ]) => { paste! { - $(#[$m])* + $(#[$cfg])* pub enum $name {} - $(#[$m])* + $(#[$cfg])* impl $crate::typelevel::Sealed for $name {} - $(#[$m])* + $(#[$cfg])* impl $crate::async_hal::interrupts::InterruptSource for $name { unsafe fn enable() { $($crate::pac::Interrupt::$irq.enable();)+ @@ -48,6 +50,10 @@ macro_rules! declare_multiple_interrupts { fn unpend() { $($crate::pac::Interrupt::$irq.unpend();)+ } + + fn set_priority(prio: $crate::async_hal::interrupts::Priority){ + $($crate::pac::Interrupt::$irq.set_priority(prio);)+ + } } } }; @@ -55,11 +61,8 @@ macro_rules! declare_multiple_interrupts { // ---------- DMAC Interrupts ---------- // #[cfg(all(feature = "dma", feature = "thumbv7"))] -seq!(N in 0..=3{ - paste! { - declare_interrupts!{DMAC_ ~N} - } -}); +declare_multiple_interrupts!(DMAC: [DMAC_0, DMAC_1, DMAC_2, DMAC_OTHER]); + #[cfg(all(feature = "dma", feature = "thumbv7"))] declare_interrupts!(DMAC_OTHER); @@ -72,7 +75,7 @@ seq!(N in 0..=7 { #[cfg(all(feature = "has-" sercom~N, feature = "thumbv6"))] declare_interrupts!(SERCOM~N); #[cfg(all(feature = "has-" sercom~N, feature = "thumbv7"))] - declare_multiple_interrupts!([], [], [], [], []); + declare_multiple_interrupts!([]: [ [], [], [], [] ]); } }); @@ -100,12 +103,28 @@ seq!(N in 0..= 15 { } }); +/// Interrupt source. This trait may implemented directly when multiple +/// interrupt sources are needed to operate a single peripheral (eg, SERCOM and +/// DMAC for thumbv7 devices). If using one interrupt source per peripheral, +/// implement [`Interrupt`] instead. When implemented on a type that handles +/// multiple interrupt sources, the methods will act on all interrupt sources at +/// once. pub trait InterruptSource: crate::typelevel::Sealed { + /// Enable the interrupt. + /// + /// # Safety + /// + /// Do not enable any interrupt inside a critical section. unsafe fn enable(); + /// Disable the interrupt. fn disable(); + /// Unset interrupt pending. fn unpend(); + + /// Set the interrupt priority. + fn set_priority(prio: Priority); } impl InterruptSource for T { @@ -120,11 +139,16 @@ impl InterruptSource for T { fn unpend() { Self::unpend(); } + + fn set_priority(prio: Priority) { + Self::set_priority(prio); + } } /// Type-level interrupt. /// -/// This trait is implemented for all typelevel interrupt types in this module. +/// This trait is implemented for all typelevel single interrupt types in this +/// module. pub trait Interrupt: crate::typelevel::Sealed { /// Interrupt enum variant. /// diff --git a/hal/src/async_hal/mod.rs b/hal/src/async_hal/mod.rs index e739155093b3..333f6478170b 100644 --- a/hal/src/async_hal/mod.rs +++ b/hal/src/async_hal/mod.rs @@ -20,22 +20,37 @@ pub mod timer; /// ``` #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { - #[derive(Copy, Clone)] - $vis struct $name; + ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + #[derive(Copy, Clone)] + $vis struct $name; - $( - #[allow(non_snake_case)] - #[no_mangle] - unsafe extern "C" fn $irq() { - $( - <$handler as $crate::async_hal::interrupts::Handler<$crate::async_hal::interrupts::$irq>>::on_interrupt(); - )* - } + $( + #[allow(non_snake_case)] + #[no_mangle] + unsafe extern "C" fn $irq() { + $( + <$handler as $crate::async_hal::interrupts::Handler<$crate::async_hal::interrupts::$irq>>::on_interrupt(); + )* + } - $( - unsafe impl $crate::async_hal::interrupts::Binding<$crate::async_hal::interrupts::$irq, $handler> for $name {} - )* - )* - }; + $( + unsafe impl $crate::async_hal::interrupts::Binding<$crate::async_hal::interrupts::$irq, $handler> for $name {} + )* + )* + }; + + ($vis:vis struct $name:ident { $int_source:ident: [ $($irq:ident),+ ] => $handler:ty; }) => { + #[derive(Copy, Clone)] + $vis struct $name; + + $( + #[allow(non_snake_case)] + #[no_mangle] + unsafe extern "C" fn $irq() { + <$handler as $crate::async_hal::interrupts::Handler<$crate::async_hal::interrupts::$int_source>>::on_interrupt(); + } + )+ + + unsafe impl $crate::async_hal::interrupts::Binding<$crate::async_hal::interrupts::$int_source, $handler> for $name {} + }; } diff --git a/hal/src/dmac/async_api.rs b/hal/src/dmac/async_api.rs index f1429d0a3035..7a81a9a87a46 100644 --- a/hal/src/dmac/async_api.rs +++ b/hal/src/dmac/async_api.rs @@ -1,17 +1,11 @@ //! APIs for async DMAC operations. use crate::{ - async_hal::interrupts::Handler, + async_hal::interrupts::{Handler, DMAC}, dmac::{waker::WAKERS, TriggerSource}, util::BitIter, }; -#[cfg(feature = "thumbv6")] -use crate::async_hal::interrupts::DMAC; - -#[cfg(feature = "thumbv7")] -use crate::async_hal::interrupts::{DMAC_0, DMAC_1, DMAC_2, DMAC_3, DMAC_OTHER}; - // Interrupt handler for the DMAC peripheral. pub struct InterruptHandler { _private: (), @@ -64,73 +58,36 @@ impl Handler for InterruptHandler { } #[cfg(feature = "thumbv7")] -fn on_interrupt(channel: usize) { - let dmac = unsafe { crate::pac::Peripherals::steal().DMAC }; - - let wake = if dmac.channel[channel].chintflag.read().tcmpl().bit_is_set() { - // Transfer complete. Don't clear the flag, but - // disable the interrupt. Flag will be cleared when polled - dmac.channel[channel] - .chintenclr - .modify(|_, w| w.tcmpl().set_bit()); - true - } else if dmac.channel[channel].chintflag.read().terr().bit_is_set() { - // Transfer error - dmac.channel[channel] - .chintenclr - .modify(|_, w| w.terr().set_bit()); - true - } else { - false - }; - - if wake { - dmac.channel[channel].chctrla.modify(|_, w| { - w.enable().clear_bit(); - w.trigsrc().variant(TriggerSource::DISABLE) - }); - WAKERS[channel].wake(); - } -} - -#[cfg(feature = "thumbv7")] -impl Handler for InterruptHandler { - unsafe fn on_interrupt() { - on_interrupt(0); - } -} - -#[cfg(feature = "thumbv7")] -impl Handler for InterruptHandler { - unsafe fn on_interrupt() { - on_interrupt(1); - } -} - -#[cfg(feature = "thumbv7")] -impl Handler for InterruptHandler { - unsafe fn on_interrupt() { - on_interrupt(2); - } -} - -#[cfg(feature = "thumbv7")] -impl Handler for InterruptHandler { - unsafe fn on_interrupt() { - on_interrupt(3); - } -} - -#[cfg(feature = "thumbv7")] -impl Handler for InterruptHandler { +impl Handler for InterruptHandler { unsafe fn on_interrupt() { let dmac = unsafe { crate::pac::Peripherals::steal().DMAC }; - // Get pending channels, but ignore first 4 since they're handled by other - // interrupts. - let pending_channels = BitIter(dmac.intstatus.read().bits() & !0b1111); - for pend_chan in pending_channels { - on_interrupt(pend_chan as usize); + let pending_channels = BitIter(dmac.intstatus.read().bits()); + for channel in pending_channels.map(|c| c as usize) { + let wake = if dmac.channel[channel].chintflag.read().tcmpl().bit_is_set() { + // Transfer complete. Don't clear the flag, but + // disable the interrupt. Flag will be cleared when polled + dmac.channel[channel] + .chintenclr + .modify(|_, w| w.tcmpl().set_bit()); + true + } else if dmac.channel[channel].chintflag.read().terr().bit_is_set() { + // Transfer error + dmac.channel[channel] + .chintenclr + .modify(|_, w| w.terr().set_bit()); + true + } else { + false + }; + + if wake { + dmac.channel[channel].chctrla.modify(|_, w| { + w.enable().clear_bit(); + w.trigsrc().variant(TriggerSource::DISABLE) + }); + WAKERS[channel].wake(); + } } } } diff --git a/hal/src/dmac/dma_controller.rs b/hal/src/dmac/dma_controller.rs index 019a328be600..1691cb5d98a6 100644 --- a/hal/src/dmac/dma_controller.rs +++ b/hal/src/dmac/dma_controller.rs @@ -39,15 +39,6 @@ pub use crate::pac::dmac::channel::{ chprilvl::PRILVLSELECT_A as PriorityLevel, }; -#[cfg(all(feature = "async", feature = "thumbv6"))] -type Irq = crate::async_hal::interrupts::DMAC; - -/// On thumbv7 targets, we can only check that one interrupt is correctly bound, -/// lest we dive into typelevel insanity once more. We just have to trust the -/// user has bound all relevant interrupts sources. -#[cfg(all(feature = "async", feature = "thumbv7"))] -type Irq = crate::async_hal::interrupts::DMAC_0; - use super::{ channel::{Channel, Uninitialized}, DESCRIPTOR_SECTION, WRITEBACK, @@ -218,49 +209,20 @@ impl DmaController { /// you are required to configure the desired interrupt priorities prior to /// calling this method. Consult [`crate::async_hal::interrupts`] /// module-level documentation for more information. - /// - /// # Note for SAMx5x users - /// - /// The DMAC on SAMD51/SAMD53/SAME53/SAME54 has 5 NVIC interrupt sources: - /// * DMAC_0 (channel 0) - /// * DMAC_1 (channel 1) - /// * DMAC_2 (channel 2) - /// * DMAC_3 (channel 3) - /// * DMAC_OTHER (all other channels). - /// - /// You **must** bind all 5 sources using /// [`bind_interrupts`](crate::bind_interrupts). #[cfg(feature = "async")] #[inline] pub fn into_future(self, _interrupts: I) -> DmaController where - I: crate::async_hal::interrupts::Binding, + I: crate::async_hal::interrupts::Binding< + crate::async_hal::interrupts::DMAC, + super::async_api::InterruptHandler, + >, { - use crate::async_hal::interrupts::Interrupt; - - #[cfg(feature = "thumbv6")] - { - use crate::async_hal::interrupts::DMAC; - DMAC::unpend(); - unsafe { DMAC::enable() }; - } + use crate::async_hal::interrupts::{InterruptSource, DMAC}; - #[cfg(feature = "thumbv7")] - { - use crate::async_hal::interrupts::{DMAC_0, DMAC_1, DMAC_2, DMAC_3, DMAC_OTHER}; - DMAC_0::unpend(); - DMAC_1::unpend(); - DMAC_2::unpend(); - DMAC_3::unpend(); - DMAC_OTHER::unpend(); - unsafe { - DMAC_0::enable(); - DMAC_1::enable(); - DMAC_2::enable(); - DMAC_3::enable(); - DMAC_OTHER::enable(); - } - } + DMAC::unpend(); + unsafe { DMAC::enable() }; DmaController { dmac: self.dmac, @@ -347,7 +309,10 @@ impl DmaController { #[cfg(feature = "async")] impl DmaController where - I: crate::async_hal::interrupts::Binding, + I: crate::async_hal::interrupts::Binding< + crate::async_hal::interrupts::DMAC, + super::async_api::InterruptHandler, + >, { /// Release the DMAC and return the register block. /// @@ -413,7 +378,10 @@ macro_rules! define_split_future { #[cfg(feature = "async")] impl DmaController where - I: crate::async_hal::interrupts::Binding, + I: crate::async_hal::interrupts::Binding< + crate::async_hal::interrupts::DMAC, + super::async_api::InterruptHandler, + >, { with_num_channels!(define_split_future); } diff --git a/hal/src/sercom/mod.rs b/hal/src/sercom/mod.rs index 03fc136c87ac..a9411271cf9a 100644 --- a/hal/src/sercom/mod.rs +++ b/hal/src/sercom/mod.rs @@ -79,6 +79,7 @@ pub trait Sercom: Sealed + Deref { #[cfg(feature = "dma")] const DMA_TX_TRIGGER: TriggerSource; + #[cfg(feature = "async")] type Interrupt: crate::async_hal::interrupts::InterruptSource; /// Enable the corresponding APB clock @@ -128,7 +129,7 @@ macro_rules! sercom { type Interrupt = crate::async_hal::interrupts::SERCOM~N; #[cfg(all(feature = "async", feature = "thumbv7"))] - type Interrupt = crate::async_hal::interrupts::[]; + type Interrupt = crate::async_hal::interrupts::[]; #[inline] fn enable_apb_clock(&mut self, ctrl: &APB_CLK_CTRL) { diff --git a/hal/src/sercom/spi/async_api.rs b/hal/src/sercom/spi/async_api.rs index d8c0b1d883ab..0d4d45e16abe 100644 --- a/hal/src/sercom/spi/async_api.rs +++ b/hal/src/sercom/spi/async_api.rs @@ -89,11 +89,10 @@ where } #[cfg(feature = "defmt")] -impl defmt::Format for SpiFuture +impl defmt::Format for SpiFuture where C: ValidConfig, A: Capability, - N: InterruptNumber, { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "SpiFuture defmt shim\n"); diff --git a/hal/src/thumbv6m/eic/mod.rs b/hal/src/thumbv6m/eic/mod.rs index cdef5493e7a3..e9d22dbebb6b 100644 --- a/hal/src/thumbv6m/eic/mod.rs +++ b/hal/src/thumbv6m/eic/mod.rs @@ -63,4 +63,5 @@ mod async_api { pub(super) static WAKERS: [AtomicWaker; NUM_CHANNELS] = [NEW_WAKER; NUM_CHANNELS]; } +#[cfg(feature = "async")] pub use async_api::*; diff --git a/hal/src/thumbv7em/eic/mod.rs b/hal/src/thumbv7em/eic/mod.rs index 20767b049fe3..345f96af5da4 100644 --- a/hal/src/thumbv7em/eic/mod.rs +++ b/hal/src/thumbv7em/eic/mod.rs @@ -130,3 +130,6 @@ mod async_api { const NEW_WAKER: AtomicWaker = AtomicWaker::new(); pub(super) static WAKERS: [AtomicWaker; NUM_CHANNELS] = [NEW_WAKER; NUM_CHANNELS]; } + +#[cfg(feature = "async")] +pub use async_api::*;