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 communication by TMS320F2812

Other Parts Discussed in Thread: TMS320F2812

Dear Sir,

I want to use SPI protocol as a master ADAS1000 (http://www.element14.com/community/view-product.jspa?fsku=2213358&nsku=NULL&COM=noscript) and  slave as TMS320F2812.
I have another evaluation board which a Korean company has made for TMS320F2812 PGFA(attacted in Korean version, have a look the diagram.) .For this purpose I am using CCS V3.3 IDE platform.
Could you kindly give me instruction that how to use code for interface ADAS1000 with TMS320F2812PGFA?
.
According to datasheet explanation, ADAS1000 chip select( CS) will repeat after each 8 SPI clock . 
The  code for  read and write a register should be   4 bytes (32bit) at a time. Data has to be send  4 bytes at a time because  SPI works by clocking data in & out at the same time.:
ADAS1000 SPI connector J4 functionality works in 3.3v, IOVDD = 1.65 V to 3.6 V. To interface with TMS320F2812 PGFA do we need level translator ?
/***************************************************************************//**
 *   @file   ADAS1000.c
 *   @brief  Implementation of ADAS1000 Driver.
 *   @author ACozma (andrei.cozma@analog.com)
********************************************************************************
 * Copyright 2012(c) Analog Devices, Inc.
 *
 * All rights reserved.
 *
 * 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 Analog Devices, Inc. nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *  - The use of this software may or may not infringe the patent rights
 *    of one or more patent holders.  This license does not release you
 *    from the requirement that you obtain separate licenses from these
 *    patent holders to use this software.
 *  - Use of the software either in source or binary form, must be run
 *    on or directly connected to an Analog Devices Inc. component.
 *
 * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
 *
********************************************************************************
 *   SVN Revision: 570
*******************************************************************************/

/*****************************************************************************/
/***************************** Include Files *********************************/
/*****************************************************************************/
#include "ADAS1000.h"			
#include "Communication.h"		

/*****************************************************************************/
/************************ Variables Definitions ******************************/
/*****************************************************************************/
static unsigned long frameSize 		 = 0; //ADAS1000 frame size in bytes
static unsigned long frameRate 		 = 0; //ADAS1000 frame rate
static unsigned long inactiveWordsNo = 0; //number of inactive words in a frame

/***************************************************************************//**
 * @brief Initializes the SPI communication with ADAS1000 and checks if the 
 * 		  device is present by reading its ID. If the ID read is ok the ADAS1000
 *		  is configured with the spefified frame rate and all the words in a
 *		  frame are activated.
 *
 * @param rate - ADAS1000 frame rate.
 *
 * @return status - Result of the initialization procedure.
 *                  Example: 1 - if initialization was successful;
 *                           0 - if initialization was unsuccessful.
*******************************************************************************/
unsigned char ADAS1000_Init(unsigned long rate)
{ 
	unsigned long minSpiFreq = 0;
	unsigned long revId 	 = 0;
    
	//store the selected frame rate
	frameRate = rate;
	
	// Compute the SPI clock frequency.
	switch(frameRate)
	{
		case ADAS1000_16KHZ_FRAME_RATE:
			minSpiFreq = ADAS1000_16KHZ_FRAME_RATE * 
					  	 ADAS1000_16KHZ_WORD_SIZE * 
					  	 ADAS1000_16KHZ_FRAME_SIZE;
		break;
		case ADAS1000_128KHZ_FRAME_RATE:
			minSpiFreq = ADAS1000_128KHZ_FRAME_RATE * 
					  	 ADAS1000_128KHZ_WORD_SIZE * 
					  	 ADAS1000_128KHZ_FRAME_SIZE;
		break;
		case ADAS1000_31_25HZ_FRAME_RATE:
			minSpiFreq = (ADAS1000_31_25HZ_FRAME_RATE * 
					  	 ADAS1000_31_25HZ_WORD_SIZE * 
					  	 ADAS1000_31_25HZ_FRAME_SIZE) / 100;
		break;
		default: // ADAS1000_2KHZ__FRAME_RATE
			minSpiFreq = ADAS1000_2KHZ_FRAME_RATE * 
					  	 ADAS1000_2KHZ_WORD_SIZE * 
					  	 ADAS1000_2KHZ_FRAME_SIZE;
		break;
	}

	// Initialize the SPI controller. 
	// The SPI frequency must be greater or equal to minSpiFreq.
	if(!SPI_Init(0, minSpiFreq, 1, 1))
	{		
		return 0;
	}

	// Reset the ADAS1000.
	ADAS1000_SoftwareReset();

	// Activate all the channels
	inactiveWordsNo = 0;
	ADAS1000_SetInactiveFrameWords(0);

	//Set the frame rate
	ADAS1000_SetFrameRate(frameRate);

	return 1;
}

/***************************************************************************//**
 * @brief Reads the value of the selected register
 *
 * @param regAddress - The address of the register to read.
 * @param regVal - Pointer to a variable where to store the read data.
 *
 * @return None.
*******************************************************************************/
void ADAS1000_GetRegisterValue(unsigned char regAddress, 
							   unsigned long* regVal)
{
	unsigned char readCmd[4]	= {0, 0, 0, 0};
	unsigned char readData[4]	= {0, 0, 0, 0};

	// Select the register (For register reads, data is shifted out
	// during the next word).
	readCmd[0] = regAddress;	// Register address.
	SPI_Write(readCmd, 4);
	
	// Read the data from the device.
	SPI_Read(readData, 4);
	*regVal = ((unsigned long)readData[1] << 16) +
			  ((unsigned long)readData[2] << 8) +
			  ((unsigned long)readData[3] << 0);
}

/***************************************************************************//**
 * @brief Writes a value to the selected register
 *
 * @param regAddress - The address of the register to write to.
 * @param regValue - The value to write to the register.
 *
 * @return None.    
*******************************************************************************/
void ADAS1000_SetRegisterValue(unsigned char regAddress,
                               unsigned long regVal)
{
	unsigned char writeCmd[4] = {0, 0, 0, 0};
	
	writeCmd[0] = 0x80 + regAddress;	// Write bit and register address.
	writeCmd[1] = (unsigned char)((regVal & 0xFF0000) >> 16);
	writeCmd[2] = (unsigned char)((regVal & 0x00FF00) >> 8);
	writeCmd[3] = (unsigned char)((regVal & 0x0000FF) >> 0);
	SPI_Write(writeCmd, 4);
}

/***************************************************************************//**
 * @brief Resets the ADAS1000 part.
 *
 * @return None.
*******************************************************************************/
void ADAS1000_SoftwareReset(void)
{
	// Clear all registers to their reset value.
	ADAS1000_SetRegisterValue(ADAS1000_ECGCTL, ADAS1000_ECGCTL_SWRST);

	// The software reset requires a NOP command to complete the reset.
	ADAS1000_SetRegisterValue(ADAS1000_NOP, 0);
}

/***************************************************************************//**
 * @brief Selects which words are not included in a data frame.
 *
 * @param channelsMask - Specifies the words to be excluded from the data 
 * 						 frame using a bitwise or of the corresponding bits
 * 						 from the Frame Control Register.
 * 
 * @return None.
*******************************************************************************/
void ADAS1000_SetInactiveFrameWords(unsigned long wordsMask)
{
	unsigned long frmCtrlRegVal = 0;
	unsigned char i = 0;
	
	// Read the current value of the Frame Control Register
	ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);

	//set the inactive channles
	frmCtrlRegVal &= ~ADAS1000_FRMCTL_WORD_MASK;
	frmCtrlRegVal |= wordsMask;

	// Write the new value to the Frame Coontrol register.
	ADAS1000_SetRegisterValue(ADAS1000_FRMCTL, frmCtrlRegVal);
	
	//compute the number of inactive words
	inactiveWordsNo = 0;
	for(i = 0; i < 32; i++)
	{
		if(wordsMask & 0x00000001ul)
		{
			inactiveWordsNo++;
		}
		wordsMask >>= 1;
	}
	
	//compute the new frame size
	switch(frameRate)
	{
		case ADAS1000_16KHZ_FRAME_RATE:
			frameSize = (ADAS1000_16KHZ_WORD_SIZE / 8) *
						(ADAS1000_16KHZ_FRAME_SIZE - inactiveWordsNo);
		break;
		case ADAS1000_128KHZ_FRAME_RATE:
			frameSize = (ADAS1000_128KHZ_WORD_SIZE / 8) *
						(ADAS1000_128KHZ_FRAME_SIZE - inactiveWordsNo);
		break;
		case ADAS1000_31_25HZ_FRAME_RATE:
			frameSize = ((ADAS1000_31_25HZ_WORD_SIZE / 8) *
						(ADAS1000_31_25HZ_FRAME_SIZE - inactiveWordsNo)) / 100;
		break;
		default: // ADAS1000_2KHZ__FRAME_RATE
			frameSize = (ADAS1000_2KHZ_WORD_SIZE / 8) *
						(ADAS1000_2KHZ_FRAME_SIZE - inactiveWordsNo);
		break;
	}
}

