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.

Sending data as Slave

Other Parts Discussed in Thread: EK-TM4C1294XL, TM4C1294NCPDT

Hi !

I am developing a SPI communication between two peripherals in the same Launchpad (EK-TM4C1294XL).

The idea is that both the Master and the Slave can send and receive information. My code is quite simple until now with only one sending and the other one receiving.

#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"
#include "inc/hw_ints.h"
#include "driverlib/interrupt.h"

#define NUM_SSI_DATA            8

uint32_t ui32SysClkFreq;

uint32_t pui32DataTx[NUM_SSI_DATA];
uint32_t pui32DataRx[NUM_SSI_DATA];
uint32_t ui32Index = 0;

void SSI1IntHandler(void){

	SSIIntClear(SSI1_BASE, SSI_RXFF);
	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index]);
	UARTprintf("Recebendo: '%c' \n", pui32DataRx[ui32Index]);
	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index+1]);
	UARTprintf("Recebendo: '%c' \n", pui32DataRx[ui32Index+1]);
	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index+2]);
	UARTprintf("Recebendo: '%c' \n", pui32DataRx[ui32Index+2]);
	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index+3]);
	UARTprintf("Recebendo: '%c' \n", pui32DataRx[ui32Index+3]);

}


int main(void) {

	/****************UART Configuration*****************/
	ui32SysClkFreq = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

	GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_1);

	GPIOPinConfigure(GPIO_PA0_U0RX);
	GPIOPinConfigure(GPIO_PA1_U0TX);
	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	UARTStdioConfig(0, 115200, ui32SysClkFreq);

	/**********************SSI**********************/
	// SSI1 -> MASTER ; SSI0 -> SLAVE
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

	GPIOPinConfigure(GPIO_PA2_SSI0CLK);
	GPIOPinConfigure(GPIO_PA3_SSI0FSS);
	GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
	GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);

	GPIOPinConfigure(GPIO_PB5_SSI1CLK);
	GPIOPinConfigure(GPIO_PB4_SSI1FSS);
	GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
	GPIOPinConfigure(GPIO_PE5_SSI1XDAT1);

	GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
			GPIO_PIN_2);

	GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_5 | GPIO_PIN_4);
	GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

	SSIConfigSetExpClk(SSI1_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0,
			SSI_MODE_MASTER, 2000000, 8); 

	SSIConfigSetExpClk(SSI0_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0,
			SSI_MODE_SLAVE, 2000000, 8); 

	SSIEnable(SSI0_BASE);
	SSIEnable(SSI1_BASE);

	pui32DataTx[0] = 'a';
	pui32DataTx[1] = 'b';
	pui32DataTx[2] = 'c';
	pui32DataTx[3] = 'd';
	pui32DataTx[4] = 'e';
	pui32DataTx[5] = 'f';
	pui32DataTx[6] = 'g';
	pui32DataTx[7] = 'h';

	IntMasterEnable();

	SSIIntEnable(SSI1_BASE, SSI_RXFF);

	IntEnable(INT_SSI1);

	while(ui32Index<8){
		UARTprintf("Enviando: '%c' \n", pui32DataTx[ui32Index]);
		SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
		ui32Index++;
	}

	return 0;
}

This way, the interrupt never happens as if there is nothing to receive in the FIFO.  When I change the MASTER and the SLAVE (lines below) making the MASTER send and the SLAVE receive, it works perfectly.

SSIConfigSetExpClk(SSI1_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0,
SSI_MODE_SLAVE, 2000000, 8);

SSIConfigSetExpClk(SSI0_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, 2000000, 8);

