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.

TM4C1294NCPDT: SSI bus Communication to support 3-wire SPI communication protocol

Part Number: TM4C1294NCPDT

Hi all,

I am currently working on TM4C1294NCPDT evaluation board microcontroller. 

I am trying to configure SSI bus to 3-Wire SPI bus with bitrate 16-bits per frame and external peripheral device is AD9834 waveform generator. 

As I was debugging through SPI bus using logic analyzer. The output result are different than the data provided by me in a Code. 

If someone can help me with troubleshoot please let me know. 

#include <stdbool.h>
#include <stdint.h>
#include <inc/hw_types.h>
#include <inc/hw_ssi.h>
#include "inc/hw_memmap.h"
#include <driverlib/gpio.h>
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include <string.h>
#include "main.h"


// Number of bytes to Send.
//
//*****************************************************************************
#define NUM_SSI_DATA            4

#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif


uint32_t ui32SysClocks;
//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void InitConsole(void){

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTStdioConfig(0, 9600, ui32SysClocks);
}
void InitSPI(void){

        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        GPIOPinConfigure(GPIO_PA2_SSI0CLK);
        GPIOPinConfigure(GPIO_PA3_SSI0FSS);
        GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
        GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
        GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
        SSIConfigSetExpClk(SSI0_BASE, ui32SysClocks, SSI_FRF_MOTO_MODE_2, SSI_MODE_MASTER, 40000000, 16);
}

void SPI_write(const uint8_t* dataBuffer, uint8_t count){

    while(count--){
    SSIDataPut(SSI0_BASE, *dataBuffer++);
    }
    while(SSIBusy(SSI0_BASE));
}
//*****************************************************************************
//Main function Entry.
//
//*****************************************************************************
int
main(void)
{


uint8_t dataTX[4] = {0x40, 0x4F, 0x4F, 0x04};
uint8_t count;

    ui32SysClocks = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_240), 120000000);
    InitConsole();


    UARTprintf("SPI -> Master to Slave\n");
    UARTprintf("SPI Bit_Rate: 16-bit\n\n");
    InitSPI();
            SSIEnable(SSI0_BASE);
            SPI_write(dataTX, 4);
            for(count = 0; count < NUM_SSI_DATA; count = count + 1){
            UARTprintf("The byte is transferred is: %X\n", dataTX[count]);
            }

UARTprintf("Done transferring the data\r\n");
UARTprintf("----------------------------------------------------------------------");
UARTprintf("\r\n\n");

while(1);
}

SSI bus configuration

1) SCLk -> 20MHZ,

2) Data is sampled on falling edge and transferred on raising edge. 

3) Bit Rate = 16-bits

Please let me know, 

Looking forward to hearing from you.

Thanks and Regards,

