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.

RTOS/TMS320F2812: Cannot transmit/receive more than FIFO size (15 words) using SPI (Non-interrupt)

Part Number: TMS320F2812


Tool/software: TI-RTOS

My current setup is - PC(TwinCAT) --> EtherCAT --> ET1100 piggyback --> SPI --> TI DSP

Everything works perfectly when I transmit/receive less than one FIFO buffer full of data bytes. When I want to call the transmit/receive functions in a loop to transmit/receive more than one FIFO buffer of data, it does not work as intended. Please help me identify the problem because I read the code atleast 20 times but cannot see an error. 

There is NO interrupt usage. 

/*
 * SOES Simple Open EtherCAT Slave
 *
 * File    : esc_hw.c
 * Version : 0.9.2
 * Date    : 22-02-2010
 * Copyright (C) 2007-2010 Arthur Ketels
 *
 * SOES is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License version 2 as published by the Free
 * Software Foundation.
 *
 * SOES is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * As a special exception, if other files instantiate templates or use macros
 * or inline functions from this file, or you compile this file and link it
 * with other works to produce a work based on this file, this file does not
 * by itself cause the resulting work to be covered by the GNU General Public
 * License. However the source code for this file must still be made available
 * in accordance with section (3) of the GNU General Public License.
 *
 * This exception does not invalidate any other reasons why a work based on
 * this file might be covered by the GNU General Public License.
 *
 * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
 * property of, and protected by Beckhoff Automation GmbH.
 */
/* Device header file */

#include <stdint.h>        /* Includes uint16_t definition                    */
#include <stdbool.h>       /* Includes true/false definition                  */
#include <DSP281x_Device.h>
#include "utypes.h"
#include "esc.h"
#include "esc_coe.h"
#include "CPU.h"                                                               // Local include file

#define ESC_ETHERCAT_READ			0x02
#define ESC_ETHERCAT_READ_WAIT		0x03
#define ESC_ETHERCAT_WRITE			0x04
#define ESC_ETHERCAT_3BYTEADDR		0x06
#define ESC_ETHERCAT_WAIT			0xFF
#define ESC_ETHERCAT_CONTINUE		0x00
#define ESC_ETHERCAT_RDTERMINATE	0xFF


#define CPU_RATE 16.667L // for a 60MHz CPU clock speed
#define DELAY_US(A)  DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L)


/*---------------------------------------------------------------------------------------------------------------------
; F U N C T I O N   D E F I N I T I O N S
;----------------------------------------------------------------------------------------------------------------------
*/


void InitGpio(void)
{

	EALLOW;
//	IER = 0x0000;
//	IFR = 0x0000;

	// Enable the four I/O pins for the SPI interface
	GpioMuxRegs.GPFMUX.bit.SPISIMOA_GPIOF0 = 1;                                // Slave In, Master Out
	GpioMuxRegs.GPFMUX.bit.SPISOMIA_GPIOF1 = 1;                                // Slave Out, Master In
	GpioMuxRegs.GPFMUX.bit.SPICLKA_GPIOF2 = 1;                                 // Serial Clock
	GpioMuxRegs.GPFMUX.bit.SPISTEA_GPIOF3 = 1;                                 // Slave Transmit Enable (SYNC)

	EDIS;
}


void InitSPI(void)
{

	EALLOW;
	// Initialize SPI FIFO registers
	SpiaRegs.SPICCR.bit.SPISWRESET=0; // Reset SPI

	SpiaRegs.SPICCR.bit.SPICHAR = 0x7; // Character Length  = 8

	SpiaRegs.SPICCR.bit.CLKPOLARITY = 1; // Rising edge

	SpiaRegs.SPICTL.bit.SPIINTENA = 1;		// Enabled
	SpiaRegs.SPICTL.bit.TALK = 1;			//
	SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1;	// Master mode
	SpiaRegs.SPICTL.bit.CLK_PHASE = 0;		// 1/2-cycle delay of Clk wrt SPISTEA (0 - no delay, 1 - delay)
	SpiaRegs.SPICTL.bit.OVERRUNINTENA = 1;	// Overrun Interrupt enabled

	//ClkCfgRegs.LOSPCP.all = 0x1; // 0 = sysclk/1 = 200M; 1 = sysclk/2 = 100M

	SpiaRegs.SPISTS.all=0x0000;		// Clear Status bits (TxBufFull,INT, Overrun)
	SpiaRegs.SPIBRR=0x0005;		// Baud Rate = LSPCLK / (SPIBRR+1) [LSPCLK=SysClk/4 by default=50M]
	//---------------------------------------------------------------------------------------------

	SpiaRegs.SPIFFTX.all=0xC022;      	// Enable FIFO's, reset them, set TX FIFO IntLevl = 2,TXINT disabled
	SpiaRegs.SPIFFTX.bit.TXFFIENA = 0;	// Disable TXFF INT

	SpiaRegs.SPIFFRX.all=0x006A;      	// Enable FIFO's, reset them, set RXFFIL= 10(dec)
	SpiaRegs.SPIFFRX.bit.RXFFIL = 0x02;
	SpiaRegs.SPIFFRX.bit.RXFFIENA = 0;	// disable RXFF INT

	//----------------------------------------------------------------------------------------------
	SpiaRegs.SPIFFCT.all=0x00;			// FFTXDLY = 0 (delay btw Tx transfers)
	SpiaRegs.SPIPRI.all=0x0020;			// Stop after transaction complete on EmuStop

	SpiaRegs.SPICCR.bit.SPISWRESET=1;  // Enable SPI

	SpiaRegs.SPIFFTX.bit.TXFIFO=1;		// Reset Tx FIFO
	SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;

	EDIS;
}


