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.

TMS320F28027: How to use SPI

Part Number: TMS320F28027
Other Parts Discussed in Thread: CONTROLSUITE

Hi, I don't have very musch experience working with SPI. I had a project with Arduino and an ADXL355 sensor. I used the Arduino SPI library. From the ADXL355 datasheetfrom datasheet

To access the ID register, the register address is shifted to the left by 1 and ORed with 1. Then the ID is sent. Is this correct?

Is it a 16 bit interface or 8 bit? When I try this code with adapted from the SPI no interrupt example from controlSuite:

sdata = 0x01;
SPI_write(mySpi, sdata);

while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
{
}
rdata = SPI_read(mySpi);

rdata is 1.

If change

    SPI_setCharLength(mySpi, SPI_CharLength_16_Bits);

to

    SPI_setCharLength(mySpi, SPI_CharLength_8_Bits);

and make sdata and rdata uint8_t, rdata is 0x100 accroding to the debugger which doesn't make sense because it is 8 bits. What am I doing wrong?

  • Hi Ray,

    Looking at the timing diagram you shared, it look like the SPI is configured for 8-bit configuration. This means that you need to configure the SPI in your C2000 device as 8-bit. Also you need to make sure the baud rate and clock polarities also match.
    I do not understand how the rdata variable is read as 0x100 since the rdata variable itself of uint8 type. Also since you have changed the data length of SPI to 8, it is a good idea to mask the received data by 0xFF.
    Can you also check the RXBUF register in the SPI module and see whether the data is received properly?

    Thanks and Regards,
    Veena
  • with this code:

    uint8_t sdata;  // send data
    uint8_t rdata;  // received data
    uint8_t SPIRXContents;
    
    //...
    
    sdata = 0x01;
    SPI_write(mySpi, sdata);
    
    while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
    {}
    rdata = (SPI_read(mySpi) & 0xff);
    SPIRXContents = (SpiaRegs.SPIRXBUF & 0xff);

    rdata is 0 and SPIRXContents is 200 (0xC8)

  • From to the ADX355 data sheet:

    based on this post:  https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/319066 and TMS320x2802x SPI guide:

    SpiaRegs.SPICCR.all =0x0007;
    SpiaRegs.SPICTL.all =0x0006;
    SpiaRegs.SPICCR.all =0x0087;

    returns the same results as the previously.

      

  • Hi,

    Can you provide us more details on what data you are sending and what is the expected data in?

    I hope you are aware that SPI is a full-duplex protocol. A SPI transmit always accompanies a receive.

    When you send a command via SPI, the response is not expected to be part of this transaction. You need to initiate another SPI transaction (you could send some dummy data) to get the actual response form the slave.

    I believe in your code you are reading the RX BUF register immediately after the one SPI send. I believe you should follow the sequence below:

    • Send command to the slave
    • Do a dummy read to RXBUF (the slave might respond with some dummy data)
    • Send some dummy data (to get the actual response)
    • Read RXBUF for the actual response.

    Thanks and Regards,

    Veena

  • Thank you for your help Veena.

    I am trying to access the the ID register of the device which is at address 0x00. According to the sensor data sheet it expects the address shifted to the left and the LSB is RW' bit. So the data sent is 0x01 to read the device ID register. 

    the following still is not working:

        sdata = 0x01;
        SPI_write(mySpi, sdata);
    
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
        sdata = 0x00; //dummy data
        SPI_write(mySpi, sdata);
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
        rdata = (SPI_read(mySpi) & 0xff);

    I am new with SPI and C2000, Thank you for your help.

  • Hi Ray,

    I currently do not have such a setup to experiment. But looking at your code snippet, I do not see a read from the RX buffer after the first transaction. Can you try adding a SPI read after the first wait and before the second write

    sdata = 0x01;
    SPI_write(mySpi, sdata);


    while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
    {
    }
    <------ Add a dummy SPI read here

    sdata = 0x00; //dummy data
    SPI_write(mySpi, sdata);
    while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
    {
    }
    rdata = (SPI_read(mySpi) & 0xff);


    Thanks and Regards,
    Veena
  • Hi Veena.

    Still not working.

    Complete code:

    //#############################################################################
    //
    //  File:   Example_F2802xSpi_FFDLB.c
    //
    //  Title:  F2802x Device Spi Digital Loop Back program.
    //
    //! \addtogroup example_list
    //!  <h1>SPI Digital Loop Back</h1>
    //!
    //!   This program is a SPI example that uses the internal loopback of
    //!   the peripheral.  Interrupts are not used.
    //!
    //!   A stream of data is sent and then compared to the received stream.
    //!
    //!   The sent data looks like this:
    //!   0000 0001 0002 0003 0004 0005 0006 0007 .... FFFE FFFF
    //!
    //!   This pattern is repeated forever.
    //!
    //!   Watch Variables:
    //!   - sdata - sent data
    //!   - rdata - received data
    //
    //#############################################################################
    // $TI Release: F2802x Support Library v230 $
    // $Release Date: Fri May  8 07:43:05 CDT 2015 $
    // $Copyright: Copyright (C) 2008-2015 Texas Instruments Incorporated -
    //             http://www.ti.com/ ALL RIGHTS RESERVED $
    //#############################################################################
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    #include "f2802x_common/include/adc.h"
    #include "f2802x_common/include/clk.h"
    #include "f2802x_common/include/flash.h"
    #include "f2802x_common/include/gpio.h"
    #include "f2802x_common/include/pie.h"
    #include "f2802x_common/include/pll.h"
    #include "f2802x_common/include/spi.h"
    #include "f2802x_common/include/wdog.h"
    
    // Prototype statements for functions found within this file.
    // interrupt void ISRTimer2(void);
    void delay_loop(void);
    void spi_xmit(uint16_t a);
    void spi_fifo_init(void);
    void spi_init(void);
    void error(void);
    
    ADC_Handle myAdc;
    CLK_Handle myClk;
    FLASH_Handle myFlash;
    GPIO_Handle myGpio;
    PIE_Handle myPie;
    SPI_Handle mySpi;
    
    uint8_t sdata;  // send data
    uint8_t rdata;  // received data
    uint8_t SPIRXContents;
    
    void main(void)
    {
    
        CPU_Handle myCpu;
        PLL_Handle myPll;
        WDOG_Handle myWDog;
    
        // Initialize all the handles needed for this application
        myAdc = ADC_init((void *)ADC_BASE_ADDR, sizeof(ADC_Obj));
        myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
        myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));
        myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
        myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
        myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
        myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
        mySpi = SPI_init((void *)SPIA_BASE_ADDR, sizeof(SPI_Obj));
        myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));
    
        // Perform basic system initialization
        WDOG_disable(myWDog);
        CLK_enableAdcClock(myClk);
        (*Device_cal)();
    
        //Select the internal oscillator 1 as the clock source
        CLK_setOscSrc(myClk, CLK_OscSrc_Internal);
    
        // Setup the PLL for x10 /2 which will yield 50Mhz = 10Mhz * 10 / 2
        PLL_setup(myPll, PLL_Multiplier_10, PLL_DivideSelect_ClkIn_by_2);
    
        // Disable the PIE and all interrupts
        PIE_disable(myPie);
        PIE_disableAllInts(myPie);
        CPU_disableGlobalInts(myCpu);
        CPU_clearIntFlags(myCpu);
    
        // If running from flash copy RAM only functions to RAM
    #ifdef _FLASH
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
    #endif
    
        // Initialize GPIO
        GPIO_setPullUp(myGpio, GPIO_Number_16, GPIO_PullUp_Enable);
        GPIO_setPullUp(myGpio, GPIO_Number_17, GPIO_PullUp_Enable);
        GPIO_setPullUp(myGpio, GPIO_Number_18, GPIO_PullUp_Enable);
        GPIO_setPullUp(myGpio, GPIO_Number_19, GPIO_PullUp_Enable);
        GPIO_setQualification(myGpio, GPIO_Number_16, GPIO_Qual_ASync);
        GPIO_setQualification(myGpio, GPIO_Number_17, GPIO_Qual_ASync);
        GPIO_setQualification(myGpio, GPIO_Number_18, GPIO_Qual_ASync);
        GPIO_setQualification(myGpio, GPIO_Number_19, GPIO_Qual_ASync);
        GPIO_setMode(myGpio, GPIO_Number_16, GPIO_16_Mode_SPISIMOA);
        GPIO_setMode(myGpio, GPIO_Number_17, GPIO_17_Mode_SPISOMIA);
        GPIO_setMode(myGpio, GPIO_Number_18, GPIO_18_Mode_SPICLKA);
        GPIO_setMode(myGpio, GPIO_Number_19, GPIO_19_Mode_SPISTEA_NOT);
    
        // Setup a debug vector table and enable the PIE
        PIE_setDebugIntVectorTable(myPie);
        PIE_enable(myPie);
    
        spi_init();         // Initialize SPI
        spi_fifo_init();    // Initialize the SPI FIFOs
    
        sdata = 0x01;
        SPI_write(mySpi, sdata);
    
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
        rdata = (SPI_read(mySpi) & 0xff);
    
        sdata = 0x00; //dummy data
        SPI_write(mySpi, sdata);
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
        rdata = (SPI_read(mySpi) & 0xff);
        SPIRXContents = (SpiaRegs.SPIRXBUF & 0xff);
    
        while(1);    
    }
    
    void delay_loop()
    {
        long      i;
    
        for (i = 0; i < 1000000; i++)
        {
        }
    
        return;
    }
    
    void error(void)
    {
        __asm(" ESTOP0");     // Test failed!! Stop!
        for (;;)
        {
        }
    }
    
    void spi_init()
    {
        CLK_enableSpiaClock(myClk);
    
        // Reset on, rising edge, 16-bit char bits
        SPI_setCharLength(mySpi, SPI_CharLength_8_Bits);
    
        // Enable master mode, normal phase,
        // enable talk, and SPI int disabled.
        SPI_setMode(mySpi, SPI_Mode_Master);
        SPI_enableTx(mySpi);
    
        SPI_setBaudRate(mySpi, SPI_BaudRate_1_MBaud);
    
        // Relinquish SPI from Reset
        SPI_enableLoopBack(mySpi);
        SPI_enable(mySpi);
    
        // Set so breakpoints don't disturb xmission
        SPI_setPriority(mySpi, SPI_Priority_FreeRun);
    
    //    SpiaRegs.SPICCR.all =0x0007;
    //    SpiaRegs.SPICTL.all =0x0006;
    //    SpiaRegs.SPICCR.all =0x0087;
    
        return;
    }
    
    void spi_fifo_init()
    {
        // Initialize SPI FIFO registers
        SPI_enableChannels(mySpi);
        SPI_enableFifoEnh(mySpi);
        SPI_resetTxFifo(mySpi);
        SPI_clearTxFifoInt(mySpi);
        SPI_resetRxFifo(mySpi);
        SPI_clearRxFifoInt(mySpi);
        SPI_setRxFifoIntLevel(mySpi, SPI_FifoLevel_4_Words);
    
        return; 
    }
    
    //===========================================================================
    // No more.
    //===========================================================================
    
    

     

  • Ray,

    When operating the C2000 SPI with less than a 16-bit word, the transmit data must be left justified. As the SPI is just a shift register, it will shift the MSBit left out to the transmit line, and receive the MSBit into the right most bit. Check out Section 1.5.2 Data Format in the SPI Users Guide SPRUG71 for a great explanation of the concept. This behavior is clear when you look at your current situation. you write 0x01 to SPITXBUF and the SPI will start transmitting 8 bits. after 8 bits are sent, SPIRXBUF sees 0x0100. That 1 was shifted left by 8 bits and the data it received was all zeros.

    As Veena mentioned, when you read the RXBUF, you will see 16-bits, but since you only care about the 8 bits received, you will need to mask off the extra bits.

    Overall, your program flow looks fine, so I think that you are on the right track.

    Thanks,
    Mark
  • Thank you for your help.  I now understand why about transmit data must to be left justified. As a sanity check, I fetch the data with an Arduino and I run the loopback program with SOMI connected to SIMO and both check out.

    I commented out the SPI_enableLoopBack(). All that is ever returned is 0xff.

  • Thank you for your help Veena.
    Mark's reply about the transmit data being left justified was helpful. I ran sanity checks by fetching data with an Arduino and running the loopback program with SOMI and SIMO connected and they checked out.

    I also commented out SPI_enableLoopBack(). All that is ever returned is 0xff
  • Shouldn't this code work?

     sdata = 0x0100;
        SPI_write(mySpi, sdata);
    
        // Wait until data is received
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
    
        rdata = SPI_read(mySpi);
        SPI_write(mySpi, sdata);
    
        // Wait until data is received
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
    
        rdata = (SPI_read(mySpi)&  0xff);
    

  • Ray,

    This looks like it would work. is it not?

    -Mark
  • It's working with the following code. SPI_setCharLength(mySpi, SPI_CharLength_16_Bits) sets the ionterface to 16 bits. I thought it should be 16 becasue of the ADXL355 datasheet. Thanks alot for your help.

    //#############################################################################
    // $TI Release: F2802x Support Library v230 $
    // $Release Date: Fri May  8 07:43:05 CDT 2015 $
    // $Copyright: Copyright (C) 2008-2015 Texas Instruments Incorporated -
    //             http://www.ti.com/ ALL RIGHTS RESERVED $
    //#############################################################################
    
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    #include "f2802x_common/include/adc.h"
    #include "f2802x_common/include/clk.h"
    #include "f2802x_common/include/flash.h"
    #include "f2802x_common/include/gpio.h"
    #include "f2802x_common/include/pie.h"
    #include "f2802x_common/include/pll.h"
    #include "f2802x_common/include/spi.h"
    #include "f2802x_common/include/wdog.h"
    
    // Prototype statements for functions found within this file.
    // interrupt void ISRTimer2(void);
    void delay_loop(void);
    void spi_xmit(uint16_t a);
    void spi_fifo_init(void);
    void spi_init(void);
    void error(void);
    
    ADC_Handle myAdc;
    CLK_Handle myClk;
    FLASH_Handle myFlash;
    GPIO_Handle myGpio;
    PIE_Handle myPie;
    SPI_Handle mySpi;
    
    uint16_t sdata;  // send data
    uint16_t rdata;  // received data
    
    void main(void)
    {
    
        CPU_Handle myCpu;
        PLL_Handle myPll;
        WDOG_Handle myWDog;
    
        // Initialize all the handles needed for this application
        myAdc = ADC_init((void *)ADC_BASE_ADDR, sizeof(ADC_Obj));
        myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
        myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));
        myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
        myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
        myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
        myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
        mySpi = SPI_init((void *)SPIA_BASE_ADDR, sizeof(SPI_Obj));
        myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));
    
        // Perform basic system initialization
        WDOG_disable(myWDog);
        CLK_enableAdcClock(myClk);
        (*Device_cal)();
    
        //Select the internal oscillator 1 as the clock source
        CLK_setOscSrc(myClk, CLK_OscSrc_Internal);
    
        // Setup the PLL for x10 /2 which will yield 50Mhz = 10Mhz * 10 / 2
        PLL_setup(myPll, PLL_Multiplier_10, PLL_DivideSelect_ClkIn_by_2);
    
        // Disable the PIE and all interrupts
        PIE_disable(myPie);
        PIE_disableAllInts(myPie);
        CPU_disableGlobalInts(myCpu);
        CPU_clearIntFlags(myCpu);
    
        // If running from flash copy RAM only functions to RAM
    #ifdef _FLASH
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
    #endif
    
        // Initialize GPIO
        GPIO_setPullUp(myGpio, GPIO_Number_16, GPIO_PullUp_Enable);
        GPIO_setPullUp(myGpio, GPIO_Number_17, GPIO_PullUp_Enable);
        GPIO_setPullUp(myGpio, GPIO_Number_18, GPIO_PullUp_Enable);
        GPIO_setPullUp(myGpio, GPIO_Number_19, GPIO_PullUp_Enable);
        GPIO_setQualification(myGpio, GPIO_Number_16, GPIO_Qual_ASync);
        GPIO_setQualification(myGpio, GPIO_Number_17, GPIO_Qual_ASync);
        GPIO_setQualification(myGpio, GPIO_Number_18, GPIO_Qual_ASync);
        GPIO_setQualification(myGpio, GPIO_Number_19, GPIO_Qual_ASync);
        GPIO_setMode(myGpio, GPIO_Number_16, GPIO_16_Mode_SPISIMOA);
        GPIO_setMode(myGpio, GPIO_Number_17, GPIO_17_Mode_SPISOMIA);
        GPIO_setMode(myGpio, GPIO_Number_18, GPIO_18_Mode_SPICLKA);
        GPIO_setMode(myGpio, GPIO_Number_19, GPIO_19_Mode_SPISTEA_NOT);
    
        // Setup a debug vector table and enable the PIE
        PIE_setDebugIntVectorTable(myPie);
        PIE_enable(myPie);
    
        spi_init();         // Initialize SPI
        spi_fifo_init();    // Initialize the SPI FIFOs
    
        sdata = 0x0100;
        SPI_write(mySpi, sdata);
    
        // Wait until data is received
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
    
        rdata = SPI_read(mySpi);
        SPI_write(mySpi, sdata);
    
        // Wait until data is received
        while(SPI_getRxFifoStatus(mySpi) == SPI_FifoStatus_Empty)
        {
        }
    
        // Check against sent data
    
        rdata = (SPI_read(mySpi)&  0xff);
    
         while(1);
    
    
    }
    
    void delay_loop()
    {
        long      i;
    
        for (i = 0; i < 1000000; i++)
        {
        }
    
        return;
    }
    
    void error(void)
    {
        __asm(" ESTOP0");     // Test failed!! Stop!
        for (;;)
        {
        }
    }
    
    void spi_init()
    {
        CLK_enableSpiaClock(myClk);
    
        // Reset on, rising edge, 16-bit char bits
        SPI_setCharLength(mySpi, SPI_CharLength_16_Bits);
    
        // Enable master mode, normal phase,
        // enable talk, and SPI int disabled.
        SPI_setMode(mySpi, SPI_Mode_Master);
        SPI_enableTx(mySpi);
    
        SPI_setBaudRate(mySpi, SPI_BaudRate_1_MBaud);
    
        // Relinquish SPI from Reset
        //SPI_enableLoopBack(mySpi);
        SPI_enable(mySpi);
    
        // Set so breakpoints don't disturb xmission
        SPI_setPriority(mySpi, SPI_Priority_FreeRun);
    
        return;
    }
    
    void spi_fifo_init()
    {
        // Initialize SPI FIFO registers
        SPI_enableChannels(mySpi);
        SPI_enableFifoEnh(mySpi);
        SPI_resetTxFifo(mySpi);
        SPI_clearTxFifoInt(mySpi);
        SPI_resetRxFifo(mySpi);
        SPI_clearRxFifoInt(mySpi);
        SPI_setRxFifoIntLevel(mySpi, SPI_FifoLevel_4_Words);
    
        return;
    }
    
    //===========================================================================
    // No more.
    //===========================================================================
    
  • Ray,

    Ah yes, we both must have overlooked that. I am glad that you were able to resolve the issue. Please don't hesitate to post if you encounter issues again in the future.

    Regards,
    Mark