diff --git a/src/adc.rs b/src/adc.rs index a0f3384a..7cb573c9 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use embedded_hal::adc::{Channel, OneShot}; -use crate::dma::{dma1::C1, CircBuffer, Receive, RxDma, Transfer, TransferPayload, W}; +use crate::dma::{dma1::C1, CircBuffer, Receive, RxDma, TransferPayload, TransferW}; use crate::gpio::Analog; use crate::gpio::{gpioa, gpiob, gpioc}; use crate::rcc::{Clocks, Enable, Reset, APB2}; @@ -737,14 +737,12 @@ where } } -impl crate::dma::ReadDma for AdcDma -where - Self: TransferPayload, - B: StaticWriteBuffer, -{ - 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. +impl AdcDma { + #[inline(always)] + fn configure_read(&mut self, buffer: &mut B) + where + B: StaticWriteBuffer, + { let (ptr, len) = unsafe { buffer.static_write_buffer() }; self.channel .set_peripheral_address(unsafe { &(*ADC1::ptr()).dr as *const _ as u32 }, false); @@ -766,8 +764,30 @@ where .dir() .clear_bit() }); - self.start(); + } +} - Transfer::w(buffer, self) +impl crate::dma::ReadDma for AdcDma +where + Self: TransferPayload, + B: StaticWriteBuffer, +{ + fn read(mut self, mut buffer: B) -> TransferW { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + self.configure_read(&mut buffer); + self.start(); + TransferW::new(buffer, self) + } +} +impl crate::dma::BlockingReadDma for AdcDma +where + Self: TransferPayload, + B: StaticWriteBuffer, +{ + fn blocking_read(&mut self, buffer: &mut B) { + self.configure_read(buffer); + self.start(); + self.channel.wait_transfer(); } } diff --git a/src/dma.rs b/src/dma.rs index b999fc28..f655f839 100644 --- a/src/dma.rs +++ b/src/dma.rs @@ -1,10 +1,7 @@ //! # Direct Memory Access #![allow(dead_code)] -use core::{ - marker::PhantomData, - sync::atomic::{compiler_fence, Ordering}, -}; +use core::sync::atomic::{compiler_fence, Ordering}; use embedded_dma::{StaticReadBuffer, StaticWriteBuffer}; use crate::rcc::AHB; @@ -59,43 +56,42 @@ pub trait TransferPayload { fn start(&mut self); fn stop(&mut self); } - -pub struct Transfer +/// Read transfer +pub struct TransferR +where + PAYLOAD: TransferPayload, +{ + buffer: BUFFER, + payload: PAYLOAD, +} +/// Write transfer +pub struct TransferW where PAYLOAD: TransferPayload, { - _mode: PhantomData, buffer: BUFFER, payload: PAYLOAD, } -impl Transfer +impl TransferR where PAYLOAD: TransferPayload, { - pub(crate) fn r(buffer: BUFFER, payload: PAYLOAD) -> Self { - Transfer { - _mode: PhantomData, - buffer, - payload, - } + pub(crate) fn new(buffer: BUFFER, payload: PAYLOAD) -> Self { + Self { buffer, payload } } } -impl Transfer +impl TransferW where PAYLOAD: TransferPayload, { - pub(crate) fn w(buffer: BUFFER, payload: PAYLOAD) -> Self { - Transfer { - _mode: PhantomData, - buffer, - payload, - } + pub(crate) fn new(buffer: BUFFER, payload: PAYLOAD) -> Self { + Self { buffer, payload } } } -impl Drop for Transfer +impl Drop for TransferR where PAYLOAD: TransferPayload, { @@ -105,11 +101,15 @@ where } } -/// Read transfer -pub struct R; - -/// Write transfer -pub struct W; +impl Drop for TransferW +where + PAYLOAD: TransferPayload, +{ + fn drop(&mut self) { + self.payload.stop(); + compiler_fence(Ordering::SeqCst); + } +} macro_rules! dma { ($($DMAX:ident: ($dmaX:ident, { @@ -128,7 +128,7 @@ macro_rules! dma { use crate::pac::{$DMAX, dma1}; - use crate::dma::{CircBuffer, DmaExt, Error, Event, Half, Transfer, W, RxDma, TxDma, TransferPayload}; + use crate::dma::{CircBuffer, DmaExt, Error, Event, Half, TransferR, TransferW , RxDma, TxDma, TransferPayload}; use crate::rcc::{AHB, Enable}; #[allow(clippy::manual_non_exhaustive)] @@ -177,6 +177,22 @@ macro_rules! dma { pub fn in_progress(&self) -> bool { self.isr().$tcifX().bit_is_clear() } + + #[inline(always)] + pub(crate) fn wait_transfer(&mut self) { + while self.in_progress() {} + + atomic::compiler_fence(Ordering::Acquire); + + self.stop(); + + // we need a read here to make the Acquire fence effective + // we do *not* need this if `dma.stop` does a RMW operation + unsafe { ptr::read_volatile(&0); } + + // we need a fence here for the same reason we need one in `Transfer.wait` + atomic::compiler_fence(Ordering::Acquire); + } } impl $CX { @@ -295,7 +311,7 @@ macro_rules! dma { } } - impl Transfer> + impl TransferW> where RxDma: TransferPayload, { @@ -304,19 +320,7 @@ macro_rules! dma { } pub fn wait(mut self) -> (BUFFER, RxDma) { - while !self.is_done() {} - - atomic::compiler_fence(Ordering::Acquire); - - self.payload.stop(); - - // we need a read here to make the Acquire fence effective - // we do *not* need this if `dma.stop` does a RMW operation - unsafe { ptr::read_volatile(&0); } - - // we need a fence here for the same reason we need one in `Transfer.wait` - atomic::compiler_fence(Ordering::Acquire); - + self.payload.channel.wait_transfer(); // `Transfer` needs to have a `Drop` implementation, because we accept // managed buffers that can free their memory on drop. Because of that // we can't move out of the `Transfer`'s fields, so we use `ptr::read` @@ -333,7 +337,7 @@ macro_rules! dma { } } - impl Transfer> + impl TransferR> where TxDma: TransferPayload, { @@ -342,19 +346,7 @@ macro_rules! dma { } pub fn wait(mut self) -> (BUFFER, TxDma) { - while !self.is_done() {} - - atomic::compiler_fence(Ordering::Acquire); - - self.payload.stop(); - - // we need a read here to make the Acquire fence effective - // we do *not* need this if `dma.stop` does a RMW operation - unsafe { ptr::read_volatile(&0); } - - // we need a fence here for the same reason we need one in `Transfer.wait` - atomic::compiler_fence(Ordering::Acquire); - + self.payload.channel.wait_transfer(); // `Transfer` needs to have a `Drop` implementation, because we accept // managed buffers that can free their memory on drop. Because of that // we can't move out of the `Transfer`'s fields, so we use `ptr::read` @@ -371,7 +363,7 @@ macro_rules! dma { } } - impl Transfer> + impl TransferW> where RxDma: TransferPayload, { @@ -521,7 +513,7 @@ where B: StaticWriteBuffer, Self: core::marker::Sized + TransferPayload, { - fn read(self, buffer: B) -> Transfer; + fn read(self, buffer: B) -> TransferW; } /// Trait for DMA writing from memory to peripheral. @@ -530,5 +522,23 @@ where B: StaticReadBuffer, Self: core::marker::Sized + TransferPayload, { - fn write(self, buffer: B) -> Transfer; + fn write(self, buffer: B) -> TransferR; +} + +/// Trait for DMA blocking readings from peripheral to memory. It starts DMA transfer and waits for complete. +pub trait BlockingReadDma: Receive +where + B: StaticWriteBuffer, + Self: core::marker::Sized + TransferPayload, +{ + fn blocking_read(&mut self, buffer: &mut B); +} + +/// Trait for DMA blocking writing from memory to peripheral. It starts DMA transfer and waits for complete. +pub trait BlockingWriteDma: Transmit +where + B: StaticReadBuffer, + Self: core::marker::Sized + TransferPayload, +{ + fn blocking_write(&mut self, buffer: &B); } diff --git a/src/serial.rs b/src/serial.rs index 31c16365..731e59cc 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -48,7 +48,7 @@ use embedded_dma::{StaticReadBuffer, StaticWriteBuffer}; use embedded_hal::serial::Write; use crate::afio::MAPR; -use crate::dma::{dma1, CircBuffer, RxDma, Transfer, TxDma, R, W}; +use crate::dma::{dma1, CircBuffer, RxDma, TransferR, TransferW, TxDma}; use crate::gpio::gpioa::{PA10, PA2, PA3, PA9}; use crate::gpio::gpiob::{PB10, PB11, PB6, PB7}; use crate::gpio::gpioc::{PC10, PC11}; @@ -572,6 +572,26 @@ macro_rules! serialdma { channel ) } + + #[inline(always)] + fn configure_read(&mut self, buffer: &mut B) where + B: StaticWriteBuffer, + { + let (ptr, len) = unsafe { buffer.static_write_buffer() }; + self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ 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() + .pl() .medium() + .msize() .bits8() + .psize() .bits8() + .circ() .clear_bit() + .dir() .clear_bit() + }); + } } impl $txdma { @@ -583,6 +603,29 @@ macro_rules! serialdma { channel, ) } + + #[inline(always)] + fn configure_write(&mut self, buffer: &B) where + B: StaticReadBuffer, + { + let (ptr, len) = unsafe { buffer.static_read_buffer() }; + + self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ 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() + .pl() .medium() + .msize() .bits8() + .psize() .bits8() + .circ() .clear_bit() + .dir() .set_bit() + }); + } } impl crate::dma::CircReadDma for $rxdma @@ -619,26 +662,12 @@ macro_rules! serialdma { where B: StaticWriteBuffer, { - fn read(mut self, mut buffer: B) -> Transfer { + fn read(mut self, mut buffer: B) -> TransferW { // 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.static_write_buffer() }; - self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ 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() - .pl() .medium() - .msize() .bits8() - .psize() .bits8() - .circ() .clear_bit() - .dir() .clear_bit() - }); + self.configure_read(&mut buffer); self.start(); - - Transfer::w(buffer, self) + TransferW::new(buffer, self) } } @@ -646,29 +675,34 @@ macro_rules! serialdma { where B: StaticReadBuffer, { - fn write(mut self, buffer: B) -> Transfer { + fn write(mut self, buffer: B) -> TransferR { // 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.static_read_buffer() }; - - self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false); - - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); + self.configure_write(&buffer); + self.start(); + TransferR::new(buffer, self) + } + } - self.channel.ch().cr.modify(|_, w| { w - .mem2mem() .clear_bit() - .pl() .medium() - .msize() .bits8() - .psize() .bits8() - .circ() .clear_bit() - .dir() .set_bit() - }); + impl crate::dma::BlockingReadDma for $rxdma + where + B: StaticWriteBuffer, + { + fn blocking_read(&mut self, buffer: &mut B) { + self.configure_read(buffer); self.start(); + self.channel.wait_transfer(); + } + } - Transfer::r(buffer, self) + impl crate::dma::BlockingWriteDma for $txdma + where + B: StaticReadBuffer, + { + fn blocking_write(&mut self, buffer: &B) { + self.configure_write(buffer); + self.start(); + self.channel.wait_transfer(); } } )+ diff --git a/src/spi.rs b/src/spi.rs index 234316a0..8865049e 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -43,7 +43,7 @@ use crate::afio::MAPR; use crate::dma::dma1::{C3, C5}; #[cfg(feature = "connectivity")] use crate::dma::dma2::C2; -use crate::dma::{Transfer, TransferPayload, Transmit, TxDma, R}; +use crate::dma::{TransferPayload, TransferR, Transmit, TxDma}; use crate::gpio::gpioa::{PA5, PA6, PA7}; use crate::gpio::gpiob::{PB13, PB14, PB15, PB3, PB4, PB5}; #[cfg(feature = "connectivity")] @@ -539,13 +539,12 @@ macro_rules! spi_dma { } } - impl crate::dma::WriteDma for SpiTxDma<$SPIi, REMAP, PIN, $TCi> - where - B: StaticReadBuffer, - { - 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. + impl SpiTxDma<$SPIi, REMAP, PINS, $TCi> { + #[inline(always)] + fn configure_write(&mut self, buffer: &B) + where + B: StaticReadBuffer, + { let (ptr, len) = unsafe { buffer.static_read_buffer() }; self.channel.set_peripheral_address( unsafe { &(*$SPIi::ptr()).dr as *const _ as u32 }, @@ -576,9 +575,31 @@ macro_rules! spi_dma { .dir() .set_bit() }); + } + } + + impl crate::dma::WriteDma for SpiTxDma<$SPIi, REMAP, PIN, $TCi> + where + B: StaticReadBuffer, + { + fn write(mut self, buffer: B) -> TransferR { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + self.configure_write(&buffer); self.start(); + TransferR::new(buffer, self) + } + } - Transfer::r(buffer, self) + impl crate::dma::BlockingWriteDma + for SpiTxDma<$SPIi, REMAP, PIN, $TCi> + where + B: StaticReadBuffer, + { + fn blocking_write(&mut self, buffer: &B) { + self.configure_write(buffer); + self.start(); + self.channel.wait_transfer(); } } };