@@ -351,6 +351,19 @@ where
351
351
}
352
352
}
353
353
354
+ impl < BUFFER , PAYLOAD > Transfer < RW , BUFFER , PAYLOAD >
355
+ where
356
+ PAYLOAD : TransferPayload ,
357
+ {
358
+ pub ( crate ) fn rw ( buffer : BUFFER , payload : PAYLOAD ) -> Self {
359
+ Transfer {
360
+ _mode : PhantomData ,
361
+ buffer,
362
+ payload,
363
+ }
364
+ }
365
+ }
366
+
354
367
impl < MODE , BUFFER , PAYLOAD > Drop for Transfer < MODE , BUFFER , PAYLOAD >
355
368
where
356
369
PAYLOAD : TransferPayload ,
@@ -367,6 +380,86 @@ pub struct R;
367
380
/// Write transfer
368
381
pub struct W ;
369
382
383
+ /// Read/Write transfer
384
+ pub struct RW ;
385
+
386
+ macro_rules! for_all_pairs {
387
+ ( $mac: ident: $( $x: ident) * ) => {
388
+ // Duplicate the list
389
+ for_all_pairs!( @inner $mac: $( $x) * ; $( $x) * ) ;
390
+ } ;
391
+
392
+ // The end of iteration: we exhausted the list
393
+ ( @inner $mac: ident: ; $( $x: ident) * ) => { } ;
394
+
395
+ // The head/tail recursion: pick the first element of the first list
396
+ // and recursively do it for the tail.
397
+ ( @inner $mac: ident: $head: ident $( $tail: ident) * ; $( $x: ident) * ) => {
398
+ $(
399
+ $mac!( $head $x) ;
400
+ ) *
401
+ for_all_pairs!( @inner $mac: $( $tail) * ; $( $x) * ) ;
402
+ } ;
403
+ }
404
+
405
+ macro_rules! rx_tx_channel_mapping {
406
+ ( $CH_A: ident $CH_B: ident) => {
407
+ impl <BUFFER , PAYLOAD > Transfer <RW , BUFFER , RxTxDma <PAYLOAD , $CH_A, $CH_B>>
408
+ where
409
+ RxTxDma <PAYLOAD , $CH_A, $CH_B>: TransferPayload ,
410
+ {
411
+ pub fn is_done( & self ) -> bool {
412
+ !self . payload. rx_channel. in_progress( ) && !self . payload. tx_channel. in_progress( )
413
+ }
414
+
415
+ pub fn wait( mut self ) -> ( BUFFER , RxTxDma <PAYLOAD , $CH_A, $CH_B>) {
416
+ // XXX should we check for transfer errors here?
417
+ // The manual says "A DMA transfer error can be generated by reading
418
+ // from or writing to a reserved address space". I think it's impossible
419
+ // to get to that state with our type safe API and *safe* Rust.
420
+ while !self . is_done( ) { }
421
+
422
+ self . payload. stop( ) ;
423
+
424
+ // TODO can we weaken this compiler barrier?
425
+ // NOTE(compiler_fence) operations on `buffer` should not be reordered
426
+ // before the previous statement, which marks the DMA transfer as done
427
+ atomic:: compiler_fence( Ordering :: SeqCst ) ;
428
+
429
+ // `Transfer` needs to have a `Drop` implementation, because we accept
430
+ // managed buffers that can free their memory on drop. Because of that
431
+ // we can't move out of the `Transfer`'s fields, so we use `ptr::read`
432
+ // and `mem::forget`.
433
+ //
434
+ // NOTE(unsafe) There is no panic branch between getting the resources
435
+ // and forgetting `self`.
436
+ unsafe {
437
+ let buffer = ptr:: read( & self . buffer) ;
438
+ let payload = ptr:: read( & self . payload) ;
439
+ core:: mem:: forget( self ) ;
440
+ ( buffer, payload)
441
+ }
442
+ }
443
+ }
444
+
445
+ impl <BUFFER , PAYLOAD > Transfer <RW , BUFFER , RxTxDma <PAYLOAD , $CH_A, $CH_B>>
446
+ where
447
+ RxTxDma <PAYLOAD , $CH_A, $CH_B>: TransferPayload ,
448
+ {
449
+ pub fn peek<T >( & self ) -> & [ T ]
450
+ where
451
+ BUFFER : AsRef <[ T ] >,
452
+ {
453
+ let pending = self . payload. rx_channel. get_cndtr( ) as usize ;
454
+
455
+ let capacity = self . buffer. as_ref( ) . len( ) ;
456
+
457
+ & self . buffer. as_ref( ) [ ..( capacity - pending) ]
458
+ }
459
+ }
460
+ } ;
461
+ }
462
+
370
463
macro_rules! dma {
371
464
( $( $DMAX: ident: ( $dmaX: ident, $dmaXen: ident, $dmaXrst: ident, {
372
465
$( $CX: ident: (
@@ -395,12 +488,14 @@ macro_rules! dma {
395
488
use core:: ptr;
396
489
use stable_deref_trait:: StableDeref ;
397
490
398
- use crate :: dma:: { CircBuffer , FrameReader , FrameSender , DMAFrame , DmaExt , Error , Event , Half , Transfer , W , R , RxDma , TxDma , TransferPayload } ;
491
+ use crate :: dma:: { CircBuffer , FrameReader , FrameSender , DMAFrame , DmaExt , Error , Event , Half , Transfer , W , R , RW , RxDma , RxTxDma , TxDma , TransferPayload } ;
399
492
use crate :: rcc:: AHB1 ;
400
493
401
494
#[ allow( clippy:: manual_non_exhaustive) ]
402
495
pub struct Channels ( ( ) , $( pub $CX) ,+) ;
403
496
497
+ for_all_pairs!( rx_tx_channel_mapping: $( $CX) +) ;
498
+
404
499
$(
405
500
/// A singleton that represents a single DMAx channel (channel X in this case)
406
501
///
@@ -1096,8 +1191,8 @@ pub struct TxDma<PAYLOAD, TXCH> {
1096
1191
/// DMA Receiver/Transmitter
1097
1192
pub struct RxTxDma < PAYLOAD , RXCH , TXCH > {
1098
1193
pub ( crate ) payload : PAYLOAD ,
1099
- pub rxchannel : RXCH ,
1100
- pub txchannel : TXCH ,
1194
+ pub rx_channel : RXCH ,
1195
+ pub tx_channel : TXCH ,
1101
1196
}
1102
1197
1103
1198
pub trait Receive {
@@ -1110,6 +1205,12 @@ pub trait Transmit {
1110
1205
type ReceivedWord ;
1111
1206
}
1112
1207
1208
+ pub trait ReceiveTransmit {
1209
+ type RxChannel ;
1210
+ type TxChannel ;
1211
+ type TransferedWord ;
1212
+ }
1213
+
1113
1214
/// Trait for circular DMA readings from peripheral to memory.
1114
1215
pub trait CircReadDma < B , RS > : Receive
1115
1216
where
@@ -1137,3 +1238,12 @@ where
1137
1238
{
1138
1239
fn write ( self , buffer : B ) -> Transfer < R , B , Self > ;
1139
1240
}
1241
+
1242
+ /// Trait for DMA simultaneously writing and reading between memory and peripheral.
1243
+ pub trait TransferDma < B , TS > : ReceiveTransmit
1244
+ where
1245
+ B : StaticWriteBuffer < Word = TS > ,
1246
+ Self : core:: marker:: Sized + TransferPayload ,
1247
+ {
1248
+ fn transfer ( self , buffer : B ) -> Transfer < RW , B , Self > ;
1249
+ }
0 commit comments