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 garbage data with 16 bit MCU

Other Parts Discussed in Thread: MSP430G2533

Hi,

I need some advice on connecting the TIVA C Launchpad(Master) with 16 bit MCU(MSP430) through SPI.
The SSI is set for 1MHz frequency and 8-bit mode.The slave MSP430G2533 is running at 16mhz.
The slave reset(CS) is done through a GPIO.

The communications seems to be proper but I always receive garabge data on both the
Master and Slave buffers. Below is the code used from the StellarisWare.
I have been trying this for a while without success, please let me know if there is anything
else to be considered when using TIVA C's SSI module.

int main()
{

// Number of bytes to send and receive.
//
#define NUM_SSI_DATA 7

unsigned long ulDataTx;
unsigned long ulDataRx;
unsigned long ulindex;

// Set the clocking to run directly from the crystal.
ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);


// The SSI0 peripheral must be enabled for use.
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

// The SSI0 peripheral must be enabled for use.
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

// TODO: change this to whichever GPIO port you are using.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);


// TODO: change this to select the port/pin you are using.
GPIOPinConfigure(GPIO_PA4_SSI0RX);
GPIOPinConfigure(GPIO_PA5_SSI0TX);
GPIOPinConfigure(GPIO_PA2_SSI0CLK);
GPIOPinConfigure(GPIO_PA3_SSI0FSS);


// Configure the GPIO settings for the SSI pins.
// SSI0CLK - PF2 (was PA2)
// SSI0Fss - PF3 (was PA3)
// SSI0Rx - PF0 (was PA4)
// SSI0Tx - PF1 (was PA5)
GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5| GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);


// Configure and enable the SSI port for SPI master mode. Use SSI0,
// system clock supply, idle clock level low and active low clock in
// freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8);


// Enable the SSI0 module.
SSIEnable(SSI0_BASE);

// Read any residual data from the SSI port.
while(SSIDataGetNonBlocking(SSI0_BASE, &ulDataRx))
{
}


