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.

spi-fifo problem in cc3200

Other Parts Discussed in Thread: CC3200

Hi,

I am working on cc3200's spi module, here spi is configured in slave mode. Here the application is written like a loopback mode.

SPI-dma is enabled for both tx and rx channel.

SPI-Dma-rx handler function is

Disable spi.

1) disable spi-dma-rx interrupt,

2) configure spi-dma-tx channel (with the received packet as source). 

3) configure fifo for depth for tx channel and enable it.

4) clear spi-irq-status register 

5) enable spi-dma-tx interrupt.

Enable spi.

SPI-Dma-tx handler function:

Disable spi

1) disable spi-dma-tx interrupt,

2) configure spi-dma-rx channel (for receiving new packet).

3) configure fifo for depth for rx channel and enable it.

4) clear irq-status register.

5) enable spi-dma-rx interrupt.

Enable spi.

 

 

 

Everything is working as expected ( receiving a  packet from master and re sending it when master issues next dummy packet) without fifo, but when fifo is enabled dma-tx done is triggered immediately after rx-handler completes dma-tx-channel configuration, and clears all other pending interrupts if any.

Can any one help me how to handle this.

Here I attached the code.

 

//*****************************************************************************
// main.c
//
// The demo application focuses on showing the required initialization
// sequence to enable the CC3200 SPI module in full duplex 4-wire master
// and slave mode(s).
//
// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
//
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//
//    Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//    Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the
//    distribution.
//
//    Neither the name of Texas Instruments Incorporated nor the names of
//    its contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
//  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
//  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
#include <string.h>
#include "hw_types.h"
#include "hw_memmap.h"
#include "hw_common_reg.h"
#include "hw_mcspi.h"
#include "hw_ints.h"
#include "spi.h"
#include "pin.h"
#include "rom.h"
#include "rom_map.h"
#include "utils.h"
#include "prcm.h"
#include "interrupt.h"
#include "pinmux.h"
#include "uart.h"
#include "udma.h"
#include "uart_if.h"
#include "udma_if.h"
//*****************************************************************************
//
// Application Master/Slave mode selector macro
//
// MASTER_MODE = 1 : Application in master mode
// MASTER_MODE = 0 : Application in slave mode
//
//*****************************************************************************
#define MASTER_MODE      0
#define SPI_IF_BIT_RATE  100000
#define TR_BUFF_SIZE     32
#define ENABLE_FIFO
//*****************************************************************************
// Global variables
//*****************************************************************************
static unsigned char g_ucTxBuff[TR_BUFF_SIZE];
static unsigned char g_ucRxBuff[TR_BUFF_SIZE];
static unsigned char ucTxBuffNdx;
static unsigned char ucRxBuffNdx;
#if defined(ccs)
extern void (* const g_pfnVectors[])(void);
#endif
#if defined(ewarm)
extern uVectorEntry __vector_table;
#endif
//*****************************************************************************
//
//! SPI Slave Interrupt handler
//!
//! This function is invoked when SPI slave has its receive register full or
//! transmit register empty.
//!
//! \return None.
//
//*****************************************************************************
void dump_pkt(unsigned char *pkt, int len){
int i;
for(i=0;i<len;i++){
if(i%6 == 0)
Message("\n\r");
Report("%02x, ",pkt[i]);
}
}
void for_rx_intr()
{
SPIDisable(GSPI_BASE);
SPIIntDisable(GSPI_BASE,SPI_INT_DMARX);
dump_pkt(g_ucRxBuff, TR_BUFF_SIZE);
#ifdef ENABLE_FIFO
SPIFIFODisable(GSPI_BASE, SPI_RX_FIFO|SPI_TX_FIFO);
SPIFIFOLevelSet(GSPI_BASE,8,8);
SPIFIFOEnable(GSPI_BASE, SPI_TX_FIFO);
SetupTransfer(UDMA_CH31_GSPI_TX,UDMA_MODE_BASIC,TR_BUFF_SIZE,
UDMA_SIZE_8,UDMA_ARB_8,
g_ucTxBuff,UDMA_SRC_INC_8,(void *)(GSPI_BASE + MCSPI_O_TX0),
UDMA_DST_INC_NONE);
#else
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);
#endif
MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMARX|SPI_INT_DMATX);
HWREG(GSPI_BASE+ MCSPI_O_IRQSTATUS) = 0x0003000F;
SPIIntEnable(GSPI_BASE,SPI_INT_DMATX);
Message("Prepared dma for tx\n\r");
SPIEnable(GSPI_BASE);
}
void for_tx_intr()
{
unsigned long ulRecvData;
SPIDisable(GSPI_BASE);
SPIIntDisable(GSPI_BASE,SPI_INT_DMATX);
memset(g_ucRxBuff,0, TR_BUFF_SIZE);
#ifdef ENABLE_FIFO
SPIFIFODisable(GSPI_BASE, SPI_TX_FIFO|SPI_RX_FIFO);
SPIFIFOLevelSet(GSPI_BASE,8,8);
SPIFIFOEnable(GSPI_BASE, SPI_RX_FIFO);
SetupTransfer(UDMA_CH30_GSPI_RX,UDMA_MODE_BASIC,TR_BUFF_SIZE,
UDMA_SIZE_8,UDMA_ARB_8,
(void *)(GSPI_BASE + MCSPI_O_RX0),UDMA_SRC_INC_NONE,
g_ucRxBuff,UDMA_DST_INC_8);
#else
SetupTransfer(UDMA_CH30_GSPI_RX,UDMA_MODE_BASIC,TR_BUFF_SIZE,
UDMA_SIZE_8,UDMA_ARB_1,
(void *)(GSPI_BASE + MCSPI_O_RX0),UDMA_SRC_INC_NONE,
g_ucRxBuff,UDMA_DST_INC_8);
#endif
MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMARX|SPI_INT_DMATX);
SPIIntEnable(GSPI_BASE,SPI_INT_DMARX);
Message("prepared dma for rx\n\r");
SPIEnable(GSPI_BASE);
}
static void SlaveIntHandler()
{
unsigned long ulRecvData;
unsigned long ulStatus;
ulStatus = MAP_SPIIntStatus(GSPI_BASE,true);
Report("irq = 0x%x\n\r",ulStatus);
if(ulStatus & SPI_INT_DMARX){
MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMARX);
Message("Rx, ");
for_rx_intr();
}
if(ulStatus & SPI_INT_DMATX){
MAP_SPIIntClear(GSPI_BASE,SPI_INT_DMATX);
Message("Tx, ");
for_tx_intr();
}
}
//*****************************************************************************
//
//! SPI Slave mode main loop
//!
//! This function configures SPI modelue as slave and enables the channel for
//! communication
//!
//! \return None.
//
//*****************************************************************************
void SlaveMain()
{
unsigned long ulNdx;
//
// Initialize the message
//
for(ulNdx=0; ulNdx < TR_BUFF_SIZE; ulNdx++)
{
g_ucTxBuff[ulNdx] = ulNdx;
}
//
// Set Tx buffer index
//
ucTxBuffNdx = 0;
ucRxBuffNdx = 0;
//
// Reset SPI
//
MAP_SPIReset(GSPI_BASE);
//
// Initialize UDMA
//
UDMAInit();
//
// Configure SPI interface
//
MAP_SPIConfigSetExpClk(GSPI_BASE,MAP_PRCMPeripheralClockGet(PRCM_GSPI),
SPI_IF_BIT_RATE,SPI_MODE_SLAVE,SPI_SUB_MODE_0,
(SPI_HW_CTRL_CS |
SPI_4PIN_MODE |
SPI_TURBO_OFF |
SPI_CS_ACTIVELOW |
SPI_WL_8));
//
// Register Interrupt Handler
//
MAP_SPIIntRegister(GSPI_BASE,SlaveIntHandler);
#ifdef ENABLE_FIFO
//SPIWordCountSet(GSPI_BASE,TR_BUFF_SIZE);
SetupTransfer(UDMA_CH30_GSPI_RX,UDMA_MODE_BASIC,TR_BUFF_SIZE,
UDMA_SIZE_8,UDMA_ARB_8,
(void *)(GSPI_BASE + MCSPI_O_RX0),UDMA_SRC_INC_NONE,
g_ucRxBuff,UDMA_DST_INC_8);
SPIFIFOLevelSet(GSPI_BASE,8,8);
SPIFIFOEnable(GSPI_BASE, SPI_RX_FIFO);
#else
SetupTransfer(UDMA_CH30_GSPI_RX,UDMA_MODE_BASIC,TR_BUFF_SIZE,
UDMA_SIZE_8,UDMA_ARB_1,
(void *)(GSPI_BASE + MCSPI_O_RX0),UDMA_SRC_INC_NONE,
g_ucRxBuff,UDMA_DST_INC_8);
#endif
SPIDmaEnable(GSPI_BASE,SPI_RX_DMA|SPI_TX_DMA);
MAP_SPIIntEnable(GSPI_BASE,SPI_INT_DMARX);
//
// Enable SPI for communication
//
MAP_SPIEnable(GSPI_BASE);
//
// Print mode on uart
//
Message("Enabled SPI Interface in Slave Mode\n\rReceived : ");
}
//*****************************************************************************
//
//! Board Initialization & Configuration
//!
//! \param  None
//!
//! \return None
//
//*****************************************************************************
static void
BoardInit(void)
{
/* In case of TI-RTOS vector table is initialize by OS itself */
#ifndef USE_TIRTOS
//
// Set vector table base
//
#if defined(ccs)
MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
#endif
#if defined(ewarm)
MAP_IntVTableBaseSet((unsigned long)&__vector_table);
#endif
#endif
//
// Enable Processor
//
MAP_IntMasterEnable();
MAP_IntEnable(FAULT_SYSTICK);
PRCMCC3200MCUInit();
}
//*****************************************************************************
//
//! Main function for spi demo application
//!
//! \param none
//!
//! \return None.
//
//*****************************************************************************
void main()
{
//
// Initialize Board configurations
//
BoardInit();
//
// Muxing UART and SPI lines.
//
PinMuxConfig();
//
// Enable the SPI module clock
//
MAP_PRCMPeripheralClkEnable(PRCM_GSPI,PRCM_RUN_MODE_CLK);
//
// Initialising the Terminal.
//
InitTerm();
//
// Clearing the Terminal.
//
ClearTerm();
//
// Display the Banner
//
Message("\n\n\n\r");
Message("\t\t   ********************************************\n\r");
Message("\t\t        CC3200 SPI Demo Application  \n\r");
Message("\t\t   ********************************************\n\r");
Message("\n\n\n\r");
//
// Reset the peripheral
//
MAP_PRCMPeripheralReset(PRCM_GSPI);
#if MASTER_MODE
MasterMain();
#else
SlaveMain();
#endif
while(1)
{
}
}

 

