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.
已解决! 转到解答。
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;
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;