// Send N bytes of data.
for(ulindex = 0; ulindex < NUM_SSI_DATA; ulindex++)
{

ulDataTx = ulindex;
// Send the data using the "blocking" put function. This function
// will wait until there is room in the send FIFO before returning.
SSIDataPut(SSI0_BASE,ulDataTx);


// Wait until SSI0 is done transferring all the data in the transmit FIFO.
while(SSIBusy(SSI0_BASE))
{
}

//Receive Data
SSIDataGet(SSI0_BASE,&ulDataRx);

//Mask off the 8 bit data
ulDataRx &= 0x00FF;

}

}

  • Must note - code you've provided does not reveal, "great attention to detail."  In its forum presentation - doubtful that it ran!

    // Set the clocking to run directly from the crystal.
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    // The SSI0 peripheral must be enabled for use.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

    // The SSI0 peripheral must be enabled for use.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

    // TODO: change this to whichever GPIO port you are using.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);

    a)   // Set the clocking to run directly from the crystal.   *** not really - USE_PLL & SYSDIV_5 argue against! 
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    b) // The SSI0 peripheral must be enabled for use.  *** two for price of one - and poor Port_A (SSI0) was not enabled!SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

    // The SSI0 peripheral must be enabled for use.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

    c) // TODO: change this to whichever GPIO port you are using.   *** yet you later, "Pin Config & Pin Type" GPIOA !
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP); 

    Suspect your post - and code reality - differ.  Might further (i.e. some) time in "proof" better enable analysis? {GI->GO}

  • Thank you so much for the quick comments.
    And I am sorry for posting incomplete code.

    Actually the clock setting is below:
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    And I have enabled the necessary peripheral also.
    The actual code is the attached one, above I just tried to minimize which made the
    wrong impression about the settings.

    //*****************************************************************************
    // 
    //  Based on Stellaris sample code(Stellaris launchPad)
    // 
    // Copyright (c) 2012 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 9453 of the EK-LM4F120XL Firmware Package.
    //
    //*****************************************************************************
    
    
    
    #include "inc/lm4f120h5qr.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"
    #include "utils/uartstdio.h"
    
    #include "inc/hw_ssi.h"
    #include "driverlib/ssi.h"
    
    #include <stdint.h>
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Timer (timers)</h1>
    //!
    //!
    //! UART0, connected to the Stellaris Virtual Serial Port and running at 115,200,
    //! 8-N-1, is used to display messages from this application.
    //
    //*****************************************************************************
    
    
    //*****************************************************************************
    //
    // Flags that contain the current value of the interrupt indicator as displayed
    // on the UART.
    //
    //*****************************************************************************
    unsigned long g_ulFlags;
    
    void UARTInitialize();
    void SPIInitialize();
    void SPI_Send();
    void SlaveSelect();
    
    volatile uint32_t ui32Loop;
    //*****************************************************************************
    //
    // Number of bytes to send and receive.
    //
    //*****************************************************************************
    #define NUM_SSI_DATA 7
    
    unsigned long ulDataTx; 
    unsigned long ulDataRx; 
    unsigned long sent[8];
    unsigned long ulindex;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }
    #endif
    
    
    //UART to display status on the terminal
    
    void UARTInitialize()
    {
    	//! The following UART signals are configured only for displaying console
    	//! messages for this example.  These are not required for operation of SSI0.
    	//! - UART0 peripheral
    	//! - GPIO Port A peripheral (for UART0 pins)
    	//! - UART0RX - PA0
    	//! - UART0TX - PA1
        // Initialize the UART and write status.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
        UARTStdioInit(0);
    
    }
    
    void SPIInitialize()
    {
    	//! This example uses the following peripherals and I/O signals.  You must
    	//! review these and change as needed for your own board:
    	//! - SSI0 peripheral
    	//! - GPIO Port A peripheral (for SSI0 pins)
    	//! - SSI0CLK - PA2
    	//! - SSI0Fss - PA3
    	//! - SSI0Rx  - PA4
    	//! - SSI0Tx  - PA5
    
        // Display the setup on the console.
        //
        UARTprintf("SSI ->\n");
        UARTprintf("  Mode: SPI\n");
        UARTprintf("  Data: 8-bit\n\n");
    
    
    	    //
    	    // The SSI0 peripheral must be enabled for use.
    	    //
    	    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    
    	    //
    	        // The SSI0 peripheral must be enabled for use.
    	        //
    	        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    	        //
    	        // For this example SSI0 is used with PortF[3:0] (was PortA[5:2]).  The actual port and pins
    	        // used may be different on your part, consult the data sheet for more
    	        // information.  GPIO port A needs to be enabled so these pins can be used.
    	        // TODO: change this to whichever GPIO port you are using.
    	        //
    	        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    
    	        //
    	        // Configure the pin muxing for SSI0 functions on port (F0,F1,F2,F3 (was A2, A3, A4, and A5.)
    	        // This step is not necessary if your part does not support pin muxing.
    	        // TODO: change this to select the port/pin you are using.
    	        //
    	        GPIOPinConfigure(GPIO_PA4_SSI0RX);
    	        GPIOPinConfigure(GPIO_PA5_SSI0TX);
    	        GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    	        GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    
    	        //
    	        // Configure the GPIO settings for the SSI pins.  This function also gives
    	        // control of these pins to the SSI hardware.  Consult the data sheet to
    	        // see which functions are allocated per pin.
    	        // The pins are assigned as follows:
    	        // SSI0CLK - PF2 (was PA2)
    	        // SSI0Fss - PF3 (was PA3)
    	        // SSI0Rx  - PF0 (was PA4)
    	        // SSI0Tx  - PF1 (was PA5)
    	        // TODO: change this to select the port/pin you are using.
    	        //
    	        GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5| GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
    
    	        //
    	        // Configure and enable the SSI port for SPI master mode.  Use SSI0,
    	        // system clock supply, idle clock level low and active low clock in
    	        // freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
    	        // For SPI mode, you can set the polarity of the SSI clock when the SSI
    	        // unit is idle.  You can also configure what clock edge you want to
    	        // capture data on.  Please reference the datasheet for more information on
    	        // the different SPI modes.
    	        //
    	        SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8);
    
    	        //
    	        // Enable the SSI0 module.
    	        //
    	        SSIEnable(SSI0_BASE);
    
    	        //enable SSI (internal) loopback mode
    	        //HWREG(SSI0_BASE + SSI_O_CR1) |= SSI_CR1_LBM;
    
    }
    
    //Send and receive the data through SPI
    
    void SPI_Send()
    {
        //
        // Read any residual data from the SSI port.  This makes sure the receive
        // FIFOs are empty, so we don't read any unwanted junk.  This is done here
        // because the SPI SSI mode is full-duplex, which allows you to send and
        // receive at the same time.  The SSIDataGetNonBlocking function returns
        // "true" when data was returned, and "false" when no data was returned.
        // The "non-blocking" function checks if there is any data in the receive
        // FIFO and does not "hang" if there isn't.
        //
        while(SSIDataGetNonBlocking(SSI0_BASE, &ulDataRx))
        {
        }
    
    
        // Send N bytes of data.
        //
        for(ulindex = 0; ulindex < NUM_SSI_DATA; ulindex++)
        {
        	
            ulDataTx = ulindex;
            //
            // Display the data that SSI is transferring.
            //
            UARTprintf("\nSent:\n  ");
            UARTprintf("'%x' ", ulDataTx);
            sent[ulindex]=ulDataTx;
    
            //
            // Send the data using the "blocking" put function.  This function
            // will wait until there is room in the send FIFO before returning.
            // This allows you to assure that all the data you send makes it into
            // the send FIFO.
            //
            SSIDataPut(SSI0_BASE,ulDataTx); 
      
            //
            // Wait until SSI0 is done transferring all the data in the transmit FIFO.
            //
            while(SSIBusy(SSI0_BASE))
            {
            }
    
            //Receive Data
            SSIDataGet(SSI0_BASE,&ulDataRx); //&ulDataRx[ulindex]);
    
            //Mask off the 8 bit data
            ulDataRx &= 0x00FF;
          
            UARTprintf("\nReceived:\n  ");
            UARTprintf("'%x' ", ulDataRx);
    
            UARTprintf("\n");
            
            //Delay between the transfers
            for(ui32Loop = 0; ui32Loop < 300000; ui32Loop++)
            {
            }
    
        }
    
    
    
    }
    
    
    
    int main(void)
    {
        int i;
    
        // Enable lazy stacking for interrupt handlers.  This allows floating-point
        // instructions to be used within interrupt handlers, but at the expense of
        // extra stack usage.
        ROM_FPULazyStackingEnable();
    
    
       // Set the clocking to run directly from the crystal.
       ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
       // ROM_SysCtlClockSet(SYSCTL_SYSDIV_7 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    
        UARTInitialize();
        UARTprintf("This is SPI sample program\n");
        SPIInitialize();
    
        SlaveSelect();
    
       //Send and receive the data
        SPI_Send();
    
        while(1);
    
    }
    
    
    void SlaveSelect()
    {
    	 //
    	    // Enable the GPIO port that is used for the on-board LED.
    	    //
    	    SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF;
    
    	    //
    	    // Do a dummy read to insert a few cycles after enabling the peripheral.
    	    //
    	    ui32Loop = SYSCTL_RCGC2_R;
    
    	    //
    	    // Enable the GPIO pin for the LED (PF3).  Set the direction as output, and
    	    // enable the GPIO pin for digital function.
    	    //
    	    GPIO_PORTF_DIR_R = 0x08;
    
    	    //
    	        // Reset the slave
    	        //
    	        GPIO_PORTF_DATA_R &= ~(0x08);
    	        for(ui32Loop = 0; ui32Loop < 200; ui32Loop++)
    	        {
    	        }
    	        GPIO_PORTF_DATA_R |= 0x08;
    
    	        //
    	        // Wait for slave to initialize
    	        //
    	        for(ui32Loop = 0; ui32Loop < 400000; ui32Loop++)
    	        {
    	        }
    	        for(ui32Loop = 0; ui32Loop < 400000; ui32Loop++)
    	        {
    
    }
    
    

  • No one wants/seeks your sorrow.  Realize that your, "real code" saves time, effort, wear/tear upon your, "remote staff."

    I'm jammed right now - your corrected/reviewed code should prove more enticing to (quicker) others... 

    You may further ease analysis by reporting any scope captures or other observations bit beyond, "garbage" or (famed) "did not work!"  And - KISS always in favor - thus the attempt at passing 1 or 2 test bytes (rather than the 7 your code indicates) may "unmask and/or prevent" over-runs or other unwanted complications...

  • Thank you, after doing the analysis I was able to able to resolve the problem.
    the frame format inside SSIConfigSetExpClk() was set to "SSI_FRF_MOTO_MODE_1" and
    it was supposed to be set as "SSI_FRF_MOTO_MODE_3".

  • Prad1 said:
    after doing the analysis I was able to able to resolve the problem.

    Good for you - very good news.

    You're not alone - the same massive feature set which makes the ARM so attractive has the downside that. "great attention to detail" must be observed/practiced.  And - now you've "drilled down" - matched your slave's need to your more flexible master - and have succeeded.

    Good job and neat that you've "closed the loop" and guided others who may encounter similar...  Merci et bon chance, mon ami...