/***************************************************************************//**
 * @brief Sets the frame rate.
 *
 * @param rate - ADAS1000 frame rate.
 * 
 * @return None.
*******************************************************************************/
void ADAS1000_SetFrameRate(unsigned long rate)
{
	unsigned long frmCtrlRegVal = 0;
	
	// Store the selected frame rate
	frameRate = rate;
	
	// Read the current value of the Frame Control Register
	ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);
	frmCtrlRegVal &= ~ADAS1000_FRMCTL_FRMRATE_MASK;
	
	// Compute the new frame size and update the Frame Control Register value
	switch(frameRate)
	{
		case ADAS1000_16KHZ_FRAME_RATE:
			frameSize = (ADAS1000_16KHZ_WORD_SIZE / 8) *
						(ADAS1000_16KHZ_FRAME_SIZE - inactiveWordsNo);
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_16KHZ;
		break;
		case ADAS1000_128KHZ_FRAME_RATE:
			frameSize = (ADAS1000_128KHZ_WORD_SIZE / 8) *
						(ADAS1000_128KHZ_FRAME_SIZE - inactiveWordsNo);
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_128KHZ;
		break;
		case ADAS1000_31_25HZ_FRAME_RATE:
			frameSize = ((ADAS1000_31_25HZ_WORD_SIZE / 8) *
						(ADAS1000_31_25HZ_FRAME_SIZE - inactiveWordsNo)) / 100;
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_31_25HZ;
		break;
		default: // ADAS1000_2KHZ__FRAME_RATE
			frameSize = (ADAS1000_2KHZ_WORD_SIZE / 8) *
						(ADAS1000_2KHZ_FRAME_SIZE - inactiveWordsNo);
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_2KHZ;
		break;
	}
	
	// Write the new Frame control Register value
	ADAS1000_SetRegisterValue(ADAS1000_FRMCTL, frmCtrlRegVal);
}

