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: SSI Communication Issue in Master Mode receive (with Arduino)

Part Number: EK-TM4C123GXL

Tool/software: Code Composer Studio

I am trying SSI communication with TM4C123GXL and Arduino Uno. I am using TM4C123GXL as Master and Arduino Uno as Slave and I want to read data sent by slave. But on configuring the master (SSI0) I am getting 1MHz CLK and CS pin is also working fine(Refer Picture Clock and Chip Select). While on Tx pin of Tiva Board There is some issue.(Refer Picture TX Tiva).  I want to receive data from UNO using SSI. My main goal is to interface LS7366R Encoder Buffer with TM4C123GXL which works on SPI. So can anyone help on this. I am attaching pictures of oscilloscope.

#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 "driverlib/buttons.h"
#include "utils/uartstdio.h"

#define OFF 0x00
#define RED 0x02
#define BLUE 0x04
#define GREEN 0x08

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

    // Enable UART0
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    // Configure GPIO Pins for UART mode.
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_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);
}

/******************************************************************************
 * Configure the onboard LED.  This must be called before changing LED state. *
 ******************************************************************************/
void ConfigureLED(void)
{
	// Configure on-board LED and turn it off
	// First, enable the peripheral
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

	// Define output to the 3 possible colors as they are bound to 3 different pins
	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
	// Write binary output to these 3 pins
	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, OFF);

	// It just wait a little bit (looping)
	SysCtlDelay(20000000);
}

/***************************************
 * Main function, program entry point. *
 ***************************************/
