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.

CCS/EK-TM4C123GXL: Send/Receive data using SSI

Part Number: EK-TM4C123GXL

Tool/software: Code Composer Studio

Hello i am using following code to send and receive data using SSI interface between master and slave, my goal is i send some value from master to slave and slave returns the value multiplied with some number.

the issue with following code is slave can receive value "ui32Message"  which is 800 but the value Master receives "ui32MessageX" it stays zero.And also there is another issue when i use SSIDataGet(SSI0_BASE, &ui32Message) in one controller to recieve data and dont power the other controller(simply other controller is not connected), program gets stuck on that point next statments arent performed unless i connect it to other controller(power the other controller).

//Slave

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/flash.h"
#include "driverlib/adc.h"
#include "driverlib/ssi.h"
#include "drivers/buttons.h"
#include "utils/uartstdio.h"


/******************************************************************************
 * Configure the UART and its pins.  This must be called before UARTprintf(). *
 ******************************************************************************/
void ConfigureUART(void)
{
    // Enable the GPIO Peripheral used by the UART.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    // Enable UART0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    // Configure GPIO Pins for UART mode.
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    // Initialize the UART for console I/O.
    UARTStdioConfig(0, 115200, 16000000);
}

/***************************************
 * Main function, program entry point. *
 ***************************************/
int main(void)
{
    
    uint32_t ui32Message = 0;
    uint32_t ui32MessageX = 0;
    // Set the clocking to run at 50 MHz from the PLL.
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                       SYSCTL_OSC_MAIN);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 10000, 16);
    SSIEnable(SSI0_BASE);

    // Initialize the UART and configure it
    ConfigureUART();
    UARTprintf("\n******************\n* SSI slave logs *\n******************\n");

    while(1)
    {
        UARTprintf("\n ui32Message \n");
        SSIDataGet(SSI0_BASE, &ui32Message);
        UARTprintf("%d",ui32Message);
        UARTprintf("\n ui32Message recieved \n");        
        SysCtlDelay(SysCtlClockGet()/100);
        while(SSIBusy(SSI0_BASE));
        ui32MessageX=ui32Message+2;
        UARTprintf("%d",mx);
        SSIDataPut(SSI0_BASE, ui32MessageX);
        while(SSIBusy(SSI0_BASE));        
        UARTprintf("\------ui32MessageX Sent-----\n");

    }
}


//  Master

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/flash.h"
#include "driverlib/adc.h"
#include "driverlib/ssi.h"
#include "drivers/buttons.h"
#include "utils/uartstdio.h"



/******************************************************************************
 * Configure the UART and its pins.  This must be called before UARTprintf(). *
 ******************************************************************************/
void ConfigureUART(void)
{
    // Enable the GPIO Peripheral used by the UART.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    // Enable UART0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    // Configure GPIO Pins for UART mode.
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    // Initialize the UART for console I/O.
    UARTStdioConfig(0, 115200, 16000000);
}

uint32_t ui32Message = 0;
unit32_t ui32MessageX= 0;
int main(void)
{




    // Set the clocking to run at 50 MHz from the PLL.
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                       SYSCTL_OSC_MAIN);


