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.

TM4C1294NCPDT: I2C SDA line not sending the right data in the Tivaware driver library

Part Number: TM4C1294NCPDT

Hello, I'm trying to talk to an OLED display (ssd1306) on my custom board via i2c with my tm4c1294ncpdt. ) I seem to be having an issue with the library (version TivaWare_C_Series-2.2.0.295). I have gotten to the point in my configuration where I can see some basic i2c data on my scope but it always seems to send to an address of 0x7F not 0x3C (i have also tried 0x78, 0x3D, 0x7A all output 0x7F) and no data. (and yes I have pull up resistors installed if that a question, I found that 1k seems to make the clock rise really sharp).

UNLESS i use an address of 0x00, then it seems to spit data of 0x7F

Here is the code for my config. 

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "inc/hw_ints.h"
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/systick.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "utils/uartstdio.h"
#include "i2c.h"
#include "ssd1306.h"

uint32_t g_ui32SysClock;

void I2C_2_config()
{
    // Configure I2C3 for pins PN4 and PN5
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C2);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C2);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);

    while (!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C2)){
    }
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPION)){
    }

    GPIOPinConfigure(GPIO_PN5_I2C2SCL);
    GPIOPinConfigure(GPIO_PN4_I2C2SDA);

    GPIOPinTypeI2CSCL(GPIO_PORTN_BASE, GPIO_PIN_5);
    GPIOPinTypeI2C(GPIO_PORTN_BASE, GPIO_PIN_4);

    //config for sda line (heard this in a thread somewhere)
    GPIOPadConfigSet(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);

    //also heard this in a thread somewhere
    I2CMasterGlitchFilterConfigSet(I2C2_BASE, I2C_MASTER_GLITCH_FILTER_8);

    I2CMasterInitExpClk(I2C2_BASE, g_ui32SysClock, false); //the true false doesnt seem to change the speed from 100k to 400k

    I2CMasterTimeoutSet(I2C2_BASE, 0x7D);

    I2CMasterEnable(I2C2_BASE);

}


void I2C_sendSingleByte(uint8_t slave_addr, char data)
{
    I2CMasterSlaveAddrSet(I2C2_BASE, slave_addr, false);
    I2CMasterDataPut(I2C2_BASE, data);
    I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    while (I2CMasterBusy(I2C2_BASE));
}

int main(void)
{
    g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);

    I2C_2_config();

    while(I2CMasterBusy(I2C2_BASE));

    I2C_sendSingleByte(0x00, 0x00); //if i use any address other than 0x00, it actually sends address 0x7F
                                    //If i do use address 0x00, then it sends data 0x7F
    while (1)
    {

    }
}

Another weird thing that I noticed about this built-in i2c library is that when I use the I2CMasterInitExpClk(I2C2_BASE, g_ui32SysClock, false);, changing the true or false doesn't seem to effect the speed at which the i2c data comes out at. Perhaps this is some sort of bug in the driver? 

I have also bit banged my own basic i2c program where I force the correct address and the OLED display seems to respond (when i get the right address, i verified it doesn't do the same pull down stuff if the address is incorrect) as i can tell from the SDA line being pulled down. 

And i know its the OLED display pulling the line down because with the same exact code with the OLED display removed, the line isnt pulled down the same way at all.

Here is my bitbang i2c code please ignore the uglyness of the code, just trying to force i2c like bits to verify the goodness of the display. 

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "inc/hw_ints.h"
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/systick.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "utils/uartstdio.h"
#include "i2c.h"
#include "ssd1306.h"

uint32_t g_ui32SysClock;

void I2C_2_config()
{ // Configure I2C3 for pins PN4 and PN5

    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C2);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C2);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    GPIOPinConfigure(GPIO_PN5_I2C2SCL);
    GPIOPinConfigure(GPIO_PN4_I2C2SDA);
    GPIOPinTypeI2CSCL(GPIO_PORTN_BASE, GPIO_PIN_5);
    GPIOPinTypeI2C(GPIO_PORTN_BASE, GPIO_PIN_4);
    I2CMasterInitExpClk(I2C2_BASE, g_ui32SysClock, false);
}


void I2C_sendSingleByte(uint8_t slave_addr, char data)
{
    I2CMasterSlaveAddrSet(I2C2_BASE, slave_addr, false);
    I2CMasterDataPut(I2C2_BASE, data);
    I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    while (I2CMasterBusy(I2C2_BASE));
}

void I2C_sendMultipleBytes(uint8_t slave_addr, uint8_t numOfBytes, char by[]){
  uint8_t i;
  I2CMasterSlaveAddrSet(I2C2_BASE, slave_addr, false);
  I2CMasterDataPut(I2C2_BASE, by[0]);
  I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_START);
  while(I2CMasterBusy(I2C2_BASE));
  for(i = 1; i < numOfBytes - 1; i++){
    I2CMasterDataPut(I2C2_BASE, by[i]);
    I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    while(I2CMasterBusy(I2C2_BASE));
  }
  I2CMasterDataPut(I2C2_BASE, by[numOfBytes - 1]);
  I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
  while(I2CMasterBusy(I2C2_BASE));
}

