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/TM4C123GH6PM: The SSI(SPI) communication in TIVA TM4C123GXL

Part Number: TM4C123GH6PM


Tool/software: Code Composer Studio

Hello,

I am trying to implement a launchpad to launchpad communication using SSI(SPI) protocol present in the TIVA C TM4C123GXL launchpad. 

I am configuring one launchpad in Master mode and the other one in Slave mode. Master and slave both are configured using SSI0. 

My concept is when I press the switch at the master side, data should get transmitted to slave from master and it should get printed on PC's serial monitor and this part is working fine. And in the same way, when I press the switch slave side, data should get transmitted to the master from slave and it should get printed on PC's serial monitor but this not happening. The interesting part is that data sent from slave to master is getting printed on the serial monitor during transmission of data from the master to slave. 

And as I read in the datasheet that the master only should initiate the transmission of data from the slave to master. I am not getting how to do this. Kindly give a solution to my issue as soon as possible. And also I have attached the master and slave code for your reference.

/*MASTER*/
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/uart.h"
#include "uartstdio.h"
#define NUM_SSI_DATA            3
uint32_t pui32DataTx[NUM_SSI_DATA];
uint32_t pui32DataRx[NUM_SSI_DATA];
uint32_t ui32Index;
void SSI0_MASTER_Interrupt(void)
{
uint32_t ui32Status;
ui32Status=SSIIntStatus(SSI0_BASE,1);
UARTprintf("Int Status is  %i\n",ui32Status);
if(ui32Status & SSI_RXFF|SSI_RXTO)
{
        for(ui32Index=0;ui32Index < NUM_SSI_DATA; ui32Index++)
        {
        SSIDataGet(SSI0_BASE, &pui32DataRx[ui32Index]);
        UARTprintf("%c", pui32DataRx[ui32Index]);
        }
        UARTprintf("\n");
}
SSIIntClear(SSI0_BASE, SSI_RXFF|SSI_RXTO|SSI_RXOR);
}
void InitConsole(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // enable UART0 GPIO peripheral
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTStdioConfig(0, 9600, SysCtlClockGet());
}
int main(void)
{
    SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    InitConsole();
    UARTprintf("SSI Master->\n");
    UARTprintf("  Mode: SPI\n");
    UARTprintf("  Data: 8-bit\n\n");
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
    GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_4MA,GPIO_PIN_TYPE_STD_WPU);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |GPIO_PIN_2);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER,4000000, 8);
    SSIEnable(SSI0_BASE);
    SSIIntRegister(SSI0_BASE,SSI0_MASTER_Interrupt);
    IntEnable(INT_SSI0);
    SSIIntEnable(SSI0_BASE,SSI_RXFF|SSI_RXTO);
    while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
    {
    }
    SSIIntClear(SSI0_BASE,SSI_RXFF|SSI_RXTO);
    pui32DataTx[0] = 's';
    pui32DataTx[1] = 'p';
    pui32DataTx[2] = 'i';
    while(SSIBusy(SSI0_BASE))
    {
    }
    while(1)
    {
if(!GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_4))
{
    UARTprintf("Sent data to slave\n");
    for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
    {
    SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
    }
     SysCtlDelay(13333333/2);
}
    }
}
/*SLAVE*/
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/uart.h"
#include "uartstdio.h"
#define NUM_SSI_DATA            3
uint32_t pui32DataTx[NUM_SSI_DATA];
uint32_t pui32DataRx[NUM_SSI_DATA];
uint32_t ui32Index;
volatile unsigned long g_ulSSI2RXTO = 0;
void SSI0_SLAVE_Interrupt(void)
{
uint32_t ui32Status;
ui32Status=SSIIntStatus(SSI0_BASE,1);
UARTprintf("Int Status is  %i\n",ui32Status);
if(ui32Status & SSI_RXFF|SSI_RXTO)
{
        for(ui32Index=0;ui32Index < NUM_SSI_DATA; ui32Index++)
        {
        SSIDataGet(SSI0_BASE, &pui32DataRx[ui32Index]);
        UARTprintf("%c", pui32DataRx[ui32Index]);
        }
  UARTprintf("\n");
}
SSIIntClear(SSI0_BASE, ui32Status);
}
void InitConsole(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // enable UART0 GPIO peripheral
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTStdioConfig(0, 9600, SysCtlClockGet()); // 115200 baud
}
int main(void)
{
SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    uint32_t ui32clock= SysCtlClockGet();
    InitConsole();
    UARTprintf("SSI Slave->\n");
    UARTprintf("  Mode: SPI\n");
    UARTprintf("  Data: 8-bit\n\n");
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
    GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_4MA,GPIO_PIN_TYPE_STD_WPU);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |GPIO_PIN_2);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_3,SSI_MODE_SLAVE,4000000, 8);
    SSIEnable(SSI0_BASE);
    SSIIntRegister(SSI0_BASE,SSI0_SLAVE_Interrupt);
    SSIIntEnable(SSI0_BASE,SSI_RXFF|SSI_RXTO);
    while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
    {
    }
    SSIIntClear(SSI0_BASE,SSI_RXFF|SSI_RXTO);
    pui32DataTx[0] = 'S';
    pui32DataTx[1] = 'P';
    pui32DataTx[2] = 'I';
    while(SSIBusy(SSI0_BASE))
    {
    }
    IntEnable(INT_SSI0);
    while(1)
    {
    if(!GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_4))
    {
      UARTprintf("Data Sent to master\n");
       for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
        {
       SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
        }
       SysCtlDelay(13333333/2);
    }
    }
}

 

  • You read correctly, an SPI slave cannot initiate a transmission. You must have the SPI master continually transferring dummy data and checking for valid return data from the slave, or add another signal between the two boards. A digital output from the slave to an input on the master that can generate an interrupt or be polled to indicate that the slave has new data to send.

    If you want independent two way communications, consider using a UART instead.

  • Greetings,

    Our small tech group agrees w/vendor's Bob - yet (perhaps) this poster has a (valid) reason for seeking an SPI-based solution.   (And 'that' - demands explanation...)

    Should that prove the case - our group successfully implemented, TWO SPI-based MCUs with (each) being able to switch into "Master Mode."   (of course - "only one at a time" serving as master.)

    Key design elements of this "Multi-Master" SPI implementation included:

    • both MCUs defaulted into Slave Mode
    • beyond the 4 'normal' SPI interconnects we added a total of 2 GPIO lines - such that (either) MCU could alert the other that it was, "Switching to Master Mode"  (and would shortly pass a "Command-Control" message)
    • upon message completion the "Master MCU" reverted to Slave Mode.  (the receiving MCU would uniquely pulse its GPIO output line to confirm 'message receipt.')

    The merit of this method was that (either) MCU could - at any time - originate communication.   It proved critical that (never) were both MCUs able to "Switch to Master mode" with any overlap.   (as this could produce destructive "Output Contention" upon (each) MCU's SPI Clock line!)

    In addition - we investigated a "Time-based, Ping-Pong method of Enabling a Master."    (this "saved" the use of those "alerting GPIOs" - described above - yet required regular "clock synchronization' between the MCUs)   This method also succeeded - yet added a "Response Latency" - thus was bypassed in favor of the "Alerting/Signalling" GPIOs.

    As earlier stated - unless the "Demand for SPI proves (otherwise) justified" - this "solution'" (while it worked) is NOT Recommended!   (due to complexity...)

  • It is working now. Thank you. 

  • Thank you, Bob Crosby, for clearing my doubt. And the method you told is easy and working properly now.