diff --git a/examples/aes-dma.rs b/examples/aes-dma.rs index bab64e27..ae42aaaf 100644 --- a/examples/aes-dma.rs +++ b/examples/aes-dma.rs @@ -10,19 +10,30 @@ extern crate panic_semihosting; use core::pin::Pin; +use cortex_m::{ + asm, + interrupt, +}; use cortex_m_rt::entry; use stm32l0xx_hal::{ prelude::*, aes::AES, - dma::DMA, - pac, + dma::{ + self, + DMA, + }, + pac::{ + self, + Interrupt, + }, rcc::Config, }; #[entry] fn main() -> ! { - let dp = pac::Peripherals::take().unwrap(); + let mut cp = pac::CorePeripherals::take().unwrap(); + let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.freeze(Config::hsi16()); let mut aes = AES::new(dp.AES, &mut rcc); @@ -54,23 +65,45 @@ fn main() -> ! { loop { let mut ctr_stream = aes.start_ctr_stream(key, ivr); - let tx_transfer = ctr_stream.tx + let mut tx_transfer = ctr_stream.tx .write_all( &mut dma.handle, data, dma.channels.channel1, - ) - .start(); - let rx_transfer = ctr_stream.rx + ); + let mut rx_transfer = ctr_stream.rx .read_all( &mut dma.handle, encrypted, dma.channels.channel2, - ) - .start(); + ); + + let (tx_res, rx_res) = interrupt::free(|_| { + cp.NVIC.enable(Interrupt::DMA1_CHANNEL1); + cp.NVIC.enable(Interrupt::DMA1_CHANNEL2_3); + + let interrupts = dma::Interrupts { + transfer_error: true, + transfer_complete: true, + .. Default::default() + }; + + tx_transfer.enable_interrupts(interrupts); + rx_transfer.enable_interrupts(interrupts); + + let tx_transfer = tx_transfer.start(); + let rx_transfer = rx_transfer.start(); + + asm::wfi(); + + let tx_res = tx_transfer.wait().unwrap(); + let rx_res = rx_transfer.wait().unwrap(); + + cp.NVIC.disable(Interrupt::DMA1_CHANNEL1); + cp.NVIC.disable(Interrupt::DMA1_CHANNEL2_3); - let tx_res = tx_transfer.wait().unwrap(); - let rx_res = rx_transfer.wait().unwrap(); + (tx_res, rx_res) + }); ctr_stream.tx = tx_res.target; ctr_stream.rx = rx_res.target; @@ -83,23 +116,45 @@ fn main() -> ! { assert_ne!(encrypted, data); let mut ctr_stream = aes.start_ctr_stream(key, ivr); - let tx_transfer = ctr_stream.tx + let mut tx_transfer = ctr_stream.tx .write_all( &mut dma.handle, encrypted, dma.channels.channel1, - ) - .start(); - let rx_transfer = ctr_stream.rx + ); + let mut rx_transfer = ctr_stream.rx .read_all( &mut dma.handle, decrypted, dma.channels.channel2, - ) - .start(); + ); + + let (tx_res, rx_res) = interrupt::free(|_| { + cp.NVIC.enable(Interrupt::DMA1_CHANNEL1); + cp.NVIC.enable(Interrupt::DMA1_CHANNEL2_3); + + let interrupts = dma::Interrupts { + transfer_error: true, + transfer_complete: true, + .. Default::default() + }; + + tx_transfer.enable_interrupts(interrupts); + rx_transfer.enable_interrupts(interrupts); + + let tx_transfer = tx_transfer.start(); + let rx_transfer = rx_transfer.start(); + + asm::wfi(); + + let tx_res = tx_transfer.wait().unwrap(); + let rx_res = rx_transfer.wait().unwrap(); + + cp.NVIC.disable(Interrupt::DMA1_CHANNEL1); + cp.NVIC.disable(Interrupt::DMA1_CHANNEL2_3); - let tx_res = tx_transfer.wait().unwrap(); - let rx_res = rx_transfer.wait().unwrap(); + (tx_res, rx_res) + }); ctr_stream.tx = tx_res.target; ctr_stream.rx = rx_res.target; diff --git a/src/dma.rs b/src/dma.rs index facb3503..4fc834ab 100644 --- a/src/dma.rs +++ b/src/dma.rs @@ -185,6 +185,10 @@ impl Transfer } } + pub fn enable_interrupts(&mut self, interrupts: Interrupts) { + self.res.channel.enable_interrupts(interrupts); + } + pub fn start(self) -> Transfer { compiler_fence(Ordering::SeqCst); @@ -264,6 +268,7 @@ pub trait Channel: Sized { fn set_transfer_len(&self, _: &mut Handle, len: u16); fn configure(&self, _: &mut Handle, dir: ccr1::DIRW) where Word: SupportedWordSize; + fn enable_interrupts(&self, interrupts: Interrupts); fn start(&self); fn is_active(&self) -> bool; fn error_occured(&self) -> bool; @@ -363,6 +368,19 @@ macro_rules! impl_channel { }); } + fn enable_interrupts(&self, interrupts: Interrupts) { + // Safe, because we're only accessing a register that this + // channel has exclusive access to. + let ccr = &unsafe { &*pac::DMA1::ptr() }.$ccr; + + ccr.modify(|_, w| + w + .teie().bit(interrupts.transfer_error) + .htie().bit(interrupts.half_transfer) + .tcie().bit(interrupts.transfer_complete) + ); + } + fn start(&self) { // Safe, because we're only accessing a register that this // channel has exclusive access to. @@ -487,3 +505,21 @@ impl SupportedWordSize for u32 { ccr1::MSIZEW::BIT32 } } + + +#[derive(Clone, Copy)] +pub struct Interrupts { + pub transfer_error: bool, + pub half_transfer: bool, + pub transfer_complete: bool, +} + +impl Default for Interrupts { + fn default() -> Self { + Self { + transfer_error: false, + half_transfer: false, + transfer_complete: false, + } + } +}