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.

SPI communication with two TM4c1230d5pm

Other Parts Discussed in Thread: TM4C1230D5PM

I am new to TM4C Microcontroller. I want to communicate between two TM4c1230d5pm through SPI, So that immediately after sending 1 byte as command by the master, the slave returns a byte of data.

1)  RXFF Interrupt is raised only if RX FIFO is half-full or more. In case I would like to receive just one Byte, I should try another way.

2) RXTO Interrupt is raised basically 32 SSIClk periods after at least one character has been received into the RX FIFO. With this approach, if only one byte is recieved, I will get this interrupt with 32 SSIClk delay and this delay is a problem for my application.

That's why I used GPIO_INT, So when the falling edge occur in CS pin, Slave must return a Byte of data according to received Byte of command. But stuck in SSIDataGet(SSI0_BASE,&DataRx0[0]) in the interrupt handler.

 

Regards,

B.

/////////////////////////////SPI slave code///////////////////////////
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/debug.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"
#include "inc/hw_gpio.h"
#include "driverlib/rom.h"
#include "driverlib/i2c.h"
#include "driverlib/ssi.h"
#include "driverlib/eeprom.h"
#include "driverlib/adc.h"

//SPI0 Definition
#define SSI0_PERIPH		SYSCTL_PERIPH_GPIOA
#define SSI0_PORT		GPIO_PORTA_BASE

#define SCK0_PIN		GPIO_PIN_2
#define CS_PIN			GPIO_PIN_3
#define RX0_PIN			GPIO_PIN_4
#define TX0_PIN			GPIO_PIN_5

uint32_t DataRx0[4];
uint32_t DataTx0[4];
uint8_t Int_Active=0;

void SPI0Init(void);
void GPIOIntHandler(void);

int main(void)
{
	
	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_3);
	
	SPI0Init();

	IntEnable(INT_GPIOA);
	GPIOIntClear(GPIO_PORTA_BASE,GPIO_PIN_3);
	GPIOIntTypeSet(GPIO_PORTA_BASE,GPIO_PIN_3,GPIO_FALLING_EDGE);
	GPIOIntEnable(GPIO_PORTA_BASE, GPIO_PIN_3);
	IntMasterEnable();

	while(1)
	{
		
	}

}

void SPI0Init(void)
{
	uint32_t FIFO;

	//
	// The SSI1 peripheral must be enabled for use.
	//
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
	//
	// For this example SSI1 is used with PortD[3:0].  The actual port and pins
	//
	SysCtlPeripheralEnable(SSI0_PERIPH);
	//
	// Configure the pin muxing for SSI1 functions on port D0, D1, D2, and D3.
	//
	GPIOPinConfigure(GPIO_PA2_SSI0CLK);
	//	GPIOPinConfigure(GPIO_PA3_SSI0FSS);
	GPIOPinConfigure(GPIO_PA4_SSI0RX);
	GPIOPinConfigure(GPIO_PA5_SSI0TX);

	//
	// 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
	GPIOPinTypeSSI(SSI0_PORT, SCK0_PIN | RX0_PIN | TX0_PIN );

	// Configure and enable the SSI port for SPI master mode.  Use SSI1,
	// 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.
	SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
			SSI_MODE_SLAVE, 1000000, 8);
	//
	// Enable the SSI1 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, &FIFO));
}

void GPIOIntHandler(void)
{
	GPIOIntClear(GPIO_PORTA_BASE,GPIO_PIN_3);

	SSIDataGet(SSI0_BASE,&DataRx0[0]);
	while(SSIBusy(SSI0_BASE));

	if(DataRx0[0]==0x11)
	{
		SSIDataPut(SSI0_BASE,0x01);
		while(SSIBusy(SSI0_BASE));
		SSIDataGet(SSI0_BASE,&DataRx0[1]);
	}
	else if(DataRx0[0]==0x22)
	{
		SSIDataPut(SSI0_BASE,0x02);
		while(SSIBusy(SSI0_BASE));
		SSIDataGet(SSI0_BASE,&DataRx0[1]);
	}
}
/////////////////////////////SPI master code///////////////////////////
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/debug.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"
#include "inc/hw_gpio.h"
#include "driverlib/rom.h"
#include "driverlib/i2c.h"
#include "driverlib/ssi.h"
#include "driverlib/eeprom.h"
#include "driverlib/adc.h"

//SPI1 Definition
#define CS_PERIPH  	SYSCTL_PERIPH_GPIOD
#define CS_PORT		GPIO_PORTD_BASE
#define CS_PIN		GPIO_PIN_1

#define SSI1_PERIPH		SYSCTL_PERIPH_GPIOD
#define SSI1_PORT		GPIO_PORTD_BASE

#define SCK1_PIN		GPIO_PIN_0
#define RX1_PIN			GPIO_PIN_2
#define TX1_PIN			GPIO_PIN_3

uint32_t DataRx1[4];
uint32_t DataTx1[4];

void SPI1Init(void);

