Not all data sent out SPI using DMA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Not all data sent out SPI using DMA

Jump to solution
977 Views
DanKSI
Contributor III

Hi.

I am using an Emcraft Vybrid SOM and am trying to transmit SPI data using DMA.  This is occurring on the M4 and I have the SPI configured using MQX, but use the following source for the actual transmit.  What I see on the SPI signals is that some of the data is sent, but not all of it, but it is the same data everytime.  I am sending a 48 byte buffer of incrementing values (0, 1, 2, 3, 4, 5, etc.).  What I am seeing makes me think that the DMA is sending data to the SPI transmit register as fast as it can, and is not being throttled by the SPI TFFF DMA request.  I am viewing the transmit data on a logic analyzer.  The SPI TCR is of size 13, and the TXFR FIFO registers show the data that was actually transmitted.  I am not using the receive of the SPI.

INIT FUNCTION

---------------------------------

#define SIZE8  0

#define SIZE16 1

#define SIZE32 2

#define SIZE64 3

//Test using DMA 0 Channel 20, MUX 1

CCM_CCGR0 |= CCM_CCGR0_CG5(3); //DMA Channel Mux1

CCM_CCPGR1 |= CCM_CCPGR1_PPCG8(3) | CCM_CCPGR1_PPCG9(3); //DMA0

_int_install_kernel_isr(NVIC_DSPI2, SPI2_ISR);

_bsp_int_init(NVIC_DSPI2, 3, 0, TRUE);

SPI2_RSER |= 0x03000000; //Enable DMA request for TFFF (transmit buffer fill flash)

SPI2_MCR = 0x803F1002;

SPI2_TCR = 0;

DMAMUX1_CHCFG9 = 0; //Clear source

DMA0_TCD20_SADDR = 0; //Source Address For Transfer

DMA0_TCD20_ATTR = DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(SIZE8) //Modulo and access size for source

  | DMA_ATTR_DMOD(0) | DMA_ATTR_DSIZE(SIZE8);//and destination

DMA0_TCD20_SOFF = 1; //source address offset in bytes after each access

DMA0_TCD20_SLAST = 0; //source address adjustment on major loop completion - used to reset TCD

DMA0_TCD20_DADDR = (volatile void*)(&SPI2_PUSHR); //Destination Address For Transfer

DMA0_TCD20_CITER_ELINKNO = 1; //current major count

DMA0_TCD20_DOFF = 0; //destination address offset in bytes after each access

DMA0_TCD20_DLASTSGA = 0; //destination address adjustment on major loop completion - used to reset TCD

DMA0_TCD20_BITER_ELINKNO = 1; //total major iteration count

DMA0_SERQ = 20;

TRANSMIT FUNCTION

---------------------------------

//Setup the structure (data pointer and data size)

rw.BUFFER_LENGTH = writeData->dataSize;

rw.WRITE_BUFFER = (char_ptr)writeData->data;

rw.READ_BUFFER = NULL;

_DCACHE_FLUSH(); //Cleans up data in external memory

DMAMUX1_CHCFG9 = 0; //Source = Clear

DMA0_TCD20_SADDR = (uint32_t)(rw.WRITE_BUFFER); //Source Address For Transfer

DMA0_TCD20_NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(rw.BUFFER_LENGTH); //total number of bytes in minor loop

DMAMUX1_CHCFG9 = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(11); //Source = SPI.2.TX

DMA0_TCD20_CSR = 0x08; //set all bits to zero

DMA0_TCD20_CSR |= 1;

RESULTS

---------------------------------

0x00, 0x01, 0x02, 0x03, 0x04, 0x07, 0x0C, 0x12, 0x18, 0x1E, 0x24, 0x29, 0x2F

Thanks for any help,

Dan K.

Tags (3)
0 Kudos
Reply
1 Solution
715 Views
DanKSI
Contributor III

I now have this functioning as I would expect.  The major changes I made were to change the DMAMux channel to be a modulus of the DMA channel (not sure if this is needed) and switching the data send counts between the minor and major loops.

INIT FUNCTION

---------------------------------

#define SIZE8  0

#define SIZE16 1

#define SIZE32 2

#define SIZE64 3

//Test using DMA 0 Channel 20, MUX 1 (SPI2)

CCM_CCGR0 |= CCM_CCGR0_CG5(3); //DMA Channel Mux1

CCM_CCPGR1 |= CCM_CCPGR1_PPCG8(3) | CCM_CCPGR1_PPCG9(3); //DMA0

_int_install_kernel_isr(NVIC_DSPI2, SPI2_ISR);

_bsp_int_init(NVIC_DSPI2, 3, 0, TRUE);

SPI2_RSER |= 0x03000000; //Enable DMA request for TFFF (transmit buffer fill flash)

SPI2_CTAR0 &= 0xFFFF0000;

SPI2_MCR = 0x803F1002;

SPI2_TCR = 0;

DMAMUX1_CHCFG4 = 0; //Clear source

DMA0_TCD20_SADDR = 0; //Source Address For Transfer

DMA0_TCD20_ATTR = DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(SIZE8) //Modulo and access size for source

  | DMA_ATTR_DMOD(0) | DMA_ATTR_DSIZE(SIZE8);//and destination

