AnsweredAssumed Answered

SPI-DMA on K70: RX DMA channel always interrupts as if it's set to INTHALF

Question asked by mb_apt on Oct 8, 2015
Latest reply on Oct 28, 2015 by mb_apt

I am writing a completely non-blocking SPI-DMA driver that uses "current MAJOR loop iteration count" (TCDn_CITER) of RX DMA channel "reaching 0" (INTMAJOR set in DMA_TCDn_CSR register to generate DMA interrupt for RX DMA channel) as indicator that SPI transfer has completed (to kick off task wake semaphore). What I am observing however is that when RX DMA channel interrupt is generated TCDn_CITER is always ~1/2 of TCDn_BITER indicating that it's always generating interrupt as if it's set to INTHALF (which is not the case). I also tried forcing it to INTHALF and saw the exact same thing happen indicating that no matter whether you set INTMAJOR or INTHALF it will always operate as if it's set to INTHALF. To get around this problem I simply double the number of bytes i am expecting to receive for TCDn_CITER and TCDn_CITER when I setup the RX DMA channel and it starts to work flawlessly (tested by writing and reading back to verify Megabytes to SPI NOR Flash).

 

Any idea why it's doing what it's doing?

 

Below is more details about my SPI-DMA setup.

 

SPI settings:

 

Both RX and TX FIFOs enabled (disabling makes no difference on described problem)

 

Global DMA settings:

 

Both DMA channel and group arbitration is set to operate in round-robin fashion.

Minor loop is enabled.

RX DMA channel is 10. TX DMA channel is 12.

 

TX DMA channel:

 

Channel enabled and linked to SPI TX of appropriate SPI channel.

CITER = *transfer length*

BITER = *transfer length*

NBYTES = 4

SADDR = *pointer to uint32_t array*

SOFF = 4

SLAST = 0

DADDR = *SPI PUSHR of appropriate SPI channel*

DOFF = 0

DLAST = 0

ATTR = 32-bit and no SMOD for both source and destination

CSR = INTMAJOR | DREQ

 

RX DMA channel:

 

Channel enabled and linked to SPI RX of appropriate SPI channel.

CITER = *receive length* (described problem is fixed by doubling of *receive length*)

BITER = *receive length* (described problem is fixed by doubling of *receive length*)

NBYTES = 1

SADDR = *SPI POPR of appropriate SPI channel*

SOFF = 0

SLAST = 0

DADDR = *pointer to uint8_t array*

DOFF = 1

DLAST = 0

ATTR = 8-bit and no MOD for both source and destination

CSR = INTMAJOR | DREQ

 

Transfer is started by:

 

MCR of SPI channel = HALT | CLR_TXF | CLR_RXF

RSER of SPI channel = TFFF_RE | TFFF_DIRS | RFDF_RE | RFDF_DIRS

SR of SPI channel = EOQF | TCF

MCR of SPI channel &= ~HALT

 

DMA0->SERQ = *RX DMA channel number*

DMA0->SERQ = *TX DMA channel number*

 

*wait for wake semaphore*

 

MCR of SPI channel |= HALT

 

Transfer is completed when:

 

RX DMA channel generates and interrupt and task is awaken via semaphore

 

 

 

EDIT: Tested it on 1N96B and 3N96B K70 devices with the same behavior. We don't have 4N96B on any of our K70-TWR kits.

 

EDIT: Triggering off of TX DMA channel interrupt (INTMAJOR) does not have the same problem with CITER = ~1/2 BITER. However, you'd think it's safer to trigger off of RX DMA channel which guarantees that all of the data is finished both transmitting and receiving (simultaneous SPI TX and RX, TX byte count = RX byte count).

 

EDIT: Changing around TX and RX DMA channel numbers has no impact.

Outcomes