int main(void)
{
	uint32_t c=0;
	
	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_0| GPIO_PIN_1);

	SPI1Init();

	while(1)
	{
		// send data every 5s
		c++;

		if (c==5)
		{
			// send data1
			//CS=1   CS=0
			GPIOPinWrite(CS_PORT,CS_PIN,CS_PIN);
			SysCtlDelay(SysCtlClockGet()/3/100000);
			GPIOPinWrite(CS_PORT,CS_PIN,0);
			SysCtlDelay(SysCtlClockGet()/3/100000);

			SSIDataPut(SSI1_BASE,0x11);
			while(SSIBusy(SSI1_BASE));
			SSIDataGet(SSI1_BASE,&DataRx1[0]);
			while(SSIBusy(SSI1_BASE));

			GPIOPinWrite(CS_PORT,CS_PIN,CS_PIN);
			SysCtlDelay(SysCtlClockGet()/3/100000);
		}

		else if (c==10)
		{
			c = 0;
			// send data2
			//CS=1   CS=0
			GPIOPinWrite(CS_PORT,CS_PIN,CS_PIN);
			SysCtlDelay(SysCtlClockGet()/3/100000);
			GPIOPinWrite(CS_PORT,CS_PIN,0);
			SysCtlDelay(SysCtlClockGet()/3/100000);

			SSIDataPut(SSI1_BASE,0x22);
			while(SSIBusy(SSI1_BASE));
			SSIDataGet(SSI1_BASE,&DataRx1[0]);

			GPIOPinWrite(CS_PORT,CS_PIN,CS_PIN);
			SysCtlDelay(SysCtlClockGet()/3/100000);
		}
		
		SysCtlDelay(SysCtlClockGet()/3);
	}
}

void SPI1Init(void)
{
	uint32_t FIFO;

	//	CS=1
	SysCtlPeripheralEnable(CS_PERIPH);
	GPIOPinTypeGPIOOutput(CS_PORT, CS_PIN);
	GPIOPinWrite(CS_PORT,CS_PIN,CS_PIN);

	//
	// The SSI1 peripheral must be enabled for use.
	//
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
	//
	// For this example SSI1 is used with PortD[3:0].  The actual port and pins
	//
	SysCtlPeripheralEnable(SSI1_PERIPH);
	//
	// Configure the pin muxing for SSI1 functions on port D0, D1, D2, and D3.
	//
	GPIOPinConfigure(GPIO_PD0_SSI1CLK);
	//	GPIOPinConfigure(GPIO_PD1_SSI1FSS);
	GPIOPinConfigure(GPIO_PD2_SSI1RX);
	GPIOPinConfigure(GPIO_PD3_SSI1TX);

	//
	// 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
	GPIOPinTypeSSI(SSI1_PORT, SCK1_PIN | RX1_PIN | TX1_PIN);

	// Configure and enable the SSI port for SPI master mode.  Use SSI1,
	// 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.
	SSIConfigSetExpClk(SSI1_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
			SSI_MODE_MASTER, 1000000, 8);
	//
	// Enable the SSI1 module.
	//
	SSIEnable(SSI1_BASE);
	//
	while(SSIDataGetNonBlocking(SSI1_BASE, &FIFO));
}

  • Only make one post for a problem please.

    Why SPI? There are other choices and if you are communicating off board then SPI would seem to be the least good fit.

    Robert
  • Hello user4654273,

    What about the connection between the SPI controllers? How have they been connected on the board?

    Regards
    Amit
  • Robert Adsett72 said:
    Only make one post for a problem please.

    Agreed - yet it must be mentioned that (sometimes) delightful "moderation" confuses posters (delays the presentation of their post) thus causes (multiple strikes) of the Post button.

    Always of interest - yet never disclosed - (and to your point) is "how & why" poster chose that specific serial link.   As poster Robert well notes - off board data transmission most always benefits from line drivers/receivers (RS232/485, CAN etc.).   Lengthy cable runs degrade signals & subject the board to unwanted noise invasion.

    Unmentioned yet is the test/verify of a solid Ground connection between each board - and the adequacy of power - delivered to - and measured at - each board.

  • Moderation, good point. Although moderation that delays posts but fails to delete multiple posts has arguably achieved the worst of both options.

    I was also thinking that SPI's strength is communicating to simple devices whose interface can be viewed as simple registers. That can be extended with perhaps some difficulties to using a micro as slave. However, as soon as you require your slave micro to do any calculation or decision making during the transfer you have moved well beyond the strengths of SPI. Other protocols are better suited to that kind of task.

    I suspect, given the description of the problem so far, that SPI is not a good choice even if communication is confined to a single board.

    Robert
  • Robert Adsett72 said:
    has arguably achieved the worst of both options. 

    I submit that, "Failure by Vendor to "Guide Posters" achieves "top dog.""

    While it is possible that "both MCUs" sit on the same board - odds favor (at least at some point) those MCUs connecting over some distance.   And then - as you initially noted - "Goodbye SPI."   Perhaps better to plan for - and expect - that eventually.

    Now if it is - and will remain - multi-MCU/single board design - why not promote from 4 pin SPI to 9/10 pin (full) parallel?   (2 extra bits for clock/alert or direction)  Parallel always faster and avoids the "joy" of master-slave SPI considerations.

    Yet again - we are (forced to guess) as esteemed vendor refuses to "guide posters to explain - at least somewhat - How/Why they've made their design considerations."