diff --git a/CHANGELOG.md b/CHANGELOG.md index cd6a5b38..65498e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - `timer.rs` refactoring +- Demacrofy `RxDma`/`TxDma` implementations ## [v0.11.0] - 2025-09-09 diff --git a/src/adc.rs b/src/adc.rs index 05ac87a6..ba025620 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -5,9 +5,6 @@ use core::ops::Deref; use embedded_hal_02::adc::{Channel, OneShot}; use fugit::HertzU32 as Hertz; -#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] -use crate::dma::dma2; -use crate::dma::{dma1, CircBuffer, Receive, RxDma, Transfer, TransferPayload, W}; use crate::gpio::{self, Analog}; use crate::rcc::{Enable, Rcc, Reset}; use crate::time::kHz; @@ -18,6 +15,9 @@ use embedded_dma::WriteBuffer; use crate::pac::{self, RCC}; use crate::pacext::adc::{AdcRB, Cr1W, Cr2R, Cr2W, Dr, ExtSelW}; +mod dma; +pub use dma::*; + const TEMP_CHANNEL: u8 = 16; const VREF_CHANNEL: u8 = 17; @@ -609,12 +609,6 @@ impl Adc { } } -pub struct AdcPayload { - adc: Adc, - pins: PINS, - _mode: PhantomData, -} - pub trait ChannelTimeSequence { /// Set ADC sampling time for particular channel fn set_channel_sample_time(&mut self, chan: u8, sample_time: SampleTime); @@ -655,221 +649,3 @@ pub trait SetChannels: ChannelTimeSequence { fn set_samples(&mut self); fn set_sequence(&mut self); } - -pub type AdcDma = RxDma, CHANNEL>; - -macro_rules! adcdma { - ($ADCX:ty: ( - $rxdma:ident, - $dmarxch:ty, - )) => { - pub type $rxdma = AdcDma<$ADCX, PINS, MODE, $dmarxch>; - - impl Receive for AdcDma<$ADCX, PINS, MODE, $dmarxch> { - type RxChannel = $dmarxch; - type TransmittedWord = u16; - } - - impl TransferPayload for AdcDma<$ADCX, PINS, Continuous, $dmarxch> { - fn start(&mut self) { - self.channel.start(); - self.payload.adc.rb.cr2().modify(|_, w| w.cont().set_bit()); - self.payload.adc.rb.cr2().modify(|_, w| w.adon().set_bit()); - } - fn stop(&mut self) { - self.channel.stop(); - self.payload - .adc - .rb - .cr2() - .modify(|_, w| w.cont().clear_bit()); - } - } - - impl TransferPayload for AdcDma<$ADCX, PINS, Scan, $dmarxch> { - fn start(&mut self) { - self.channel.start(); - self.payload.adc.rb.cr2().modify(|_, w| w.adon().set_bit()); - } - fn stop(&mut self) { - self.channel.stop(); - } - } - - impl Adc<$ADCX> { - pub fn with_dma( - mut self, - pins: PIN, - dma_ch: $dmarxch, - ) -> AdcDma<$ADCX, PIN, Continuous, $dmarxch> - where - PIN: Channel<$ADCX, ID = u8>, - { - self.rb.cr1().modify(|_, w| w.discen().clear_bit()); - self.rb - .cr2() - .modify(|_, w| w.align().variant(self.align.into())); - self.set_channel_sample_time(PIN::channel(), self.sample_time); - self.rb - .sqr3() - .modify(|_, w| unsafe { w.sq1().bits(PIN::channel()) }); - self.rb.cr2().modify(|_, w| w.dma().set_bit()); - - let payload = AdcPayload { - adc: self, - pins, - _mode: PhantomData, - }; - RxDma { - payload, - channel: dma_ch, - } - } - - pub fn with_scan_dma( - mut self, - pins: PINS, - dma_ch: $dmarxch, - ) -> AdcDma<$ADCX, PINS, Scan, $dmarxch> - where - Self: SetChannels, - { - self.rb.cr2().modify(|_, w| { - w.adon().clear_bit(); - w.dma().clear_bit(); - w.cont().clear_bit(); - w.align().variant(self.align.into()) - }); - self.rb - .cr1() - .modify(|_, w| w.scan().set_bit().discen().clear_bit()); - self.set_samples(); - self.set_sequence(); - self.rb - .cr2() - .modify(|_, w| w.dma().set_bit().adon().set_bit()); - - let payload = AdcPayload { - adc: self, - pins, - _mode: PhantomData, - }; - RxDma { - payload, - channel: dma_ch, - } - } - } - - impl AdcDma<$ADCX, PINS, Continuous, $dmarxch> - where - Self: TransferPayload, - { - pub fn split(mut self) -> (Adc<$ADCX>, PINS, $dmarxch) { - self.stop(); - - let AdcDma { payload, channel } = self; - payload.adc.rb.cr2().modify(|_, w| w.dma().clear_bit()); - payload.adc.rb.cr1().modify(|_, w| w.discen().set_bit()); - - (payload.adc, payload.pins, channel) - } - } - - impl AdcDma<$ADCX, PINS, Scan, $dmarxch> - where - Self: TransferPayload, - { - pub fn split(mut self) -> (Adc<$ADCX>, PINS, $dmarxch) { - self.stop(); - - let AdcDma { payload, channel } = self; - payload.adc.rb.cr2().modify(|_, w| w.dma().clear_bit()); - payload.adc.rb.cr1().modify(|_, w| w.discen().set_bit()); - payload.adc.rb.cr1().modify(|_, w| w.scan().clear_bit()); - - (payload.adc, payload.pins, channel) - } - } - - impl crate::dma::CircReadDma for AdcDma<$ADCX, PINS, MODE, $dmarxch> - where - Self: TransferPayload, - &'static mut [B; 2]: WriteBuffer, - B: 'static, - { - fn circ_read(mut self, mut buffer: &'static mut [B; 2]) -> CircBuffer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.write_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$ADCX>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - - self.channel.ch().cr().modify(|_, w| { - w.mem2mem().clear_bit(); - w.pl().medium(); - w.msize().bits16(); - w.psize().bits16(); - w.circ().set_bit(); - w.dir().clear_bit() - }); - - self.start(); - - CircBuffer::new(buffer, self) - } - } - - impl crate::dma::ReadDma for AdcDma<$ADCX, PINS, MODE, $dmarxch> - where - Self: TransferPayload, - B: WriteBuffer, - { - fn read(mut self, mut buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.write_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$ADCX>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - self.channel.ch().cr().modify(|_, w| { - w.mem2mem().clear_bit(); - w.pl().medium(); - w.msize().bits16(); - w.psize().bits16(); - w.circ().clear_bit(); - w.dir().clear_bit() - }); - self.start(); - - Transfer::w(buffer, self) - } - } - }; -} - -adcdma! { - pac::ADC1: ( - AdcDma1, - dma1::C1, - ) -} - -#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] -adcdma! { - pac::ADC3: ( - AdcDma3, - dma2::C5, - ) -} diff --git a/src/adc/dma.rs b/src/adc/dma.rs new file mode 100644 index 00000000..6a9651c4 --- /dev/null +++ b/src/adc/dma.rs @@ -0,0 +1,227 @@ +use super::*; + +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +use crate::dma::dma2; +use crate::dma::{dma1, Ch, CircBuffer, DmaExt, Receive, RxDma, Transfer, TransferPayload, W}; + +pub struct AdcPayload { + adc: Adc, + pins: PINS, + _mode: PhantomData, +} + +pub type AdcDma = RxDma, CHANNEL>; + +impl TransferPayload + for AdcDma> +{ + fn start(&mut self) { + self.channel.start(); + self.payload.adc.rb.cr2().modify(|_, w| w.cont().set_bit()); + self.payload.adc.rb.cr2().modify(|_, w| w.adon().set_bit()); + } + fn stop(&mut self) { + self.channel.stop(); + self.payload + .adc + .rb + .cr2() + .modify(|_, w| w.cont().clear_bit()); + } +} + +impl TransferPayload + for AdcDma> +{ + fn start(&mut self) { + self.channel.start(); + self.payload.adc.rb.cr2().modify(|_, w| w.adon().set_bit()); + } + fn stop(&mut self) { + self.channel.stop(); + } +} + +impl Adc { + pub fn with_dma(mut self, pins: PIN, dma_ch: CH) -> AdcDma + where + AdcPayload: Receive, + PIN: Channel, + { + self.rb.cr1().modify(|_, w| w.discen().clear_bit()); + self.rb + .cr2() + .modify(|_, w| w.align().variant(self.align.into())); + self.set_channel_sample_time(PIN::channel(), self.sample_time); + self.rb + .sqr3() + .modify(|_, w| unsafe { w.sq1().bits(PIN::channel()) }); + self.rb.cr2().modify(|_, w| w.dma().set_bit()); + + let payload = AdcPayload { + adc: self, + pins, + _mode: PhantomData, + }; + RxDma { + payload, + channel: dma_ch, + } + } + + pub fn with_scan_dma(mut self, pins: PINS, dma_ch: CH) -> AdcDma + where + AdcPayload: Receive, + Self: SetChannels, + { + self.rb.cr2().modify(|_, w| { + w.adon().clear_bit(); + w.dma().clear_bit(); + w.cont().clear_bit(); + w.align().variant(self.align.into()) + }); + self.rb + .cr1() + .modify(|_, w| w.scan().set_bit().discen().clear_bit()); + self.set_samples(); + self.set_sequence(); + self.rb + .cr2() + .modify(|_, w| w.dma().set_bit().adon().set_bit()); + + let payload = AdcPayload { + adc: self, + pins, + _mode: PhantomData, + }; + RxDma { + payload, + channel: dma_ch, + } + } +} + +impl AdcDma +where + Self: TransferPayload, +{ + pub fn split(mut self) -> (Adc, PINS, CH) { + self.stop(); + + let AdcDma { payload, channel } = self; + payload.adc.rb.cr2().modify(|_, w| w.dma().clear_bit()); + payload.adc.rb.cr1().modify(|_, w| w.discen().set_bit()); + + (payload.adc, payload.pins, channel) + } +} + +impl AdcDma +where + Self: TransferPayload, +{ + pub fn split(mut self) -> (Adc, PINS, CH) { + self.stop(); + + let AdcDma { payload, channel } = self; + payload.adc.rb.cr2().modify(|_, w| w.dma().clear_bit()); + payload.adc.rb.cr1().modify(|_, w| w.discen().set_bit()); + payload.adc.rb.cr1().modify(|_, w| w.scan().clear_bit()); + + (payload.adc, payload.pins, channel) + } +} + +impl crate::dma::CircReadDma + for AdcDma> +where + AdcPayload: Receive>, + Self: TransferPayload, + &'static mut [B; 2]: WriteBuffer, + B: 'static, +{ + fn circ_read(mut self, mut buffer: &'static mut [B; 2]) -> CircBuffer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.write_buffer() }; + self.channel + .set_peripheral_address(unsafe { (*ADC::ptr()).dr().as_ptr() as u32 }, false); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + + self.channel.ch().cr().modify(|_, w| { + w.mem2mem().clear_bit(); + w.pl().medium(); + w.msize().bits16(); + w.psize().bits16(); + w.circ().set_bit(); + w.dir().clear_bit() + }); + + self.start(); + + CircBuffer::new(buffer, self) + } +} + +impl crate::dma::ReadDma + for AdcDma> +where + AdcPayload: Receive>, + Self: TransferPayload, + B: WriteBuffer, +{ + fn read(mut self, mut buffer: B) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.write_buffer() }; + self.channel + .set_peripheral_address(unsafe { (*ADC::ptr()).dr().as_ptr() as u32 }, false); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + self.channel.ch().cr().modify(|_, w| { + w.mem2mem().clear_bit(); + w.pl().medium(); + w.msize().bits16(); + w.psize().bits16(); + w.circ().clear_bit(); + w.dir().clear_bit() + }); + self.start(); + + Transfer::w(buffer, self) + } +} + +macro_rules! adcdma { + ($ADCX:ty: ( + $rxdma:ident, + $dmarxch:ty, + )) => { + pub type $rxdma = AdcDma<$ADCX, PINS, MODE, $dmarxch>; + + impl Receive for AdcPayload<$ADCX, PINS, MODE> { + type RxChannel = $dmarxch; + type TransmittedWord = u16; + } + }; +} + +adcdma! { + pac::ADC1: ( + AdcDma1, + dma1::C1, + ) +} + +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +adcdma! { + pac::ADC3: ( + AdcDma3, + dma2::C5, + ) +} diff --git a/src/dma.rs b/src/dma.rs index c90ac132..e7a196f9 100644 --- a/src/dma.rs +++ b/src/dma.rs @@ -553,3 +553,35 @@ where { fn read_write(self, rx_buffer: RXB, tx_buffer: TXB) -> Transfer; } + +impl Receive for RxDma +where + P: Receive, +{ + type RxChannel = CH; + type TransmittedWord = W; +} + +impl Transmit for TxDma +where + P: Transmit, +{ + type TxChannel = CH; + type ReceivedWord = W; +} + +impl Receive for RxTxDma +where + P: Receive, +{ + type RxChannel = RXCH; + type TransmittedWord = W; +} + +impl Transmit for RxTxDma +where + P: Transmit, +{ + type TxChannel = TXCH; + type ReceivedWord = W; +} diff --git a/src/lib.rs b/src/lib.rs index d1549ca3..69580101 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,15 +166,18 @@ impl Sealed for Periph {} pub trait Ptr: Sealed { /// RegisterBlock structure type RB; + /// Pointer to the register block + const PTR: *const Self::RB; /// Return the pointer to the register block - fn ptr() -> *const Self::RB; + #[inline(always)] + fn ptr() -> *const Self::RB { + Self::PTR + } } impl Ptr for Periph { type RB = RB; - fn ptr() -> *const Self::RB { - Self::ptr() - } + const PTR: *const Self::RB = Self::PTR; } pub trait Steal: Sealed { @@ -195,6 +198,7 @@ pub trait Steal: Sealed { } impl Steal for Periph { + #[inline(always)] unsafe fn steal() -> Self { Self::steal() } diff --git a/src/serial.rs b/src/serial.rs index 838036dd..6763ca63 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -95,16 +95,15 @@ use core::sync::atomic::{self, Ordering}; use embedded_dma::{ReadBuffer, WriteBuffer}; use crate::afio::{self, RInto, Rmp}; -#[cfg(any(all(feature = "stm32f103", feature = "high"), feature = "connectivity"))] -use crate::dma::dma2; -use crate::dma::{self, dma1, CircBuffer, RxDma, Transfer, TxDma}; use crate::gpio::{Floating, PushPull, UpMode}; use crate::pac::{self}; use crate::rcc::{BusClock, Clocks, Enable, Rcc, Reset}; use crate::time::{Bps, U32Ext}; +mod dma; mod hal_02; mod hal_1; +pub use dma::*; use crate::pacext::uart::{SrR, UartRB}; @@ -830,222 +829,3 @@ pub type Rx2 = Rx; pub type Tx2 = Tx; pub type Rx3 = Rx; pub type Tx3 = Tx; - -use crate::dma::{Receive, TransferPayload, Transmit}; - -macro_rules! serialdma { - ( - $USARTX:ty, - $rxdma:ident, - $txdma:ident, - rx: $dmarxch:ty, - tx: $dmatxch:ty - ) => { - pub type $rxdma = RxDma, $dmarxch>; - pub type $txdma = TxDma, $dmatxch>; - - impl Receive for $rxdma { - type RxChannel = $dmarxch; - type TransmittedWord = u8; - } - - impl Transmit for $txdma { - type TxChannel = $dmatxch; - type ReceivedWord = u8; - } - - impl TransferPayload for $rxdma { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } - } - - impl TransferPayload for $txdma { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } - } - - impl Rx<$USARTX> { - pub fn with_dma(self, channel: $dmarxch) -> $rxdma { - unsafe { - (*<$USARTX>::ptr()).cr3().modify(|_, w| w.dmar().set_bit()); - } - RxDma { - payload: self, - channel, - } - } - } - - impl Tx<$USARTX> { - pub fn with_dma(self, channel: $dmatxch) -> $txdma { - unsafe { - (*<$USARTX>::ptr()).cr3().modify(|_, w| w.dmat().set_bit()); - } - TxDma { - payload: self, - channel, - } - } - } - - impl $rxdma { - pub fn release(mut self) -> (Rx<$USARTX>, $dmarxch) { - self.stop(); - unsafe { - (*<$USARTX>::ptr()) - .cr3() - .modify(|_, w| w.dmar().clear_bit()); - } - let RxDma { payload, channel } = self; - (payload, channel) - } - } - - impl $txdma { - pub fn release(mut self) -> (Tx<$USARTX>, $dmatxch) { - self.stop(); - unsafe { - (*<$USARTX>::ptr()) - .cr3() - .modify(|_, w| w.dmat().clear_bit()); - } - let TxDma { payload, channel } = self; - (payload, channel) - } - } - - impl crate::dma::CircReadDma for $rxdma - where - &'static mut [B; 2]: WriteBuffer, - B: 'static, - { - fn circ_read(mut self, mut buffer: &'static mut [B; 2]) -> CircBuffer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.write_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$USARTX>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - - self.channel.ch().cr().modify(|_, w| { - w.mem2mem().clear_bit(); - w.pl().medium(); - w.msize().bits8(); - w.psize().bits8(); - w.circ().set_bit(); - w.dir().clear_bit() - }); - - self.start(); - - CircBuffer::new(buffer, self) - } - } - - impl crate::dma::ReadDma for $rxdma - where - B: WriteBuffer, - { - fn read(mut self, mut buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.write_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$USARTX>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - self.channel.ch().cr().modify(|_, w| { - w.mem2mem().clear_bit(); - w.pl().medium(); - w.msize().bits8(); - w.psize().bits8(); - w.circ().clear_bit(); - w.dir().clear_bit() - }); - self.start(); - - Transfer::w(buffer, self) - } - } - - impl crate::dma::WriteDma for $txdma - where - B: ReadBuffer, - { - fn write(mut self, buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.read_buffer() }; - - self.channel.set_peripheral_address( - unsafe { (*<$USARTX>::ptr()).dr().as_ptr() as u32 }, - false, - ); - - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - - self.channel.ch().cr().modify(|_, w| { - w.mem2mem().clear_bit(); - w.pl().medium(); - w.msize().bits8(); - w.psize().bits8(); - w.circ().clear_bit(); - w.dir().set_bit() - }); - self.start(); - - Transfer::r(buffer, self) - } - } - }; -} - -serialdma! { - pac::USART1, - RxDma1, - TxDma1, - rx: dma1::C5, - tx: dma1::C4 -} -serialdma! { - pac::USART2, - RxDma2, - TxDma2, - rx: dma1::C6, - tx: dma1::C7 -} -serialdma! { - pac::USART3, - RxDma3, - TxDma3, - rx: dma1::C3, - tx: dma1::C2 -} -#[cfg(any(all(feature = "stm32f103", feature = "high"), feature = "connectivity"))] -serialdma! { - pac::UART4, - RxDma4, - TxDma4, - rx: dma2::C3, - tx: dma2::C5 -} diff --git a/src/serial/dma.rs b/src/serial/dma.rs new file mode 100644 index 00000000..9d80ab9b --- /dev/null +++ b/src/serial/dma.rs @@ -0,0 +1,227 @@ +use super::*; +#[cfg(any(all(feature = "stm32f103", feature = "high"), feature = "connectivity"))] +use crate::dma::dma2; +use crate::dma::{self, dma1, Ch, CircBuffer, DmaExt, RxDma, Transfer, TxDma}; + +use crate::dma::{Receive, TransferPayload, Transmit}; + +use crate::pacext::uart::Cr3W; + +impl TransferPayload for RxDma, Ch> { + fn start(&mut self) { + self.channel.start(); + } + fn stop(&mut self) { + self.channel.stop(); + } +} + +impl TransferPayload for TxDma, Ch> { + fn start(&mut self) { + self.channel.start(); + } + fn stop(&mut self) { + self.channel.stop(); + } +} + +impl Rx +where + Self: Receive, +{ + pub fn with_dma(self, channel: CH) -> RxDma { + let usart = unsafe { &*USART::PTR }; + usart.cr3().modify(|_, w| w.dmar().set_bit()); + RxDma { + payload: self, + channel, + } + } +} + +impl Tx +where + Self: Transmit, +{ + pub fn with_dma(self, channel: CH) -> TxDma { + let usart = unsafe { &*USART::PTR }; + usart.cr3().modify(|_, w| w.dmat().set_bit()); + TxDma { + payload: self, + channel, + } + } +} + +impl RxDma, CH> +where + Self: TransferPayload, +{ + pub fn release(mut self) -> (Rx, CH) { + self.stop(); + let usart = unsafe { &*USART::PTR }; + usart.cr3().modify(|_, w| w.dmar().clear_bit()); + (self.payload, self.channel) + } +} + +impl TxDma, CH> +where + Self: TransferPayload, +{ + pub fn release(mut self) -> (Tx, CH) { + self.stop(); + let usart = unsafe { &*USART::PTR }; + usart.cr3().modify(|_, w| w.dmat().clear_bit()); + (self.payload, self.channel) + } +} + +impl crate::dma::CircReadDma + for RxDma, Ch> +where + Rx: Receive>, + &'static mut [B; 2]: WriteBuffer, + B: 'static, +{ + fn circ_read(mut self, mut buffer: &'static mut [B; 2]) -> CircBuffer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.write_buffer() }; + self.channel + .set_peripheral_address(unsafe { &*USART::PTR }.dr().as_ptr() as u32, false); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + + self.channel.ch().cr().modify(|_, w| { + w.mem2mem().clear_bit(); + w.pl().medium(); + w.msize().bits8(); + w.psize().bits8(); + w.circ().set_bit(); + w.dir().clear_bit() + }); + + self.start(); + + CircBuffer::new(buffer, self) + } +} + +impl crate::dma::ReadDma + for RxDma, Ch> +where + Rx: Receive>, + B: WriteBuffer, +{ + fn read(mut self, mut buffer: B) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.write_buffer() }; + self.channel + .set_peripheral_address(unsafe { &*USART::PTR }.dr().as_ptr() as u32, false); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + self.channel.ch().cr().modify(|_, w| { + w.mem2mem().clear_bit(); + w.pl().medium(); + w.msize().bits8(); + w.psize().bits8(); + w.circ().clear_bit(); + w.dir().clear_bit() + }); + self.start(); + + Transfer::w(buffer, self) + } +} + +impl crate::dma::WriteDma + for TxDma, Ch> +where + Tx: Transmit>, + B: ReadBuffer, +{ + fn write(mut self, buffer: B) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.read_buffer() }; + + self.channel + .set_peripheral_address(unsafe { &*USART::PTR }.dr().as_ptr() as u32, false); + + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + + self.channel.ch().cr().modify(|_, w| { + w.mem2mem().clear_bit(); + w.pl().medium(); + w.msize().bits8(); + w.psize().bits8(); + w.circ().clear_bit(); + w.dir().set_bit() + }); + self.start(); + + Transfer::r(buffer, self) + } +} + +macro_rules! serialdma { + ( + $USARTX:ty, + $rxdma:ident, + $txdma:ident, + rx: $dmarxch:ty, + tx: $dmatxch:ty + ) => { + pub type $rxdma = RxDma, $dmarxch>; + pub type $txdma = TxDma, $dmatxch>; + + impl Receive for Rx<$USARTX> { + type RxChannel = $dmarxch; + type TransmittedWord = u8; + } + + impl Transmit for Tx<$USARTX> { + type TxChannel = $dmatxch; + type ReceivedWord = u8; + } + }; +} + +serialdma! { + pac::USART1, + RxDma1, + TxDma1, + rx: dma1::C5, + tx: dma1::C4 +} +serialdma! { + pac::USART2, + RxDma2, + TxDma2, + rx: dma1::C6, + tx: dma1::C7 +} +serialdma! { + pac::USART3, + RxDma3, + TxDma3, + rx: dma1::C3, + tx: dma1::C2 +} +#[cfg(any(all(feature = "stm32f103", feature = "high"), feature = "connectivity"))] +serialdma! { + pac::UART4, + RxDma4, + TxDma4, + rx: dma2::C3, + tx: dma2::C5 +} diff --git a/src/spi.rs b/src/spi.rs index b21cf823..fedc5dd3 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -62,18 +62,16 @@ ``` */ +mod dma; mod hal_02; mod hal_1; +pub use dma::*; use core::ops::{Deref, DerefMut}; use crate::pac::{self, RCC}; use crate::afio::{self, RInto, Rmp}; -use crate::dma::dma1; -#[cfg(feature = "connectivity")] -use crate::dma::dma2; -use crate::dma::{self, Receive, RxDma, RxTxDma, Transfer, TransferPayload, Transmit, TxDma}; use crate::gpio::{Floating, PushPull, UpMode}; use crate::rcc::{BusClock, Enable, Rcc, Reset}; use crate::time::Hertz; @@ -315,7 +313,8 @@ pub enum SpiBitFormat { pub trait Instance: crate::Sealed - + Deref + + crate::Ptr + + Deref + Enable + Reset + BusClock @@ -796,581 +795,3 @@ where Ok(()) } } - -// DMA - -pub type SpiTxDma = TxDma, CHANNEL>; -pub type SpiRxDma = RxDma, CHANNEL>; -pub type SpiRxTxDma = - RxTxDma, RXCHANNEL, TXCHANNEL>; - -pub type SpiSlaveTxDma = - TxDma, CHANNEL>; -pub type SpiSlaveRxDma = - RxDma, CHANNEL>; -pub type SpiSlaveRxTxDma = - RxTxDma, RXCHANNEL, TXCHANNEL>; - -macro_rules! spi_dma { - ( - $SPIi:ty, - rx: $RCi:ty, - tx: $TCi:ty, - $rxdma:ident, - $txdma:ident, - $rxtxdma:ident, - $slaverxdma:ident, - $slavetxdma:ident, - $slaverxtxdma:ident - ) => { - pub type $rxdma = SpiRxDma<$SPIi, $RCi, PULL>; - pub type $txdma = SpiTxDma<$SPIi, $TCi, PULL>; - pub type $rxtxdma = SpiRxTxDma<$SPIi, $RCi, $TCi, PULL>; - - impl Transmit for SpiTxDma<$SPIi, $TCi, PULL> { - type TxChannel = $TCi; - type ReceivedWord = u8; - } - - impl Receive for SpiRxDma<$SPIi, $RCi, PULL> { - type RxChannel = $RCi; - type TransmittedWord = u8; - } - - impl Transmit for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> { - type TxChannel = $TCi; - type ReceivedWord = u8; - } - - impl Receive for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> { - type RxChannel = $RCi; - type TransmittedWord = u8; - } - - impl Spi<$SPIi, u8, PULL> { - pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, $TCi, PULL> { - self.spi.cr2().modify(|_, w| w.txdmaen().set_bit()); - SpiTxDma { - payload: self, - channel, - } - } - pub fn with_rx_dma(self, channel: $RCi) -> SpiRxDma<$SPIi, $RCi, PULL> { - self.spi.cr2().modify(|_, w| w.rxdmaen().set_bit()); - SpiRxDma { - payload: self, - channel, - } - } - pub fn with_rx_tx_dma( - self, - rxchannel: $RCi, - txchannel: $TCi, - ) -> SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> { - self.spi - .cr2() - .modify(|_, w| w.rxdmaen().set_bit().txdmaen().set_bit()); - SpiRxTxDma { - payload: self, - rxchannel, - txchannel, - } - } - } - - impl SpiTxDma<$SPIi, $TCi, PULL> { - pub fn release(self) -> (Spi<$SPIi, u8, PULL>, $TCi) { - let SpiTxDma { payload, channel } = self; - payload.spi.cr2().modify(|_, w| w.txdmaen().clear_bit()); - (payload, channel) - } - } - - impl SpiRxDma<$SPIi, $RCi, PULL> { - pub fn release(self) -> (Spi<$SPIi, u8, PULL>, $RCi) { - let SpiRxDma { payload, channel } = self; - payload.spi.cr2().modify(|_, w| w.rxdmaen().clear_bit()); - (payload, channel) - } - } - - impl SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> { - pub fn release(self) -> (Spi<$SPIi, u8, PULL>, $RCi, $TCi) { - let SpiRxTxDma { - payload, - rxchannel, - txchannel, - } = self; - payload - .spi - .cr2() - .modify(|_, w| w.rxdmaen().clear_bit().txdmaen().clear_bit()); - (payload, rxchannel, txchannel) - } - } - - impl TransferPayload for SpiTxDma<$SPIi, $TCi, PULL> { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } - } - - impl TransferPayload for SpiRxDma<$SPIi, $RCi, PULL> { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } - } - - impl TransferPayload for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> { - fn start(&mut self) { - self.rxchannel.start(); - self.txchannel.start(); - } - fn stop(&mut self) { - self.txchannel.stop(); - self.rxchannel.stop(); - } - } - - impl crate::dma::ReadDma for SpiRxDma<$SPIi, $RCi, PULL> - where - B: WriteBuffer, - { - fn read(mut self, mut buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.write_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - self.channel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // write to memory - w.dir().clear_bit() - }); - self.start(); - - Transfer::w(buffer, self) - } - } - - impl crate::dma::WriteDma for SpiTxDma<$SPIi, $TCi, PULL> - where - B: ReadBuffer, - { - fn write(mut self, buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.read_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - self.channel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // read from memory - w.dir().set_bit() - }); - self.start(); - - Transfer::r(buffer, self) - } - } - - impl crate::dma::ReadWriteDma - for SpiRxTxDma<$SPIi, $RCi, $TCi, PULL> - where - RXB: WriteBuffer, - TXB: ReadBuffer, - { - fn read_write( - mut self, - mut rxbuffer: RXB, - txbuffer: TXB, - ) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (rxptr, rxlen) = unsafe { rxbuffer.write_buffer() }; - let (txptr, txlen) = unsafe { txbuffer.read_buffer() }; - - if rxlen != txlen { - panic!("receive and send buffer lengths do not match!"); - } - - self.rxchannel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.rxchannel.set_memory_address(rxptr as u32, true); - self.rxchannel.set_transfer_length(rxlen); - - self.txchannel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.txchannel.set_memory_address(txptr as u32, true); - self.txchannel.set_transfer_length(txlen); - - atomic::compiler_fence(Ordering::Release); - self.rxchannel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // write to memory - w.dir().clear_bit() - }); - self.txchannel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // read from memory - w.dir().set_bit() - }); - self.start(); - - Transfer::w((rxbuffer, txbuffer), self) - } - } - - pub type $slaverxdma = - SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL>; - pub type $slavetxdma = - SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL>; - pub type $slaverxtxdma = - SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL>; - - impl Transmit for SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> { - type TxChannel = $TCi; - type ReceivedWord = u8; - } - - impl Receive for SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> { - type RxChannel = $RCi; - type TransmittedWord = u8; - } - - impl Transmit for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> { - type TxChannel = $TCi; - type ReceivedWord = u8; - } - - impl Receive for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> { - type RxChannel = $RCi; - type TransmittedWord = u8; - } - - impl SpiSlave<$SPIi, u8, Otype, PULL> { - pub fn with_tx_dma(self, channel: $TCi) -> SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> { - self.spi.cr2().modify(|_, w| w.txdmaen().set_bit()); - SpiSlaveTxDma { - payload: self, - channel, - } - } - pub fn with_rx_dma(self, channel: $RCi) -> SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> { - self.spi.cr2().modify(|_, w| w.rxdmaen().set_bit()); - SpiSlaveRxDma { - payload: self, - channel, - } - } - pub fn with_rx_tx_dma( - self, - rxchannel: $RCi, - txchannel: $TCi, - ) -> SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> { - self.spi - .cr2() - .modify(|_, w| w.rxdmaen().set_bit().txdmaen().set_bit()); - SpiSlaveRxTxDma { - payload: self, - rxchannel, - txchannel, - } - } - } - - impl SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> { - pub fn release(self) -> (SpiSlave<$SPIi, u8, Otype, PULL>, $TCi) { - let SpiSlaveTxDma { payload, channel } = self; - payload.spi.cr2().modify(|_, w| w.txdmaen().clear_bit()); - (payload, channel) - } - } - - impl SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> { - pub fn release(self) -> (SpiSlave<$SPIi, u8, Otype, PULL>, $RCi) { - let SpiSlaveRxDma { payload, channel } = self; - payload.spi.cr2().modify(|_, w| w.rxdmaen().clear_bit()); - (payload, channel) - } - } - - impl SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> { - pub fn release(self) -> (SpiSlave<$SPIi, u8, Otype, PULL>, $RCi, $TCi) { - let SpiSlaveRxTxDma { - payload, - rxchannel, - txchannel, - } = self; - payload - .spi - .cr2() - .modify(|_, w| w.rxdmaen().clear_bit().txdmaen().clear_bit()); - (payload, rxchannel, txchannel) - } - } - - impl TransferPayload for SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } - } - - impl TransferPayload for SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } - } - - impl TransferPayload for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> { - fn start(&mut self) { - self.rxchannel.start(); - self.txchannel.start(); - } - fn stop(&mut self) { - self.txchannel.stop(); - self.rxchannel.stop(); - } - } - - impl crate::dma::ReadDma for SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL> - where - B: WriteBuffer, - { - fn read(mut self, mut buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.write_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - self.channel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // write to memory - w.dir().clear_bit() - }); - self.start(); - - Transfer::w(buffer, self) - } - } - - impl crate::dma::WriteDma for SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL> - where - B: ReadBuffer, - { - fn write(mut self, buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.read_buffer() }; - self.channel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - self.channel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // read from memory - w.dir().set_bit() - }); - self.start(); - - Transfer::r(buffer, self) - } - } - - impl crate::dma::ReadWriteDma - for SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL> - where - RXB: WriteBuffer, - TXB: ReadBuffer, - { - fn read_write( - mut self, - mut rxbuffer: RXB, - txbuffer: TXB, - ) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (rxptr, rxlen) = unsafe { rxbuffer.write_buffer() }; - let (txptr, txlen) = unsafe { txbuffer.read_buffer() }; - - if rxlen != txlen { - panic!("receive and send buffer lengths do not match!"); - } - - self.rxchannel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.rxchannel.set_memory_address(rxptr as u32, true); - self.rxchannel.set_transfer_length(rxlen); - - self.txchannel.set_peripheral_address( - unsafe { (*<$SPIi>::ptr()).dr().as_ptr() as u32 }, - false, - ); - self.txchannel.set_memory_address(txptr as u32, true); - self.txchannel.set_transfer_length(txlen); - - atomic::compiler_fence(Ordering::Release); - self.rxchannel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // write to memory - w.dir().clear_bit() - }); - self.txchannel.ch().cr().modify(|_, w| { - // memory to memory mode disabled - w.mem2mem().clear_bit(); - // medium channel priority level - w.pl().medium(); - // 8-bit memory size - w.msize().bits8(); - // 8-bit peripheral size - w.psize().bits8(); - // circular mode disabled - w.circ().clear_bit(); - // read from memory - w.dir().set_bit() - }); - self.start(); - - Transfer::w((rxbuffer, txbuffer), self) - } - } - }; -} - -spi_dma!( - pac::SPI1, - rx: dma1::C2, - tx: dma1::C3, - Spi1RxDma, - Spi1TxDma, - Spi1RxTxDma, - SpiSlave1RxDma, - SpiSlave1TxDma, - SpiSlave1RxTxDma -); -spi_dma!( - pac::SPI2, - rx: dma1::C4, - tx: dma1::C5, - Spi2RxDma, - Spi2TxDma, - Spi2RxTxDma, - SpiSlave2RxDma, - SpiSlave2TxDma, - SpiSlave2RxTxDma -); -#[cfg(feature = "connectivity")] -spi_dma!( - pac::SPI3, - rx: dma2::C1, - tx: dma2::C2, - Spi3RxDma, - Spi3TxDma, - Spi3RxTxDma, - SpiSlave3RxDma, - SpiSlave3TxDma, - SpiSlave3RxTxDma -); diff --git a/src/spi/dma.rs b/src/spi/dma.rs new file mode 100644 index 00000000..7b66e106 --- /dev/null +++ b/src/spi/dma.rs @@ -0,0 +1,366 @@ +use super::*; + +#[cfg(feature = "connectivity")] +use crate::dma::dma2; +use crate::dma::{self, Receive, RxDma, RxTxDma, Transfer, TransferPayload, Transmit, TxDma}; +use crate::dma::{dma1, Ch, DmaExt}; + +pub type SpiTxDma = TxDma, CHANNEL>; +pub type SpiRxDma = RxDma, CHANNEL>; +pub type SpiRxTxDma = + RxTxDma, RXCHANNEL, TXCHANNEL>; + +pub type SpiSlaveTxDma = + TxDma, CHANNEL>; +pub type SpiSlaveRxDma = + RxDma, CHANNEL>; +pub type SpiSlaveRxTxDma = + RxTxDma, RXCHANNEL, TXCHANNEL>; + +macro_rules! spi_impl { + ($Spi:ident) => { + impl TransferPayload + for RxDma<$Spi, Ch> + { + fn start(&mut self) { + self.channel.start(); + } + fn stop(&mut self) { + self.channel.stop(); + } + } + + impl TransferPayload + for TxDma<$Spi, Ch> + { + fn start(&mut self) { + self.channel.start(); + } + fn stop(&mut self) { + self.channel.stop(); + } + } + + impl + TransferPayload for RxTxDma<$Spi, Ch, Ch> + { + fn start(&mut self) { + self.rxchannel.start(); + self.txchannel.start(); + } + fn stop(&mut self) { + self.txchannel.stop(); + self.rxchannel.stop(); + } + } + + impl $Spi + where + Self: Transmit, + { + pub fn with_tx_dma(self, channel: CH) -> TxDma<$Spi, CH> { + self.spi.cr2().modify(|_, w| w.txdmaen().set_bit()); + TxDma { + payload: self, + channel, + } + } + } + impl $Spi + where + Self: Receive, + { + pub fn with_rx_dma(self, channel: CH) -> RxDma<$Spi, CH> { + self.spi.cr2().modify(|_, w| w.rxdmaen().set_bit()); + RxDma { + payload: self, + channel, + } + } + } + impl $Spi + where + Self: Receive, + Self: Transmit, + { + pub fn with_rx_tx_dma( + self, + rxchannel: RXCH, + txchannel: TXCH, + ) -> RxTxDma<$Spi, RXCH, TXCH> { + self.spi + .cr2() + .modify(|_, w| w.rxdmaen().set_bit().txdmaen().set_bit()); + RxTxDma { + payload: self, + rxchannel, + txchannel, + } + } + } + + impl TxDma<$Spi, CH> { + pub fn release(self) -> ($Spi, CH) { + // self.stop(); ? + self.payload + .spi + .cr2() + .modify(|_, w| w.txdmaen().clear_bit()); + (self.payload, self.channel) + } + } + + impl RxDma<$Spi, CH> { + pub fn release(self) -> ($Spi, CH) { + // self.stop(); ? + self.payload + .spi + .cr2() + .modify(|_, w| w.rxdmaen().clear_bit()); + (self.payload, self.channel) + } + } + + impl RxTxDma<$Spi, RXCH, TXCH> { + pub fn release(self) -> ($Spi, RXCH, TXCH) { + // self.stop(); ? + self.payload + .spi + .cr2() + .modify(|_, w| w.rxdmaen().clear_bit().txdmaen().clear_bit()); + (self.payload, self.rxchannel, self.txchannel) + } + } + + impl crate::dma::ReadDma + for RxDma<$Spi, Ch> + where + $Spi: Receive>, + B: WriteBuffer, + { + fn read(mut self, mut buffer: B) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.write_buffer() }; + self.channel + .set_peripheral_address(unsafe { (*SPI::ptr()).dr().as_ptr() as u32 }, false); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + self.channel.ch().cr().modify(|_, w| { + // memory to memory mode disabled + w.mem2mem().clear_bit(); + // medium channel priority level + w.pl().medium(); + // 8-bit memory size + w.msize().bits8(); + // 8-bit peripheral size + w.psize().bits8(); + // circular mode disabled + w.circ().clear_bit(); + // write to memory + w.dir().clear_bit() + }); + self.start(); + + Transfer::w(buffer, self) + } + } + + impl crate::dma::WriteDma + for TxDma<$Spi, Ch> + where + $Spi: Transmit>, + B: ReadBuffer, + { + fn write(mut self, buffer: B) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.read_buffer() }; + self.channel + .set_peripheral_address(unsafe { (*SPI::ptr()).dr().as_ptr() as u32 }, false); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + self.channel.ch().cr().modify(|_, w| { + // memory to memory mode disabled + w.mem2mem().clear_bit(); + // medium channel priority level + w.pl().medium(); + // 8-bit memory size + w.msize().bits8(); + // 8-bit peripheral size + w.psize().bits8(); + // circular mode disabled + w.circ().clear_bit(); + // read from memory + w.dir().set_bit() + }); + self.start(); + + Transfer::r(buffer, self) + } + } + + impl< + SPI: Instance, + PULL, + RXDMA: DmaExt, + const RXC: u8, + RXB, + TXDMA: DmaExt, + const TXC: u8, + TXB, + > crate::dma::ReadWriteDma + for RxTxDma<$Spi, Ch, Ch> + where + $Spi: + Receive> + Transmit>, + RXB: WriteBuffer, + TXB: ReadBuffer, + { + fn read_write( + mut self, + mut rxbuffer: RXB, + txbuffer: TXB, + ) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (rxptr, rxlen) = unsafe { rxbuffer.write_buffer() }; + let (txptr, txlen) = unsafe { txbuffer.read_buffer() }; + + if rxlen != txlen { + panic!("receive and send buffer lengths do not match!"); + } + + self.rxchannel + .set_peripheral_address(unsafe { (*SPI::ptr()).dr().as_ptr() as u32 }, false); + self.rxchannel.set_memory_address(rxptr as u32, true); + self.rxchannel.set_transfer_length(rxlen); + + self.txchannel + .set_peripheral_address(unsafe { (*SPI::ptr()).dr().as_ptr() as u32 }, false); + self.txchannel.set_memory_address(txptr as u32, true); + self.txchannel.set_transfer_length(txlen); + + atomic::compiler_fence(Ordering::Release); + self.rxchannel.ch().cr().modify(|_, w| { + // memory to memory mode disabled + w.mem2mem().clear_bit(); + // medium channel priority level + w.pl().medium(); + // 8-bit memory size + w.msize().bits8(); + // 8-bit peripheral size + w.psize().bits8(); + // circular mode disabled + w.circ().clear_bit(); + // write to memory + w.dir().clear_bit() + }); + self.txchannel.ch().cr().modify(|_, w| { + // memory to memory mode disabled + w.mem2mem().clear_bit(); + // medium channel priority level + w.pl().medium(); + // 8-bit memory size + w.msize().bits8(); + // 8-bit peripheral size + w.psize().bits8(); + // circular mode disabled + w.circ().clear_bit(); + // read from memory + w.dir().set_bit() + }); + self.start(); + + Transfer::w((rxbuffer, txbuffer), self) + } + } + }; +} + +spi_impl!(Spi); +spi_impl!(SpiSlave); + +macro_rules! spi_dma { + ( + $SPIi:ty, + rx: $RCi:ty, + tx: $TCi:ty, + $rxdma:ident, + $txdma:ident, + $rxtxdma:ident, + $slaverxdma:ident, + $slavetxdma:ident, + $slaverxtxdma:ident + ) => { + pub type $rxdma = SpiRxDma<$SPIi, $RCi, PULL>; + pub type $txdma = SpiTxDma<$SPIi, $TCi, PULL>; + pub type $rxtxdma = SpiRxTxDma<$SPIi, $RCi, $TCi, PULL>; + + impl Transmit for Spi<$SPIi, u8, PULL> { + type TxChannel = $TCi; + type ReceivedWord = u8; + } + + impl Receive for Spi<$SPIi, u8, PULL> { + type RxChannel = $RCi; + type TransmittedWord = u8; + } + + pub type $slaverxdma = + SpiSlaveRxDma<$SPIi, $RCi, Otype, PULL>; + pub type $slavetxdma = + SpiSlaveTxDma<$SPIi, $TCi, Otype, PULL>; + pub type $slaverxtxdma = + SpiSlaveRxTxDma<$SPIi, $RCi, $TCi, Otype, PULL>; + + impl Transmit for SpiSlave<$SPIi, u8, Otype, PULL> { + type TxChannel = $TCi; + type ReceivedWord = u8; + } + + impl Receive for SpiSlave<$SPIi, u8, Otype, PULL> { + type RxChannel = $RCi; + type TransmittedWord = u8; + } + }; +} + +spi_dma!( + pac::SPI1, + rx: dma1::C2, + tx: dma1::C3, + Spi1RxDma, + Spi1TxDma, + Spi1RxTxDma, + SpiSlave1RxDma, + SpiSlave1TxDma, + SpiSlave1RxTxDma +); +spi_dma!( + pac::SPI2, + rx: dma1::C4, + tx: dma1::C5, + Spi2RxDma, + Spi2TxDma, + Spi2RxTxDma, + SpiSlave2RxDma, + SpiSlave2TxDma, + SpiSlave2RxTxDma +); +#[cfg(feature = "connectivity")] +spi_dma!( + pac::SPI3, + rx: dma2::C1, + tx: dma2::C2, + Spi3RxDma, + Spi3TxDma, + Spi3RxTxDma, + SpiSlave3RxDma, + SpiSlave3TxDma, + SpiSlave3RxTxDma +); diff --git a/src/time.rs b/src/time.rs index b76087e2..74ca82a9 100644 --- a/src/time.rs +++ b/src/time.rs @@ -35,7 +35,8 @@ use cortex_m::peripheral::{DCB, DWT}; use crate::rcc::Clocks; /// Bits per second -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Bps(pub u32); pub use fugit::{