//    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
//    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0xFF;
//


    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_3 | GPIO_PIN_2);


    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 10000, 16);
    SSIEnable(SSI0_BASE);
    // Initialize the UART and configure it
    ConfigureUART();
    UARTprintf("\n******************\n* SSI Master logs *\n******************\n");

    while(1)
    {
        ui32Message = 800;
        SSIDataPut(SSI0_BASE, ui32Message);
        while(SSIBusy(SSI0_BASE));
        UARTprintf("\ui32Message Sent\n");
        SysCtlDelay(SysCtlClockGet()/100);
        SSIDataGet(SSI0_BASE, &ui32MessageX);
        UARTprintf("%d",ui32MessageX);
        UARTprintf("\n ui32Message received \n");
        while(SSIBusy(SSI0_BASE));
    }
}

  • The SSI does a full duplex transmission each time the master dos an SSIDataPut(). Since you only did one SSIDataPut() from the master, the master sent 800, and stored in its receive buffer 0 because there was nothing in the slave's transmit buffer. Then the slave loads 802 in its transmit buffer, but the transfer will not start until the master does another call to SSIDataPut().

    What I think you want to do is:

           SSIDataPut(SSI0_BASE, ui32Message); // Send 800
           SSIDataGet(SSI0_BASE, &ui32MessageX); // Dummy read to empty buffer
           // Delay some time for slave to load new number
           SSIDataPut(SSI0_BASE, ui32Message); // Dummy send to get read data
           SSIDataGet(SSI0_BASE, &ui32MessageX); // Now we should get the 802
     

    That snippet of code will cause two full duplex transmissions in the first, the data from master to slave is valid, the data from slave to master is not valid. In the second, the data from master to slave is don't care, and the data from slave to master is valid.

  • using this code ui32MessageX value is now 65535.
  • i just realized i made a stupid mistake , i didnt add GPIOPinConfigure(GPIO_PA4_SSI0RX) in master code, and GPIOPinConfigure(GPIO_PA5_SSI0TX) in slave code so after adding this its working fine.
  • Bob,

    May we note & applaud the "detail, clarity, and care" which "filled" your response?    Most excellent!

    I believe it constructive to "break down" your response:

    • An, "introductory narrative" - well listed & explained the MCU's basic (yet necessary),  "SSI Ground Rules."     (SO important - yet rarely does such appear...)
    • Following then - nicely illustrating and commenting code    (to "drive home" adherence to the "ground rules")    (even cb1 was able to well understand)
    • Ending w/an "epilogue" (closing) which provided "unusual insight" into your MCU's SSI Mechanics.

    Surely a "Model Post" -  I'd "POUND" the  **  LIKE  ** button - but (somehow) the REWARD of LIKE - has, "Left the building..."

  • yep i totally agree, i thank all the community members i am getting a lot of help from you guys.
  • Good to hear such - Thank you!     Bob "Left the Park" on that posting - and I felt that the post's "uniqueness" deserved memorialization...
    Simply terrific...    (and serves as a highly effective,  "Model Response.")     (faster/lesser - "machine-gun" responses - Not so much!)

    The "method" by which "Bob chose to resolve poster's issue" proved that,  "High Detail" and "Ground-rules" - COULD be delivered - in a compact & time-efficient manner!

  •         for (i=0; i < 3 ; i++)
            {
    
            SSIDataGet(SSI0_BASE, &ui32Message[i]);
            SSIDataPut(SSI0_BASE, ui32MessageX[i]);
    
            SysCtlDelay(SysCtlClockGet()/100);
            while(SSIBusy(SSI0_BASE));
    
            SSIDataGet(SSI0_BASE, &ui32Message[i]);
            SSIDataPut(SSI0_BASE, ui32MessageX[i]);
            while(SSIBusy(SSI0_BASE));
    
            }
        

    Is there anyway to read multiple variables from slave like position and velocity of a motor? i could use an array with for loop but the other controller (master) wouldn't which value is position and which one is velocity?

  • As your Slave is an MCU - and if you've properly installed and enabled the proper "Position Sensor" - then both "Position & Velocity" are potentially available. (Velocity is defined as "delta P/delta t.")

    You would present the desired, "Position and Velocity" to the SPI's fifo in a known order. If you don't mind passing a slower data-rate you may present a "unique data byte" prior to either of those 2 variables - which would (very) well identify, "which is which."
  • i am using following code to get data in sequence,i works fine initially but when i reset the controller which is sending data, data sequence changes on receiving end,is there anyway get data in sequence.

    #define TM4C123GH6PM
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/flash.h"
    #include "driverlib/adc.h"
    #include "driverlib/ssi.h"
    #include "drivers/buttons.h"
    #include "inc/tm4c123gh6pm.h"
    #include "utils/uartstdio.h"
    
    
    /******************************************************************************
     * Configure the UART and its pins.  This must be called before UARTprintf(). *
     ******************************************************************************/
    void ConfigureUART(void)
    {
        // Enable the GPIO Peripheral used by the UART.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        // Enable UART0
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
        // Configure GPIO Pins for UART mode.
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
        // Use the internal 16MHz oscillator as the UART clock source.
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
        // Initialize the UART for console I/O.
        UARTStdioConfig(0, 115200, 16000000);
    }
    
    /***************************************
     * Main function, program entry point. *
     ***************************************/
        uint32_t ui32Message  [4];
        uint32_t ui32MessageX [4];
    
        uint32_t i;
    int main(void)
    {
    
    
        // Set the clocking to run at 50 MHz from the PLL.
        SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                           SYSCTL_OSC_MAIN);
        SysCtlPeripheralReset(SYSCTL_PERIPH_SSI0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    
        SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        GPIOPinConfigure(GPIO_PA2_SSI0CLK);
        GPIOPinConfigure(GPIO_PA3_SSI0FSS);
        GPIOPinConfigure(GPIO_PA4_SSI0RX);
        GPIOPinConfigure(GPIO_PA5_SSI0TX);
        GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
        SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 10000, 16);
        SSIEnable(SSI0_BASE);
        SSIIntEnable(SSI0_BASE, SSI_RXFF);
        SSIIntClear(SSI0_BASE, SSI_RXFF);
        SSIIntEnable(SSI0_BASE, SSI_RXOR);
        SSIIntClear(SSI0_BASE, SSI_RXOR);
        IntEnable ( INT_SSI0 ) ;
        IntMasterEnable();
    
        // Initialize the UART and configure it
        ConfigureUART();
        UARTprintf("\n******************\n* SSI slave logs *\n******************\n");
    
        while(1)
        {
        }
    
    
    }
    void SSI0IntHandler(void)
            {
        ui32MessageX[0]=5;
        ui32MessageX[1]=4;
        ui32MessageX[2]=3;
                unsigned long status=SSIIntStatus(SSI0_BASE, true);
                if(status & SSI_RXFF & SSI_RXOR)
                        {
                    for (i=0; i<4; i++)
                    {
                            SSIDataGetNonBlocking(SSI0_BASE, &ui32Message[i]);
                    }
    
                        }
                UARTprintf("\n Slave Data received\n");
                for (i=0; i<4; i++)
                {
                UARTprintf("\n %d \n",ui32Message[i]);
                SysCtlDelay(SysCtlClockGet()/1000);
                }
                SSIIntClear(SSI0_BASE, SSI_RXFF);
            }


    ///////////////           MasterCode     //////////////////////

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/flash.h"
    #include "driverlib/adc.h"
    #include "driverlib/ssi.h"
    #include "drivers/buttons.h"
    #include "utils/uartstdio.h"

    /******************************************************************************
    * Configure the UART and its pins. This must be called before UARTprintf(). *
    ******************************************************************************/


    uint32_t MISO_M[4];
    uint32_t MOSI_M[]={6,7,8,9};

    int main(void)
    {
    // Set the clocking to run at 50 MHz from the PLL.
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
    SYSCTL_OSC_MAIN);


    // HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    // HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0xFF;

    SysCtlPeripheralReset(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

    SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    // GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);


    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 10000, 16);
    SSIEnable(SSI0_BASE);
    // Initialize the UART and configure it

    while(1)
    {

    uint32_t i;
    for (i=0; i < 4 ; i++)
    {
    SSIDataPut(SSI0_BASE, MOSI_M[i]);

    SysCtlDelay(SysCtlClockGet()/100);

    while(SSIBusy(SSI0_BASE));

    }
    }
    }

  • Awais Mughal said:
    When I reset the controller which is sending data, data sequence changes on receiving end.    Is there anyway to get data in sequence?

    If you only,  "Reset the "Sending Controller" - it is difficult to accept your claim that,  "the data sequence changes on the receiving end."     (It proves far more likely (and logical) that your Sending Sequence has altered - as ONLY the Sending Controller has been reset.    Your "Receiving Controller" is "powerless" to alter such sequence - it simply "Reports what's been delivered" - don't you (now) agree?)

    You may consider adding a,  "Sequence Alignment byte" - sent immediately following any MCU Reset.    Upon the "Receiving Ends reception" (and recognition) - your prescribed "Sequence Order" is far better insured.     To add even more - "Sequence robustness" - you may "Periodically send the,  "Sequence Alignment byte" - which the Receive End can process - and greatly assists  your,  "Maintaining Correct Sequence!"    

    Note that I am suggesting that this,  "Periodic Sequence Alignment Byte" be  "Regularly Sent" - not just after any "Sending Controller's Reset."     And make high effort to insure that this "Alignment Byte is most UNLIKELY to occur - under "normal conditions!"     If this cannot be assured - then you must consider "Several such Alignment BYTES - sent (and received) "back to back!"     (operation is identical to that earlier described.)