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 with DMA in slave mode needs a SPI reset after each transfer

Other Parts Discussed in Thread: CC3200

Hello,

this posting is somewhat related to my last SPI/DMA question:
e2e.ti.com/.../399482

I now have a setup that works at 4MHz and allows me to transfer an arbitrary number of 1024 byte blocks over SPI and DMA and with FIFO between two CC3200 boards. However, my setup requires me to restart the slave's SPI interface after every transfer (after every End of Word (EOW) interrupt).
The master simply requires me to setup the DMA requests again:
void spi_transfer(uint8_t* tx, uint8_t* rx)
{
    transfer_complete = 0;
    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);    
    SPICSEnable(GSPI_BASE);
    // wait for the transfer to complete
    while(!transfer_complete)
    {}
}

However, the slave requires me to issue a SPIReset and then configure the SPI interface again (I would expect to only need the two SetupTransfer calls):
void spi_transfer(uint8_t* tx, uint8_t* rx)
{
    MAP_SPIReset(GSPI_BASE);

    //UDMAInit();

    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_ACTIVEHIGH |
                     SPI_WL_8));    
    MAP_SPIIntRegister(GSPI_BASE,interrupt_handler);

    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);
    
    MAP_SPIWordCountSet( GSPI_BASE, DMA_SIZE);
    MAP_SPIFIFOLevelSet( GSPI_BASE, 1, 1);
    MAP_SPIFIFOEnable( GSPI_BASE, SPI_RX_FIFO);
    MAP_SPIFIFOEnable( GSPI_BASE, SPI_TX_FIFO);
    MAP_SPIDmaEnable(GSPI_BASE,SPI_RX_DMA|SPI_TX_DMA);
    MAP_SPIIntEnable( GSPI_BASE, SPI_INT_EOW);
    MAP_SPIEnable(GSPI_BASE);

}


I attached the master.c and slave.c, as well as a ZIP archive of the whole project.

Am I setting SPI up correctly? Is there any other error in my code?

Thank you for your time!

Severin

#include "common.h"

uint32_t transfer_complete = 0;

static void interrupt_handler()
{
	uint32_t status = MAP_SPIIntStatus(GSPI_BASE,true);
	MAP_SPIIntClear(GSPI_BASE,SPI_INT_EOW);
	SPICSDisable(GSPI_BASE);
	transfer_complete = 1;

	if(!(status & SPI_INT_EOW) )
	{
		Message("Error: Unexpected SPI interrupt!\n\r");
		while(1){};
	}
}

void spi_setup()
{
	MAP_SPIReset(GSPI_BASE);

	UDMAInit();

    MAP_SPIConfigSetExpClk(GSPI_BASE,MAP_PRCMPeripheralClockGet(PRCM_GSPI),
                     SPI_IF_BIT_RATE,SPI_MODE_MASTER,SPI_SUB_MODE_0,
                     (SPI_SW_CTRL_CS |
                     SPI_4PIN_MODE |
                     SPI_TURBO_OFF |
                     SPI_CS_ACTIVEHIGH |
                     SPI_WL_8));	
	MAP_SPIIntRegister(GSPI_BASE,interrupt_handler);

	MAP_SPIWordCountSet(GSPI_BASE, DMA_SIZE);
	MAP_SPIFIFOLevelSet(GSPI_BASE, 1, 1);
	MAP_SPIFIFOEnable(GSPI_BASE, SPI_RX_FIFO);
    MAP_SPIFIFOEnable(GSPI_BASE, SPI_TX_FIFO); 
	MAP_SPIDmaEnable(GSPI_BASE,SPI_RX_DMA);
	MAP_SPIDmaEnable(GSPI_BASE,SPI_TX_DMA);
	MAP_SPIIntEnable(GSPI_BASE, SPI_INT_EOW);
	MAP_SPIEnable(GSPI_BASE);

}

void spi_transfer(uint8_t* tx, uint8_t* rx)
{
	transfer_complete = 0;
	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);	
	SPICSEnable(GSPI_BASE);
	// wait for the transfer to complete
	while(!transfer_complete)
	{}
}

