@@ -10,10 +10,14 @@ use embedded_hal_async::spi::SpiBus;
1010use futures_util:: join;
1111use futures_util:: task:: AtomicWaker ;
1212
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 ,
1721} ;
1822
1923use super :: { Error , Instance , Spi , Word } ;
@@ -42,19 +46,33 @@ where
4246 where
4347 CH : DmaChannel ,
4448 {
49+ assert ! ( self . inner. is_transmitter( ) ) ;
4550 SpiDma :: new_simplex_transmitter ( self , channel)
4651 }
4752
53+ /// Use DMA for receiving data only in simplex receiver mode, or in half duplex mode as a
54+ /// receiver
4855 pub fn use_dma_rx < CH > (
4956 self ,
5057 channel : CH ,
5158 ) -> SpiDma < SPI , DmaRx < SPI , W , CH > , W >
5259 where
5360 CH : DmaChannel ,
5461 {
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+ ) ;
5572 SpiDma :: new_simplex_receiver ( self , channel)
5673 }
5774
75+ /// Use DMA for full duplex transfers
5876 pub fn use_dma_duplex < TX , RX > (
5977 self ,
6078 tx_channel : TX ,
6482 TX : DmaChannel ,
6583 RX : DmaChannel ,
6684 {
85+ assert ! (
86+ self . inner. communication_mode( ) == CommunicationMode :: FullDuplex
87+ ) ;
6788 SpiDma :: new_duplex ( self , tx_channel, rx_channel)
6889 }
6990}
@@ -73,9 +94,10 @@ pub struct SpiDma<SPI, MODE, W: Word = u8> {
7394 mode : MODE ,
7495}
7596
97+ #[ allow( private_bounds) ]
7698impl < SPI , MODE , W > SpiDma < SPI , MODE , W >
7799where
78- SPI : Instance ,
100+ SPI : Instance + Waker ,
79101 W : Word ,
80102{
81103 pub fn new ( spi : Spi < SPI , W > , mode : MODE ) -> Self {
@@ -199,9 +221,10 @@ where
199221 }
200222}
201223
224+ #[ allow( private_bounds) ]
202225impl < SPI , MODE , W > SpiDma < SPI , MODE , W >
203226where
204- SPI : Instance ,
227+ SPI : Instance + Waker ,
205228 W : Word + DmaWord ,
206229 MODE : Rx < W > ,
207230{
@@ -233,9 +256,10 @@ where
233256 }
234257}
235258
259+ #[ allow( private_bounds) ]
236260impl < SPI , MODE , W > SpiDma < SPI , MODE , W >
237261where
238- SPI : Instance ,
262+ SPI : Instance + Waker ,
239263 W : Word + DmaWord ,
240264 MODE : Tx < W > ,
241265{
@@ -266,9 +290,10 @@ where
266290 }
267291}
268292
293+ #[ allow( private_bounds) ]
269294impl < SPI , TX , RX , W > SpiDma < SPI , DmaDuplex < SPI , W , TX , RX > , W >
270295where
271- SPI : Instance ,
296+ SPI : Instance + Waker ,
272297 W : Word + DmaWord ,
273298 TX : DmaChannel ,
274299 RX : DmaChannel ,
@@ -278,6 +303,12 @@ where
278303 read : & ' a mut [ W ] ,
279304 write : & ' a [ W ] ,
280305 ) -> 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+
281312 let tx_config = DmaConfig :: new ( ) . with_request ( SPI :: tx_dma_request ( ) ) ;
282313 let rx_config = DmaConfig :: new ( ) . with_request ( SPI :: rx_dma_request ( ) ) ;
283314
@@ -332,7 +363,7 @@ where
332363
333364impl < SPI , CH , W > SpiBus < W > for SpiDma < SPI , DmaTx < SPI , W , CH > , W >
334365where
335- SPI : Instance ,
366+ SPI : Instance + Waker ,
336367 W : Word + DmaWord ,
337368 CH : DmaChannel ,
338369{
@@ -367,7 +398,7 @@ where
367398
368399impl < SPI , CH , W > SpiBus < W > for SpiDma < SPI , DmaRx < SPI , W , CH > , W >
369400where
370- SPI : Instance ,
401+ SPI : Instance + Waker ,
371402 W : Word + DmaWord ,
372403 CH : DmaChannel ,
373404{
@@ -402,7 +433,7 @@ where
402433
403434impl < SPI , TX , RX , W > SpiBus < W > for SpiDma < SPI , DmaDuplex < SPI , W , TX , RX > , W >
404435where
405- SPI : Instance ,
436+ SPI : Instance + Waker ,
406437 W : Word + DmaWord ,
407438 TX : DmaChannel ,
408439 RX : DmaChannel ,
@@ -438,46 +469,84 @@ where
438469
439470struct SpiDmaFuture < ' a , SPI : Instance , MODE , W : Word > {
440471 spi : & ' a mut SpiDma < SPI , MODE , W > ,
441- waker : AtomicWaker ,
442472}
443473
444474impl < ' a , SPI : Instance , MODE , W : Word > SpiDmaFuture < ' a , SPI , MODE , W > {
445475 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 }
450478 }
451479}
452480
453481impl < SPI : Instance , MODE , W : Word > Unpin for SpiDmaFuture < ' _ , SPI , MODE , W > { }
454482
455483impl < SPI : Instance , MODE , W : Word > Drop for SpiDmaFuture < ' _ , SPI , MODE , W > {
456484 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 ( ) ;
464486 }
465487}
466488
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+ {
468492 type Output = Result < ( ) , Error > ;
469493
470494 fn poll (
471495 mut self : Pin < & mut Self > ,
472496 cx : & mut Context < ' _ > ,
473497 ) -> Poll < Self :: Output > {
474- self . waker . register ( cx. waker ( ) ) ;
498+ SPI :: waker ( ) . register ( cx. waker ( ) ) ;
475499
476500 if self . spi . is_transaction_complete ( ) {
477- self . spi . disable ( ) ;
478501 Poll :: Ready ( Ok ( ( ) ) )
479502 } else {
480503 Poll :: Pending
481504 }
482505 }
483506}
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