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.

Compiler/TM4C123GH6PZ: Communication between two TIVA board using I2C

Part Number: TM4C123GH6PZ

Tool/software: TI C/C++ Compiler

Hi sir,

I am using two tiva board one act as a master and other one act as a slave.I am trying to send some string from master to slave and then slave send the same data back to the master and display the data through UART, but I am unable to send back the data.

When I tried to send data from master to slave, the data reading correctly through UART. But when I am trying to send back the same data to master it is not working properly.Please help me to solve the issue.

Given below is the master code,

#define SLAVE_ADDRESS 0x20
//void InitConsole(void);
unsigned long k=0;
void InitConsole(void);

uint32_t n=3,i;
char char_tx[]="abc";
char char_rx[3],data;

int main()
{
	SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC |SYSCTL_XTAL_8MHZ|SYSCTL_OSC_MAIN);

	InitConsole();
	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0));
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));
	//configure the muxing and GPIO settings to bring the SSI functions out to the pins
	GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
	GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
	GPIOPinConfigure(GPIO_PB2_I2C0SCL);
	GPIOPinConfigure(GPIO_PB3_I2C0SDA);
	I2CMasterEnable(I2C0_BASE);

	I2CMasterInitExpClk(I2C0_BASE,SysCtlClockGet(),false);

	while(1)
	{
		I2CMasterSlaveAddrSet(I2C0_BASE,SLAVE_ADDRESS,false);
		//put data to be sent into FIFO
		I2CMasterDataPut(I2C0_BASE, char_tx[0]);

		if(char_tx[1] == '\0')
		{
			//Initiate send of data from the MCU
			I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);

			// Wait until MCU is done transferring.
			while(I2CMasterBusy(I2C0_BASE)); 

		}
		else{

			I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

			// Wait until MCU is done transferring.
			while(I2CMasterBusy(I2C0_BASE));

			I2CMasterSlaveAddrSet(I2C0_BASE,SLAVE_ADDRESS,true); 
			I2CMasterControl(I2C0_BASE,I2C_MASTER_CMD_BURST_RECEIVE_START);
			char_rx[0]= I2CMasterDataGet(I2C0_BASE);
			while(I2CMasterBusy(I2C0_BASE));
			UARTCharPut(UART0_BASE,char_rx[0]);

			while(char_tx[i + 1] != '\0')
				for(i=1;i<n;i++)
				{
					I2CMasterSlaveAddrSet(I2C0_BASE,SLAVE_ADDRESS,false);
					//put next piece of data into I2C FIFO
					I2CMasterDataPut(I2C0_BASE, char_tx[i]);
					// 
					//send next data that was just placed into FIFO
					I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

					// Wait until MCU is done transferring.
					while(I2CMasterBusy(I2C0_BASE));
					I2CMasterSlaveAddrSet(I2C0_BASE,SLAVE_ADDRESS,true); 
					char_rx[i]= I2CMasterDataGet(I2C0_BASE);
					I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
					while(I2CMasterBusy(I2C0_BASE));
					UARTCharPut(UART0_BASE,char_rx[i]);
					i++;
				}
			I2CMasterSlaveAddrSet(I2C0_BASE,SLAVE_ADDRESS,false); 
			//put last piece of data into I2C FIFO
			I2CMasterDataPut(I2C0_BASE,char_tx[n]);

			//send next data that was just placed into FIFO
			I2CMasterControl(I2C0_BASE,I2C_MASTER_CMD_BURST_SEND_FINISH);
			while(I2CMasterBusy(I2C0_BASE));
			I2CMasterSlaveAddrSet(I2C0_BASE,SLAVE_ADDRESS,true); 
			char_rx[n]= I2CMasterDataGet(I2C0_BASE);
			I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
			while(I2CMasterBusy(I2C0_BASE));
			UARTCharPut(UART0_BASE,char_rx[n]);

		}
	}
}

	void InitConsole(void)
	{
		//
		// Enable the UART0 module.
		//
		SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
		//
		// Wait for the UART0 module to be ready.
		//
		while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0));
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
		while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA));
		GPIOPinConfigure(GPIO_PA0_U0RX);
		GPIOPinConfigure(GPIO_PA1_U0TX);
		//UARTClockSourceSet(SYSCTL_PERIPH_UART0,UART_CLOCK_SYSTEM);
		// UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
		GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
		UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 9600,(UART_CONFIG_WLEN_8|UART_CONFIG_STOP_ONE|UART_CONFIG_PAR_NONE));
		UARTCharPut(UART0_BASE, 'J'); 
	}

Slave code

