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.

TMDSDOCK28335: Incoming SPI data from slave (TMDSDOCK28335) is wrong

Part Number: TMDSDOCK28335
Other Parts Discussed in Thread: CC3200-LAUNCHXL, CC3200

Hello everyone,

For those who have been helping me in the past (much appreciated by the way), this is the latest update of the SPI code I have been working on.

So far, the data sent from the master (CC3200-LAUNCHXL) to the slave (TMDSDOCK28335) is correct. But the problem lies on the fifth transfer (which is the only time the slave is sending data), the values are completely wrong. I try to fix the received data using some correction code, but I still get the lsb wrong. I have some example data along with the code so you can see the problem.

What is loaded into the TMDSDOCK28335 transfer buffer What is being received on the receive buffer After the receive buffer correction (lines 151-155 from CC3200 code)
0x0011 0x0080 0x0010
0xAAAA 0x5555 0xAAAA
0x5555 0xAA2a 0x5554
0xFFFF 0xFF7F 0xFFFE
0x0000 0x0000 0x0000
0xABCD 0xE655 0xABCC
0x274E 0xA713 0x274E

CC3200-LAUNCHXL Code

//Code is based off of "SPI Demo" that came with the CC3200-LAUNCHXL board

//Standard Includes
#include <string.h>

//Driver Library Includes
#include "hw_types.h"
#include "hw_memmap.h"
#include "hw_common_reg.h"
#include "hw_ints.h"
#include "spi.h"
#include "rom.h"
#include "rom_map.h"
#include "utils.h"
#include "prcm.h"
#include "uart.h"
#include "interrupt.h"

//Common Interface Includes
#include "uart_if.h"
#include "pinmux.h"

//Useful Macros
#define SPI_IF_BIT_RATE  100000 //in bits per second (bps) originally 100,000
#define TR_BUFF_SIZE     2

//*****Start of Global Variables*****
static unsigned char sendtoDSP[TR_BUFF_SIZE];
static unsigned char receivefromDSP[TR_BUFF_SIZE];
unsigned int char_array_to_int, store_msb, remove_lsb,correct_integer_backwards, correct_integer;

//Not too sure what this stuff does here, but came with SPI example
#if defined(ccs)
extern void (* const g_pfnVectors[])(void);
#endif
#if defined(ewarm)
extern uVectorEntry __vector_table;
#endif
//*****End of Global Variables*****

//*****Start of Board Initialization & Configuration***** (Came with SPI Demo as well)
static void
BoardInit(void)
{
/* In case of TI-RTOS vector table is initialize by OS itself */
#ifndef USE_TIRTOS
  //
  // Set vector table base
  //
#if defined(ccs)
    MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
#endif
#if defined(ewarm)
    MAP_IntVTableBaseSet((unsigned long)&__vector_table);
#endif
#endif
    //
    // Enable Processor
    //
    MAP_IntMasterEnable();
    MAP_IntEnable(FAULT_SYSTICK);

    PRCMCC3200MCUInit();
}
//*****End of Board Initialization & Configuration*****

