Skip to content

Commit

Permalink
Tentative TxDma and RxTxDma for SPI
Browse files Browse the repository at this point in the history
  • Loading branch information
korken89 committed May 23, 2021
1 parent bc42e92 commit 119a885
Show file tree
Hide file tree
Showing 2 changed files with 369 additions and 45 deletions.
116 changes: 113 additions & 3 deletions src/dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,19 @@ where
}
}

impl<BUFFER, PAYLOAD> Transfer<RW, BUFFER, PAYLOAD>
where
PAYLOAD: TransferPayload,
{
pub(crate) fn rw(buffer: BUFFER, payload: PAYLOAD) -> Self {
Transfer {
_mode: PhantomData,
buffer,
payload,
}
}
}

impl<MODE, BUFFER, PAYLOAD> Drop for Transfer<MODE, BUFFER, PAYLOAD>
where
PAYLOAD: TransferPayload,
Expand All @@ -367,6 +380,86 @@ pub struct R;
/// Write transfer
pub struct W;

/// Read/Write transfer
pub struct RW;

macro_rules! for_all_pairs {
($mac:ident: $($x:ident)*) => {
// Duplicate the list
for_all_pairs!(@inner $mac: $($x)*; $($x)*);
};

// The end of iteration: we exhausted the list
(@inner $mac:ident: ; $($x:ident)*) => {};

// The head/tail recursion: pick the first element of the first list
// and recursively do it for the tail.
(@inner $mac:ident: $head:ident $($tail:ident)*; $($x:ident)*) => {
$(
$mac!($head $x);
)*
for_all_pairs!(@inner $mac: $($tail)*; $($x)*);
};
}

macro_rules! rx_tx_channel_mapping {
($CH_A:ident $CH_B:ident) => {
impl<BUFFER, PAYLOAD> Transfer<RW, BUFFER, RxTxDma<PAYLOAD, $CH_A, $CH_B>>
where
RxTxDma<PAYLOAD, $CH_A, $CH_B>: TransferPayload,
{
pub fn is_done(&self) -> bool {
!self.payload.rx_channel.in_progress() && !self.payload.tx_channel.in_progress()
}

pub fn wait(mut self) -> (BUFFER, RxTxDma<PAYLOAD, $CH_A, $CH_B>) {
// XXX should we check for transfer errors here?
// The manual says "A DMA transfer error can be generated by reading
// from or writing to a reserved address space". I think it's impossible
// to get to that state with our type safe API and *safe* Rust.
while !self.is_done() {}

self.payload.stop();

// TODO can we weaken this compiler barrier?
// NOTE(compiler_fence) operations on `buffer` should not be reordered
// before the previous statement, which marks the DMA transfer as done
atomic::compiler_fence(Ordering::SeqCst);

// `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);
core::mem::forget(self);
(buffer, payload)
}
}
}

impl<BUFFER, PAYLOAD> Transfer<RW, BUFFER, RxTxDma<PAYLOAD, $CH_A, $CH_B>>
where
RxTxDma<PAYLOAD, $CH_A, $CH_B>: TransferPayload,
{
pub fn peek<T>(&self) -> &[T]
where
BUFFER: AsRef<[T]>,
{
let pending = self.payload.rx_channel.get_cndtr() as usize;

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

&self.buffer.as_ref()[..(capacity - pending)]
}
}
};
}

macro_rules! dma {
($($DMAX:ident: ($dmaX:ident, $dmaXen:ident, $dmaXrst:ident, {
$($CX:ident: (
Expand Down Expand Up @@ -395,12 +488,14 @@ macro_rules! dma {
use core::ptr;
use stable_deref_trait::StableDeref;

use crate::dma::{CircBuffer, FrameReader, FrameSender, DMAFrame, DmaExt, Error, Event, Half, Transfer, W, R, RxDma, TxDma, TransferPayload};
use crate::dma::{CircBuffer, FrameReader, FrameSender, DMAFrame, DmaExt, Error, Event, Half, Transfer, W, R, RW, RxDma, RxTxDma, TxDma, TransferPayload};
use crate::rcc::AHB1;

#[allow(clippy::manual_non_exhaustive)]
pub struct Channels((), $(pub $CX),+);

for_all_pairs!(rx_tx_channel_mapping: $($CX)+);

$(
/// A singleton that represents a single DMAx channel (channel X in this case)
///
Expand Down Expand Up @@ -1096,8 +1191,8 @@ pub struct TxDma<PAYLOAD, TXCH> {
/// DMA Receiver/Transmitter
pub struct RxTxDma<PAYLOAD, RXCH, TXCH> {
pub(crate) payload: PAYLOAD,
pub rxchannel: RXCH,
pub txchannel: TXCH,
pub rx_channel: RXCH,
pub tx_channel: TXCH,
}

pub trait Receive {
Expand All @@ -1110,6 +1205,12 @@ pub trait Transmit {
type ReceivedWord;
}

pub trait ReceiveTransmit {
type RxChannel;
type TxChannel;
type TransferedWord;
}

/// Trait for circular DMA readings from peripheral to memory.
pub trait CircReadDma<B, RS>: Receive
where
Expand Down Expand Up @@ -1137,3 +1238,12 @@ where
{
fn write(self, buffer: B) -> Transfer<R, B, Self>;
}

/// Trait for DMA simultaneously writing and reading between memory and peripheral.
pub trait TransferDma<B, TS>: ReceiveTransmit
where
B: StaticWriteBuffer<Word = TS>,
Self: core::marker::Sized + TransferPayload,
{
fn transfer(self, buffer: B) -> Transfer<RW, B, Self>;
}

0 comments on commit 119a885

Please sign in to comment.