@@ -10,10 +10,14 @@ use embedded_hal_async::spi::SpiBus;
10
10
use futures_util:: join;
11
11
use futures_util:: task:: AtomicWaker ;
12
12
13
- use crate :: gpdma:: {
14
- config:: DmaConfig ,
15
- periph:: { DmaDuplex , DmaRx , DmaTx , Rx , RxAddr , Tx , TxAddr } ,
16
- DmaChannel , DmaTransfer , Error as DmaError , Word as DmaWord ,
13
+ use crate :: {
14
+ gpdma:: {
15
+ config:: DmaConfig ,
16
+ periph:: { DmaDuplex , DmaRx , DmaTx , Rx , RxAddr , Tx , TxAddr } ,
17
+ DmaChannel , DmaTransfer , Error as DmaError , Word as DmaWord ,
18
+ } ,
19
+ interrupt,
20
+ spi:: CommunicationMode ,
17
21
} ;
18
22
19
23
use super :: { Error , Instance , Spi , Word } ;
@@ -42,19 +46,33 @@ where
42
46
where
43
47
CH : DmaChannel ,
44
48
{
49
+ assert ! ( self . inner. is_transmitter( ) ) ;
45
50
SpiDma :: new_simplex_transmitter ( self , channel)
46
51
}
47
52
53
+ /// Use DMA for receiving data only in simplex receiver mode, or in half duplex mode as a
54
+ /// receiver
48
55
pub fn use_dma_rx < CH > (
49
56
self ,
50
57
channel : CH ,
51
58
) -> SpiDma < SPI , DmaRx < SPI , W , CH > , W >
52
59
where
53
60
CH : DmaChannel ,
54
61
{
62
+ // Using DMA for receiving data requires that the SPI is configured as a simplex receiver or
63
+ // in half duplex mode when receiving data only
64
+ // otherwise no data will be received because no clock pulses are generated
65
+ assert ! (
66
+ self . inner. communication_mode( )
67
+ == CommunicationMode :: SimplexReceiver
68
+ || ( self . inner. communication_mode( )
69
+ == CommunicationMode :: HalfDuplex
70
+ && !self . inner. is_half_duplex_transmitter( ) )
71
+ ) ;
55
72
SpiDma :: new_simplex_receiver ( self , channel)
56
73
}
57
74
75
+ /// Use DMA for full duplex transfers
58
76
pub fn use_dma_duplex < TX , RX > (
59
77
self ,
60
78
tx_channel : TX ,
64
82
TX : DmaChannel ,
65
83
RX : DmaChannel ,
66
84
{
85
+ assert ! (
86
+ self . inner. communication_mode( ) == CommunicationMode :: FullDuplex
87
+ ) ;
67
88
SpiDma :: new_duplex ( self , tx_channel, rx_channel)
68
89
}
69
90
}
@@ -73,9 +94,10 @@ pub struct SpiDma<SPI, MODE, W: Word = u8> {
73
94
mode : MODE ,
74
95
}
75
96
97
+ #[ allow( private_bounds) ]
76
98
impl < SPI , MODE , W > SpiDma < SPI , MODE , W >
77
99
where
78
- SPI : Instance ,
100
+ SPI : Instance + Waker ,
79
101
W : Word ,
80
102
{
81
103
pub fn new ( spi : Spi < SPI , W > , mode : MODE ) -> Self {
@@ -199,9 +221,10 @@ where
199
221
}
200
222
}
201
223
224
+ #[ allow( private_bounds) ]
202
225
impl < SPI , MODE , W > SpiDma < SPI , MODE , W >
203
226
where
204
- SPI : Instance ,
227
+ SPI : Instance + Waker ,
205
228
W : Word + DmaWord ,
206
229
MODE : Rx < W > ,
207
230
{
@@ -233,9 +256,10 @@ where
233
256
}
234
257
}
235
258
259
+ #[ allow( private_bounds) ]
236
260
impl < SPI , MODE , W > SpiDma < SPI , MODE , W >
237
261
where
238
- SPI : Instance ,
262
+ SPI : Instance + Waker ,
239
263
W : Word + DmaWord ,
240
264
MODE : Tx < W > ,
241
265
{
@@ -266,9 +290,10 @@ where
266
290
}
267
291
}
268
292
293
+ #[ allow( private_bounds) ]
269
294
impl < SPI , TX , RX , W > SpiDma < SPI , DmaDuplex < SPI , W , TX , RX > , W >
270
295
where
271
- SPI : Instance ,
296
+ SPI : Instance + Waker ,
272
297
W : Word + DmaWord ,
273
298
TX : DmaChannel ,
274
299
RX : DmaChannel ,
@@ -278,6 +303,12 @@ where
278
303
read : & ' a mut [ W ] ,
279
304
write : & ' a [ W ] ,
280
305
) -> Result < ( DmaTransfer < ' a , TX > , DmaTransfer < ' a , RX > ) , Error > {
306
+ assert_eq ! (
307
+ read. len( ) ,
308
+ write. len( ) ,
309
+ "Read and write buffers must have the same length"
310
+ ) ;
311
+
281
312
let tx_config = DmaConfig :: new ( ) . with_request ( SPI :: tx_dma_request ( ) ) ;
282
313
let rx_config = DmaConfig :: new ( ) . with_request ( SPI :: rx_dma_request ( ) ) ;
283
314
@@ -332,7 +363,7 @@ where
332
363
333
364
impl < SPI , CH , W > SpiBus < W > for SpiDma < SPI , DmaTx < SPI , W , CH > , W >
334
365
where
335
- SPI : Instance ,
366
+ SPI : Instance + Waker ,
336
367
W : Word + DmaWord ,
337
368
CH : DmaChannel ,
338
369
{
@@ -367,7 +398,7 @@ where
367
398
368
399
impl < SPI , CH , W > SpiBus < W > for SpiDma < SPI , DmaRx < SPI , W , CH > , W >
369
400
where
370
- SPI : Instance ,
401
+ SPI : Instance + Waker ,
371
402
W : Word + DmaWord ,
372
403
CH : DmaChannel ,
373
404
{
@@ -402,7 +433,7 @@ where
402
433
403
434
impl < SPI , TX , RX , W > SpiBus < W > for SpiDma < SPI , DmaDuplex < SPI , W , TX , RX > , W >
404
435
where
405
- SPI : Instance ,
436
+ SPI : Instance + Waker ,
406
437
W : Word + DmaWord ,
407
438
TX : DmaChannel ,
408
439
RX : DmaChannel ,
@@ -438,46 +469,84 @@ where
438
469
439
470
struct SpiDmaFuture < ' a , SPI : Instance , MODE , W : Word > {
440
471
spi : & ' a mut SpiDma < SPI , MODE , W > ,
441
- waker : AtomicWaker ,
442
472
}
443
473
444
474
impl < ' a , SPI : Instance , MODE , W : Word > SpiDmaFuture < ' a , SPI , MODE , W > {
445
475
fn new ( spi : & ' a mut SpiDma < SPI , MODE , W > ) -> Self {
446
- Self {
447
- spi,
448
- waker : AtomicWaker :: new ( ) ,
449
- }
476
+ spi. inner . enable_dma_transfer_interrupts ( ) ;
477
+ Self { spi }
450
478
}
451
479
}
452
480
453
481
impl < SPI : Instance , MODE , W : Word > Unpin for SpiDmaFuture < ' _ , SPI , MODE , W > { }
454
482
455
483
impl < SPI : Instance , MODE , W : Word > Drop for SpiDmaFuture < ' _ , SPI , MODE , W > {
456
484
fn drop ( & mut self ) {
457
- if !self . spi . is_transaction_complete ( ) {
458
- self . spi . abort_transaction ( ) ;
459
- } else if self . spi . inner . is_enabled ( ) {
460
- self . spi . disable ( ) ;
461
- } else {
462
- // do nothing if the transaction is already complete
463
- }
485
+ self . spi . disable ( ) ;
464
486
}
465
487
}
466
488
467
- impl < SPI : Instance , MODE , W : Word > Future for SpiDmaFuture < ' _ , SPI , MODE , W > {
489
+ impl < SPI : Instance + Waker , MODE , W : Word > Future
490
+ for SpiDmaFuture < ' _ , SPI , MODE , W >
491
+ {
468
492
type Output = Result < ( ) , Error > ;
469
493
470
494
fn poll (
471
495
mut self : Pin < & mut Self > ,
472
496
cx : & mut Context < ' _ > ,
473
497
) -> Poll < Self :: Output > {
474
- self . waker . register ( cx. waker ( ) ) ;
498
+ SPI :: waker ( ) . register ( cx. waker ( ) ) ;
475
499
476
500
if self . spi . is_transaction_complete ( ) {
477
- self . spi . disable ( ) ;
478
501
Poll :: Ready ( Ok ( ( ) ) )
479
502
} else {
480
503
Poll :: Pending
481
504
}
482
505
}
483
506
}
507
+
508
+ trait Waker {
509
+ fn waker ( ) -> & ' static AtomicWaker ;
510
+ }
511
+
512
+ macro_rules! spi_dma_irq {
513
+ ( $SPI: ident) => {
514
+ paste:: item! {
515
+ static [ <$SPI _WAKER>] : AtomicWaker = AtomicWaker :: new( ) ;
516
+
517
+ impl Waker for $SPI {
518
+ #[ inline( always) ]
519
+ fn waker( ) -> & ' static AtomicWaker {
520
+ & [ <$SPI _WAKER>]
521
+ }
522
+ }
523
+
524
+ #[ interrupt]
525
+ fn $SPI( ) {
526
+ let spi = unsafe { & * $SPI:: ptr( ) } ;
527
+ unsafe { spi. ier( ) . write_with_zero( |w| w) ; } ;
528
+ $SPI:: waker( ) . wake( ) ;
529
+ }
530
+ }
531
+ } ;
532
+ }
533
+ use crate :: pac:: { SPI1 , SPI2 , SPI3 } ;
534
+
535
+ spi_dma_irq ! ( SPI1 ) ;
536
+ spi_dma_irq ! ( SPI2 ) ;
537
+ spi_dma_irq ! ( SPI3 ) ;
538
+
539
+ #[ cfg( feature = "rm0481" ) ]
540
+ mod rm0481 {
541
+ use super :: * ;
542
+ use crate :: pac:: SPI4 ;
543
+ spi_dma_irq ! ( SPI4 ) ;
544
+ }
545
+
546
+ #[ cfg( feature = "h56x_h573" ) ]
547
+ mod h56x_h573 {
548
+ use super :: * ;
549
+ use crate :: pac:: { SPI5 , SPI6 } ;
550
+ spi_dma_irq ! ( SPI5 ) ;
551
+ spi_dma_irq ! ( SPI6 ) ;
552
+ }
0 commit comments