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.

GSPI with DMA-FIFO on RX problem

Other Parts Discussed in Thread: CC3200

Hello all,

I want to configure the CC3200 GSPI module to receive 19 Bytes from a slave device.

I was successful in doing so using GSPI in normal transmit-receive mode.

But i want to do the same using DMA-FIFO mode.

I have used the following configuration and SPI interrupt handler:-

#define RX_BUFF_SIZE            19

//*****************************************************************************
//
//! SPI Master mode main loop
//!
//! This function configures SPI modelue as master and enables the channel for
//! communication
//!
//! \return None.
//
//*****************************************************************************
void Init_SPI_ETH()
{

    unsigned long ulUserData;
    unsigned long ulDummy;

signed int s32_Fn_LoopCountI;
static char c_Fn_ToggleJ = 0;

//
    // Reset SPI
    //
    MAP_SPIReset(GSPI_BASE);

    //
    // Configure SPI interface
    //
    MAP_SPIConfigSetExpClk(GSPI_BASE,MAP_PRCMPeripheralClockGet(PRCM_GSPI),
                     SPI_IF_BIT_RATE,SPI_MODE_MASTER,SPI_SUB_MODE_1,
                     (SPI_SW_CTRL_CS |
                     SPI_4PIN_MODE |
                     SPI_TURBO_OFF |
                     SPI_CS_ACTIVELOW |
                     SPI_WL_8));

    /*SPI_SUB_MODE_1 wherein GSPI clock is active-high and sampling occurs on falling edge
    i.e. CPOL = 0 and CPHA = 2nd EDGE ~analogus to MCD*/

    //
    // Enable SPI for communication
    //
    MAP_SPIEnable(GSPI_BASE);

MAP_SPICSEnable(GSPI_BASE);

//Transfer initialization data of SLAVE device

 MAP_SPITransfer(GSPI_BASE,g_ucTxBuff1,g_ucRxBuff1,50,
            SPI_CS_ENABLE/*|SPI_CS_DISABLE*/);

MAP_uDMAChannelAssign( UDMA_CH30_GSPI_RX);
    //MAP_uDMAChannelAssign( UDMA_CH31_GSPI_TX );

    SetupTransfer(UDMA_CH30_GSPI_RX,UDMA_MODE_BASIC,RX_BUFF_SIZE,
                UDMA_SIZE_8,UDMA_ARB_1,
                (void *)(GSPI_BASE + MCSPI_O_RX0),UDMA_SRC_INC_NONE,
                &g_ucRxBuff,UDMA_DST_INC_8);

  /*SetupTransfer(UDMA_CH31_GSPI_TX,UDMA_MODE_BASIC,TR_BUFF_SIZE,
                UDMA_SIZE_8,UDMA_ARB_1,
                &g_ucTxBuff,UDMA_SRC_INC_8,(void *)(GSPI_BASE + MCSPI_O_TX0),
                UDMA_DST_INC_NONE);*/

    MAP_SPIWordCountSet(GSPI_BASE,RX_BUFF_SIZE);

    MAP_SPIFIFOLevelSet(GSPI_BASE,1,19);

    MAP_SPIFIFOEnable(GSPI_BASE,SPI_RX_FIFO);

    MAP_SPIDmaEnable(GSPI_BASE,SPI_RX_DMA);


    //
    // Register Interrupt Handler
    //
    MAP_SPIIntRegister(GSPI_BASE,SPI_IntHandler);

    //
    // Enable Interrupts
    //
    MAP_SPIIntEnable(GSPI_BASE, SPI_INT_DMARX);
}

//*****************************************************************************
//
//! SPI Interrupt handler
//!
//! This function is invoked when ASIC SPI has its receive register full or
//! transmit register empty.
//!
//! \return None.
//
//*****************************************************************************
static void SPI_IntHandler()
{
    unsigned long ulRecvData;

  ulStatus = MAP_SPIIntStatus(GSPI_BASE,true);

  MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMARX);