DMA0_TCD20_SOFF = 1; //source address offset in bytes after each access

DMA0_TCD20_SLAST = 0; //source address adjustment on major loop completion - used to reset TCD

DMA0_TCD20_DADDR = (volatile void*)(&SPI2_PUSHR); //Destination Address For Transfer

DMA0_TCD20_CITER_ELINKNO = 1; //current major count

DMA0_TCD20_DOFF = 0; //destination address offset in bytes after each access

DMA0_TCD20_DLASTSGA = 0; //destination address adjustment on major loop completion - used to reset TCD

DMA0_TCD20_BITER_ELINKNO = 1; //total major iteration count

TRANSMIT FUNCTION

---------------------------------

//Setup the structure (data pointer and data size)

rw.BUFFER_LENGTH = writeData->dataSize;

rw.WRITE_BUFFER = (char_ptr)writeData->data;

rw.READ_BUFFER = NULL;

minorLoopSize = 1;

majorLoopSize = rw.BUFFER_LENGTH / minorLoopSize;

DMAMUX1_CHCFG4 = 0; //Source = Clear

DMA0_TCD20_SADDR = (uint32_t)(rw.WRITE_BUFFER); //Source Address For Transfer

DMA0_TCD20_NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(minorLoopSize); //total number of bytes in minor loop

DMA0_TCD20_CITER_ELINKNO = majorLoopSize; //current major count

DMA0_TCD20_BITER_ELINKNO = majorLoopSize; //total major iteration count

DMAMUX1_CHCFG4 = DMAMUX_CHCFG_SOURCE(11); //Source = SPI.2.TX

DMAMUX1_CHCFG4 |= DMAMUX_CHCFG_ENBL_MASK;

DMA0_TCD20_CSR = 0x08; //set all bits to zero

DMA0_SERQ = 20;

DMA0_TCD20_CSR |= 1;

View solution in original post

0 Kudos
Reply
1 Reply
716 Views
DanKSI
Contributor III

I now have this functioning as I would expect.  The major changes I made were to change the DMAMux channel to be a modulus of the DMA channel (not sure if this is needed) and switching the data send counts between the minor and major loops.

INIT FUNCTION

---------------------------------

#define SIZE8  0

#define SIZE16 1

#define SIZE32 2

#define SIZE64 3

//Test using DMA 0 Channel 20, MUX 1 (SPI2)

CCM_CCGR0 |= CCM_CCGR0_CG5(3); //DMA Channel Mux1

CCM_CCPGR1 |= CCM_CCPGR1_PPCG8(3) | CCM_CCPGR1_PPCG9(3); //DMA0

_int_install_kernel_isr(NVIC_DSPI2, SPI2_ISR);

_bsp_int_init(NVIC_DSPI2, 3, 0, TRUE);

SPI2_RSER |= 0x03000000; //Enable DMA request for TFFF (transmit buffer fill flash)

SPI2_CTAR0 &= 0xFFFF0000;

SPI2_MCR = 0x803F1002;

SPI2_TCR = 0;

DMAMUX1_CHCFG4 = 0; //Clear source

DMA0_TCD20_SADDR = 0; //Source Address For Transfer

DMA0_TCD20_ATTR = DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(SIZE8) //Modulo and access size for source

  | DMA_ATTR_DMOD(0) | DMA_ATTR_DSIZE(SIZE8);//and destination

DMA0_TCD20_SOFF = 1; //source address offset in bytes after each access

DMA0_TCD20_SLAST = 0; //source address adjustment on major loop completion - used to reset TCD

DMA0_TCD20_DADDR = (volatile void*)(&SPI2_PUSHR); //Destination Address For Transfer

DMA0_TCD20_CITER_ELINKNO = 1; //current major count

DMA0_TCD20_DOFF = 0; //destination address offset in bytes after each access

DMA0_TCD20_DLASTSGA = 0; //destination address adjustment on major loop completion - used to reset TCD

DMA0_TCD20_BITER_ELINKNO = 1; //total major iteration count

TRANSMIT FUNCTION

---------------------------------

//Setup the structure (data pointer and data size)

rw.BUFFER_LENGTH = writeData->dataSize;

rw.WRITE_BUFFER = (char_ptr)writeData->data;

rw.READ_BUFFER = NULL;

minorLoopSize = 1;

majorLoopSize = rw.BUFFER_LENGTH / minorLoopSize;

DMAMUX1_CHCFG4 = 0; //Source = Clear

DMA0_TCD20_SADDR = (uint32_t)(rw.WRITE_BUFFER); //Source Address For Transfer

DMA0_TCD20_NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(minorLoopSize); //total number of bytes in minor loop

DMA0_TCD20_CITER_ELINKNO = majorLoopSize; //current major count

DMA0_TCD20_BITER_ELINKNO = majorLoopSize; //total major iteration count

DMAMUX1_CHCFG4 = DMAMUX_CHCFG_SOURCE(11); //Source = SPI.2.TX

DMAMUX1_CHCFG4 |= DMAMUX_CHCFG_ENBL_MASK;

DMA0_TCD20_CSR = 0x08; //set all bits to zero

DMA0_SERQ = 20;

DMA0_TCD20_CSR |= 1;

0 Kudos
Reply