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.
Hi,
I have checked the errata of K70, the issue is not mentioned in errata. Have you checked the DMA_ES to know if any error happen?
BR
XiangJun Rong
Hi XiangJun,
No error flags in DMA_ES are set and nothing out of the ordinary observed in any DMA registers.
Regards