if(ulStatus & SPI_INT_RX_FULL)
    {

//COPY DATA FROM FIFO INTO DATA BUFFER
     memcpy(Databuffer,g_ucRxBuff,RX_BUFF_SIZE);
    }
}


Ideally i should get the spi interrupt after 19 bytes are received from the SLAVE device.

But, i am not getting the spi interrupt.

I have initialized the slave correctly since it works in normal mode (without DMA-FIFO).

Please point-out if i am going wrong anywhere.

Thank you in advance.

Warm regards,

Abhishek.

  • Hello Abhishek,

    you do not call UDMAInit(); anywhere. I also think that if you want to use DMA on the RX side, you need to enable it on the TX side as well.

    A couple of week ago I posted an SPI/DMA example, see if it maybe helps you:
    github.com/.../cc3200_dma_spi_example

    Cheers,
    Severin
  • Hello Severin,
    Thank you very much for replying.
    Actually i have called UDMAInit(); from my main() function which i didn't paste here.

    I will refer to the link and get back here.

    Thank you once again.

    Warm regards,
    Abhishek.
  • Hello Severin,
    Things still unclear!!
    I got the configuration part, but i am confused with the interrupt handler part.
    Which interrupt should i check for reading 19 bytes from the FIFO, the SPI_INT_DMARX or SPI_INT_RX_FULL ??


    One more question, is is necessary to use DMA with FiFo, i can i only configure FiFo to read 19 bytes from slave without DMA ??

    Please reply.

    Warm regards,
    Abhishek.
  • Hello Abhishek,

    I only ever used DMA together with FIFO. If you do so, you need to enable (and catch) the SPI_INT_EOW (End of [SPI]Word) interrupt.

    I am not sure if they are of help, but I asked a lot of questions about SPI/DMA and Preveen gave me some great answers. Maybe my old threads also help you:
    e2e.ti.com/.../397270
    e2e.ti.com/.../399482
    e2e.ti.com/.../402137

    Cheers,
    Severin
  • Hello Severin,
    Thank you for replying.
    I think i will remove the DMA part and only read the FiFo.
    I will go through the links and get back.

    Warm regards,
    Abhishek.
  • Hello Severin,
    I went through the links you sent and came up with this code...
    I have taken reference from one your code to write this.

    #define RX_BUFF_SIZE 19

    static unsigned char g_ucTxBuff[RX_BUFF_SIZE];
    static unsigned char g_ucRxBuff[RX_BUFF_SIZE];

    UDMAInit();

    MAP_PRCMPeripheralReset(PRCM_GSPI);

    MAP_SPIReset(GSPI_BASE);

    MAP_SPIConfigSetExpClk(GSPI_BASE,MAP_PRCMPeripheralClockGet(PRCM_GSPI),
    SPI_IF_BIT_RATE,SPI_MODE_MASTER,SPI_SUB_MODE_1,
    (SPI_SW_CTRL_CS |
    SPI_4PIN_MODE |
    SPI_TURBO_OFF |
    SPI_CS_ACTIVELOW |
    SPI_WL_8));

    MAP_uDMAChannelAssign( UDMA_CH30_GSPI_RX);
    MAP_uDMAChannelAssign( UDMA_CH31_GSPI_TX );

    SetupTransfer(UDMA_CH30_GSPI_RX,UDMA_MODE_BASIC,RX_BUFF_SIZE,
    UDMA_SIZE_8,UDMA_ARB_1,
    (void *)(GSPI_BASE + MCSPI_O_RX0),UDMA_SRC_INC_NONE,
    &g_ucRxBuff,UDMA_DST_INC_8);

    SetupTransfer(UDMA_CH31_GSPI_TX,UDMA_MODE_BASIC,RX_BUFF_SIZE,
    UDMA_SIZE_8,UDMA_ARB_1,
    &g_ucTxBuff,UDMA_SRC_INC_8,(void *)(GSPI_BASE + MCSPI_O_TX0),
    UDMA_DST_INC_NONE);

    MAP_SPIWordCountSet(GSPI_BASE,RX_BUFF_SIZE);

    MAP_SPIFIFOLevelSet(GSPI_BASE,1,1);

    MAP_SPIFIFOEnable(GSPI_BASE,SPI_RX_FIFO | SPI_TX_FIFO);

    MAP_SPIDmaEnable(GSPI_BASE,SPI_RX_DMA | SPI_TX_DMA);

    MAP_SPIIntRegister(GSPI_BASE,SPI_IntHandler);

    MAP_SPIIntEnable(GSPI_BASE, SPI_INT_DMARX | SPI_INT_DMATX);

    MAP_SPIIntEnable(GSPI_BASE, SPI_INT_EOW);

    MAP_SPIEnable(GSPI_BASE);


    //*****************************************************************************
    //
    //! SPI Interrupt handler
    //!
    //! This function is invoked when ASIC SPI has its receive register full or
    //! transmit register empty.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static void SPI_IntHandler()
    {
    unsigned long ulRecvData;
    unsigned char ff = 0;

    ulStatus = MAP_SPIIntStatus(GSPI_BASE,true);

    MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMARX | SPI_INT_DMATX | SPI_INT_EOW);

    if(ulStatus & SPI_INT_EOW)
    {
    // MAP_SPIIntClear(GSPI_BASE,SPI_INT_EOW);
    // SPIIntDisable(GSPI_BASE, SPI_INT_EOW );
    // SPIDisable(GSPI_BASE);
    // uDMADisable();
    // setup();
    }
    if(ulStatus & SPI_INT_DMATX)
    {
    // SPIDataPut(GSPI_BASE,5);
    //HWREG(GSPI_BASE + MCSPI_O_TX0) = 5;
    // MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMATX);
    // SPIIntDisable(GSPI_BASE, SPI_INT_DMATX );
    // return;
    }
    if(ulStatus & SPI_INT_DMARX)
    {
    // SPIDataGet(GSPI_BASE,&tmp);
    //tmp = HWREG(GSPI_BASE + MCSPI_O_RX0);
    // MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMARX);
    // SPIIntDisable(GSPI_BASE, SPI_INT_DMARX );
    // return;
    }

    }


    Now, in which interrupt should i read the received fifo(g_ucRxBuff) of 19 bytes from the slave, SPI_INT_DMARX or SPI_INT_EOW ??

    Kindly reply.

    Thank you in advance.

    Warm regards,
    Abhishek.
  • Hello Abhishek,

    after the transfer you should see SPI_INT_EOW.
    This example should be close to what you try to do:
    github.com/.../master.c

    Cheers,
    Severin
  • Hello Severin,

    I went through the above code, but it deals with the transmission part.

    The interrupt handler handles the transmit part.

    I want to receive data from the slave device.

    Can you please provide an example which receives data from slave using FIFO-DMA ??

    Thank you in advance.

    Warm regards,

    Abhishek.

  • Hello Abhishek,

    SPI communication is always bi-directional. To receive one byte from the slave, the master *must* first write one byte (even if it is immediately discarded by the client). That is the reason, why (non-dma, non-fifo) SPI communication will always look like this:

    SPICSEnable(GSPI_BASE);
    for(int i = 0; i < TR_BUFF_SIZE; i++){
    SPIDataPut(GSPI_BASE,tx_buffer[i]);
    SPIDataGet(GSPI_BASE,&rx_buffer[i]);
    }
    SPICSDisable(GSPI_BASE);

    So when you set up the DMA/FIFO transfer, the DMA controller will send N bytes and also receive N bytes.

    Cheers,
    Severin
  • Hello Severin,
    Thank you for replying.
    That's right.
    It means i need to send 19 bytes to the slave in order to read back 19 bytes from it.
    Question is, where exactly in the code am i receiving the data from the slave (my CC3200 is the master) ??
    I didn't find that in the interrupt handler.

    Kindly reply.

    Warm regards,
    Abhishek.
  • Hello Abhishek,

    I am now referencing this file:
    github.com/.../master.c

    spi_transfer() will start the transfer. So the DMA controller will move data from the register GSPI_BASE + MCSPI_O_RX0 to the buffer rx and from the buffer tx to the register GSPI_BASE + MCSPI_O_TX0.
    After DMA_SIZE bytes are transferred, the DMA controller will cause an SPI_INT_EOW interrupt. At this point the transfer is complete and the slave will have received the master's tx_buffer and the master will have the slave data in the its rx_buffer.

    Cheers,
    Severin
  • Hello Severin,

    Thank you very much.
    Really appreciate your feedback.
    I will implement this and get back.

    Warm regards,
    Abhishek.
  • Hello Severin,

    In that case, my handler looks like this:-

    static void interrupt_handler()

    {

    uint32_t status = MAP_SPIIntStatus(GSPI_BASE,true);

    MAP_SPIIntClear(GSPI_BASE,SPI_INT_EOW);

    SPICSDisable(GSPI_BASE);

    transfer_status = COMPLETE;

    if(status & SPI_INT_EOW)

    {

    memcpy(local_buffer, rx_buffer, sizeof(rx_buffer) );

    }

    if(!(status & SPI_INT_EOW) )

    {

    Message("Error: Unexpected SPI interrupt!\n\r");

    while(1){};

    }

    }

    One more thing, do i need to clear any interrupts or flags in the interrupt handler??

    Kindly reply.

    Warm regards,

    Abhishek.

  • Hello Abhishek,

    Yes the interrupt handler looks ok.

    > One more thing, do i need to clear any interrupts or flags in the interrupt handler??
    MAP_SPIIntClear(GSPI_BASE,SPI_INT_EOW) will clear the interrupt for you. If you want to start another transfer you just have to call spi_transfer again.

    Cheers,
    Severin
  • Hello Severin,
    Thanks a lot for helping me out.
    I will implement this and get back to you.

    Warm regards,
    Abhishek.
  • Hello Severin,

    1] What have you defined DMA_SIZE ??

    I want to receive 19 bytes from the slave in each cycle, so should i define DMA_SIZE = 19 ??

    2] Also, you have not configured FIFO anywhere. Are you using FIFO, or only DMA transfer??

    3] And, is it ok if i define

    SetupTransfer(UDMA_CH30_GSPI_RX,UDMA_MODE_BASIC,DMA_SIZE,

    UDMA_SIZE_8,UDMA_ARB_1,

    (void *)(GSPI_BASE + MCSPI_O_RX0),UDMA_SRC_INC_NONE,

    rx,UDMA_DST_INC_8);

    SetupTransfer(UDMA_CH31_GSPI_TX,UDMA_MODE_BASIC,DMA_SIZE,

    UDMA_SIZE_8,UDMA_ARB_1,

    tx,UDMA_SRC_INC_8,

    (void *)(GSPI_BASE + MCSPI_O_TX0),UDMA_DST_INC_NONE);

    only once in the initialization and only enable chip select when i want to receive data ??

    Please reply.

    Warm regards,

    Abhishek.

  • > 1] What have you defined DMA_SIZE ??
    > 2] Also, you have not configured FIFO anywhere. Are you using FIFO, or only DMA transfer??

    The definitions and setup code can be found in common.h and common.c:
    github.com/.../common.h
    github.com/.../common.c

    > 3] And, is it ok if i define
    I think it should be fine, although I personally prefer to encapsulate these calls in spi_transfer. I think this makes the code more readable :)

    Cheers,
    Severin
  • Hi Abhishek.

    Did your queries got answered. If yes please press the "Verify Answer" button to close this thread.

    Thanks and Regards,
    Siddaram
  • Hello Severin,
    Thank you very much for helping me out.

    Warm regards,
    Abhishek.