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.

Simple C2000/28069 SPI non-interrupt example

Other Parts Discussed in Thread: DAC161S997

Folks - this is just an FYI.  The code below provides an example of a 28069 communicating with a TI DAC161S997 using SPI.  I had a hard time finding a good example and found many folks reverted to bit-banging to get SPI to work properly.  The code is intended to be self-documenting, but two points are worth calling out:

1. The code supports a device that requires a 24-bit SPI interface with the C2000/28069's 16-bit interface.  This was a particular stumbling block for me, and others based on posts.

2. My device required delay phase.  this was a bugger to figure out, something only determined through trial-and-error

In the code below, I leave many commented in such that one can see alternate settings, ones that didn't work or weren't optimal for me, but may be for you.

The code: 

int spi_xmit(Uint16 DACreg, Uint16 byte1, Uint16 byte2)
{
int i,x;
Uint16 spi_out1,spi_out2,spi_out3,spi_in1,spi_in2,spi_in3,t;


//This particular DAC (TI DAC161S997) requires a 24-bit command+data SPI interface
//The C2000/28069 only supports up to a 16-bit interface
//BUT, the DAC will accept any sequence that is a multiple of 24-bits and not report a frame error
//In this case, the DAC will only process the last 24-bits send before the chip select is raised
//The trick is as follows:
// - Basic least common multiple math: C2000 sends 16 bits, DAC wants 24 bits, LCM=48 bits.
// - Send three 16-bit commands from the C2000. This satisfies the C2000 max 16-bit requirement.
// - The DAC will only handle the last 24 bits of the 48 bits sent. This satisfies the DAC requirements.
// - Send the following 3 16-bit words, listed as byte pairs where DC = don't care:
// - [DC][DC] [DC][DACreg] [byte1][byte2]
// - One more thing: don't use the SPISTEA because this will bring the DAC chip select high
// after each 16 bits above. Use a GPIO pin that you control (GPIO6 below) to
// bring the chip select low before the first of the 48 bits above, and high after the last
// bit is sent.

//Return values:
// 0 = success
// -500 = timeout waiting for data to clock out of DAC
// -501 = transmission error where readback of sent bits did not match
// DAC Status Register = this is a special case to capture the DAC status

//Setup the three words to send. Here we simply send the 24-bit sequence twice.
spi_out1=DACreg*256+byte1;
spi_out2=byte2*256+DACreg;
spi_out3=byte1*256+byte2;

//Pull the chip select low. Don't use SPISTEA. This will also help if you have more than one SPI device
GpioDataRegs.GPACLEAR.bit.GPIO6 = 1; //Enable 4-20mA DAC

//Small delay after chip select is brought low and before blasting data words
for (i=0;i<100;i++);

//Send the three 16-bit words.
//x is used as a timeout value. The timeout value (1000 below) will depend on your SPI clock speed
//1000 was arrived at by looking at how many loop iterations it took for a successful transmission
//and multiplying by 10

//Write the first word
SpiaRegs.SPITXBUF=spi_out1; //Use the transmit FIFO
x=0;
while((SpiaRegs.SPIFFRX.bit.RXFFST == 0) && (x++<1000)) {}
if (x==1001) return(-500);
spi_in1 = SpiaRegs.SPIRXBUF;

//Write the second word
SpiaRegs.SPITXBUF=spi_out2; //Use the transmit FIFO
x=0;
while((SpiaRegs.SPIFFRX.bit.RXFFST == 0) && (x++<1000)) {}
if (x==1001) return(-500);
spi_in2 = SpiaRegs.SPIRXBUF;

//Write the third word
SpiaRegs.SPITXBUF=spi_out3; //Use the transmit FIFO
x=0;
while((SpiaRegs.SPIFFRX.bit.RXFFST == 0) && (x++<1000)) {}
if (x==1001) return(-500);
spi_in3 = SpiaRegs.SPIRXBUF;

//Small delay after last bit is sent before the chip select is brought high
for (i=0;i<100;i++);
GpioDataRegs.GPASET.bit.GPIO6 = 1; //Disable 4-20mA DAC

//This completes the logic to talk to a 24-bit SPI device using the C2000 16-bit max SPI interface
//The remainder of this code is additional device/DAC-specific error checking

//This particular DAC echos all the bits back verbatim when not asking for status.
//As such, the dummy data, i.e. the first copy of the Addr+Byte1+Byte2 should reflect back
//We can use this as a data validation:
t = spi_in2&0xFF;
t = spi_in3>>8;
t =spi_in3&0xFF;
if ((DACreg != (Uint16) (spi_in2&0xFF)) |
(byte1 != (Uint16) (spi_in3>>8)) |
(byte2 != (Uint16) (spi_in3&0xFF))) return (-501);

//Special case to grab the DAC Status. For this to work properly, the call sequence to this function is:
// spi_xmit (0xFF,0x00,0x00) ... this clocks in the read status command
// spi_xmit (0x00,0x00,0x00) ... this trips this special case to grab the response of the previous command
if (DACreg==0) return (spi_in2>>8);

return(0);
}

Uint16 spi_recv()
{
// Wait until data is received
while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }
return (SpiaRegs.SPIRXBUF);
}