Sai 

  • Hi,

    1) SCLk -> 20MHZ,

    What is wrong with your output? You only say the output is different from your your code intended. Are you saying baud rate is wrong as you specify 40Mhz, not 20Mhz. Perhaps you want to clarify what is the expected output and what are you getting. 

    SSIConfigSetExpClk(SSI0_BASE, ui32SysClocks, SSI_FRF_MOTO_MODE_2, SSI_MODE_MASTER, 40000000, 16);

  • Hi Charles, 

    Thank you so much for replying back to me. 

    As you can see from above code. 

                   1) UART serial data

                   2) SPI serial data.

    On my serial port terminal, I can see the data. However, I have connected the logic analyzer to debug data transferring from MOSI. 

    I don't see any data in my logic analyzer. Please giver me few directions to modify SPI_Write code. 

    Any suggestions would be helpful.

    Expected output is: dataTx[4] = {0x40, 0x4F, 0x4F, 0x04} from MOSI. 

    Thanks and Regards,

    Sai 

  • I think you are missing the below call to enable the SSI module. 

    SSIEnable(SSI0_BASE);

  • Hi Charles, 

    Thank You for responding. 

    I have mentioned SSIEnable(SSI0_Base);

    Let me explain you little more detail

    1) In idle case

        i) SCLK-> High

        ii) SFss-> High

    2) Data is Sampled on falling edge and propagated on rising edge.

    3) SCLK -> 40MHZ

    4) Bit Rate is 16-bits frame.

    I have connected the logic analyzer and still unbale to debug the information 

    sample data: {0x40, 0x4F, 0x4F, 0x04}. 

    Are there any troubleshooting and debugging steps to do. 

    Please let me know, Looking forward to hearing from you. 

    Do I need to Enable SSI Interrupt? 

    Thanks,
    Sai 

  • Hi Charles, 

    Are there any alternative to configure for SSI --> SPI 3-Wire ?

    Please let me know. 

    Thanks and Regards,

    Sai  

  • Hi,

      While I'm looking at your code again, can you please try the TivaWare example for ssi at C:\ti\TivaWare_C_Series-2.2.0.295\examples\peripherals\ssi\spi_master.c example.

  • Can you try this below example I create. It just repeats sending out the same character. 

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/ssi.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/rom.h"
    #include "utils/uartstdio.h"
    
    
    //*****************************************************************************
    //
    //! \addtogroup ssi_examples_list
    //! <h1>SPI Master (spi_master)</h1>
    //!
    //! This example shows how to configure the SSI0 as SPI Master.  The code will
    //! send three characters on the master Tx then polls the receive FIFO until
    //! 3 characters are received on the master Rx.
    //!
    //! 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
    //!
    //! 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
    //!
    //! This example uses the following interrupt handlers.  To use this example
    //! in your own application you must add these interrupt handlers to your
    //! vector table.
    //! - None.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Number of bytes to send and receive.
    //
    //*****************************************************************************
    #define NUM_SSI_DATA            3
    
    //*****************************************************************************
    //
    // This function sets up UART0 to be used for a console to display information
    // as the example is running.
    //
    //*****************************************************************************
    void
    InitConsole(void)
    {
        //
        // Enable GPIO port A which is used for UART0 pins.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Configure the pin muxing for UART0 functions on port A0 and A1.
        // 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_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
    
        //
        // Enable UART0 so that we can configure the clock.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        //
        // Select the alternate (UART) function for these pins.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    
    }
    
    //*****************************************************************************
    //
    // Configure SSI0 in master Freescale (SPI) mode.  This example will send out
    // 3 bytes of data, then wait for 3 bytes of data to come in.  This will all be
    // done using the polling method.
    //
    //*****************************************************************************
    int
    main(void)
    {
    #if defined(TARGET_IS_TM4C129_RA0) ||                                         \
        defined(TARGET_IS_TM4C129_RA1) ||                                         \
        defined(TARGET_IS_TM4C129_RA2)
        uint32_t ui32SysClock;
    #endif
    
        uint32_t pui32DataTx[NUM_SSI_DATA];
        uint32_t pui32DataRx[NUM_SSI_DATA];
        uint32_t ui32Index;
    
        //
        // Set the clocking to run directly from the external crystal/oscillator.
        // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
        // crystal on your board.
        //
    #if defined(TARGET_IS_TM4C129_RA0) ||                                         \
        defined(TARGET_IS_TM4C129_RA1) ||                                         \
        defined(TARGET_IS_TM4C129_RA2)
        ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                           SYSCTL_OSC_MAIN |
                                           SYSCTL_USE_PLL), 120000000);
    #else
        SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);
    #endif
    
        //
        // Set up the serial console to use for displaying messages.  This is
        // just for this example program and is not needed for SSI operation.
        //
        InitConsole();
    
        //
        // 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.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    
        //
        // For this example SSI0 is used with 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_GPIOA);
    
        //
        // Configure the pin muxing for SSI0 functions on port 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_PA2_SSI0CLK);
        GPIOPinConfigure(GPIO_PA3_SSI0FSS);
        GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
        GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
    
    
        //
        // 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:
        //      PA5 - SSI0Tx
        //      PA4 - SSI0Rx
        //      PA3 - SSI0Fss
        //      PA2 - SSI0CLK
        // 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.
        //
    #if defined(TARGET_IS_TM4C129_RA0) ||                                         \
        defined(TARGET_IS_TM4C129_RA1) ||                                         \
        defined(TARGET_IS_TM4C129_RA2)
        SSIConfigSetExpClk(SSI0_BASE, ui32SysClock, SSI_FRF_MOTO_MODE_2,
                           SSI_MODE_MASTER, 40000000, 16);
    #else
        SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
                           SSI_MODE_MASTER, 1000000, 8);
    #endif
    
        //
        // Enable the SSI0 module.
        //
        SSIEnable(SSI0_BASE);
    
        //
        // 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, &pui32DataRx[0]))
        {
        }
    
        //
        // Initialize the data to send.
        //
        pui32DataTx[0] = 's';
        pui32DataTx[1] = 'p';
        pui32DataTx[2] = 'i';
    
    
        //
        // Display indication that the SSI is transmitting data.
        //
        UARTprintf("Sent:\n  ");
    
        //
        // Send 3 bytes of data.
        //
        //for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
        ui32Index=0;
        while (1)
        {
            //
            // Display the data that SSI is transferring.
            //
            UARTprintf("'%c' ", pui32DataTx[ui32Index]);
    
            //
            // 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, pui32DataTx[ui32Index]);
        }
    
    
        //
        // Return no errors
        //
        return(0);
    }
    

  • I modified your code just slightly and it is working too. It just transmits the same 4 bytes continuously.

    #include <stdbool.h>
    #include <stdint.h>
    #include <inc/hw_types.h>
    #include <inc/hw_ssi.h>
    #include "inc/hw_memmap.h"
    #include <driverlib/gpio.h>
    #include "driverlib/pin_map.h"
    #include "driverlib/ssi.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #include <string.h>
    //#include "main.h"
    
    
    // Number of bytes to Send.
    //
    //*****************************************************************************
    #define NUM_SSI_DATA            4
    
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    
    uint32_t ui32SysClocks;
    //*****************************************************************************
    //
    // This function sets up UART0 to be used for a console to display information
    // as the example is running.
    //
    //*****************************************************************************
    void InitConsole(void){
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
        UARTStdioConfig(0, 9600, ui32SysClocks);
    }
    void InitSPI(void){
    
            SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
            SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
            GPIOPinConfigure(GPIO_PA2_SSI0CLK);
            GPIOPinConfigure(GPIO_PA3_SSI0FSS);
            GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
            GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
            GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
            SSIConfigSetExpClk(SSI0_BASE, ui32SysClocks, SSI_FRF_MOTO_MODE_2, SSI_MODE_MASTER, 40000000, 16);
    }
    
    void SPI_write(const uint8_t* dataBuffer, uint8_t count){
    
        while(count--){
        SSIDataPut(SSI0_BASE, *dataBuffer++);
        }
        while(SSIBusy(SSI0_BASE));
    }
    //*****************************************************************************
    //Main function Entry.
    //
    //*****************************************************************************
    int
    main(void)
    {
    
    
    uint8_t dataTX[4] = {0x40, 0x4F, 0x4F, 0x04};
    uint8_t count;
    
        ui32SysClocks = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_240), 120000000);
        InitConsole();
    
    
        UARTprintf("SPI -> Master to Slave\n");
        UARTprintf("SPI Bit_Rate: 16-bit\n\n");
        InitSPI();
        SSIEnable(SSI0_BASE);
        while (1)
        {
    //    	for(count = 0; count < NUM_SSI_DATA; count = count + 1){
    //    		UARTprintf("The byte is transferred is: %X\n", dataTX[count]);
            SPI_write(dataTX, 4);
    
    //    	}
        }
    
    UARTprintf("Done transferring the data\r\n");
    UARTprintf("----------------------------------------------------------------------");
    UARTprintf("\r\n\n");
    
    while(1);
    }

  • Hi Charles,

    Could you please confirm the pins naming for SPI?

    1) SCLK -> Clock

    2) SFss -> Chip Select

    3) SDATA0 -> MOSI(TX)

    4) SDATA1 -> MISO(RX)

    Looking forward to hearing from you. 

    Thanks and Regards,

    Sai 

  • Hi,

      Yes, your understanding of the pin naming is correct. 

  • Hi Charles,

    If I'm not using SSIODAT1(RX). Should I have to connect the Pin to GND or VCC? 

    Please let me know, As I am working on 3-Wire SPI communication protocol for my project.

    Resources required are

    1) SSI0SCLK 2) SSI0Fss and 3) SSI0DAT0(TX).  

    Regards,

    Sai

  • Hi,

      You can leave the RX pin as NC.