/******************************************************************************
 * Function:        void ESC_read(uint16_t address, uint16_t *buf,
 *                                uint16_t len, uint16_t *tALevent))
 *
 * PreCondition:    SPI initialized
 *                  EthetCAT initialized
 *
 * Input:           uint16_t address = EtherCAT register address
 *                  uint16_t *buf = Pointer to write data to
 *                  uint16_t len = Size of data to read
 *
 * Output:          uint16_t *tALevent = Status returned
 *
 * Side Effects:    None
 *
 * Overview:        This is the main EthetCAT read function
 *****************************************************************************/
void ESC_read(uint16_t offset_addr, void *buf, uint16_t len, void *tALevent)
{

	uint16_t i,cmd, numwords = 0, j;
	static uint16_t readval =0;
	uint16_t *ptr = (uint16_t *)0;
	uint16_t readphase[16];  // FIFO=16,Up to 13 words can be read (Addrphase takes 2Addr+1WS)
	uint16_t loop_count = 0;

	ptr = (uint16_t *)tALevent;

	if(len > 0 && len <= 26) //It is only possible to read 26 bytes of payload (+4 bytes of address) at a time from the TI SPI's FIFO
	{
		// Construct Address cmd bytes into 16-bit words for SPI xmission,
		//    SPI xmits MSBit 1st, so must swap bytes in this 16b word for transmission
		// Byte order of READ cmd sequence:
		// Byte 0: A[12:5]
		// Byte 1: A[4:0], 110b   			(110b is 3-byte cmd extension)
		// Byte 2: A[15:13], CMD[2:0], 00b	(011b is READ w/ WS)
		// Byte 3: FFh						(Wait State)
		//cmd = offset_addr & 0x1f
	
		cmd =(offset_addr & 0x1FE0)<<3; // offset_addr[12:5] is 1st address phase byte, shift to upper byte
		cmd |= (((offset_addr & 0x1F) << 3) | ESC_ETHERCAT_3BYTEADDR);
		readphase[0] = cmd;
		numwords++;
		readphase[1] = (offset_addr & 0xE000) | (ESC_ETHERCAT_READ_WAIT <<10) | ESC_ETHERCAT_WAIT;
		numwords++;
	
		for(i=2, j = 0; j<len ; i++, j+=2)   //numwords is in no. of bytes;
		{
			readphase[i] = (uint16_t) ESC_ETHERCAT_CONTINUE;
			numwords++;
		}
		readphase[--i] |= (ESC_ETHERCAT_RDTERMINATE); // set last byte as 0xFF
	
		/*Disable Interrupts*/
		DINT;
	
		for(i = 0; i < numwords; i++)
		{
			while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
			SpiaRegs.SPITXBUF = readphase[i] & (0xFF00);
			while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
			SpiaRegs.SPITXBUF = ((readphase[i] & (0xFF)) << 8);
			loop_count++;
		}
		if(loop_count != numwords)
		{
	
				asm(" ESTOP0");
				while(1);
		}
	
		CPU_DELAY_US(5);
		j = numwords;
	
	
		while(SpiaRegs.SPIFFRX.bit.RXFFST < j);
		readval = (SpiaRegs.SPIRXBUF) & 0xFF; // Read to tALevent
		*(ptr) = (readval & 0xFF);
		CPU_DELAY_US(5);	//delay before reading next byte
		readval = (SpiaRegs.SPIRXBUF) & 0xFF; // Read to tALevent
		*(ptr) |= ((readval & 0xFF) << 8);
		CPU_DELAY_US(5);	//delay before reading next byte
	
		readval = SpiaRegs.SPIRXBUF; // ignore
		CPU_DELAY_US(5);	//delay before reading next byte
		readval = SpiaRegs.SPIRXBUF; // ignore
		CPU_DELAY_US(5);	//delay before reading next byte
	
		ptr = (uint16_t *)buf;
			for(i=0;((SpiaRegs.SPIFFRX.bit.RXFFST != 0));i++)
			{
				readval = (SpiaRegs.SPIRXBUF) & 0xFF;
				ptr[i]= (readval & 0xFF);
	
				CPU_DELAY_US(2);	//delay before reading next byte
	
				readval = (SpiaRegs.SPIRXBUF) & 0xFF;
				ptr[i] |= (readval & 0xFF)<<8;
	
				CPU_DELAY_US(2);	//delay before reading next byte
	
			}
	
	
		SpiaRegs.SPIFFRX.bit.RXFIFORESET = 0; //reset the FIFO pointer
		SpiaRegs.SPIFFRX.bit.RXFIFORESET = 1; //reenable the FIFO operation
	
		/*Enable Interrupts*/
		EINT;
		CPU_DELAY_US(10);	//delay before reading next byte
	
	}
}