void main(){

   //Initialize Board Configurations
   BoardInit();

   //Muxing UART and SPI Lines
   //All this does is configure pins for MOSI, MISO, Chip Select, and Clock.
   PinMuxConfig();

   //Enable the SPI Module Clock
   //Enables clock to peripheral
   //PRCM_GSPI = Macro for the SPI Peripheral (0x00000003)
   //PRCM_RUN_MODE_CLK = Ungates clock to the peripheral (could also be PRCM_SLP_MODE_CLK
   //which keeps the clocks ungated in sleep)
   MAP_PRCMPeripheralClkEnable(PRCM_GSPI,PRCM_RUN_MODE_CLK);

   //Reset the Peripheral
   //PRCM_GSPI = Macro for the SPI Peripheral (resets the SPI Peripheral)
   MAP_PRCMPeripheralReset(PRCM_GSPI);

   //Reset SPI
   //Performs a software reset to the SPI Module
   //GSPI_BASE = Macro for the SPI Base Address (0x44021000)
   MAP_SPIReset(GSPI_BASE);

   //Configure SPI Interface (all values are MACROS)
   //1st argument is base address of SPI Module (which is GSPI_BASE)
   //2nd argument is rate of clock being supplied to SPI Module
   //3rd argument is the desired bit rate (which is defined in the "useful macro" section above)
   //4th argument is SPI_MODE_MASTER, which configures board as the master
   //5th argument is SPI_SUB_MODE_0, which sets clock polarity and phase to 0
   //6th argument is logical OR combination, which sets chip select to be controlled by software (SPI_SW_CTRL_CS),
   //sets module to 4 pin mode (SPI_4PIN_MODE), sets turbo mode off (SPI_TURBO_OFF) and I have no idea what turbo mode is,
   //sets chip select to be active low (SPI_CS_ACTIVELOW), and sets the bit length to 8 bits per character (SPI_WL_8)
   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_ACTIVELOW |
   SPI_WL_8));

   //Enable SPI for Communication
   //GSPI_BASE = Macro for the SPI Base Address (0x44021000)
   MAP_SPIEnable(GSPI_BASE);

   while(1){
   //Load first data set into transfer buffer
   sendtoDSP[0] = 'A'; //0x41
   sendtoDSP[1] = 'B'; //0x42

   //Send data over MOSI pin
   //1st argument is base address of SPI Module (GSPI_BASE)
   //2nd argument is pointer to transfer buffer (sendtoDSP)
   //3rd argument is pointer to receive buffer (receivefromDSP)
   //4th argument is size of data in bytes (1 byte = 8 bits)
   //5th argument is logical OR that enable chip select pin before transmission,
   //and disables chip select pin after transmission (SPI_CS_ENABLE|SPI_CS_DISABLE)
   MAP_SPITransfer(GSPI_BASE,sendtoDSP,receivefromDSP,2,SPI_CS_ENABLE|SPI_CS_DISABLE);

   //Load second data set into transfer buffer
   sendtoDSP[0] = 'C'; //0x43
   sendtoDSP[1] = 'D'; //0x44

   MAP_SPITransfer(GSPI_BASE,sendtoDSP,receivefromDSP,2,SPI_CS_ENABLE|SPI_CS_DISABLE);

   //Load third data set into transfer buffer
   sendtoDSP[0] = 'E'; //0x45
   sendtoDSP[1] = 'F'; //0x46

   MAP_SPITransfer(GSPI_BASE,sendtoDSP,receivefromDSP,2,SPI_CS_ENABLE|SPI_CS_DISABLE);

   //Load fourth data set into transfer buffer
   sendtoDSP[0] = 'G'; //0x47
   sendtoDSP[1] = 'H'; //0x48

   MAP_SPITransfer(GSPI_BASE,sendtoDSP,receivefromDSP,2,SPI_CS_ENABLE|SPI_CS_DISABLE);

   //Load nothing into transfer buffer for fifth transfer
   sendtoDSP[0] = 0x00;
   sendtoDSP[1] = 0x00;

   MAP_SPITransfer(GSPI_BASE,sendtoDSP,receivefromDSP,2,SPI_CS_ENABLE|SPI_CS_DISABLE);

   //Receive Buffer Correction
   char_array_to_int = (receivefromDSP[1]<<8)|(receivefromDSP[0]&0xFF);
   store_msb = (char_array_to_int>>15)&0x0001;
   remove_lsb = (char_array_to_int<<1)&0xFFFE;
   correct_integer_backwards = remove_lsb|store_msb;
   correct_integer = ((correct_integer_backwards<<8)&0xFF00)|((correct_integer_backwards>>8)&0x00FF);
   }
}

TMDSDOCK28335 Code

//Code Based off of TMS320F28335 SPI Example

