I2C interface on Tiva

11,837

Solution 1

The problem has been resolved. There were issues:

  • It is essential to populate external pull ups.
  • Use GPIOPinTypeI2C() 2nd parameter as a bit field instead of a bit number.
  • The procedure SysCtlClockSet() is dedicated specially to TM4C123 devices. Instead use g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);
  • For a Master clock setting do not use SysCtlClockGet() procedure. This is also dedicated to TM4C123 devices. Instead use I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);

Here is the updated code,

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "inc/tm4c129xnczad.h"

#define SLAVE_ADDRESS 0x3C

void    delay   (void)
{
  volatile uint32_t ui32Loop;   
    for(ui32Loop = 0; ui32Loop < 200; ui32Loop++);
}


volatile uint32_t  result;
    uint32_t    g_ui32SysClock;

int main(void)
{
    g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000); 
    //
    // Enable the GPIO port that is used for the on-board LED.
    //
    SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
    //
    // Do a dummy read to insert a few cycles after enabling the peripheral.
    //
    result = SYSCTL_RCGCGPIO_R;
    //
    // Enable the GPIO pin for the LED (PD3).  Set the direction as output, and
    // enable the GPIO pin for digital function.
    //
    GPIO_PORTD_AHB_DIR_R = 0x8;
    GPIO_PORTD_AHB_DEN_R = 0x8;

    SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6); // Mode Clock Gating Control for I2C modules 4 and 6

    GPIOPinConfigure(GPIO_PK6_I2C4SCL);
    GPIOPinConfigure(GPIO_PK7_I2C4SDA);
    GPIOPinConfigure(GPIO_PB6_I2C6SCL);
    GPIOPinConfigure(GPIO_PB7_I2C6SDA);

    GPIOPinTypeI2C(GPIO_PORTK_BASE, (1 << 7));       // Configures SDA
    GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, (1 << 6));    // Configures SCL
    GPIOPinTypeI2C(GPIO_PORTB_BASE, (1 << 7));       // Configures SDA
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, (1 << 6));    // Configures SCL

    I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);

    I2CSlaveEnable(I2C6_BASE);
    I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
    I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
    //
    // Loop forever.
    //
    while(1)
    {
        //
        // Turn on the LED.
        //
        GPIO_PORTD_AHB_DATA_R |= 0x8;

        I2CMasterDataPut(I2C4_BASE, 0x33);
        I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
        //
        // Wait until the slave has received and acknowledged the data.
        //
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));           
        //
        // Read the data from the slave.
        //
        result = I2CSlaveDataGet(I2C6_BASE);
        //
        // Wait until master module is done transferring.
        //
        while(I2CMasterBusy(I2C4_BASE));
        //
        // Delay for a bit.
        //
        delay   ();
        //
        // Turn off the LED.
        //
        GPIO_PORTD_AHB_DATA_R &= ~(0x8);
        //
        // Delay for a bit.
        //
        delay   ();
    }
}

Solution 2

I was able to get I2C working on TIVA Launchpad TM4C123GH6PM. I used the the Tivaware library. I created 3 functions, init and write. Here are the functions.

Initialization

void initI2C0(void)
{
   SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

   //reset I2C module
   SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

   //enable GPIO peripheral that contains I2C
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

   // 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;
}

I2C Write Function

void writeI2C0(uint16_t device_address, uint16_t device_register, uint8_t device_data)
{
   //specify that we want to communicate to device address with an intended write to bus
   I2CMasterSlaveAddrSet(I2C0_BASE, device_address, false);

   //register to be read
   I2CMasterDataPut(I2C0_BASE, device_register);

   //send control byte and register address byte to slave device
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

   //wait for MCU to finish transaction
   while(I2CMasterBusy(I2C0_BASE));

   I2CMasterSlaveAddrSet(I2C0_BASE, device_address, true);

   //specify data to be written to the above mentioned device_register
   I2CMasterDataPut(I2C0_BASE, device_data);

   //wait while checking for MCU to complete the transaction
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

   //wait for MCU & device to complete transaction
   while(I2CMasterBusy(I2C0_BASE));
}