void ESC_readBlock(uint16_t* pData, uint16_t offset_addr,uint16_t numbytes)
{
	uint16_t i = 0, current_bytes = 0;
	if(numbytes & 0x1)
	{
		current_bytes = (numbytes + 0x1); // even align
	}
	else
	{
		current_bytes = numbytes;
	}


	while(current_bytes > 0) // input is actually in bytes
	{
		if( current_bytes >= 26)
		{
			ESC_read(offset_addr + (2*i), (void *) &pData[i], 26, (void *) &ESCvar.ALevent);
			current_bytes -= 26;
			i+= 13; // data is in 16 bits
		}
		else
		{
			ESC_read(offset_addr + (2*i), (void *) &pData[i], current_bytes, (void *) &ESCvar.ALevent);
			current_bytes = 0;
		}
	}
}



/******************************************************************************
 * Function:        void ESC_write(uint16_t address, uint16_t *buf,
 *                                 uint16_t len, uint16_t *tALevent)
 *
 * PreCondition:    SPI initialized
 *                  EthetCAT initialized
 *
 * Input:           uint16_t address = EtherCAT register address
 *                  uint16_t *buf = Pointer read data from
 *                  uint16_t len = Size of data to write
 *
 * Output:          uint16_t *tALevent = Status returned
 *
 * Side Effects:    None
 *
 * Overview:        This is the main EthetCAT write function
 *****************************************************************************/
void ESC_write(uint16_t offset_addr, void *wrdata, uint16_t len, void *tALevent)
{
	uint16_t i, j,cmd, readval, numwords = 0;
	uint16_t wptr,highbyte,lowbyte;
	uint16_t *ptr = (uint16_t *)0;
	uint16_t writephase[16];


	if(len >0 &&  len <= 26) //It is only possible to transmit 26 bytes of payload (+4 bytes of address) at a time from the TI SPI's FIFO
	{
		// Construct Address cmd bytes into 16-bit words for SPI xmission,
		//    SPI xmits MSBit 1st, so must swap bytes in this 16b word for transmission
			// Byte order of READ cmd sequence:
			// Byte 0: A[12:5]
				// Byte 1: A[4:0], 110b   			(110b is 3-byte cmd extension)
				// Byte 2: A[15:13], CMD[2:0], 00b  (110b is 3-byte cmd extension)
				// Byte 3: A[15:13], CMD[2:0], 00b	(100b is READ w/ WS)
				//cmd = offset_addr & 0x1f

		cmd =(offset_addr & 0x1FE0)<<3; // offset_addr[12:5] is 1st address phase byte, shift to upper byte
		cmd |= (((offset_addr & 0x1F) << 3) | ESC_ETHERCAT_3BYTEADDR);
		writephase[0] = cmd;
		numwords++;
		cmd = 0x0000;
		cmd = (((offset_addr & 0xE000) >> 8) | (ESC_ETHERCAT_3BYTEADDR << 2)) << 8;
		cmd |= (((offset_addr & 0xE000) | (ESC_ETHERCAT_WRITE <<10)) >> 8);
		writephase[1] = cmd;
		numwords++;

		ptr = (uint16_t *) wrdata;

		wptr=0;
		for(i=2, j = 0; j < len ; i++, wptr++)
		{
			// Swap Bytes so low-byte goes first since ET110 i/f uses BYTE addressing
			lowbyte = ptr[wptr] << 8;
			j++;
			highbyte = ptr[wptr] >> 8;
			j++;
			writephase[i] = highbyte | lowbyte;
			numwords++;
		}

		/*Disable Interrupts*/
		DINT;


		for(i=0;i<numwords;i++)
		{

			while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
			SpiaRegs.SPITXBUF = writephase[i] & (0xFF00);
			while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
			SpiaRegs.SPITXBUF = ((writephase[i] & (0xFF)) << 8);

		}

		CPU_DELAY_US(10);

		j = numwords;
		ptr = (uint16_t *)tALevent;

		while(SpiaRegs.SPIFFRX.bit.RXFFST < j);

		readval = (SpiaRegs.SPIRXBUF) & 0xFF;
		*(ptr) = (readval & 0xFF);
		CPU_DELAY_US(2);	//delay before reading next byte
		readval = (SpiaRegs.SPIRXBUF) & 0xFF;
		*(ptr) |= ((readval & 0xFF) << 8);
		CPU_DELAY_US(2);	//delay before reading next byte


		while(SpiaRegs.SPIFFTX.bit.TXFFST != 0);
		SpiaRegs.SPIFFTX.bit.TXFIFO=0;		// Reset Tx FIFO
		SpiaRegs.SPIFFTX.bit.TXFIFO=1;		// Reset Tx FIFO
		SpiaRegs.SPIFFRX.bit.RXFIFORESET=0;
		SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;

		/*Enable Interrupts*/
		EINT;

		CPU_DELAY_US(10);	//delay before reading next byte
	}

}