int main()
{
	uint32_t tx_crc = 0;
	uint32_t tx_crc_old = 0;
	uint32_t a = 364;
	uint32_t b = 53457;
	uint32_t c = 976;
	uint32_t d = 66;
	uint32_t error_counter = 0;
	uint32_t transfer_counter = 0;


	init();
	// initialize buffers with some known value
	memset(tx_buffer,0x33,sizeof(tx_buffer));
	memset(rx_buffer,0x44,sizeof(rx_buffer));

	// wait for keystroke: this gives the user time to start the slave
    Report("Start the slave and press any key to transmit data....\n\r");
    MAP_UARTCharGet(UARTA0_BASE);
	
	spi_setup();

	tx_crc = fill_buffer(tx_buffer,DMA_SIZE);
	// One "dummy" transfer, to fill the slave's TX buffer
	// this gets rid of the first "wrong" transfer in which
	// we would only receive the slave's default buffer values
	spi_transfer(tx_buffer,rx_buffer);

	while(1)
	{
		tx_crc_old = tx_crc;
		change_seed(a++,b++,c++,d++);
		tx_crc = fill_buffer(tx_buffer,DMA_SIZE);
		
		spi_transfer(tx_buffer,rx_buffer);
		/*
		// uncomment for step-by-step transfers
		print_buffer(rx_buffer,DMA_SIZE,"RX");
		print_buffer(tx_buffer,DMA_SIZE,"TX");
		Report("Press any key to start the next transfer...\n\r");
		MAP_UARTCharGet(UARTA0_BASE);
		*/
		if(crc(rx_buffer,DMA_SIZE) != tx_crc_old)
		{
			error_counter++;
		}
		transfer_counter++;
		if(transfer_counter == 100)
		{
			Report("Transferred 100 items, %d errors!\n\r",error_counter);
			error_counter = 0;
			transfer_counter = 0;
			Report("Press any key to test again\n\r");
			MAP_UARTCharGet(UARTA0_BASE);
		}
	}
	return 0;
}

#include "common.h"

void spi_transfer(uint8_t* tx, uint8_t* rx);

static void interrupt_handler()
{
	uint32_t status = MAP_SPIIntStatus(GSPI_BASE,true);
	MAP_SPIIntClear(GSPI_BASE,SPI_INT_EOW);

	spi_transfer(tx_buffer,rx_buffer);

	if(!(status &  SPI_INT_EOW))
	{
		Message("Error: Unexpected SPI interrupt!\n\r");
		while(1){};
	}
}

/*
* Here we should get rid of everything, but the SetupTransfer calls
*/
void spi_transfer(uint8_t* tx, uint8_t* rx)
{
	MAP_SPIReset(GSPI_BASE);

	//UDMAInit();

    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_ACTIVEHIGH |
                     SPI_WL_8));	
	MAP_SPIIntRegister(GSPI_BASE,interrupt_handler);

	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);	
	MAP_SPIWordCountSet( GSPI_BASE, DMA_SIZE);
	MAP_SPIFIFOLevelSet( GSPI_BASE, 1, 1);
	MAP_SPIFIFOEnable( GSPI_BASE, SPI_RX_FIFO);
	MAP_SPIFIFOEnable( GSPI_BASE, SPI_TX_FIFO); 
	MAP_SPIDmaEnable(GSPI_BASE,SPI_RX_DMA|SPI_TX_DMA);
	MAP_SPIIntEnable( GSPI_BASE, SPI_INT_EOW);
	MAP_SPIEnable(GSPI_BASE);

}
void spi_setup()
{
	MAP_SPIReset(GSPI_BASE);

	UDMAInit();

    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_ACTIVEHIGH |
                     SPI_WL_8));	
	MAP_SPIIntRegister(GSPI_BASE,interrupt_handler);

	MAP_SPIWordCountSet( GSPI_BASE, DMA_SIZE);
	MAP_SPIFIFOLevelSet( GSPI_BASE, 1, 1);
	MAP_SPIFIFOEnable( GSPI_BASE, SPI_RX_FIFO);
    MAP_SPIFIFOEnable( GSPI_BASE, SPI_TX_FIFO); 
	MAP_SPIDmaEnable(GSPI_BASE,SPI_RX_DMA|SPI_TX_DMA);
	MAP_SPIIntEnable( GSPI_BASE, SPI_INT_EOW);
	MAP_SPIEnable(GSPI_BASE);
}

int main()
{

	init();
	// initialize buffers with some known value
	memset(tx_buffer,0x55,sizeof(tx_buffer));
	memset(rx_buffer,0x22,sizeof(rx_buffer));
	
	spi_setup();
	spi_transfer(tx_buffer,rx_buffer);

    Message("Enabled SPI Interface in Slave Mode!\n\r");

    while(1)
    {
		memcpy(tx_buffer,rx_buffer,DMA_SIZE);
		// here we could also change the tx_buffer
		// e.g.	tx_buffer[0] = 18;
    }
	return 0;
}

dma_spi_duplex_example.zip

  • Hi Severin,

    Please try disabling and re-enabling the channel using MAP_SPIDisable(GSPI_BASE) and MAP_SPIEnable(GSPI_BASE) respectively instead of resetting and reconfiguring the whole SPI.

    Thanks and Regards,
    Praveen
  • Praveen, you are the best, thank you! I changed the code to:
    void spi_transfer(uint8_t* tx, uint8_t* rx)
    {
    MAP_SPIDisable(GSPI_BASE);
    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);
    MAP_SPIEnable(GSPI_BASE);
    }

    and it works perfectly.

    Thank you and best regards,
    Severin