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 EEPROM access issues

Other Parts Discussed in Thread: TM4C129DNCPDT

Basic information:

Processor: TM4C129DNCPDT

Eeprom: Atmel AT24C256C (256kbits)

Environment: IAR Embedded Workbench

TivaWare_C_Series-2.1.0.12573

I2C set 100KHz rate.

I am trying to understand how the I2C controller works and how to make it work properly with denser EEPROMS.

Bellow the relevant code (adapted from another topic - omitted stuff to avoid too much clutter):

void eepromRead(uint16_t address_u16, uint32_t *rxdata_pu8, uint32_t rxdataLen_u32)
{
    uint32_t ret = 0;

    I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
    I2CMasterDataPut(I2C4_BASE, ((address_u16 >> 8) & 0xFF)); //MSB
    I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    SysCtlDelay(I2C_CONTROL_DELAY);
    while(I2CMasterBusy(I2C4_BASE))  {}

    I2CMasterDataPut(I2C4_BASE, (address_u16 & 0xFF)); //LSB
    I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    SysCtlDelay(I2C_CONTROL_DELAY);
    while(I2CMasterBusy(I2C4_BASE))  {}

 
    I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, true);
    I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE );
    SysCtlDelay(I2C_CONTROL_DELAY);
    while(I2CMasterBusy(I2C4_BASE))  {}

    ret = I2CMasterDataGet(I2C4_BASE) & 0xFF;
    rxdata_pu8[0] = ret;
}

int
main(void)
{
    ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_10MHZ |
                                           SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                                           SYSCTL_CFG_VCO_480), 40000000u);
    
    uint32_t rx[8];
    I2C_Init();
    while(1)
    {
        SimpleDelay();
        rx[0] = 0x0;
        eepromRead(0x248, rx, 1);
        eepromRead(0x249, rx, 1);
    }
}

To read a random byte out from the EEPROM I must issue a dummy write with two bytes and then a read.

The thing that is baffling me is that I get different results depending on the I2C_CONTROL_DELAY parameter in eepromRead(). With 100 (which if I understand it right causes a delay of about 300 clocks) the read operation works fine.

With a lower value, say 50 (around 150 clocks) I get this:

As you can see on the bottom of the screen, the LSB of the address is missed. I would like to know what I am doing wrong.

To be honest I adde the SysCtlDelay() call after reading somewhere that there was some internal delay in the microcontroller but I do not think one would need so many clocks for the I2C to set the busy flag.

Thank you in advance for any hint.

  • Hello Elder,

    The delay is required on the TM4C129 as the I2C module becoming busy from the time a command is written different when compared to TM4C123.

    Normally what we recommend is to use the I2CMasterBus as follows after writting a command. This gets rid of the delay as the system clock frequency is changed.

    while(!I2CMasterBusy(I2C4_BASE))  {}

    while(I2CMasterBusy(I2C4_BASE))  {}

    Regards

    Amit

  • Hello Amit,

    Thank you for the answer. I tried it and it worked. This would not work 100% with interrupt based software but for it is good enough for my current purposes.

    I have a different question now: how do I check if the ACK/NAK state? I tried to do as in the code bellow:

    bool eepromCheck (void)
    {
        I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
        I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_QUICK_COMMAND);
        while(!I2CMasterBusy(I2C4_BASE))  {}
        while(I2CMasterBusy(I2C4_BASE))  {}
        uint32_t ui32Err = HWREG(I2C4_BASE + I2C_O_MCS);
        //uint32_t err = I2CMasterErr(I2C4_BASE);
        return false;
    }
    

    It is run it twice right after I write to the EEPROM. I put a break on the return line. The first time it runs the eeprom returns a NAK as shown bellow. However I read 0x20 on variable ui32Err.

    The second time it runs the eeprom ACKs as it had time to execute the write. However I get the same 0x20 on that variable.

    What am I doing wrong? How do I check for this ACK/NAK?

    Again thank you in advance for your help.

  • Hello Elder

    In an interrupt based system the I2CMasterBusy must be replaced by a global variable that is set to false so that it loops in a while(!bBusy) and is set by the interrupt handler. We have done this in the past during test phase and it works.

    Regarding the second issue of ACK/NAK. The NAK is a clear on read bit. So when checking for the busy status, the read of the MCS will clear the bit when we are checking for NAK. The solution to do so would be the following instead of the I2CMasterBusy while loop.

    ui32Err = 0;

    while((ui32Status = HWREG(ui32Base + I2C_O_MCS)) & I2C_MCS_BUSY)

    {

        if((ui32Status & I2C_MCS_DATACK) == I2C_MCS_DATACK)

        {

            ui32Err = 1;

        }

        if((ui32Status & I2C_MCS_ADRACK) == I2C_MCS_ADRACK)

        {

            ui32Err = 2;

        }

    }

  • Hello Amit, that has worked, thanks a lot.

  • One more question related to the above. The EEPROM data sheet describes a reset procedure:

    Is there a simple way to do it with the I2C controller?

  • Hello Elder,

    I don't think that this sequence is possible. You may have to change it to a Bit Banged I2C for such a specific sequence.

    Regards

    Amit