diff --git a/CHANGELOG.md b/CHANGELOG.md index f91a6b99..69fb7ce9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add advanced timer dead time insertion example [#585] - Cleanups [#595] - Fix comlementary for independent channels [#599] [#603] + - Capability to release and reuse SPI peripheral after using it with DMA. - I2c dma can now use single DMA channel for TX or RX only [#598] - `ws2812::prerendered` in example diff --git a/examples/rtic-spi-slave-dma.rs b/examples/rtic-spi-slave-dma.rs index 08fb661c..cc553ab4 100644 --- a/examples/rtic-spi-slave-dma.rs +++ b/examples/rtic-spi-slave-dma.rs @@ -16,7 +16,7 @@ mod app { pac::{DMA1, SPI3}, prelude::*, rcc::RccExt, - spi::{Rx, SpiSlave, Tx}, + spi::{RxCoupledSlave, SpiSlave, TxCoupledSlave}, }; use panic_semihosting as _; use systick_monotonic::*; @@ -25,11 +25,21 @@ mod app { const ARRAY_SIZE: usize = 3; - type TxTransfer = - Transfer, 0, Tx, MemoryToPeripheral, &'static mut [u8; ARRAY_SIZE]>; - - type RxTransfer = - Transfer, 0, Rx, PeripheralToMemory, &'static mut [u8; ARRAY_SIZE]>; + type TxTransfer = Transfer< + Stream5, + 0, + TxCoupledSlave, + MemoryToPeripheral, + &'static mut [u8; ARRAY_SIZE], + >; + + type RxTransfer = Transfer< + Stream0, + 0, + RxCoupledSlave, + PeripheralToMemory, + &'static mut [u8; ARRAY_SIZE], + >; #[shared] struct Shared { diff --git a/examples/spi-dma.rs b/examples/spi-dma.rs index e99ad1b2..9ea40483 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -22,7 +22,7 @@ const ARRAY_SIZE: usize = 100; type SpiDma = Transfer< Stream4, 0, - Tx, + Tx, MemoryToPeripheral, &'static mut [u8; ARRAY_SIZE], >; diff --git a/src/spi.rs b/src/spi.rs index 2e9edd8b..ebe28ef0 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -783,83 +783,157 @@ impl Inner { } // Spi DMA +macro_rules! dma { + ($Spi:ident, $DmaBuilder:ident, $Tx:ident, $Rx:ident, $TxCoupled:ident, $RxCoupled:ident) => { + impl $Spi { + pub fn use_dma(self) -> $DmaBuilder { + $DmaBuilder { spi: self } + } + } -impl Spi { - pub fn use_dma(self) -> DmaBuilder { - DmaBuilder { - spi: self.inner.spi, + pub struct $DmaBuilder { + spi: $Spi, } - } -} -impl SpiSlave { - pub fn use_dma(self) -> DmaBuilder { - DmaBuilder { - spi: self.inner.spi, + pub struct $Tx { + spi: $Spi, } - } -} -pub struct DmaBuilder { - spi: SPI, -} + pub struct $Rx { + spi: $Spi, + } -pub struct Tx { - spi: PhantomData, -} + pub struct $TxCoupled { + spi: $Spi, + } -pub struct Rx { - spi: PhantomData, -} + pub struct $RxCoupled { + spi: PhantomData, + } -impl DmaBuilder { - pub fn tx(self) -> Tx { - self.spi.cr2.modify(|_, w| w.txdmaen().enabled()); - Tx { spi: PhantomData } - } + impl $DmaBuilder { + pub fn tx(self) -> $Tx { + self.spi.spi.cr2.modify(|_, w| w.txdmaen().enabled()); + $Tx { spi: self.spi } + } - pub fn rx(self) -> Rx { - self.spi.cr2.modify(|_, w| w.rxdmaen().enabled()); - Rx { spi: PhantomData } - } + pub fn rx(self) -> $Rx { + self.spi.spi.cr2.modify(|_, w| w.rxdmaen().enabled()); + $Rx { spi: self.spi } + } - pub fn txrx(self) -> (Tx, Rx) { - self.spi.cr2.modify(|_, w| { - w.txdmaen().enabled(); - w.rxdmaen().enabled() - }); - (Tx { spi: PhantomData }, Rx { spi: PhantomData }) - } -} + pub fn txrx(self) -> ($TxCoupled, $RxCoupled) { + self.spi.spi.cr2.modify(|_, w| { + w.txdmaen().enabled(); + w.rxdmaen().enabled() + }); + ( + $TxCoupled { spi: self.spi }, + $RxCoupled { spi: PhantomData }, + ) + } + } -unsafe impl PeriAddress for Rx { - #[inline(always)] - fn address(&self) -> u32 { - unsafe { &(*SPI::ptr()).dr as *const _ as u32 } - } + impl $Tx { + pub fn release(self) -> $Spi { + self.spi.spi.cr2.modify(|_, w| w.txdmaen().disabled()); + self.spi + } + } - type MemSize = u8; -} + impl $Rx { + pub fn release(self) -> $Spi { + self.spi.spi.cr2.modify(|_, w| w.rxdmaen().disabled()); + self.spi + } + } -unsafe impl DMASet for Rx where - SPI: DMASet -{ -} + impl $TxCoupled { + pub fn release(self, _couple: RxCoupled) -> $Spi { + self.spi.spi.cr2.modify(|_, w| { + w.rxdmaen().disabled(); + w.txdmaen().disabled() + }); + self.spi + } + } -unsafe impl PeriAddress for Tx { - #[inline(always)] - fn address(&self) -> u32 { - unsafe { &(*SPI::ptr()).dr as *const _ as u32 } - } + unsafe impl PeriAddress for $Rx { + #[inline(always)] + fn address(&self) -> u32 { + unsafe { &(*SPI::ptr()).dr as *const _ as u32 } + } - type MemSize = u8; -} + type MemSize = u8; + } -unsafe impl DMASet for Tx where - SPI: DMASet -{ + unsafe impl + DMASet for $Rx + where + SPI: DMASet, + { + } + + unsafe impl PeriAddress for $Tx { + #[inline(always)] + fn address(&self) -> u32 { + unsafe { &(*SPI::ptr()).dr as *const _ as u32 } + } + + type MemSize = u8; + } + + unsafe impl + DMASet for $Tx + where + SPI: DMASet, + { + } + + unsafe impl PeriAddress for $RxCoupled { + #[inline(always)] + fn address(&self) -> u32 { + unsafe { &(*SPI::ptr()).dr as *const _ as u32 } + } + + type MemSize = u8; + } + + unsafe impl + DMASet for $RxCoupled + where + SPI: DMASet, + { + } + + unsafe impl PeriAddress for $TxCoupled { + #[inline(always)] + fn address(&self) -> u32 { + unsafe { &(*SPI::ptr()).dr as *const _ as u32 } + } + + type MemSize = u8; + } + + unsafe impl + DMASet for $TxCoupled + where + SPI: DMASet, + { + } + }; } +dma!(Spi, DmaBuilder, Tx, Rx, TxCoupled, RxCoupled); +dma!( + SpiSlave, + DmaBuilderSlave, + TxSlave, + RxSlave, + TxCoupledSlave, + RxCoupledSlave +); + impl Spi { pub fn read_nonblocking(&mut self) -> nb::Result { if BIDI {