My goal is to send 33 continuously repeated 16-bit words to an SPI connected peripheral and receive the data returned from it as fast as possible. I've set up a DMA send and DMA ping pong receive (based on the SDK UART DMA example). I believe I've got it up and running while sending 32 word DMA transfers but I have not been able to make it work for 33 and it is very sensitive to changes in fifo empty/full level and DMA arbitration size. I have a few questions that may help me understand.
1) I've set my fifo levels both at 15 bytes. Is this the optimal value because the DMA request will transfer 16 (15+1) bytes which will not overflow the 32 bytes available?
2) When I use DMA arbitration size of 8 (UDMA_ARB_8), the data seems to be transmitted complete (for the 32 word buffer case). Other values of DMA arbitration seem to truncate the data sent per transmission cycle so I see less than 32 words transmitted. I though this value wouldn't matter since I'm not using any other DMA operation. What should I use here?
3) As I mentioned I have it sending/receiving with 32 word buffers but I really want 33 word buffers to send/receive. When I switch to 33 words the transfer is halted. Could this be due to my fifo levels, DMA arbitration size, something else?
I'm including my test source code for evaluation.
Thanks,
Alex
/* Example/Board Header files */
#include "Board.h"
// Driverlib includes
#include "hw_types.h"
#include "hw_memmap.h"
#include "hw_common_reg.h"
#include "hw_ints.h"
#include "hw_mcspi.h"
#include "spi.h"
#include "udma.h"
#include "rom.h"
#include "rom_map.h"
#include "utils.h"
#include "prcm.h"
#include "uart.h"
#include "interrupt.h"
#include "pin_mux_config.h"
// The count of SPI buffers filled, one for each ping-pong buffer.
static unsigned long g_ulg_usRxBufACount = 0;
static unsigned long g_ulg_usRxBufBCount = 0;
static unsigned long g_ulTxCount = 0;
#define BUF_SIZE 32
unsigned short g_usTxBuf[BUF_SIZE];
unsigned short g_usRxBufA[BUF_SIZE];
unsigned short g_usRxBufB[BUF_SIZE];
void SPIIntHandler(void)
{
unsigned long ulStatus;
unsigned long ulMode;
//
// Read the interrupt status of the SPI.
//
ulStatus = MAP_SPIIntStatus(GSPI_BASE, 1);
//
// Clear any pending SPI status interrupts.
//
MAP_SPIIntClear(GSPI_BASE, ulStatus);
//
// Check the DMA control table to see if the ping-pong "A" transfer is
// complete. The "A" transfer uses receive buffer "A", and the primary
// control structure.
//
ulMode = MAP_uDMAChannelModeGet(UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
//
// If the primary control structure indicates stop, that means the "A"
// receive buffer is done. The uDMA controller should still be receiving
// data into the "B" buffer.
//
if(ulMode == UDMA_MODE_STOP)
{
//
// Increment a counter to indicate data was received into buffer A.
//
g_ulg_usRxBufACount++;
//
// Set up the next transfer for the "A" buffer, using the primary
// control structure. When the ongoing receive into the "B" buffer is
// done, the uDMA controller will switch back to this one.
//
// Setup uDMA for Rx bufA
MAP_uDMAChannelControlSet(UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_8);
MAP_uDMAChannelAttributeEnable(UDMA_CH6_GSPI_RX,UDMA_ATTR_USEBURST);
MAP_uDMAChannelTransferSet(UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(GSPI_BASE + MCSPI_O_RX0), g_usRxBufA, BUF_SIZE);
MAP_uDMAChannelEnable(UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
}
//
// Check the DMA control table to see if the ping-pong "B" transfer is
// complete. The "B" transfer uses receive buffer "B", and the alternate
// control structure.
//
ulMode = MAP_uDMAChannelModeGet(UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
//
// If the alternate control structure indicates stop, that means the "B"
// receive buffer is done. The uDMA controller should still be receiving
// data into the "A" buffer.
//
if(ulMode == UDMA_MODE_STOP)
{
//
// Increment a counter to indicate data was received into buffer A.
//
g_ulg_usRxBufBCount++;
//
// Set up the next transfer for the "B" buffer, using the alternate
// control structure. When the ongoing receive into the "A" buffer is
// done, the uDMA controller will switch back to this one.
//
// Setup uDMA for Rx bufB
MAP_uDMAChannelControlSet(UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_8);
MAP_uDMAChannelAttributeEnable(UDMA_CH6_GSPI_RX,UDMA_ATTR_USEBURST);
MAP_uDMAChannelTransferSet(UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(GSPI_BASE + MCSPI_O_RX0), g_usRxBufB, BUF_SIZE);
MAP_uDMAChannelEnable(UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
}
//
// If the SPI DMA TX channel is disabled, that means the TX DMA transfer
// is done.
//
if(!MAP_uDMAChannelIsEnabled(UDMA_CH7_GSPI_TX))
{
g_ulTxCount++;
//
// Start another DMA transfer to SPI TX.
//
MAP_uDMAChannelControlSet(UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_8);
MAP_uDMAChannelAttributeEnable(UDMA_CH7_GSPI_TX,UDMA_ATTR_USEBURST);
MAP_uDMAChannelTransferSet(UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC , g_usTxBuf, (void *)(GSPI_BASE + MCSPI_O_TX0), BUF_SIZE);
MAP_uDMAChannelEnable(UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT);
}
}
/*
* ======== main ========
*/
int main(void)
{
unsigned int uIdx;
for(uIdx = 0; uIdx < BUF_SIZE; uIdx++)
{
g_usTxBuf[uIdx] = uIdx;
}
MAP_IntMasterEnable();
MAP_IntEnable(FAULT_SYSTICK);
PRCMCC3200MCUInit();
PinMuxConfig();
MAP_PRCMPeripheralClkEnable(PRCM_GSPI, PRCM_RUN_MODE_CLK);
MAP_PRCMPeripheralReset(PRCM_GSPI);
MAP_SPIReset(GSPI_BASE);
Board_initSPI();
Board_initDMA();
UDMAInit();
MAP_SPIConfigSetExpClk(GSPI_BASE,MAP_PRCMPeripheralClockGet(PRCM_GSPI),
20000000,SPI_MODE_MASTER,SPI_SUB_MODE_0,
(SPI_HW_CTRL_CS |
SPI_4PIN_MODE |
SPI_TURBO_OFF |
SPI_CS_ACTIVELOW |
SPI_WL_16));
MAP_SPIIntRegister(GSPI_BASE,SPIIntHandler);
MAP_SPIFIFOLevelSet(GSPI_BASE, 15, 15);
MAP_SPIFIFOEnable(GSPI_BASE, SPI_RX_FIFO | SPI_TX_FIFO);
MAP_SPIDmaEnable(GSPI_BASE,SPI_RX_DMA);
MAP_SPIDmaEnable(GSPI_BASE,SPI_TX_DMA);
MAP_SPIIntEnable(GSPI_BASE,SPI_INT_DMATX | SPI_INT_DMARX);
MAP_uDMAChannelAssign(UDMA_CH6_GSPI_RX);
MAP_uDMAChannelAssign(UDMA_CH7_GSPI_TX);
// Setup uDMA for Rx bufA
MAP_uDMAChannelControlSet(UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_8);
MAP_uDMAChannelAttributeEnable(UDMA_CH6_GSPI_RX,UDMA_ATTR_USEBURST);
MAP_uDMAChannelTransferSet(UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(GSPI_BASE + MCSPI_O_RX0), g_usRxBufA, BUF_SIZE);
MAP_uDMAChannelEnable(UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
// Setup uDMA for Rx bufB
MAP_uDMAChannelControlSet(UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_8);
MAP_uDMAChannelAttributeEnable(UDMA_CH6_GSPI_RX,UDMA_ATTR_USEBURST);
MAP_uDMAChannelTransferSet(UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(GSPI_BASE + MCSPI_O_RX0), g_usRxBufB, BUF_SIZE);
MAP_uDMAChannelEnable(UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
// Setup uDMA for Tx
MAP_uDMAChannelControlSet(UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_8);
MAP_uDMAChannelAttributeEnable(UDMA_CH7_GSPI_TX,UDMA_ATTR_USEBURST);
MAP_uDMAChannelTransferSet(UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC , g_usTxBuf, (void *)(GSPI_BASE + MCSPI_O_TX0), BUF_SIZE);
MAP_uDMAChannelEnable(UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT);
MAP_SPIEnable(GSPI_BASE);
while(1){};
return (0);
}