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.

I2C Interface between 2 Tiva C Launchpad

I want to interface between 2 Tiva C Launchpad by I2C Interface. Tiva Master get data from Computer by UART and then transmit data to Slave by I2C. Tiva Slave receive data and control LED turn on. 

But i have problem, and i don't know what is wrong?

Can anybody help me?

Thank you!

Master Tiva code:

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "utils/uartstdio.c"
// address of SLAVE
#define SLAVE_ADDRESS          0x3C
// Configure UART0 to console data which transmitted
void InitConsole(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTStdioConfig(0, 115200, 16000000);
}
void I2C0_Init(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    //HWREG(I2C0_BASE + I2C_O_MCR) |= 0x01;
    I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
}
void I2C0_Send(uint16_t device_address, uint8_t device_data)
{
    // Determine Slave address
    // false: transmit Master --> Slave
    // true:  receive  Master <-- Slave
    I2CMasterSlaveAddrSet(I2C0_BASE, device_address, false);
    // Put data
    I2CMasterDataPut(I2C0_BASE, device_data);
    // Transmit data
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    // Wait until finish
    while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_RREQ));
}
int main(void)
{
    uint32_t ui32DataTx;
    SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
            SYSCTL_XTAL_16MHZ);
    I2C0_Init();
    InitConsole();
    IntMasterEnable();
    UARTprintf("I2C Slave Interrupt Example ->");
    UARTprintf("\n  Module = I2C0");
    UARTprintf("\n  Mode = Receive interrupt on the Slave module");
    UARTprintf("\n  Rate = 100kbps\n\n");
    while(1)
    {
        ui32DataTx = UARTCharGet(UART0_BASE);
        UARTprintf("Transferring from: Master -> Slave\n");
        UARTprintf("  Sending: '%c'", ui32DataTx);
        I2C0_Send(SLAVE_ADDRESS, ui32DataTx);
    }
}

Slave Tiva code:

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
// address of SLAVE
#define SLAVE_ADDRESS          0x3C
// global variable to receive data
static uint32_t g_ui32DataRx;