void ESC_writeBlock(uint16_t* pData, uint16_t offset_addr,uint16_t numbytes)
{
	uint16_t i = 0; //, current_bytes = 0;
	uint16_t temp_value, temp_ALevent, current_bytes;
	current_bytes = numbytes;

	while(current_bytes > 0) // input is actually in bytes
	{
		if( current_bytes >= 26)
		{
			ESC_write (offset_addr + (2*i), (void *) &pData[i], 26, (void *) &ESCvar.ALevent);
			current_bytes -= 26;
			i+= 13; // data is in 16 bits
		}
		else
		{
			if(current_bytes & 0x1)   //Checking if the remaining bytes are ODD
			{
		//		current_bytes = numbytes + 0x1; // even align
				ESC_write (offset_addr+ (2*i), (void *) &pData[i], current_bytes-1, (void *) &ESCvar.ALevent);
				//now send the last byte with extra alignment bytes
				// note that we read the adjacent byte and write it back
				ESC_read (offset_addr+(numbytes-1), (void *)&temp_value, 2, (void *) &temp_ALevent);

				temp_value &= 0xFF00;
				temp_value |= (pData[numbytes-1]) & 0xFF;
				ESC_write (offset_addr+(numbytes-1), (void *)&temp_value, 2, (void *) &temp_ALevent);

			}
			else
			{
				ESC_write (offset_addr + (2*i), (void *) &pData[i], current_bytes, (void *) &ESCvar.ALevent);

			}
			current_bytes = 0;
		}
	}
}



  • Raghu,

    What is the error you are getting? Are you not able to recieve the data? are you getting stuck in a loop? Are you recieving data but it isnt correct?

    This will help me as I read through this!

    Regards,

    Vince Rodriguez
  • I receive/send data but it isn't correct. I sense timing issue but I couldn't use the oscilloscope to analyze correctly because it's more than 30 bytes :(
  • Raghu,

    what is the reason you are doing the below: Line 355

    while(SpiaRegs.SPIFFTX.bit.TXFFST != 0);
    SpiaRegs.SPIFFTX.bit.TXFIFO=0; // Reset Tx FIFO
    SpiaRegs.SPIFFTX.bit.TXFIFO=1; // Reset Tx FIFO
    SpiaRegs.SPIFFRX.bit.RXFIFORESET=0;
    SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;

    I would start by gaining some idea of what going on in the FIFO buffer. Run through the function once, and check the FIFO buffer. Is it empty, or is there still info that needs to be sent out?

    When you get errors, what is the data expected vs. the data recieved?

    Let me know your findings!

    Thanks,

    Vince Rodriguez
  • This is taken from http://www.ti.com/lit/ug/spru059e/spru059e.pdf 

    The FIFO buffer pointer needs to be reset back to the starting point (zero fifo level) hence the reset (writing zero). Then the FIFO needs to be enabled, hence the ONE written to TXFIFO/RXFIFO. 
    This is done for the RX also because while transmitting there is junk data read into the RXFIFO (the first couple of bytes are useful though). This data is flushed out by resetting the FIFO pointer and then enabling the RXFIFO just like the TXFIFO. 

  • The last line states that FIFO will resume operation when the bits are cleared to zero. Are you returning these to zero?

    I would suggest handling the garbage bytes in a different way, and not resetting the FIFO after every read. You could read these garbage bytes until the FIFO is empty, then continue in your software.

    Vince
  • By "these" bits, the pdf means the FIFO status bits. I wait (using while) for these bits to get to zero. So they do return to zero (read only bits).

    Also I will try what you suggest but it does not seem that I can find an explanation as to why this can go wrong. :( That's what worries me.