diff --git a/CHANGELOG.md b/CHANGELOG.md index 574dd973..647e6005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - example of using i2s in out with rtic and interrupt. - example of using USB CDC with interrupts. - Added non-blocking I2C based on DMA [#534] +- Capability to release and reuse SPI peripheral after using it with DMA. [#481]: https://github.com/stm32-rs/stm32f4xx-hal/pull/481 [#489]: https://github.com/stm32-rs/stm32f4xx-hal/pull/489 diff --git a/Cargo.toml b/Cargo.toml index a09e1de4..2432938e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ rtic-monotonic = { version = "1.0", optional = true } systick-monotonic = { version = "1.0", optional = true } bitflags = "1.3.2" embedded-storage = "0.2" +paste = "1.0.9" [dependencies.time] version = "0.3.14" diff --git a/examples/spi_dma.rs b/examples/spi_dma.rs index 3d5d8921..c1b3ed8e 100644 --- a/examples/spi_dma.rs +++ b/examples/spi_dma.rs @@ -11,6 +11,7 @@ use embedded_hal::spi::{Mode, Phase, Polarity}; use stm32f4xx_hal::pac::interrupt; use stm32f4xx_hal::{ dma::{config, traits::StreamISR, MemoryToPeripheral, Stream4, StreamsTuple, Transfer}, + gpio::{PB13, PB15}, pac, prelude::*, spi::*, @@ -21,7 +22,7 @@ const ARRAY_SIZE: usize = 100; type SpiDma = Transfer< Stream4, 0, - Tx, + Tx, MemoryToPeripheral, &'static mut [u8; ARRAY_SIZE], >; @@ -39,8 +40,8 @@ fn main() -> ! { let stream = steams.4; let gpiob = dp.GPIOB.split(); - let pb15 = gpiob.pb15.into_alternate().internal_pull_up(true); - let pb13 = gpiob.pb13.into_alternate(); + let pb15 = gpiob.pb15.internal_pull_up(true); + let pb13 = gpiob.pb13; let mode = Mode { polarity: Polarity::IdleLow, diff --git a/src/dma/traits.rs b/src/dma/traits.rs index c46432d8..c9d2fda9 100644 --- a/src/dma/traits.rs +++ b/src/dma/traits.rs @@ -6,6 +6,7 @@ use crate::{ serial, spi, timer, }; use core::ops::Deref; +use paste::paste; pub(crate) mod sealed { /// Converts value to bits for setting a register value. @@ -284,6 +285,20 @@ macro_rules! dma_map { }; } +macro_rules! dma_spi_map { + ($(($Stream:ty, $C:literal, $RxTx:ident, $Peripheral:ty, $Dir:ty)),+ $(,)*) => { + $( + unsafe impl + DMASet<$Stream, $C, $Dir> for spi::$RxTx<$Peripheral, PINS, BIDI, OPERATION> {} + + paste! { + unsafe impl + DMASet<$Stream, $C, $Dir> for spi::[<$RxTx Coupled>]<$Peripheral, PINS, BIDI, OPERATION> {} + } + )+ + }; +} + #[cfg(any( feature = "stm32f401", feature = "stm32f417", @@ -330,15 +345,36 @@ dma_map!( (Stream7, 5, timer::CCR3, MemoryToPeripheral), //TIM3_CH3 (Stream7, 5, timer::CCR3, PeripheralToMemory), //TIM3_CH3 (Stream0, 0, pac::SPI3, PeripheralToMemory), //SPI3_RX - (Stream0, 0, spi::Rx, PeripheralToMemory), //SPI3_RX (Stream2, 0, pac::SPI3, PeripheralToMemory), //SPI3_RX - (Stream2, 0, spi::Rx, PeripheralToMemory), //SPI3_RX (Stream4, 3, pac::I2C3, MemoryToPeripheral), //I2C3_TX (Stream4, 3, i2c::Tx, MemoryToPeripheral), //I2C3_TX (Stream5, 0, pac::SPI3, MemoryToPeripheral), //SPI3_TX - (Stream5, 0, spi::Tx, MemoryToPeripheral), //SPI3_TX (Stream7, 0, pac::SPI3, MemoryToPeripheral), //SPI3_TX - (Stream7, 0, spi::Tx, MemoryToPeripheral), //SPI3_TX +); + +#[cfg(any( + feature = "stm32f401", + feature = "stm32f417", + feature = "stm32f415", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f439", + feature = "stm32f437", + feature = "stm32f429", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479", +))] +dma_spi_map!( + (Stream0, 0, Rx, pac::SPI3, PeripheralToMemory), //SPI3_RX + (Stream2, 0, Rx, pac::SPI3, PeripheralToMemory), //SPI3_RX + (Stream5, 0, Tx, pac::SPI3, MemoryToPeripheral), //SPI3_TX + (Stream7, 0, Tx, pac::SPI3, MemoryToPeripheral), //SPI3_TX ); #[cfg(any( @@ -437,11 +473,9 @@ dma_map!( (Stream2, 7, pac::I2C2, PeripheralToMemory), //I2C2_RX (Stream2, 7, i2c::Rx, PeripheralToMemory), //I2C2_RX (Stream3, 0, pac::SPI2, PeripheralToMemory), //SPI2_RX - (Stream3, 0, spi::Rx, PeripheralToMemory), //SPI2_RX (Stream3, 7, pac::I2C2, PeripheralToMemory), //I2C2_RX - (Stream3, 7, spi::Rx, PeripheralToMemory), //I2C2_RX + (Stream3, 7, i2c::Rx, PeripheralToMemory), //I2C2_RX (Stream4, 0, pac::SPI2, MemoryToPeripheral), //SPI2_TX - (Stream4, 0, spi::Tx, MemoryToPeripheral), // SPI2_TX (Stream5, 1, pac::I2C1, PeripheralToMemory), //I2C1_RX (Stream5, 1, i2c::Rx, PeripheralToMemory), //I2C1_RX (Stream5, 4, pac::USART2, PeripheralToMemory), //USART2_RX @@ -453,11 +487,9 @@ dma_map!( (Stream0, 0, pac::ADC1, PeripheralToMemory), //ADC1 (Stream0, 0, Adc, PeripheralToMemory), (Stream0, 3, pac::SPI1, PeripheralToMemory), //SPI1_RX - (Stream0, 3, spi::Rx, PeripheralToMemory), //SPI1_RX (Stream1, 5, pac::USART6, PeripheralToMemory), //USART6_RX (Stream1, 5, serial::Rx, PeripheralToMemory), //USART6_RX (Stream2, 3, pac::SPI1, PeripheralToMemory), //SPI1_RX - (Stream2, 3, spi::Rx, PeripheralToMemory), //SPI1_RX (Stream2, 4, pac::USART1, PeripheralToMemory), //USART1_RX (Stream2, 4, serial::Rx, PeripheralToMemory), //USART1_RX (Stream2, 5, pac::USART6, PeripheralToMemory), //USART6_RX @@ -497,6 +529,32 @@ dma_map!( (Stream7, 0, MemoryToMemory, MemoryToMemory), ); +#[cfg(any( + feature = "stm32f401", + feature = "stm32f417", + feature = "stm32f415", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f439", + feature = "stm32f437", + feature = "stm32f429", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479", +))] +dma_spi_map!( + (Stream3, 0, Rx, pac::SPI2, PeripheralToMemory), //SPI2_RX + (Stream4, 0, Tx, pac::SPI2, MemoryToPeripheral), // SPI2_TX + (Stream0, 3, Rx, pac::SPI1, PeripheralToMemory), //SPI1_RX + (Stream2, 3, Rx, pac::SPI1, PeripheralToMemory), //SPI1_RX +); + #[cfg(any( feature = "stm32f401", feature = "stm32f417", @@ -586,9 +644,26 @@ dma_map!( (Stream7, 1, pac::I2C1, MemoryToPeripheral), //I2C1_TX (Stream7, 1, i2c::Tx, MemoryToPeripheral), //I2C1_TX (Stream3, 3, pac::SPI1, MemoryToPeripheral), //SPI1_TX - (Stream3, 3, spi::Tx, MemoryToPeripheral), //SPI1_TX (Stream5, 3, pac::SPI1, MemoryToPeripheral), //SPI1_TX - (Stream5, 3, spi::Tx, MemoryToPeripheral), //SPI1_TX +); + +#[cfg(any( + feature = "stm32f401", + feature = "stm32f417", + feature = "stm32f415", + feature = "stm32f405", + feature = "stm32f407", + feature = "stm32f427", + feature = "stm32f439", + feature = "stm32f437", + feature = "stm32f429", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479", +))] +dma_spi_map!( + (Stream3, 3, Tx, pac::SPI1, MemoryToPeripheral), //SPI1_TX + (Stream5, 3, Tx, pac::SPI1, MemoryToPeripheral), //SPI1_TX ); #[cfg(any( @@ -607,13 +682,30 @@ dma_map!( ))] dma_map!( (Stream0, 4, pac::SPI4, PeripheralToMemory), //SPI4_RX - (Stream0, 4, spi::Rx, PeripheralToMemory), //SPI4_RX (Stream1, 4, pac::SPI4, MemoryToPeripheral), //SPI4_TX - (Stream1, 4, spi::Tx, MemoryToPeripheral), //SPI4_TX (Stream3, 5, pac::SPI4, PeripheralToMemory), //SPI4_RX:DMA_CHANNEL_5 - (Stream3, 5, spi::Rx, PeripheralToMemory), //SPI4_RX:DMA_CHANNEL_5 (Stream4, 5, pac::SPI4, MemoryToPeripheral), //SPI4_TX:DMA_CHANNEL_5 - (Stream4, 5, spi::Tx, MemoryToPeripheral), //SPI4_TX:DMA_CHANNEL_5 +); + +#[cfg(any( + feature = "stm32f401", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f439", + feature = "stm32f437", + feature = "stm32f429", + feature = "stm32f446", + feature = "stm32f469", + feature = "stm32f479", +))] +dma_spi_map!( + (Stream0, 4, Rx, pac::SPI4, PeripheralToMemory), //SPI4_RX + (Stream1, 4, Tx, pac::SPI4, MemoryToPeripheral), //SPI4_TX + (Stream3, 5, Rx, pac::SPI4, PeripheralToMemory), //SPI4_RX:DMA_CHANNEL_5 + (Stream4, 5, Tx, pac::SPI4, MemoryToPeripheral), //SPI4_TX:DMA_CHANNEL_5 ); #[cfg(any( @@ -936,13 +1028,23 @@ dma_map!( (Stream7, 1, i2c::Tx, MemoryToPeripheral), //I2C1_TX:DMA_CHANNEL_1 (Stream7, 6, pac::USART2, PeripheralToMemory), //USART2_RX:DMA_CHANNEL_6 (Stream2, 2, pac::SPI1, MemoryToPeripheral), //SPI1_TX - (Stream2, 2, spi::Tx, MemoryToPeripheral), //SPI1_TX (Stream3, 3, pac::SPI1, MemoryToPeripheral), //SPI1_TX:DMA_CHANNEL_3 - (Stream3, 3, spi::Tx, MemoryToPeripheral), //SPI1_TX:DMA_CHANNEL_3 (Stream5, 3, pac::SPI1, MemoryToPeripheral), //SPI1_TX:DMA_CHANNEL_3 - (Stream5, 3, spi::Tx, MemoryToPeripheral), //SPI1_TX:DMA_CHANNEL_3 (Stream5, 5, pac::SPI5, MemoryToPeripheral), //SPI5_TX:DMA_CHANNEL_5 - (Stream5, 5, spi::Tx, MemoryToPeripheral), //SPI5_TX:DMA_CHANNEL_5 +); + +#[cfg(any( + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", +))] +dma_spi_map!( + (Stream2, 2, Tx, pac::SPI1, MemoryToPeripheral), //SPI1_TX + (Stream3, 3, Tx, pac::SPI1, MemoryToPeripheral), //SPI1_TX:DMA_CHANNEL_3 + (Stream5, 3, Tx, pac::SPI1, MemoryToPeripheral), //SPI1_TX:DMA_CHANNEL_3 + (Stream5, 5, Tx, pac::SPI5, MemoryToPeripheral), //SPI5_TX:DMA_CHANNEL_5 ); #[cfg(any( @@ -960,13 +1062,29 @@ dma_map!( ))] dma_map!( (Stream3, 2, pac::SPI5, PeripheralToMemory), //SPI5_RX - (Stream3, 2, spi::Rx, PeripheralToMemory), //SPI5_RX (Stream4, 2, pac::SPI5, MemoryToPeripheral), //SPI5_TX - (Stream4, 2, spi::Tx, MemoryToPeripheral), //SPI5_TX (Stream5, 7, pac::SPI5, PeripheralToMemory), //SPI5_RX:DMA_CHANNEL_7 - (Stream5, 7, spi::Rx, PeripheralToMemory), //SPI5_RX:DMA_CHANNEL_7 (Stream6, 7, pac::SPI5, MemoryToPeripheral), //SPI5_TX:DMA_CHANNEL_7 - (Stream6, 7, spi::Tx, MemoryToPeripheral), //SPI5_TX:DMA_CHANNEL_7 +); + +#[cfg(any( + feature = "stm32f410", + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", + feature = "stm32f427", + feature = "stm32f439", + feature = "stm32f437", + feature = "stm32f429", + feature = "stm32f469", + feature = "stm32f479", +))] +dma_spi_map!( + (Stream3, 2, Rx, pac::SPI5, PeripheralToMemory), //SPI5_RX + (Stream4, 2, Tx, pac::SPI5, MemoryToPeripheral), //SPI5_TX + (Stream5, 7, Rx, pac::SPI5, PeripheralToMemory), //SPI5_RX:DMA_CHANNEL_7 + (Stream6, 7, Tx, pac::SPI5, MemoryToPeripheral), //SPI5_TX:DMA_CHANNEL_7 ); #[cfg(any( @@ -992,8 +1110,17 @@ address!((pac::SPI5, dr, u8),); ))] dma_map!( (Stream4, 4, pac::SPI4, PeripheralToMemory), //SPI4_RX); - (Stream4, 4, spi::Rx, PeripheralToMemory), -); //SPI4_RX); +); + +#[cfg(any( + feature = "stm32f411", + feature = "stm32f412", + feature = "stm32f413", + feature = "stm32f423", +))] +dma_spi_map!( + (Stream4, 4, Rx, pac::SPI4, PeripheralToMemory), // SPI4_RX +); /* TODO: DFSDM support #[cfg(feature = "stm32f412")] @@ -1147,9 +1274,20 @@ address!( ))] dma_map!( (Stream5, 1, pac::SPI6, MemoryToPeripheral), //SPI6_TX - (Stream5, 1, spi::Tx, MemoryToPeripheral), //SPI6_TX (Stream6, 1, pac::SPI6, PeripheralToMemory), //SPI6_RX - (Stream6, 1, spi::Rx, PeripheralToMemory), //SPI6_RX +); + +#[cfg(any( + feature = "stm32f427", + feature = "stm32f439", + feature = "stm32f437", + feature = "stm32f429", + feature = "stm32f469", + feature = "stm32f479", +))] +dma_spi_map!( + (Stream5, 1, Tx, pac::SPI6, MemoryToPeripheral), //SPI6_TX + (Stream6, 1, Rx, pac::SPI6, PeripheralToMemory), //SPI6_RX ); #[cfg(any( diff --git a/src/spi.rs b/src/spi.rs index db67824b..17bc09c1 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -681,49 +681,118 @@ impl // Spi DMA -impl Spi { - pub fn use_dma(self) -> DmaBuilder { - DmaBuilder { spi: self.spi } +impl Spi { + pub fn use_dma(self) -> DmaBuilder { + DmaBuilder { spi: self } } } -pub struct DmaBuilder { - spi: SPI, +pub struct DmaBuilder { + spi: Spi, +} + +pub struct Tx { + spi: Spi, +} + +pub struct Rx { + spi: Spi, +} + +pub struct TxCoupled { + spi: Spi, +} + +pub struct RxCoupled { + spi: PhantomData>, } -pub struct 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.spi.cr2.modify(|_, w| w.rxdmaen().enabled()); + Rx { spi: self.spi } + } + + pub fn txrx( + self, + ) -> ( + TxCoupled, + RxCoupled, + ) { + self.spi + .spi + .cr2 + .modify(|_, w| w.txdmaen().enabled().rxdmaen().enabled()); + (TxCoupled { spi: self.spi }, RxCoupled { spi: PhantomData }) + } } -pub struct Rx { - spi: PhantomData, +impl Rx { + pub fn release(self) -> Spi { + self.spi.spi.cr2.modify(|_, w| w.rxdmaen().disabled()); + self.spi + } } -impl DmaBuilder { - pub fn tx(self) -> Tx { - self.new_tx() +impl Tx { + pub fn release(self) -> Spi { + self.spi.spi.cr2.modify(|_, w| w.txdmaen().disabled()); + self.spi } +} - pub fn rx(self) -> Rx { - self.new_rx() +impl TxCoupled { + pub fn release( + self, + _couple: RxCoupled, + ) -> Spi { + self.spi + .spi + .cr2 + .modify(|_, w| w.rxdmaen().disabled().txdmaen().disabled()); + self.spi } +} - pub fn txrx(self) -> (Tx, Rx) { - (self.new_tx(), self.new_rx()) +impl RxCoupled { + pub fn release( + self, + couple: TxCoupled, + ) -> Spi { + couple.release(self) } +} - fn new_tx(&self) -> Tx { - self.spi.cr2.modify(|_, w| w.txdmaen().enabled()); - Tx { spi: PhantomData } +unsafe impl PeriAddress + for Rx +{ + #[inline(always)] + fn address(&self) -> u32 { + unsafe { &(*SPI::ptr()).dr as *const _ as u32 } } - fn new_rx(self) -> Rx { - self.spi.cr2.modify(|_, w| w.rxdmaen().enabled()); - Rx { spi: PhantomData } + type MemSize = u8; +} + +unsafe impl PeriAddress + for Tx +{ + #[inline(always)] + fn address(&self) -> u32 { + unsafe { &(*SPI::ptr()).dr as *const _ as u32 } } + + type MemSize = u8; } -unsafe impl PeriAddress for Rx { +unsafe impl PeriAddress + for RxCoupled +{ #[inline(always)] fn address(&self) -> u32 { unsafe { &(*SPI::ptr()).dr as *const _ as u32 } @@ -732,7 +801,9 @@ unsafe impl PeriAddress for Rx { type MemSize = u8; } -unsafe impl PeriAddress for Tx { +unsafe impl PeriAddress + for TxCoupled +{ #[inline(always)] fn address(&self) -> u32 { unsafe { &(*SPI::ptr()).dr as *const _ as u32 }