Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DMA RX and RX/TX support to SPI #335

Merged
merged 6 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Support for CAN peripherals with the `bxcan` crate
- Add DAC, UART4, UART5 clock in RCC for the f103 high density line
- `start_raw` function and `arr`, `bsc` getters for more fine grained
control over the timer.
control over the timer
- Added RxTxDma support support to the DMA infrastructure
- Added DMA receive support for `SPI`
- Added `release` functions to SPI DMA

### Fixed
- Fix > 2 byte i2c reads
Expand All @@ -27,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Use `cortex-m-rtic` instead of `cortex-m-rtfm` in the examples
- Renamed `serial`'s `RxDma`/`TxDma`'s `split` method into `release`
- Renamed I2C's `free` method into `release`
- Enable SPI DMA in `with_tx_dma`, not in `SpiTxDma::start`

## [v0.7.0]- 2020-10-17

Expand Down
68 changes: 67 additions & 1 deletion src/dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, Transfer, W, RxDma, TxDma, RxTxDma, TransferPayload};
use crate::rcc::{AHB, Enable};

#[allow(clippy::manual_non_exhaustive)]
Expand Down Expand Up @@ -371,6 +371,45 @@ macro_rules! dma {
}
}

impl<BUFFER, PAYLOAD, MODE, TXC> Transfer<MODE, BUFFER, RxTxDma<PAYLOAD, $CX, TXC>>
where
RxTxDma<PAYLOAD, $CX, TXC>: TransferPayload,
{
pub fn is_done(&self) -> bool {
!self.payload.rxchannel.in_progress()
}

pub fn wait(mut self) -> (BUFFER, RxTxDma<PAYLOAD, $CX, TXC>) {
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);

// `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`
// and `mem::forget`.
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = ptr::read(&self.buffer);
let payload = ptr::read(&self.payload);
mem::forget(self);
(buffer, payload)
}
}
}


impl<BUFFER, PAYLOAD> Transfer<W, BUFFER, RxDma<PAYLOAD, $CX>>
where
RxDma<PAYLOAD, $CX>: TransferPayload,
Expand All @@ -387,6 +426,23 @@ macro_rules! dma {
&slice[..(capacity - pending)]
}
}

impl<RXBUFFER, TXBUFFER, PAYLOAD, TXC> Transfer<W, (RXBUFFER, TXBUFFER), RxTxDma<PAYLOAD, $CX, TXC>>
where
RxTxDma<PAYLOAD, $CX, TXC>: TransferPayload,
{
pub fn peek<T>(&self) -> &[T]
where
RXBUFFER: AsRef<[T]>,
{
let pending = self.payload.rxchannel.get_ndtr() as usize;

let slice = self.buffer.0.as_ref();
let capacity = slice.len();

&slice[..(capacity - pending)]
}
}
)+

impl DmaExt for $DMAX {
Expand Down Expand Up @@ -532,3 +588,13 @@ where
{
fn write(self, buffer: B) -> Transfer<R, B, Self>;
}

/// Trait for DMA simultaneously reading and writing within one synchronous operation. Panics if both buffers are not of equal length.
pub trait ReadWriteDma<RXB, TXB, TS>: Transmit
where
RXB: StaticWriteBuffer<Word = TS>,
TXB: StaticReadBuffer<Word = TS>,
Self: core::marker::Sized + TransferPayload,
{
fn read_write(self, rx_buffer: RXB, tx_buffer: TXB) -> Transfer<W, (RXB, TXB), Self>;
}
1 change: 1 addition & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub use crate::crc::CrcExt as _stm32_hal_crc_CrcExt;
pub use crate::dma::CircReadDma as _stm32_hal_dma_CircReadDma;
pub use crate::dma::DmaExt as _stm32_hal_dma_DmaExt;
pub use crate::dma::ReadDma as _stm32_hal_dma_ReadDma;
pub use crate::dma::ReadWriteDma as _stm32_hal_dma_ReadWriteDma;
pub use crate::dma::WriteDma as _stm32_hal_dma_WriteDma;
pub use crate::flash::FlashExt as _stm32_hal_flash_FlashExt;
pub use crate::gpio::GpioExt as _stm32_hal_gpio_GpioExt;
Expand Down
Loading