int main(void)
{

     uint32_t ui32Message = 0;

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

    // Initialize the onboard LED
    ConfigureLED();

    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    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_4 | GPIO_PIN_3 | GPIO_PIN_2);

    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8);
    SSIEnable(SSI0_BASE);
    SSIIntEnable(SSI0_BASE, SSI_RXFF);
    // Initialize the UART and configure it
    ConfigureUART();

    while(1)
    {
        SSIDataPut(SSI0_BASE,0x0F);

    	SSIDataGet(SSI0_BASE, &ui32Message);
    	if(ui32Message !=0){
    	    UARTprintf("'%c' ", ui32Message);   
    	}
    	while(SSIBusy(SSI0_BASE));
    }
}

  • It looks like a drive conflict on the SSI0TX pin. Would you please check the output of this pin when it is disconnected from the rest of your circuit (just connected to the oscilloscope)?
  • Hi Aditya,

    I don't see you configure the pin PA5 for SSI0TX in GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2). . I only see you configure PA4, PA3, and PA2 for RX, CS and CLK. Please fix this issue first.
  • I have corrected the thing and now its working. I am now using SSI2 for this and interfacing LS7366R Encoder buffer with it. But I am not able to read the encoder count. Please check and help.

    #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 "utils/uartstdio.h"
    #define NUM_SSI_DATA 4
    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);
        UARTStdioConfig(0, 115200, 16000000);
        // Initialize the UART for console I/O.
    }
    
    int main(void)
    {
       // uint32_t dataToSend = 0xFF;
        uint32_t recieved[4] = {};
        uint32_t ui32Index;
      //  unsigned int countVal[4]={};
        uint32_t Ticks=0;
      //  uint32_t received;
    
        SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    
        //Enable SSI Peripherals
      //  SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);
    
        //Enable the ports of SSI0 and SSI2
      //  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    
        //Enable PortF (to use the LED)
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
        GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    
        // Configure the pin muxing for SSI0 functions on port A2, A3, A4, and A5.
    //    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    //    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    //    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    //    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    
       //  Configure the pin muxing for SSI2 functions on port B4, B5, B6, and B7.
        GPIOPinConfigure(GPIO_PB4_SSI2CLK);
        GPIOPinConfigure(GPIO_PB5_SSI2FSS);
        GPIOPinConfigure(GPIO_PB6_SSI2RX);
        GPIOPinConfigure(GPIO_PB7_SSI2TX);
    
        //Configure SSI
     //   GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
        GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4);
    
      //  SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 100000, 8);
        SSIConfigSetExpClk(SSI2_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER,100000,8);
    
        // Enable the SSI modules
      //  SSIEnable(SSI0_BASE);
        SSIEnable(SSI2_BASE);
        ConfigureUART();
        UARTprintf("******SSI*******");
        SSIDataPut(SSI2_BASE,0x88 ); //Send data through SSI2 to write to MDR0
        while(SSIBusy(SSI2_BASE)){
    
                   }
        SSIDataPut(SSI2_BASE,0x03);  //To configure 4 byte mode
        while(SSIBusy(SSI2_BASE)){
    
                   }
        SysCtlDelay(20000000);
        while(1){
        SSIDataPut(SSI2_BASE, 0x60); //Send data through SSI2 to request count
                while(SSIBusy(SSI2_BASE)) //Wait for transmission to complete
                {
                }
                for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
                {
                SSIDataPut(SSI2_BASE, 0x00); // send dummy data to read highest byte to lowest byte
                while(SSIBusy(SSI2_BASE)) //Wait for transmission to complete
                            {
                            }
                SSIDataGet(SSI2_BASE,&recieved[ui32Index]); //recieve9
                UARTprintf("\n Received ");
                UARTprintf("%i ",ui32Index);
                UARTprintf("%i ", recieved[ui32Index]);
                }
           Ticks = (recieved[0] << 8) + recieved[1];
           Ticks = (Ticks << 8) + recieved[2];
           Ticks = (Ticks << 8) + recieved[3];
           UARTprintf("%d", Ticks);
          
        }
    }

  • Remember that every time you do an SSIDataPut(), something is read into the SSI receive FIFO. It may be garbage information. You should do an SSIDataGet() for every SSIDataPut() you use when configuring the encoder, or do multiple SSIDataGet() to empty the FIFO before you do the SSIDataPut() of dummy data used to read the encoder.
  • Hi,

    This is also not working.

  • You need to provide more information than that it is not working. I suggest you use the oscilloscope or better yet, a logic analyzer and compare the signals at the SSI with what you expect. Remember that since the Encoder chip is not from Texas Instruments I cannot help you understand that part.
  • My issue is now resolved as I have took care of everything regarding FIFO buffer. Thank you all for your advice. Now I am able to read data from LS7366R quadrature encoder buffer breakout board. I can now access the encoder values easily. Here is the code.

    #define SLAVE_SEL_1 GPIO_PIN_6              //PA_3 pin that is of port A
    #define SLAVE_SEL_2 GPIO_PIN_7              //PA_6 pin that is of port A
    #define SLAVE_SEL_3 GPIO_PIN_4              //PB_4 pin that is of port B
    #define SLAVE_SEL_4 GPIO_PIN_5              //PB_5 pin that is of port B
    #define PORT_A GPIO_PORTA_BASE
    #define PORT_B GPIO_PORTB_BASE
    #define PIN_LOW 0x00
    #define PIN_HIGH 0xFF
    
    #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 "utils/uartstdio.h"
    
    /*
     * Function to Configure UART0 For Debugging Purpose
     */
    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);
        UARTStdioConfig(0, 115200, 16000000);
        // Initialize the UART for console I/O.
    }
    /*
     * This function send the data through spi to specific register and register address module
     */
    void sendDataSPI(uint32_t portNo, uint32_t encoderNo, uint32_t registerAddress, uint32_t registerData)
    {
    
        GPIOPinWrite(portNo, encoderNo, PIN_LOW);
        SSIDataPut(SSI0_BASE, registerAddress);
        SSIDataPut(SSI0_BASE, registerData);
        while(SSIBusy(SSI0_BASE)){}
        GPIOPinWrite(portNo, encoderNo, PIN_HIGH);
    }
    
    /*
     * This function receive data from a specific register by sending dummy bytes
     */
    void receiveDataSPI(uint32_t portNo, uint32_t encoderNo, uint32_t registerAddress, uint32_t frameLength)
    {
        GPIOPinWrite(portNo, encoderNo, PIN_LOW);
        SSIDataPut(SSI0_BASE, registerAddress);
        while(frameLength)
        {
            SSIDataPut(SSI0_BASE, 0x00);
            frameLength--;
        }
        while(SSIBusy(SSI0_BASE)){}
        GPIOPinWrite(portNo,encoderNo, PIN_HIGH);
    }
    
    void initEncoders(){
        uint32_t grbCollect;
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);                             // Enable SSI Peripheral
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);                            // SSI0 is PortA
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);                            // SSI0 is PortA
        GPIOPinConfigure(GPIO_PA2_SSI0CLK);                                     // Clock is PA_2
        GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, SLAVE_SEL_1);                    // PA_3 is manually clocked
        GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, SLAVE_SEL_2);
        GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, SLAVE_SEL_3);
        GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, SLAVE_SEL_4);
    
        GPIOPinConfigure(GPIO_PA4_SSI0RX);                                      // MISO is PA_4
        GPIOPinConfigure(GPIO_PA5_SSI0TX);                                      // MOSI is PA_5
        GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);
    
        SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 8000000, 8);
        SysCtlDelay(5);
        SSIEnable(SSI0_BASE);
        while(SSIDataGetNonBlocking(SSI0_BASE,  &grbCollect)){}        //Read Garbage Data From SSI buffer if any
        //Encoder1 initialize
        sendDataSPI(PORT_A,SLAVE_SEL_1,0x88, 0x03);                       //0x88 -> Write to MDR0     0x03 -> Configure 4 byte mode for buffer
        receiveDataSPI(PORT_A,SLAVE_SEL_1, 0x98, 4);                      //0x98 -> Write to DTR      4 Times it will send 0x00 to reset the counter of buffer
        while(SSIDataGetNonBlocking(SSI0_BASE, &grbCollect)){}
        GPIOPinWrite(PORT_A, SLAVE_SEL_1, PIN_LOW);                       // Begin SPI conversation
        SSIDataPut(SSI0_BASE, 0xe0);                                      //0xE0 -> Set encoder1's current data register to center
        while(SSIBusy(SSI0_BASE)){}
        GPIOPinWrite(PORT_A, SLAVE_SEL_1, PIN_HIGH);                      //End SPI conversation
    
        //Encoder2 initialize
        sendDataSPI(PORT_A,SLAVE_SEL_2,0x88, 0x03);                       //0x88 -> Write to MDR0     0x03 -> Configure 4 byte mode for buffer
        receiveDataSPI(PORT_A,SLAVE_SEL_2, 0x98, 4);                      //0x98 -> Write to DTR      4 Times it will send 0x00 to reset the counter of buffer
        while(SSIDataGetNonBlocking(SSI0_BASE, &grbCollect)){}
        GPIOPinWrite(PORT_A, SLAVE_SEL_2, PIN_LOW);                       // Begin SPI conversation
        SSIDataPut(SSI0_BASE, 0xe0);                                      //0xE0 -> Set encoder2's current data register to center
        while(SSIBusy(SSI0_BASE)){}
        GPIOPinWrite(PORT_A, SLAVE_SEL_2, PIN_HIGH);                      //End SPI conversation
    
        //Encoder3 initialize
        sendDataSPI(PORT_B,SLAVE_SEL_3,0x88, 0x03);                       //0x88 -> Write to MDR0     0x03 -> Configure 4 byte mode for buffer
        receiveDataSPI(PORT_B,SLAVE_SEL_3, 0x98, 4);                      //0x98 -> Write to DTR      4 Times it will send 0x00 to reset the counter of buffer
        while(SSIDataGetNonBlocking(SSI0_BASE, &grbCollect)){}
        GPIOPinWrite(PORT_B, SLAVE_SEL_3, PIN_LOW);                       // Begin SPI conversation
        SSIDataPut(SSI0_BASE, 0xe0);                                      //0xE0 -> Set encoder3's current data register to center
        while(SSIBusy(SSI0_BASE)){}
        GPIOPinWrite(PORT_B, SLAVE_SEL_3, PIN_HIGH);                      //End SPI conversation
        //Encoder4 initialize
    
        sendDataSPI(PORT_B,SLAVE_SEL_4,0x88, 0x03);                       //0x88 -> Write to MDR0     0x03 -> Configure 4 byte mode for buffer
        receiveDataSPI(PORT_B,SLAVE_SEL_4, 0x98, 4);                      //0x98 -> Write to DTR      4 Times it will send 0x00 to reset the counter of buffer
        while(SSIDataGetNonBlocking(SSI0_BASE,  &grbCollect)){}
        GPIOPinWrite(PORT_B, SLAVE_SEL_4, PIN_LOW);                       // Begin SPI conversation
        SSIDataPut(SSI0_BASE, 0xe0);                                      //0xE0 -> Set encoder4's current data register to center
        while(SSIBusy(SSI0_BASE)){}
        GPIOPinWrite(PORT_B, SLAVE_SEL_4, PIN_HIGH);                      //End SPI conversation
    }
    
    int32_t readEncoder(uint32_t encoderNo){
        uint32_t pui32DataRx[4]={};
        uint32_t grbCollect;
        long countVal=0;
        // Clear the SSI0 Rx FIFO
        while(SSIDataGetNonBlocking(SSI0_BASE, &grbCollect)){}
        // Wait for SSI0 to be finished
        while(SSIBusy(SSI0_BASE)){}
    
        switch(encoderNo){
        case 1:
            // Read the values from the Encoder Buffer sensor
            receiveDataSPI(PORT_A,SLAVE_SEL_1, 0x60, 4);     //0x60 -> Request Counter data 4 here is the bytes which we have configured
            SSIDataGet(SSI0_BASE, &grbCollect);              //CLear the SSI0 Rx FIFO
            SSIDataGet(SSI0_BASE, &pui32DataRx[0]);          //Read highest order byte
            SSIDataGet(SSI0_BASE, &pui32DataRx[1]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[2]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[3]);          //Read lowest order byte
            break;
    
        case 2:
            // Read the values from the Encoder Buffer sensor
            receiveDataSPI(PORT_A,SLAVE_SEL_2, 0x60, 4);     //0x60 -> Request Counter data 4 here is the bytes which we have configured
            SSIDataGet(SSI0_BASE, &grbCollect);              //CLear the SSI0 Rx FIFO
            SSIDataGet(SSI0_BASE, &pui32DataRx[0]);          //Read highest order byte
            SSIDataGet(SSI0_BASE, &pui32DataRx[1]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[2]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[3]);          //Read lowest order byte
            break;
        case 3:
            // Read the values from the Encoder Buffer sensor
            receiveDataSPI(PORT_B,SLAVE_SEL_3, 0x60, 4);     //0x60 -> Request Counter data 4 here is the bytes which we have configured
            SSIDataGet(SSI0_BASE, &grbCollect);              //CLear the SSI0 Rx FIFO
            SSIDataGet(SSI0_BASE, &pui32DataRx[0]);          //Read highest order byte
            SSIDataGet(SSI0_BASE, &pui32DataRx[1]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[2]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[3]);          //Read lowest order byte
            break;
    
        case 4:
            // Read the values from the Encoder Buffer sensor
            receiveDataSPI(PORT_B,SLAVE_SEL_4, 0x60, 4);     //0x60 -> Request Counter data 4 here is the bytes which we have configured
            SSIDataGet(SSI0_BASE, &grbCollect);              //CLear the SSI0 Rx FIFO
            SSIDataGet(SSI0_BASE, &pui32DataRx[0]);          //Read highest order byte
            SSIDataGet(SSI0_BASE, &pui32DataRx[1]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[2]);
            SSIDataGet(SSI0_BASE, &pui32DataRx[3]);          //Read lowest order byte
            break;
        }
    
        countVal = (pui32DataRx[0]<<24)+(pui32DataRx[1]<<16)+(pui32DataRx[2]<<8)+(pui32DataRx[3]);
        return countVal;
    }
    void main(){
        ConfigureUART();
        initEncoders();
        UARTprintf("******LOGS*******");
    
        while(1){
    
            UARTprintf("\n Ticks Final: ");
            UARTprintf("%i", readEncoder(1));
            // SysCtlDelay(500000);
        }
    }