int main(void)
{
    g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);

    I2C_2_config();

    int i;
    int j;
    int k;

    GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_5);
    GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_4);

    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, GPIO_PIN_5);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_PIN_4);

    int Data = 0x78;

    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, 0x0);


//send 0x78 via SDA
    for (i = 0x100; i >= 0x1; i = i >> 1)
    {
        if ((Data & i) == i)
        {
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_PIN_4);
        }
        else
        {
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, 0x0);
        }
        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, GPIO_PIN_5);
        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, 0x0);
    }

    for(k = 0; k <= 0xF; k++){
        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_PIN_4);
    }
    
//send 0xAE via SDA
    Data = 0xAE;

        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, 0x0);

        for (i = 0x100; i >= 0x1; i = i >> 1)
        {
            if ((Data & i) == i)
            {
                GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_PIN_4);
            }
            else
            {
                GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, 0x0);
            }
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, GPIO_PIN_5);
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, 0x0);
        }

        for(k = 0; k <= 0xF; k++){
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_PIN_4);
           }

        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, GPIO_PIN_5);
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_PIN_4);

    while (1)
    {

    }
}

I'm running out of ideas and am getting a bit frustrated as it seems like everybody else using the i2c drivers and code seems to be getting it to work fairly easily. I'm not sure how my config is different. I have a suspicion that my drivers are to blame, and ive tried using an older version of the tiva library (2.1.4.178) and it does the same stuff. 

Thanks, -Sam

  • Hello Sam,

    I am a bit perplexed by this myself. The behavior doesn't make sense to me either and I don't see any clear issues with your code.

    I don't have a board I can test with today on hand but I can do some tests tomorrow. I will need to do some testing to really comment more about this issue.

    Until then a few comments:

    1) I would remove this line - it is handled by the GPIOPinTypeI2C API the only difference here is a higher drive strength which I don't think is needed at all for this.

        //config for sda line (heard this in a thread somewhere)
        GPIOPadConfigSet(GPIO_PORTN_BASE, GPIO_PIN_4, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);

    2) I would remove the glitch filter as well for now - let's dumb this down and then we can use knobs like that if it doesn't work.

    3) I don't know if you have come across this, but this app note has I2C info too: https://www.ti.com/lit/pdf/spma073

    If you are okay waiting until I test myself tomorrow feel free to set this aside and let me do some leg work on trying your code out on my own hardware and see what is going on.

    Best Regards,

    Ralph Jacobi

  • Hi Sam,

    Well this was a puzzling one for a while - but I figured it out...

    The issue isn't with the I2C module or your I2C configurations.

    The issue is you didn't set your system clock right - which is why the I2C was running at 400kHz too.

    Use this and you'll be fine (assuming on LaunchPad, otherwise update to the crystal frequency for your board)

        g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                                 SYSCTL_OSC_MAIN |
                                                 SYSCTL_USE_PLL |
                                                 SYSCTL_CFG_VCO_240), 120000000);

    Best Regards,

    Ralph Jacobi

  • Thank you for spending the time and figuring this out, however another problem arises when I use that configuration for my board, the MCU locks up after uploading this program with your clock config, then i have to go into LM flash programmer to unlock my MCU. but with the line i had setup, it never needed to do that. I have a 25MHz crystal on my main OSC. I don't have any crystal installed on the XOSC. 

    Here is my schematic. 

    Also not sure if you need this but this is the crystal that i used. 

    https://www.diodes.com/assets/Datasheets/FK-3-3V.pdf

    Perhaps this is another simple thing that I'm not seeing yet?

  • Hi Sam,

    Are you on TivaWare 2.2.0.295 with the project now?

    I did post a configuration using SYSCTL_CFG_VCO_240 which we added in 2.2.0.295. I know you mentioned that you had looked at 2.1.4 as well so want to check on that first.

    I can't really speak to the crystal you are using and if it would work the device, but it's connected to the right pins.

    The code you used before did not use the external oscillator so that's probably it worked. But without the external oscillator, you weren't getting the PLL up and running and so the system clock that you tried to set was too high versus what the device could actually sustain.

    Best Regards,

    Ralph Jacobi

  • Ok so I've got the OLED display actually accepting commands and doing stuff but right now im just running the system off of the internal OSC. Ill have to dig around some more to try to get it to run off the external 25Mhz osc but for now i can continue my development. Thank you Ralph, you have been very helpful. 

  • Ill have to dig around some more to try to get it to run off the external 25Mhz osc but for now i can continue my development.

    Is the RBIAS resistor connected on your board?

    If not, may be encountering the following errata in Tiva C Series TM4C129x Microcontrollers Silicon Revisions 1, 2, & 3 Errata (Rev. G) :

  • Hi Chester,

    Thanks for this suggestion, I hadn't thought of that after Sam's post. If RBIAS is not installed that is highly likely to be the reason for the issue.

    Best Regards,

    Ralph

  • Yes do have that 4k87 RBIAS resistor installed.