//Device Headerfile and Examples Include File
#include "DSP28x_Project.h"

//Prototype statements for functions found within this file.
void spi_fifo_init(void);
void spi_init(void);

//Global variables (used to read registers)
unsigned int first_data_set, second_data_set, third_data_set, fourth_data_set, fifth_data_set;

void main(void){

   //Initialize System Control:
   //PLL, WatchDog, enable Peripheral Clocks
   //This example function is found in the DSP2833x_SysCtrl.c file.
   InitSysCtrl();

   //Initialize GPIO:
   //This example function is found in the DSP2833x_Gpio.c file and
   //illustrates how to set the GPIO to it's default state.
   //Setup only the GP I/O only for SPI-A functionality
   //This function is found in DSP2833x_Spi.c
   InitSpiaGpio();

   //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 DSP2833x_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 will populate the entire table, even if the interrupt
   //is not used in this example.  This is useful for debug purposes.
   //The shell ISR routines are found in DSP2833x_DefaultIsr.c.
   //This function is found in DSP2833x_PieVect.c.
   InitPieVectTable();

   spi_fifo_init();   // Initialize the Spi FIFO
   spi_init();        // init SPI

   //User specific code:
   //Interrupts are not used in this example.

   for(;;)
   {
     //Load Transfer Buffer with nothing
     SpiaRegs.SPITXBUF = 0x0000;

     //Wait until first set of data is received
     while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }

     //Read in first set of data
     first_data_set = SpiaRegs.SPIRXBUF;

     //Load Transfer Buffer with nothing
     SpiaRegs.SPITXBUF = 0x0000;

     //Wait until second set of data is received
     while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }

     //Read in second set of data
     second_data_set = SpiaRegs.SPIRXBUF;

     //Load Transfer Buffer with nothing
     SpiaRegs.SPITXBUF = 0x0000;

     //Wait until third set of data is received
     while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }

     //Read in third set of data
     third_data_set = SpiaRegs.SPIRXBUF;

     //Load Transfer Buffer with nothing
     SpiaRegs.SPITXBUF = 0x0000;

     //Wait until fourth set of data is received
     while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }

     //Read in fourth set of data
     fourth_data_set = SpiaRegs.SPIRXBUF;

     //Load Transfer Buffer with new command value
     SpiaRegs.SPITXBUF = 0xAAAA; //Test values to be sent back over SPI are loaded in here

     //Wait until server CC3200 request for new command value
     while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }

     //Read in fifth set of data (should be nothing)
     fifth_data_set = SpiaRegs.SPIRXBUF;
   }
}

void spi_init(){

   //SPICCR is a 8 bit register
   //Bit 7 (Software Reset): Set to 0, must be cleared before configuration
   //Bit 6 (Clock Polarity): Set to 0, data outputted on rising edge and data incoming is falling edge
   //Bit 5 (Reserved): No writing allowed
   //Bit 4 (SPI Loopback): Set to 0 to disable, only for internal test only
   //Bit 3-0 (Character length bits): Set to 0b1111 for 16 bit character (CC3200 is sending two character totaling 16 bits)
   SpiaRegs.SPICCR.all =0x000F;

   //SPICTL is a 8 bit register
   //Bit 7-5 (Reserved): No writing allowed
   //Bit 4 (Overrun Interrupt Enable): Set to 0 for the time being, just trying to do a simple SPI connection
   //Bit 3 (Clock Phase): Set to 0, normal SPI clocking scheme (without being delayed one-half cycle)
   //Bit 2 (Master/Slave bit): Set to 0 to be the slave
   //Bit 1 (Talk bit): Set to 1, trying to send data back
   //Bit 0 (SPI Interrupt Enable): Set to 0, not worried about interrupts right now
   SpiaRegs.SPICTL.all =0x0002;

   //This register does not matter since clock is coming from CC3200-LAUNCHXL
   SpiaRegs.SPIBRR =0x007F;

   //SPICCR is a 8 bit register
   //Bit 7 (Software Reset): Set to 1, must be set when ready for data transmission
   //Bit 6 (Clock Polarity): Set to 0, data outputted on rising edge and data incoming is falling edge
   //Bit 5 (Reserved): No writing allowed
   //Bit 4 (SPI Loopback): Set to 0 to disable, only for internal test only
   //Bit 3-0 (Character length bits): Set to 0b1111 for 16 bit character (CC3200 is sending two character totaling 16 bits)
   SpiaRegs.SPICCR.all =0x008F;

   //Set so breakpoints don't disturb transmission
   SpiaRegs.SPIPRI.bit.FREE = 1;
}