Is there any other configuration that I have to do to make SLAVE send some data ?

  • Hi Mayli,

    The SPI slave could not start the data transfer. Try this way:
    1. Master writes any data (command) to slave
    2. After Slave gets this coommand, it write data to the SPI buffer
    3. Master read the data

    Regards,
    QJ
  • Hi QJ! 

    Before the while routine that sends the data, I added this lines as you suggested:

    SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);

    while(SSIBusy(SSI1_BASE))

    {
    }
    SSIDataGet(SSI0_BASE, &pui32DataRx[ui32Index]);
    UARTprintf("Recebendo: '%u' \n", pui32DataRx[ui32Index]);
    ui32Index=0;

    This way, Master sends and Slave receive. Its's ok. But in the while routine ( while(ui32Index<8)) Slave still cannot send the data to the Master. The interrupt still never happens.

    I also tried this before the while ( while(ui32Index<8)):

    SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    while(SSIBusy(SSI1_BASE))
    {
    }
    SSIDataGet(SSI0_BASE, &pui32DataRx[ui32Index]);
    UARTprintf("Recebendo: '%u' \n", pui32DataRx[ui32Index]);
    ui32Index=0;

    UARTprintf("Slave sending: '%u' \n", pui32DataTx[ui32Index+1]);
    SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index+1]);
    while(SSIBusy(SSI0_BASE))
    {
    }
    SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index+1]);
    UARTprintf("Recebendo: '%u' \n", pui32DataRx[ui32Index+1]);
    ui32Index=0;

    Now the code stops on the line: while(SSIBusy(SSI0_BASE)) and never goes to the next ones.

    Still not working =(

  • Hi Mayli,

    Slave needs the SPI clock to TX data, and the clock is generated by master.
    1. Master send a dummy data to slave, tell slave he is ready to get data from slave
    SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    2. After slave gets the data from master, it writes data (16bits) to register
    SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
    3. Master write another dummy data (16 bits) to slave, the data in salve register is also TXed t master side
    SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    4. master read the received data from its register
    SSIDataGet(SSI1_BASE, pui32DataRx[ui32Index]);

    Regards,
    QJ
  • Hi QJ,

    This is my code until now:

    /*
     * main.c
     */
    
    #include <stdio.h>
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.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 "inc/hw_ints.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/timer.h"
    
    #define NUM_SSI_DATA            8
    
    uint32_t ui32SysClkFreq;
    
    //uint32_t pui32DataTx[NUM_SSI_DATA];
    //char pui32DataTx[NUM_SSI_DATA];
    //char pui32DataRx[NUM_SSI_DATA];
    uint8_t pui32DataTx[NUM_SSI_DATA];
    uint32_t pui32DataRx[NUM_SSI_DATA];
    uint32_t ui32Index = 0;
    
    void SSI1IntHandler(void){
    
    	SSIIntClear(SSI1_BASE, SSI_RXFF);
    	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index]);
    	UARTprintf("Recebendo: '%u' \n", pui32DataRx[ui32Index]);
    	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index+1]);
    	UARTprintf("Recebendo: '%u' \n", pui32DataRx[ui32Index+1]);
    	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index+2]);
    	UARTprintf("Recebendo: '%u' \n", pui32DataRx[ui32Index+2]);
    	SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index+3]);
    	UARTprintf("Recebendo: '%u' \n", pui32DataRx[ui32Index+3]);
    
    }
    
    inline void converteFloatChar(uint32_t numero, uint8_t *vetorEnvio, char codigo) {
    
    	uint8_t aux, dezena, unidade, centena;
    
    	aux = numero*0.01;
    	centena = aux;
    	aux = numero - aux*100;
    
    	dezena = aux*0.1;
    	unidade = aux - dezena*10;
    
    	pui32DataTx[0] = codigo;
    	pui32DataTx[1] = centena;
    	pui32DataTx[2] = dezena;
    	pui32DataTx[3] = unidade;
    
    //	UARTprintf("Centena: %c = %c \nDezena: %u \nUnidade: %u \n", centena, centena+'0', dezena, unidade);
    }
    
    
    int main(void) {
    	uint32_t numeroEnviado = 123;
    	uint32_t start, delta;
    
    	/****************Time Configuration*****************/
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    	TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC_UP);
    	TimerLoadSet(TIMER1_BASE, TIMER_A, UINT32_MAX);
    	TimerEnable(TIMER1_BASE, TIMER_A);
    
    	/****************UART Configuration*****************/
    	ui32SysClkFreq = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
    	GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_1);
    
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    	UARTStdioConfig(0, 115200, ui32SysClkFreq);
    
    	/**********************SSI**********************/
    	// SSI0 -> SLAVE ; SSI1 -> MASTER
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); 
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
    	GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    	GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    	GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
    	GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
    
    	GPIOPinConfigure(GPIO_PB5_SSI1CLK);
    	GPIOPinConfigure(GPIO_PB4_SSI1FSS);
    	GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
    	GPIOPinConfigure(GPIO_PE5_SSI1XDAT1);
    
    	GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
    			GPIO_PIN_2);
    
    	GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_5 | GPIO_PIN_4);
    	GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    
    	SSIConfigSetExpClk(SSI1_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0,
    			SSI_MODE_MASTER, 2000000, 8);
    
    	SSIConfigSetExpClk(SSI0_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0,
    			SSI_MODE_SLAVE, 2000000, 8);
    	SSIEnable(SSI0_BASE);
    	SSIEnable(SSI1_BASE);
    
    	UARTprintf("Enviada: a%u\n", numeroEnviado);
    
    	start = TimerValueGet(TIMER1_BASE, TIMER_A);
    	converteFloatChar(numeroEnviado, pui32DataTx, 'a');
    	delta = TimerValueGet(TIMER1_BASE, TIMER_A) - start;
    	UARTprintf("Delta: %u\n" , delta);
    
    	IntMasterEnable();
    
    	SSIIntEnable(SSI1_BASE, SSI_RXFF);
    
    	IntEnable(INT_SSI1);
    
    	while(ui32Index<strlen(pui32DataTx)){
    		UARTprintf("Enviando: '%u' \n", pui32DataTx[ui32Index]);
    		SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    		SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
    		SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    		SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index]);
    		ui32Index++;
    	}
    
    	return 0;
    }
    

    With your correction now it works the way I wanted. But I have a couple of questions, I didn't understand why the SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index]) has to be inside the while and not only inside the interrupt. I also tryed to remove this from the while, but if I do that, the interrupt is called 2 times and I didn't understand why this is happening.

    Here is what is printed on my serial port with:

    while(ui32Index<strlen(pui32DataTx)){
    		UARTprintf("Enviando: '%u' \n", pui32DataTx[ui32Index]);
    		SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    		SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
    		SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    		SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index]);
    		ui32Index++;
    }

    Now I removed the dataGet inside the while since it makes more sense to me:

    while(ui32Index<strlen(pui32DataTx)){
    UARTprintf("Enviando: '%u' \n", pui32DataTx[ui32Index]);
    SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
    SSIDataPut(SSI1_BASE, pui32DataTx[ui32Index]);
    // SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index]);
    ui32Index++;
    
    }

    I really want to understand why it is necessary to be the first way.

    Secondly, my idea is to implement the SPI communication through two TM4C1294NCPDT. Also, this communication has to be using interrupt since I have more important things happening and I cannot stop to wait. Based on that, it wouldn't be good if I have to make a dataPut on master and only after that send the data with the Slave. So, is this the only way to write as a slave using SPI?

    Thank you very much,

    Mayli.

  • Maybe you could make one of the processors (the master one) periodically send dummy data to the slave, in order to keep the ssi clocking.

    Do both of them need to send messages to the other?

  • Yes Leonardo, Both of them.