Intially spi is configured to receive a packet, where spi-dma-tx interrupt is disabled.


When 1st packet is received spi-dma-rx handler will be called from spi-interrupt-handler

its functionality is explained above (i.e, to send the received packet).

After sending packet dma-tx interrupt will be triggered , and spi-dma-tx handler will be called from spi-interrupt-handler.

  • Hi Vinod,

    Apologies for delayed response.

    I am not sure if I got your quesstion correctly. From your code you first enable the RX DMA only. Your rx-int-handler will get called as soon as the DMA completes the transfer of TR_BUFF_SIZE bytes.

    From this handler you configure and enable TX-DMA and FIFO. Here we need to note that the SPI has a 32 byte internal FIFO i.e 32 free location. So DMA will fill in the FIFO as soon as you enable it and trigger the TX DMA complete interrupt. But the transfer from the FIFO to external MOSI pin will still be in progress.

    You will not see this when not using FIFO. DMA will transfer on byte at a time, wait for SPI to push it over the MOSI line then send next byte.

    Let me know if this is the behaviour you are observing.

     

    Thanks and Regrads,

    Praveen

  • Hi Praveen,

    Thank you for your reply. Yeah I am able to observe TX DMA complete interrupt immediately after coming out from   slavehandler, where we cleared all pending interrupts and configured DMA Tx channel for 32Bytes, Tx-FIFO depth for 8 Bytes. You could observe the same from my code flow.

    Actually once this RX DMA complete interrupt has been serviced, There is no clock from the master for 5 seconds. 

    After 5 sec master will give the same number of clocks to get first sent data back, where this TX DMA complete interrupt should come. 

    I think According to the code flow, every DMA request will copy only 8 bytes from buffer to FIFO and there it stops till 8 bytes have been transferred from FIFO (because FIFO AEL is set to 8 Bytes) to shift register, And gives TX DMA complete interrupt after 32 bytes transferred from the buffer to FIFO.

    But I'm not able to understand why its giving immediately TX DMA complete interrupt just after configured the DMA TX channel, where even no clock is given to slave to start shift of data.

    Could you tell me where I am doing wrong... 

  • Hi Vinod,

    Look at it like this

    1. DMA will transfer arbitration size data block whenever it gets a request from FIFO. In your case it is 8 byte arbitration

    2. FIFO will trigger a DMA request whenever there is at least AEL free spaces. In your case AEL = 8 bytes

    3. SPI slave will transfer data on Tx pin whenever the is some data in FIFO and there is clock.

    Now, you TX-FIFO is completely empty i.e 32 free locations or 4 * (8 byte) free locations. As per rule 2 above. FIFO will generate 4 DMA requests regardless of SPI clock being there or not. This will complete the DMA transfer and the interrupt handler will get invoked.

    You can check this out be increasing the DMA transfer size above 32 bytes. DMA will first fill out the FIFO with 32 bytes then it will wait for 8 bytes to get transferred from the FIFO before transferring next block of 8 bytes.

    Thanks and Regards,

    Praveen

  • Hi Praveen,

    Thank you for all your replies.

    I have mistaken the TRM document regarding AEL, AFL description, I thought that DMA requests would be stopped once the AEL/ AFLwas reached regardless of the enough space in the FIFO (space multiple of AEL/AFL).

    Now working fine...

  • Hi Vinod,May I ask you a quetion?
    If I want to make a communication between the master and the slave (tx and rx channel are enabled for both ), what should I do ?Only the way like yours ,using SPI-dma, can make it come true?
    It's so simple the examples given by the IAR Tool, but understand easily .When I see your process ,many part of the code that I can't understand.
    Thanks and Regrads,Leo Xiao