void spi_fifo_init(){

   //Initialize SPI FIFO registers
   SpiaRegs.SPIFFTX.all=0xE040;
   SpiaRegs.SPIFFRX.all=0x204f;
   SpiaRegs.SPIFFCT.all=0x0;
}

  • Dalen

    Please provide some oscilloscope captures. Also, verify that your phase and polarity settings agree between the devices. I know that the C2000 SPI does not necessarily match the Wikipedia definitions. seems like you might be just sampling the data on the wrong edges. At a first glance, it looks like you might be "getting lucky" and getting the correct bit value. I do find it odd that even 0xFFFF is not sampled properly, so that might not be the only thing.
    What SPICLK frequencies are you operating at?
  • This picture below is when the TMDSDOCK28335 is sending 0x274E, and I am receiving 0xA713 (as stated in the chart). Bits change roughly every 10us (or 100kHz). I also think the "spikes" at each end are start and stop signals? Also, it appears that the data is right, but I may be reading it in wrong.

    This picture below is when TMDSDOCK is sending 0xFFFF, but I am still receiving 0xFF7F. Again, the data coming in is right, but is being read wrong.

    This picture below is when TMDSDOCK is sending 0xABCD, but I am still receiving 0xE655. Again, the data coming in is right, but it appears there is an extra high bit tagged on the end.

    This picture below is when TMDSDOCK is sending 0x5555, but I am still receiving 0xAA2A. Notice that the fourth high bit stay high for twice as long as it should, and so does the last bit.

    If you look at my comment on line 98 of the CC3200 code, the clock polarity and phase has been set to 0 using the macro SPI_SUB_MODE_0. On the TMDSDOCK28335 code, the register SpiaRegs.SPICCR.all is equal to 0x008F (0b0000000010001111). Bit 6 controls the clock polarity, and when this bit is set to 0, data is outputted on rising edge and data incoming is falling edge. The register SpiaRegs.SPICTL.all is equal to 0x0002 (0b0000000000000010). Bit 3 controls the clock phase, and when this bit is set to 0, then normal SPI clocking scheme (without being delayed one-half cycle). I have all of this as comments in both code sets, plus more, if you need any more information on why I set the registers as I did.

    The bit rate set by the CC3200 is 100,000 bits per second (there is a macro setup for it on line 24). So that should make the SPICLK pin be 10uH.

  • Maybe someone from the CC3200-LAUNCHXL would know what is happening? Since it appears the data is coming in correctly, then I am guessing that the CC3200 SPI peripheral is reading in the data wrong.
  • Dalen,

    I am concerned with those spikes in your code. they should not be there. I will see if I can get a CC3200 rep over to this post.
    Can you share the scope captures with additional signal lines? A clock reference would be very useful here. If you can also add the SPISTE with the data on another plot if you cannot fit them all on that scope. I think those runt pulses will correspond with the SPISTE being driven before and after the transaction.
    Have you tried slowing down SPICLK to test? If this helps, there may be some timing questions that need to be addressed.
  • Hi Dalen,

    Yes, the additional signal lines will be needed to analyze what is happening. Please add in the Clock and CS lines to a couple of the captures.

    Thanks,
    Ben M
  • Dalen,

    Were you able to figure this out?

    Thanks,
    Mark