// The interrupt handler for the for I2C0 data slave interrupt.
void I2C0SlaveIntHandler(void)
{
    // Clear the I2C0 interrupt flag.
    I2CSlaveIntClear(I2C0_BASE);
    // Read the data from the slave.
    g_ui32DataRx = I2CSlaveDataGet(I2C0_BASE);
    I2CSlaveStatus(I2C0_BASE);
}
void I2C0_Init(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    //HWREG(I2C0_BASE + I2C_O_MCR) |= 0x01;
    //I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
}
int main(void)
{
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
            SYSCTL_XTAL_16MHZ);
    I2C0_Init();
    IntEnable(INT_I2C0);
    I2CSlaveIntEnableEx(I2C0_BASE, I2C_SLAVE_INT_DATA);
    I2CSlaveEnable(I2C0_BASE);
    I2CSlaveInit(I2C0_BASE, SLAVE_ADDRESS);
    IntMasterEnable();
    while(1)
    {
        switch (g_ui32DataRx)
        {
        case 'r':
            GPIOPinWrite(GPIO_PORTF_BASE, 0x0E, 0);
            GPIOPinWrite(GPIO_PORTF_BASE, 0x02, 0x02);
            break;
        case 'g':
            GPIOPinWrite(GPIO_PORTF_BASE, 0x0E, 0);
            GPIOPinWrite(GPIO_PORTF_BASE, 0x08, 0x08);
            break;
        case 'b':
            GPIOPinWrite(GPIO_PORTF_BASE, 0x0E, 0);
            GPIOPinWrite(GPIO_PORTF_BASE, 0x04, 0x04);
            break;
        }
    }
}

  • Hello,

    I am going to move this to the Tiva C forum for better support since your question is about the Tiva micro controller.

  • Hello Phan,

    Do you have the Pull Up resistance on the SCL and SDA? Can you also refer to the following application note.

    www.ti.com/.../spma073.pdf

    One thing I did notice in the master code is the following

    while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_RREQ));

    That is incorrect. A master cannot know about the remote slave. You should instead be using I2CMatserBusy to poll.

    Also it will be worth the effort to capture a scope snapshot to see what is happening on the bus.

    Regards
    Amit
  • Hello,

    If you just want a channel of communication I advise a SPI interface to be used instead of i2c. It's just so much more simple. (This saying from someone that doesn't like i2c :p)

    Unless you of course really need multiple slaves with just 2 I/O and/or are trying to learn for a future implementation
  • Luis Afonso said:
    If you just want a channel of communication I advise a SPI interface to be used instead of i2c.

    Yes - poster (could) do that - but isn't an obvious - and far easier "channel of communication" available?

    Poster has mastered UART - thus ALL "new learning" and struggling is eliminated by having 2 TM4C's "talk together" via UART!  

    • Multiple UARTs appear on most all ARM implementations, thus "squeezing out" a 2nd UART channel should not be difficult.
    • Poster specified MCU to MCU - so the "fringe benefit" of I2C (or SPI) is null.  
    • And - if greater distance is (or becomes) helpful and/or required - UART into RS232 well accommodates!    Both I2C and SPI "cash out" should greater distance be helpful and/or demanded...

    Ease, existing familiarity, design speed and far greater range - all point to UART as "best" for this poster...  

  • Thank you so much, my project performed! :)
  • Hello Phan

    What was the issue?

    Regards
    Amit
  • I could transmit data from Master to Slave. Now, I 'm trying to read data from Slave, but all i receive is 'y' symbol! I think command 

    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); influence my code, or may be interrupt. Please help me, Thank you so much!

    This is Master code:

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #include "utils/uartstdio.c"
    
    #define SLAVE_ADDRESS 0x3C
    volatile uint32_t 	read;
    volatile uint32_t receive;
    
    void I2C0MasterIntHandler(void)
    {
    	// Clear the I2C0 interrupt flag.
    	I2CMasterIntClear(I2C0_BASE);
    	// Read the data from the slave.
    	receive = I2CMasterDataGet(I2C0_BASE);
    }
    
    void InitConsole(void)
    {
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    	UARTStdioConfig(0, 115200, 16000000);
    }
    
    void I2C0_Master_Init(void)
    {
    	//enable GPIO peripheral that contains I2C 0
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));
    
    	//enable I2C module 0
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    	//reset module
    	SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
    
    	// Configure the pin muxing for I2C0 functions on port B2 and B3.
    	GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    	GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    
    	// Select the I2C function for these pins.
    	GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    	GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    
    	// Enable and initialize the I2C0 master module.  Use the system clock for
    	// the I2C0 module.  The last parameter sets the I2C data transfer rate.
    	// If false the data rate is set to 100kbps and if true the data rate will
    	// be set to 400kbps.
    	I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
    
    	//clear I2C FIFOs
    	// HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;
    
    }
    
    int main(void)
    {
    	SysCtlClockSet(SYSCTL_SYSDIV_1| SYSCTL_USE_OSC| SYSCTL_OSC_MAIN| SYSCTL_XTAL_16MHZ);
    
    	InitConsole();
    	I2C0_Master_Init();
    
    	IntEnable(INT_I2C0);
    	I2CMasterIntEnableEx(I2C0_BASE, I2C_MASTER_INT_DATA);
    	IntMasterEnable();
    
    	UARTprintf("Master --> Slave \n");
    
    	while(1)
    	{
    		I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, true);
    		I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    		while(I2CMasterBusy(I2C0_BASE));
    
    		UARTprintf("Received: %d \n", receive);
    		UARTprintf("received: '%c' \n", receive);
    
    		SysCtlDelay(SysCtlClockGet()/6);
    	}
    }

    And Slave:

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #include "utils/uartstdio.c"
    
    #define SLAVE_ADDRESS 0x3C
    volatile uint32_t   result = 'V';
    
    void InitConsole(void)
    {
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    	UARTStdioConfig(0, 115200, 16000000);
    }
    
    
    void I2C1_Slave_Init(void)
    {
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA));
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);
    	SysCtlPeripheralReset(SYSCTL_PERIPH_I2C1);
    
    	GPIOPinConfigure(GPIO_PA6_I2C1SCL);
    	GPIOPinConfigure(GPIO_PA7_I2C1SDA);
    
    	GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6);
    	GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7);
    
    	I2CSlaveEnable(I2C1_BASE);
    	I2CSlaveInit(I2C1_BASE, SLAVE_ADDRESS);
    }
    
    void I2C1SlaveIntHandler(void)
    {
    	// Clear the I2C0 interrupt flag.
    	I2CSlaveIntClear(I2C1_BASE);
    	// Read the data from the slave.
    	result = I2CSlaveDataGet(I2C1_BASE);
    }
    
    int main(void)
    {
    	SysCtlClockSet(SYSCTL_SYSDIV_1| SYSCTL_USE_OSC| SYSCTL_OSC_MAIN| SYSCTL_XTAL_16MHZ);
    
    	InitConsole();
    	I2C1_Slave_Init();
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
    
    	IntEnable(INT_I2C1);
    	I2CSlaveIntEnableEx(I2C1_BASE, I2C_SLAVE_INT_DATA);
    	IntMasterEnable();
    
    	while(1)
    	{
    		//I2CSlaveDataPut(I2C1_BASE, result);
    		UARTprintf(" Slave receive: '%c' \n", result);
    		SysCtlDelay(SysCtlClockGet()/12);
    
    		//while(!(I2CSlaveStatus(I2C1_BASE) & I2C_SLAVE_ACT_TREQ));
    
    		I2CSlaveDataPut(I2C1_BASE, result);
    	}
    }

  • Like you said: while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_RREQ)); is incorrect, and one more, i didn't use pull up resistor!
  • Hello Phan Vu

    Thank you for the confirmation. Indeed Pull Up is required and that is why the Application Note concentrates on why.

    Regards
    Amit