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