/***************************************************************************//**
 * @brief Reads the specified number of frames.
 *
 * @param pDataBuffer - Buffer to store the read data.
 * @param frameCnt - Number of frames to read.
 * @param startRead - Set to 1 if a the frames read sequence must be started.
 * @param stopRead - Set to 1 if a the frames read sequence must be sopped 
 *					 when exiting the function.
 * @param waitForReady - Set to 1 if the function must wait for the READY bit 
 *						 to be set in the header.
 * @param readyRepeat - Set to 1 if the device was configured to repeat the 
 *						header until the READY bit is set.
 *
 * @return  None.
*******************************************************************************/
void ADAS1000_ReadData(unsigned char* pDataBuffer, unsigned long frameCnt,
					   unsigned char startRead, unsigned char stopRead,
					   unsigned char waitForReady, unsigned char readyRepeat)
{
	unsigned char readCmd[4]	= {0, 0, 0, 0};
	unsigned long ready = 0;
	
	// If the read sequence must be started send a FRAMES command.
	if(startRead)
	{
		readCmd[0] = ADAS1000_FRAMES;	// Register address.
		SPI_Write(readCmd, 4);
	}

	// Read the number of requested frames.
	while(frameCnt)
	{
		// If waiting for the READY bit to be set read the header until the bit is set, otherwise just read the entire frame.
		if(waitForReady)
		{
			ready = 1;
			while(ready == 1)
			{
				//if the header is repeated until the READY bit is set read only the header, otherwise read the entire frame
				if(readyRepeat)
				{
					SPI_Read(pDataBuffer, 4);
					ready = *pDataBuffer & 0x40;
					if(ready == 0)
					{
						SPI_Read(pDataBuffer + 4, frameSize - 4);
						pDataBuffer += frameSize;
						frameCnt--;
					}
				}
				else
				{
					SPI_Read(pDataBuffer, frameSize);
					ready = *pDataBuffer & 0x40;
					if(ready == 0)
					{
						pDataBuffer += frameSize;			
						frameCnt--;
					}
				}
			}
		}
		else
		{
			SPI_Read(pDataBuffer, frameSize);
			pDataBuffer += frameSize;			
			frameCnt--;
		}
	}

	// If the frames read sequence must be stopped read a register to stop the frames read.
	if(stopRead)
	{
		ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &ready);
	}
}

