This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC3200MODLAUNCHXL: SPI DMA master side

Part Number: CC3200MODLAUNCHXL

Hello -

I was able to successfully stitch together the SPI DMA for the slave side where the data coming in ping pongs between two different arrays.  I want to do the same thing for the master side where data going out ping pongs from two different arrays.

I currently have it set up where I mimicked the ping ponging that was done for the slave side to the master side.  I put interrupts to check for either DMA RX and TX.  If my understanding is correctly, for the master side, when you want to send data over SPI, an interrupt will be triggered when the TX buffer is filled where the DMA will take the full TX buffer and transfer it over the SPI. 

So what I did was in the code below, I fill g_ucTxBuffA and likewise g_ucTxBuffB (since it is ping pong) and when each array gets filled, shouldn't an interrupt be triggered sending whatever is inside the g_ucTxBuffA/B over SPI?

  SPIDmaEnable(GSPI_BASE,SPI_RX_DMA | SPI_TX_DMA);
  
  MAP_SPIIntEnable(GSPI_BASE,SPI_INT_DMARX | SPI_INT_DMATX);

 MAP_SPIIntRegister(GSPI_BASE,IntHandler);

 flag = 0;

  for (i = 0; i < 10240000; i++) {
   if (i%TR_BUFF_SIZE == 0) {
    flag = ~flag;
   }
   if (flag) {
  g_ucTxBuffA[i%TR_BUFF_SIZE] = i;
   }
   else {
  g_ucTxBuffB[i%TR_BUFF_SIZE] = i;
   }
  }

This code below is in my interrupt handler (IntHandler):

  ulModeTXP = MAP_uDMAChannelModeGet(UDMA_CH31_GSPI_TX | UDMA_PRI_SELECT);
  if (ulModeTXP == UDMA_MODE_STOP) {
   ucTxBuffAcnt++;
      MAP_uDMAChannelTransferSet(UDMA_CH31_GSPI_TX | UDMA_PRI_SELECT,UDMA_MODE_PINGPONG,
        g_ucTxBuffA,
        (void *)(GSPI_BASE + MCSPI_O_TX0),
        TR_BUFF_SIZE);
   MAP_uDMAChannelEnable(UDMA_CH31_GSPI_TX);
  }
 
  ulModeTXA = MAP_uDMAChannelModeGet(UDMA_CH31_GSPI_TX | UDMA_ALT_SELECT);
  if (ulModeTXA == UDMA_MODE_STOP) {
   ucTxBuffBcnt++;
      MAP_uDMAChannelTransferSet(UDMA_CH31_GSPI_TX | UDMA_ALT_SELECT,UDMA_MODE_PINGPONG,
        g_ucTxBuffB,
        (void *)(GSPI_BASE + MCSPI_O_TX0),
        TR_BUFF_SIZE);
   MAP_uDMAChannelEnable(UDMA_CH31_GSPI_TX);
  }

Thanks

  • HI Daniel,

    The data flow for SPI + DMA RX is that when the TX FIFO in SPI peripheral is empty/near empty while the SPI interface is active, it will issue an interrupt to the DMA controller requesting more data. Thus, you won't get an interrupt once you fill up the TX buffers beyond a certain point, instead you will get an interrupt immediately if there is no data in the FIFO to send. You need to have the TX buffer filled and ready to be transferred and then issue the DMA request for the ping buffer. This is because the DMA transfers will immediately fill the FIFO with data and will keep doing so until TR_BUFF_SIZE is transferred.

    Regards,
    Michael
  • Hello Michael,

    How do you issue the DMA request? I thought the DMA request was done automatically as an interrupt. So in the snippet of code below i fill g_ucTxBuff[A/B] which are the TX buffers. Once the buffers are filled or reaches a threshold value, an interrupt should occur which pushes the values in the buffer over SPI. My FIFOLEVELSET is set to 1 which means that the moment a value is stored in g_ucTxBuff[A/B], an interrupt should occur right away. The interrupt is not happening at all for my case.

    Snippet of code:
    flag = 0;
    for (i = 0; i < 10240000; i++) {
    if (i%TR_BUFF_SIZE == 0) {
    flag = ~flag;
    }
    if (flag) {
    g_ucTxBuffA[i%TR_BUFF_SIZE] = i;
    }
    else {
    g_ucTxBuffB[i%TR_BUFF_SIZE] = i;
    }
    }

    ulModeTXP = MAP_uDMAChannelModeGet(UDMA_CH31_GSPI_TX | UDMA_PRI_SELECT);
    if (ulModeTXP == UDMA_MODE_STOP) {
    ucTxBuffAcnt++;
    MAP_uDMAChannelTransferSet(UDMA_CH31_GSPI_TX | UDMA_PRI_SELECT,UDMA_MODE_PINGPONG,
    g_ucTxBuffA,
    (void *)(GSPI_BASE + MCSPI_O_TX0),
    TR_BUFF_SIZE);
    MAP_uDMAChannelEnable(UDMA_CH31_GSPI_TX);

    Thanks
  • Hi Daniel,

    The uDMAChannelTransferSet() call is what kicks off the DMA transfer. If this call is not made, there will be no data transfer.
    Your understanding of the TX buffer operation is incorrect. Instead of the following flow:
    - add data to buffer -> DMA sees data has been updated and pushes it to SPI TX FIFO -> SPI sees new data and sends it out
    It's more like this flow:
    - SPI interface is enabled for sending and sees that there is no data in TX fifo -> SPI requests data from DMA -> DMA starts giving SPI peripheral data from specified buffer.
    Most crucially, the DMA does not/cannot know whether or not the data in the TX buffer has been updated. Thus you do not get any interrupt simply by updating a value in your tx buffer. Instead, you will get an interrupt when the SPI peripheral needs more data.

    I hope that helps clear up your confusion on how SPI + DMA operates. Let me know if you still have questions.

    Regards,
    Michael