void spi_init()
{

//This, like phase below, is a bit trial and error.  My SPI device seemed

//to indicate rising edge, which worked

SpiaRegs.SPICCR.all =0x000F; // Reset on, rising edge, 16-bit char bits
// SpiaRegs.SPICCR.all =0x004F; // Reset on, falling edge, 16-bit char bits

//Setting the correct phase was the last piece of the puzzle for me

//All my data would *strongly* suggest that normal phase would be the correct

//choice, but only delay phase worked, and worked perfectly.   

// SpiaRegs.SPICTL.all =0x0006; // Enable master mode, normal phase, enable talk, and SPI int disabled.
SpiaRegs.SPICTL.all =0x000E; // Enable master mode, delay phase, enable talk, and SPI int disabled.

SpiaRegs.SPIBRR =0x007F; // This sets baud rate to 80MHz/127=625KHz

// SpiaRegs.SPIBRR =0x0008; // This sets baud rate to 80MHz/8=10MHz
// SpiaRegs.SPICCR.all =0x009F; // Relinquish SPI from Reset, and enable loopback, 16 bit tx
SpiaRegs.SPICCR.all =0x008F; // Relinquish SPI from Reset, no loopback, 16 bit tx
SpiaRegs.SPIPRI.bit.FREE = 1; // Set so breakpoints don't disturb xmission

// Configure GPIO06 as a GPIO output pin. This will serve as the chip select (active low)
EALLOW;
GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 0;
GpioCtrlRegs.GPADIR.bit.GPIO6 = 1; //Output
GpioDataRegs.GPASET.bit.GPIO6 = 1; //Inactive
EDIS;

}

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


#if DSP28_SPIA
void InitSpiaGpio()
{

EALLOW;
/* Enable internal pull-up for the selected pins */
// Pull-ups can be enabled or disabled by the user.
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.

// GpioCtrlRegs.GPAPUD.bit.GPIO3 = 0; // Enable pull-up on GPIO3 (SPISOMIA)
// GpioCtrlRegs.GPAPUD.bit.GPIO5 = 0; // Enable pull-up on GPIO5 (SPISIMOA)

GpioCtrlRegs.GPAPUD.bit.GPIO16 = 0; // Enable pull-up on GPIO16 (SPISIMOA)
GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pull-up on GPIO17 (SPISOMIA)
GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0; // Enable pull-up on GPIO18 (SPICLKA)
GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0; // Enable pull-up on GPIO19 (SPISTEA)

// GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0; // Enable pull-up on GPIO54 (SPISIMOA)
// GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0; // Enable pull-up on GPIO55 (SPISOMIA)
// GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0; // Enable pull-up on GPIO56 (SPICLKA)
// GpioCtrlRegs.GPBPUD.bit.GPIO57 = 0; // Enable pull-up on GPIO57 (SPISTEA)

/* Set qualification for selected pins to asynch only */
// This will select asynch (no qualification) for the selected pins.
// Comment out other unwanted lines.

// GpioCtrlRegs.GPAQSEL1.bit.GPIO3 = 3; // Asynch input GPIO3 (SPISOMIA)
// GpioCtrlRegs.GPAQSEL1.bit.GPIO5 = 3; // Asynch input GPIO5 (SPISIMOA)

GpioCtrlRegs.GPAQSEL2.bit.GPIO16 = 3; // Asynch input GPIO16 (SPISIMOA)
GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch input GPIO17 (SPISOMIA)
GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch input GPIO18 (SPICLKA)
GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3; // Asynch input GPIO19 (SPISTEA)

// GpioCtrlRegs.GPBQSEL2.bit.GPIO54 = 3; // Asynch input GPIO54 (SPISIMOA)
// GpioCtrlRegs.GPBQSEL2.bit.GPIO55 = 3; // Asynch input GPIO55 (SPISOMIA)
// GpioCtrlRegs.GPBQSEL2.bit.GPIO56 = 3; // Asynch input GPIO56 (SPICLKA)
// GpioCtrlRegs.GPBQSEL2.bit.GPIO57 = 3; // Asynch input GPIO57 (SPISTEA)


/* Configure SPI-A pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be SPI functional pins.
// Comment out other unwanted lines.

// GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 2; // Configure GPIO3 as SPISOMIA
// GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 2; // Configure GPIO5 as SPISIMOA

GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA
GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA
GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1; // Configure GPIO19 as SPISTEA

// GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 1; // Configure GPIO54 as SPISIMOA
// GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 1; // Configure GPIO55 as SPISOMIA
// GpioCtrlRegs.GPBMUX2.bit.GPIO56 = 1; // Configure GPIO56 as SPICLKA
// GpioCtrlRegs.GPBMUX2.bit.GPIO57 = 1; // Configure GPIO57 as SPISTEA

EDIS;
}
#endif // endif DSP28_SPIA

  • John,

    Thanks for sharing!


    Thank you,
    Brett

  • Hi John,

                      Please can you share me the information regarding how to connect DAC  with f28069  hardware and also I want to know the how we have to send digital input to DAC from f28069.  please your information is very much valuable for me.

    Thanks in advance.

    Regards

    Naveenkumar

  • Naveenkumar - the connection from the f28069 to the DAC is simple.  To match the code I have above, one would connect:

    28069 GPIO-6  -------------------> DAC CSB

    28069 GPIO-16/SPISIMOA ----> DAC SDI

    28069 GPIO-17/SPISOMIA ----> DAC SDO

    28069 GPIO-18/SPICLKA   ----> DAC SCLK

    As far as sending the digital input to the DAC from the f28069, using the code above (I can no longer see it as I am posting, but believe it has the spi_xmit function) to send the 3 byte sequences to the DAC:

    spi_xmit(0x08,0xC3,0x3C); //Reset DAC

    spi_xmit(0x02,0x00,0x00); //NOP: Data sheet calls for a NOP after reset

    spi_xmit(0x05,0x01,0x13); //Disable SPI timeouts

    spi_xmit(0x04,DACValueHigh,DACValueLow); //Write DAC 16-bit current value

    The first 3 of 4 spi_xmit commands above are only needed for the first time through, after which the DAC can be updated with the 4th command any time there is a need to update the output current.

    Good luck!

    John