Complete code for TIVA + I2C can be found here.

Reference

Share:
11,837
MarcoPolo
Author by

MarcoPolo

Updated on June 04, 2022

Comments

  • MarcoPolo
    MarcoPolo almost 2 years

    On a Tiva (Texas Instruments Cortex M4F ARM) TM4C129XNCZAD I have a problem with I2C interface. I have enabled both a master on I2C module 4 thru port K and a slave on I2C module 6 thru port B. I have interconnected both I2C modules. Using Texas Instruments driver library I tried to send 1 byte using I2C_MASTER_CMD_SINGLE_SEND command. I spend a lot of time to make it working, but SCK line keeps Low logical level. I followed exactly TivaWare™ Peripheral Driver Library USER’S GUIDE, but the communication doesn't work. Has anybody some experience with it?

    There is my code:

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_i2c.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/gpio.h"
    #include "driverlib/i2c.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "inc/tm4c129xnczad.h"
    
    #define SLAVE_ADDRESS 0x3C
    
    void  delay  (void)
    {
        volatile uint32_t ui32Loop; 
        for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++);
    }
    
    volatile  uint32_t  result;
    
    int  main  (void)
    {
        SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); 
        //
        // Enable the GPIO port that is used for the on-board LED.
        //
        SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
        //
        // Do a dummy read to insert a few cycles after enabling the peripheral.
        //
        result = SYSCTL_RCGCGPIO_R;
        //
        // Enable the GPIO pin for the LED (PD3).  Set the direction as output, and
        // enable the GPIO pin for digital function.
        //
        GPIO_PORTD_AHB_DIR_R = 0x8;
        GPIO_PORTD_AHB_DEN_R = 0x8;
        GPIO_PORTK_DEN_R = 0xC0;        // Enable Port K for I2C module 4
    
        GPIO_PORTB_AHB_DEN_R = 0xC0;    // Enable Port B for I2C module 6
    
        SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6);  // Mode Clock Gating Control for I2C modules 4 and 6
        GPIO_PORTK_AFSEL_R = 0xC0;      // Alternate Function Select PK6, PK7
        GPIO_PORTB_AHB_AFSEL_R = 0xC0;  // Alternate Function Select PB6, PB7
        GPIOPinConfigure(GPIO_PK6_I2C4SCL);
        GPIOPinConfigure(GPIO_PK7_I2C4SDA);
        GPIOPinConfigure(GPIO_PB6_I2C6SCL);
        GPIOPinConfigure(GPIO_PB7_I2C6SDA);
    
        GPIOPinTypeI2C(GPIO_PORTK_BASE, 7);       // Configurtes SDA
        GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, 6);    // Configurtes SCL
        GPIOPinTypeI2C(GPIO_PORTB_BASE, 7);       // Configurtes SDA
        GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, 6);    // Configurtes SCL
    
        I2CMasterInitExpClk(I2C4_BASE, SysCtlClockGet(), false);
    
        I2CSlaveEnable(I2C6_BASE);
        I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
        I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
        //
        // Loop forever.
        //
        while(1)
        {
            //
            // Turn on the LED.
            //
            GPIO_PORTD_AHB_DATA_R |= 0x8;
    
            I2CMasterDataPut(I2C4_BASE, 0x33);
            I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
            //
            // Wait until the slave has received and acknowledged the data.
            //
            while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));
            //
            // Read the data from the slave.
            //
            result = I2CSlaveDataGet(I2C6_BASE);
            //
            // Wait until master module is done transferring.
            //
            while(I2CMasterBusy(I2C4_BASE));
            //
            // Delay for a bit.
            //
            delay ();
            //
            // Turn off the LED.
            //
            GPIO_PORTD_AHB_DATA_R &= ~(0x8);
            //
            // Delay for a bit.
            //
            delay ();
        }
    }
    
  • Mahendra Gunawardena
    Mahendra Gunawardena over 8 years
    @Parag The code word as it is, why do you want to change the code. The complete code is on github