int main()
{
	char data, char_rx[5],receive;
	// uint32_t pui32DataTx;
	uint32_t n=3,i;
	//uint32_t pui32DataRx[5];
	//uint32_t ui32Period;
	SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_XTAL_8MHZ|SYSCTL_OSC_MAIN); //seting system clock as 8Mhz
	//InitConsole();
	// Enable the I2C0 peripheral
	//
	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0));
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));
	//configure the muxing and GPIO settings to bring the SSI functions out to the pins
	GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
	GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
	GPIOPinConfigure(GPIO_PB2_I2C0SCL);
	GPIOPinConfigure(GPIO_PB3_I2C0SDA);
	I2CSlaveAddressSet(I2C0_BASE,0,0x20);
	I2CSlaveInit(I2C0_BASE,0x20);
	I2CSlaveEnable(I2C0_BASE);
	while(1) {
		//
		// Place the data to be sent in the data register
		//
		for(i=0;i<=n;i++){
			char_rx[i]=I2CSlaveDataGet(I2C0_BASE);

			// Wait until the slave has received and acknowledged the data.
			while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_RREQ));

			I2CSlaveDataPut(I2C0_BASE,char_rx[i]);
			while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_TREQ));

		}
	}
}

Thank you,

Alphy

  • Hello Alphy,

    Did you install external pull-up resistors on one of the two LaunchPad's? I2C needs the pull-ups to work.

    Also I don't see any UART code for the slave, so can you share that code so I can test it with the UART outputs?
  • Hello Alphy,

    I understand that you may have gotten pulled away due to holidays but please let us know by next week if this topic needs to be kept open until you return from holiday break or if we can close it as the issue has been resolved.
  • Hi sir,

    I was on leave for last one week ,so I am unable to reply. Sorry for the late reply.

    1. Did you install external pull-up resistors on one of the two LaunchPad's? I2C needs the pull-ups to work.

    Yes sir, I am using external pull-up resistors.

    2. Also I don't see any UART code for the slave, so can you share that code so I can test it with the UART outputs?

    No sir, I didn't add any UART code in my slave.Because I am connecting UART to my master device.

    What I am trying to do is sending the data from master to slave and slave send back the same data to the master and UART is connected to master, so through UART it should display whatever the data, I am sending back to master from the slave. So for this condition I was not connecting UART to slave.

    I tried master to slave communication separately and it is working fine, whatever the data I am sending from master, is receiving correctly in slave and display through UART. The issue I am facing is sending the same data back to the master from slave.

    Thank you,

    Alphy

  • Hi sir,

    I am waiting for your reply.Please help me to solve the issue.

    I was tried to send data from slave to master and that is also working fine.I am facing issues while sending data from master to slave and send the same data back to slave.Please help me to solve the issue as soon as possible.

    Thank you,

    Alphy

  • Hello Alphy,

    I had to setup a LaunchPad with pull-ups myself to be able to run your code. Unfortunately the code you have posted me does not even send from master to slave correctly. Can you please upload the code with which you verified the master to slave communication? From there we can work to add sending back the received slave data to the master, that will be the quickest way since you did have master to slave communication working before.
  • Hi Sir,

    Thank you so much for your quickest reply.

    Yeah sir, modification in working code is easy.

    The working code is given below.

    Master code

    #define SLAVE_ADDRESS 0x20
    int main()
    {

    uint32_t n=3,i;
    char char_tx[]="abcd";


    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC |SYSCTL_XTAL_8MHZ|SYSCTL_OSC_MAIN); //seting system clock as 8Mhz

    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0));
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));
    //configure the muxing and GPIO settings to bring the SSI functions out to the pins
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    I2CMasterEnable(I2C0_BASE);

    I2CMasterInitExpClk(I2C0_BASE,SysCtlClockGet(),false);

    while(1)
    {

    I2CMasterSlaveAddrSet(I2C0_BASE,SLAVE_ADDRESS,false);

    if(char_tx[1] == '\0')
    {
    //Initiate send of data from the MCU
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);

    // Wait until MCU is done transferring.
    while(I2CMasterBusy(I2C0_BASE));
    }

    else{

    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    // Wait until MCU is done transferring.
    while(I2CMasterBusy(I2C0_BASE));

    for(i=1;i<n;i++)
    {
    //put next piece of data into I2C FIFO
    I2CMasterDataPut(I2C0_BASE, char_tx[i]);

    //send next data that was just placed into FIFO
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    //
    // // Wait until MCU is done transferring.
    while(I2CMasterBusy(I2C0_BASE));
    // i++;
    }

    I2CMasterDataPut(I2C0_BASE, char_tx[n]);

    //send next data that was just placed into FIFO
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    while(I2CMasterBusy(I2C0_BASE));

    }}}

    Slave code

    int main()
    {
    char data, char_rx[5],receive;
    // uint32_t pui32DataTx;
    uint32_t n=5,i;
    //uint32_t pui32DataRx[5];
    //uint32_t ui32Period;
    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_XTAL_8MHZ|SYSCTL_OSC_MAIN); //seting system clock as 8Mhz
    InitConsole();

    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0));
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));
    //configure the muxing and GPIO settings to bring the SSI functions out to the pins
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    I2CSlaveAddressSet(I2C0_BASE,0,0x20);
    I2CSlaveInit(I2C0_BASE,0x20);
    I2CSlaveEnable(I2C0_BASE);

    while(1) {
    //
    // Place the data to be sent in the data register
    //
    for(i=0;i<=n;i++){
    //pui32DataRx[i]=I2CSlaveDataGet(I2C0_BASE);
    char_rx[i]=I2CSlaveDataGet(I2C0_BASE);
    // Wait until the slave has received and acknowledged the data.
    while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_RREQ));
    UARTCharPut(UART0_BASE,char_rx[i]);
    }}}

    //

    //UART Function for displaying the data sent from master

    //

    void InitConsole(void)
    {
    //
    // Enable the UART0 module.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    //
    // Wait for the UART0 module to be ready.
    //
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0));
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA));
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,(UART_CONFIG_WLEN_8|UART_CONFIG_STOP_ONE|UART_CONFIG_PAR_NONE));
    UARTCharPut(UART0_BASE, 'J');
    }

    Thank you,

    Alphy

  • Hello Alphy,

    Thanks for sharing the working code, made it much easier to see what was going on with the code you posted at first.

    The core of the issue is the logic you have put in place for trying to send data back and forth doesn't match with the commands you are using. You are trying to BURST SEND but you only send one byte at a time before trying to BURST RECEIVE. However the purpose of those commands are to send or receive multiple bytes at once, and the way they are used is not correct. The slave ends up not seeing the correct ending to the burst command and instead NAK's the first byte of data sent which halts the transmission. Once I changed the first code you posted to not interrupt the BURST SEND, it was able to transmit correctly again.

    In order to finish implementing sending back the receive data, you have two options available. I will describe them so you can choose what works best for you.

    1) Send all data with BURST and then receive all data with BURST. If this is done, I recommend using a header byte to inform the slave of how many bytes to expect so you can make sure you receive all the needed data.

    2) Use I2C_MASTER_CMD_SINGLE_SEND and I2C_MASTER_CMD_SINGLE_RECEIVE with current logic of send 1, receive 1 (will require some fine tuning).
  • Hi sir, 

    Thank you for your quick reply.

    I am having some doubts about the changes you mentioned.

    1. The slave ends up not seeing the correct ending to the burst command and instead NAK's the first byte of data sent which halts the transmission.

    Sir, Please explain me what are the changes I need to do in the slave code to make it work properly .

    2. Send all data with BURST and then receive all data with BURST. If this is done, I recommend using a header byte to inform the slave of how many bytes to expect so you can make sure you receive all the needed data.

    I am trying to use this method. please explain me sir, how I can implement the header byte logic.

    Thank you,

    Alphy

  • Hello Alphy,

    I would recommend reading our app note on I2C to understand better what you need to do, it explains how BURST mode is used among other things: www.ti.com/.../spma073.pdf

    Header byte logic is simple, just have the first byte or two of every packet you send be the amount of data sent. One byte if you won't send more than 255 bytes, two bytes if you will exceed that (0xFF = 255, so you can't indicate a larger transfer without using two bytes). Then on the slave, once that byte is received, the slave will know how many more bytes to expect before it receives the full packet so it can know when the transmit is done and it is allowed to echo the data back.
  • Hi sir,

    Thank you so much for supporting me to resolve the issue.

    I red the document you gave and it gives a better understanding for me. After reading the document I got a clear picture about the steps I need to follow for a proper communication.

    once again Thank you so much for your help.

    Without using header byte logic I did my communication. Still I am not understanding how I can implement header byte logic.

    Header byte logic is simple, just have the first byte or two of every packet you send be the amount of data sent. This is the place where I am confusing.I am not getting how I can send the amount of data in a header byte.

    If you don't mind, please explain it using an example.

    Thank you,

    Alphy

  • Hello Alphy,

    The idea behind that is if you are the master device, you should know how many bytes of data you want to send out from your buffer. Say you have a buffer that is 50 spaces wide. If your process required sending the first 15 bytes of that buffer, you would know that. So before sending the buffer bytes, you start the I2C communication, and then send a single byte for the length of the data you are sending first. '15' (or in HEX, 0x0F).

    Then after sending that 'header' byte, you immediately send the buffer data. So the slave device receives 16 bytes total. The 'header' byte which is '15' to say that 15 bytes of data will follow, and then the expected 15 bytes of data.

    This also lets you protect against missed data bytes as if you received only 14 bytes, you know something went wrong, and the slave can indicate this to the master then.
  • Hi sir,

    Now I got a better understanding about the header byte concept. I tried it in my code and it is working fine.

    Thank you so much for using your valuable time for detailed explanation. I am new to embedded that's why the header byte concept was difficult for me.

    once again thank you so much sir.

    Thank you,

    Alphy