/***************************************************************************//**
 * @brief Computes the CRC for a frame.
 *
 * @param pBuf - Buffer holding the frame data.
 *
 * @return Returns the CRC value for the given frame.
*******************************************************************************/
unsigned long ADAS1000_ComputeFrameCrc(unsigned char *pBuf)
{
	unsigned char i = 0;
    unsigned long crc = 0xFFFFFFFFul;
	unsigned long poly = 0;
	unsigned char bitCnt = 0;	
	unsigned long frmSize = 0;
	
	// Select the CRC poly and word size based on the frame rate.
	if(frameRate == ADAS1000_128KHZ_FRAME_RATE)
	{
		poly = CRC_POLY_128KHZ;
		bitCnt = 16;
	}
	else
	{
		poly = CRC_POLY_2KHZ_16KHZ;
		bitCnt = 24;
	}

	frmSize = frameSize;

	// Compute the CRC.
	while(frmSize--)
	{
		crc ^= (((unsigned long)*pBuf++) << (bitCnt - 8));
		for(i = 0; i < 8; i++)
		{
			if(crc & (1ul << (bitCnt - 1)))
				crc = (crc << 1) ^ poly;
            else
				crc <<= 1;
		}
	}
	
	return crc;
}
Datasheet_F2812_BUS_M_V220.pdf
Hope you will help me.
Best Regards
  • Hello!

    From looking through the ADAS datasheet, it appears that your goal of interfacing F2812 with the ADAS1000 should work. I believe that you will be working with the Secondary Serial mode of the ADAS1000. Like you said, the ADAS1000 will be the master and the F2812 will be the slave. 

    As for software, it looks pretty straightforward. The ADAS1000 in Secondary Serial mode will be constantly outputting data to the slave (F2812). The code on the F2812 will need to handle the input of 128KHz frame rate data, which should not be a problem. Be sure to look at the datasheet and understand the data that the ADAS will be outputting. What operations will you be doing on the incoming data? Will you need to send information back to the ADAS? Ensure that your clocking configuration (polarity/phase/baud rate) matches the ADAS.

    I would suggest upgrading to a newer version of CCS. CCS v3.3 is obsolete and we no longer support it on new designs. CCS v6.1 is the latest version available.

    Are you using the ADAS1000 Evaluation board? The link is broken for me. 

    It appears that if the ADAS1000 board is powered with a 5V to connectors J7 or J9, the onboard LDOs will output 3.3V to IOVDD. You have the option to supply an external voltage, but the default will allow you to connect the F2812 with the ADAS1000 using 3.3V signals.

    I hope this helps get you started!

    -Mark

  • Dear Sir, 

    Thank you very much for your response. As I am a beginner  so looks more difficulty.

    Even we could use secondary SPI section of ADAS1000, the way of code representation is same.

    Some people use it in microchip or renesas kit, but my boss wants me to use F2812.

    I have ADAS100.c and ADAS1000.h files and some spi program for microchip. If I want to write spi in ccs 3.3 version, then I need to include those file, that will not work for sure because register command of F2812 is different. Level translator is need because my F2812 works in 5 volt where ADAS1000 in 3.3 volt.

    Anyway , I am writing some  simple program for sending spi through F2812, I need also slave send receive send command,

    Here we go, kindly make correction, here is memory map error 

    #include "DSP281x_Device.h"
    #include "DSP281x_Examples.h"
    #include "DSP281x_CpuTimers.h"
    #include "DSP281x_Gpio.h"

    void main()
    {
    InitSysCtrl(); // Initialize the DSP's core Registers

    // HISPCP/LOSPCP prescale register settings, normally it will be set to default values

    SysCtrlRegs.PCLKCR.bit.SPIENCLK=1 ; //ENABLE SPIA


    while(1)
    {
    while(CpuTimer0.InterruptCount < 3); // wait for Timer 0
    CpuTimer0.InterruptCount = 0;
    EALLOW;
    SysCtrlRegs.WDKEY = 0xAA; // and service watchdog #2
    EDIS;
    }
    }

    Uint16 spi_xmit(Uint16 a);


    Uint16 spi_xmit(Uint16 a)
    {

    SpiaRegs.SPITXBUF=a<<8;
    while(SpiaRegs.SPISTS.bit.INT_FLAG != 1); //Wait until the RXBUF has received last bit
    return (SpiaRegs.SPIRXBUF<<8);
    }

    //because spitxbuf is 8 bit wide there is a bitshift operation at the beginning.and here the spi init function

    void InitSPI(void)
    {
    EALLOW;
    SpiaRegs.SPICCR.all =0x0007; // Reset on, rising edge, 8-bit char bits
    SpiaRegs.SPICTL.all =0x000E; // Enable master mode, shift phase,
    // enable talk, and SPI int disabled.
    SpiaRegs.SPIBRR =0x000C; // 3.125 MBit/s (37.5 MHz / 0x0C)
    SpiaRegs.SPICCR.all =0x0087; // Relinquish SPI from Reset
    SpiaRegs.SPIPRI.bit.FREE = 1; // Set so breakpoints don't disturb xmission
    EDIS;
    }

    //and at the end the settings for the gpios
    void Gpio_select()
    {
    // SPI Interface --------------------------------------------
    GpioMuxRegs.GPFMUX.bit.SPISIMOA_GPIOF0 = 1; // SPISIMOA
    GpioMuxRegs.GPFMUX.bit.SPISOMIA_GPIOF1 = 1; // SPISOMIA
    GpioMuxRegs.GPFMUX.bit.SPICLKA_GPIOF2 = 1; // SPICLKA
    GpioMuxRegs.GPFMUX.bit.SPISTEA_GPIOF3 = 0; // IO
    GpioMuxRegs.GPFDIR.bit.GPIOF3 = 1; // Set as Output
    GpioDataRegs.GPFSET.bit.GPIOF3 = 1; // Init as '1'
    GpioMuxRegs.GPFMUX.bit.SCIRXDA_GPIOF5 = 0; // IO
    GpioMuxRegs.GPFDIR.bit.GPIOF5 = 1; // Set as Output
    GpioDataRegs.GPFSET.bit.GPIOF5 = 1; // Init as '1'
    EDIS;
    }

    +

  • Hello,

    What issues are you having? are you having build errors with the code provided?

    I would suggest working with the F2812 SPI in internal loopback to understand first how to use the module itself. Check this link for the peripheral example codes for F2812: http://www.ti.com/tool/sprc097. Only after you understand how to use the F2812 SPI will you be able to start implementing the communication link between the ADAS1000 and F2812.

    None of the code written for Microchip or Renesas will directly port. You may be able to use the higher level drivers with some massaging, but all of the low level registers for the SPI modules will be different. The SPI of F2812 is not the same as the SPI on a Microchip or Renesas device. 

    -Mark

  • Dear Sir,

    Thank you for your kind information. Its helpful at this moment.

    As Renesas or k53 or Microchip p24FJ64GB002 etc could have different driver but they are using ADAS1000.h instruction.

    May be I need to use this ADAS1000 header file to F2812 in CCS 3.3 platform. Do you think after turn on ADAS1000 eval board, SPI signals are coming automatically ? I did not get any signal after turn off its SDP control board. That means ADAS1000.c is burned on SDP controller.

    Now problem is , how to make my code in master- slave mode?

    I also try this example code you have mentioned. This code generates SPI signal and sends data only(master mode).

    Kindly cheek this code and make some comment ,it has build error like sysctrl.c file has unresolved symbol.

    Here we go,


    #include "DSP281x_Device.h"
    #include "DSP281x_Examples.h"


    // Prototype statements for functions found within this file.
    // interrupt void ISRTimer2(void);
    void delay_loop(void);
    void spi_xmit(Uint16 a);
    void spi_fifo_init(void);
    void spi_init(void);
    void error(void);

    void main(void)
    {
    Uint16 sdata; // send data
    Uint16 rdata; // received data


    InitSysCtrl(); // Initialize the DSP's core Registers

    // HISPCP/LOSPCP prescale register settings, normally it will be set to default values

    SysCtrlRegs.PCLKCR.bit.SPIENCLK=1 ; //ENABLE SPIA


    // Step 2. Initalize GPIO:
    EALLOW;
    GpioMuxRegs.GPFMUX.all = 0x000F;
    GpioMuxRegs.GPFMUX.bit.SPISIMOA_GPIOF0 = 1; // SPISIMOA
    GpioMuxRegs.GPFMUX.bit.SPISOMIA_GPIOF1 = 1; // SPISOMIA
    GpioMuxRegs.GPFMUX.bit.SPICLKA_GPIOF2 = 1; // SPICLKA
    GpioMuxRegs.GPFMUX.bit.SPISTEA_GPIOF3 = 0; // IO
    GpioMuxRegs.GPFDIR.bit.GPIOF3 = 1; // Set as Output
    GpioDataRegs.GPFSET.bit.GPIOF3 = 1; // Init as '1'
    GpioMuxRegs.GPFMUX.bit.SCIRXDA_GPIOF5 = 0; // IO
    GpioMuxRegs.GPFDIR.bit.GPIOF5 = 1; // Set as Output
    GpioDataRegs.GPFSET.bit.GPIOF5 = 1; // Init as '1'
    EDIS;
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    DINT;


    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP281x_PieCtrl.c file.
    InitPieCtrl();
    // Disable CPU interrupts and clear all CPU interrupt flags:
    IER = 0x0000;
    IFR = 0x0000;
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This function is found in DSP281x_PieVect.c.
    InitPieVectTable();
    //Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP281x_InitPeripherals.c

    // InitPeripherals(); // Not required for this example
    spi_fifo_init(); // Initialize the Spi FIFO
    spi_init(); // init SPI

    // Step 5. User specific code:
    // Interrupts are not used in this example.
    sdata = 0x0000;
    for(;;)
    {
    // Transmit data
    spi_xmit(sdata);
    // Wait until data is received
    while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }
    // Check against sent data
    rdata = SpiaRegs.SPIRXBUF;
    if(rdata != sdata) error();
    sdata++;
    }
    }

    // Step 6. Insert all local Interrupt Service Routines (ISRs) and functions here:

    void delay_loop()
    {
    long i;
    for (i = 0; i < 1000000; i++) {}
    }


    void error(void)
    {
    asm(" ESTOP0"); // Test failed!! Stop!
    for (;;);
    }

    void spi_init()
    {
    SpiaRegs.SPICCR.all =0x000F; // Reset on, rising edge, 16-bit char bits
    SpiaRegs.SPICTL.all =0x0006; // Enable master mode, normal phase,
    // enable talk, and SPI int disabled.
    SpiaRegs.SPIBRR =0x007F;
    SpiaRegs.SPICCR.all =0x009F; // Relinquish SPI from Reset
    SpiaRegs.SPIPRI.bit.FREE = 1; // Set so breakpoints don't disturb xmission
    SpiaRegs.SPICCR.bit.CLKPOLARITY = 1;
    SpiaRegs.SPICTL.bit.CLK_PHASE = 0;
    }

    void spi_xmit(Uint16 a)
    {
    SpiaRegs.SPITXBUF=a;
    }

    void spi_fifo_init()
    {
    // Initialize SPI FIFO registers
    SpiaRegs.SPIFFTX.all=0xE040;
    SpiaRegs.SPIFFRX.all=0x204f;
    SpiaRegs.SPIFFCT.all=0x0;
    }