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.

TMS320F28335: I2c stop condition

Part Number: TMS320F28335
Other Parts Discussed in Thread: C2000WARE

Hi

I would like to use the i2c to interface an external EEPROM. I prefer to work with RM=1 and I use the ARDY and NACK interrupt to control the transfer. I'm able to select the device, to set the page address and to send all page bytes(256) but at this point if I send a stop condition by setting STP=1 in the CMDR register I receive a Lost of arbitration interrupt and a nack interrupt? Where I'm wrong?

Best Regards

  • This the sample code:

    typedef enum
    {
        WAIT_FOR_CMD,
        SELECT_DEVICE,
        SEND_HI_ADDRESS,
        SEND_LO_ADDRESS,
        START_READ_DATA,
        READ_DATA,
        SEND_STOP,
        FINISH,
        WRITE_DATA,
        WRITE_STOP,
        START_WRITE_POOL,
        WRITE_POOL,
        DEVICE_NACK
    } I2C_FSM_STATES;

    typedef enum
    {
        I2C_NO_CMD,
        I2C_WRITE_EEPROM,
        I2C_READ_EEPROM
    } I2C_COMMAND_VALUES;

    typedef struct
    {
        I2C_FSM_STATES state;
        I2C_COMMAND_VALUES cmd;
        volatile bool done;
        volatile bool nack;
        uint32_t address;
        int16_t n_reads;
        int16_t n_writes;
        uint16_t sar;
        int16_t trx_counter;
        int16_t retry;
    } I2C_DATA_TAG;

    I2C_DATA_TAG i2c;

    /* ============================================================================
        FUNCTION NAME:
        PURPOSE:
        DESCRIPTION:
        DOMAIN:
        ACCURACY:
        NOTES:
     ============================================================================ */
    interrupt void i2c_int1a_isr(void)
    {
    // Set interrupt priority:
    volatile uint16_t TempPIEIER = PieCtrlRegs.PIEIER8.all;
    uint16_t tmp;

        IER |= M_INT8;
        IER &= MINT8;
        PieCtrlRegs.PIEIER8.all &= MG81;
        PieCtrlRegs.PIEACK.all = 0xFFFF;
        asm(" NOP");
        EINT;

        // Insert ISR Code here.......
        tmp = I2caRegs.I2CISRC.all;
        switch ( tmp & 0x3 )
        {
        case I2C_NO_ISRC:
            tmp = 0;
            break;

        case I2C_ARB_ISRC:
            tmp = 0;
            break;

        case I2C_NACK_ISRC:
            i2c.nack = true;
            break;

        case I2C_ARDY_ISRC:
            i2c.done = true;
            break;

        case I2C_RX_ISRC:
            tmp = 0;
            break;

        case I2C_TX_ISRC:
            tmp = 0;
            break;

        case I2C_SCD_ISRC:
            tmp = 0;
            break;

        case I2C_AAS_ISRC:
            tmp = 0;
            break;
        }

        // Restore registers saved:
        DINT;
        PieCtrlRegs.PIEIER8.all = TempPIEIER;
    }

    /* ============================================================================
        FUNCTION NAME:
        PURPOSE:
        DESCRIPTION:
        DOMAIN:
        ACCURACY:
        NOTES:
     ============================================================================ */
    void i2c_fsm(void)
    {

        switch ( i2c.state )
        {
        case WAIT_FOR_CMD:
            if ( i2c.cmd != I2C_NO_CMD )
            {
                //  Prepare SAR
                i2c.sar = (i2c.address & 0x3FFFF) >> 16;
                i2c.sar = i2c.sar << 1;
                i2c.sar = (i2c.sar | DSC_MUSK) >> 1;
                //  next state
                i2c.state = SELECT_DEVICE;
            }
            break;

        case SELECT_DEVICE:
            //
            i2c.done = false;
            i2c.nack = false;
            //  Start operation
            I2caRegs.I2CMDR.bit.MST = 1;
            I2caRegs.I2CMDR.bit.RM = 1;
            I2caRegs.I2CMDR.bit.TRX = 1;
            I2caRegs.I2CSAR = i2c.sar;
            I2caRegs.I2CMDR.bit.STT = 1;
            //  next state
            i2c.state = SEND_HI_ADDRESS;
            break;

        case SEND_HI_ADDRESS:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    //  next state
                    i2c.state = DEVICE_NACK;
                }
                else
                {
                    I2caRegs.I2CDXR = (i2c.address >> 8) & 0xFF;
                    //  next state
                    i2c.state = SEND_LO_ADDRESS;
                }
            }
            break;

        case SEND_LO_ADDRESS:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    //  next state
                    i2c.state = DEVICE_NACK;
                }
                else
                {
                    I2caRegs.I2CDXR = i2c.address & 0xFF;
                    switch ( i2c.cmd )
                    {
                    case I2C_WRITE_EEPROM:
                        i2c.trx_counter = 0;
                        //  next state
                        i2c.state = WRITE_DATA;
                        break;

                    case I2C_READ_EEPROM:
                        i2c.trx_counter = 0;
                        //  next state
                        i2c.state = START_READ_DATA;
                        break;

                    default:
                        break;
                    }
                }
            }
            break;

        case START_READ_DATA:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    //  next state
                    i2c.state = DEVICE_NACK;
                }
                else
                {
                    I2caRegs.I2CMDR.bit.TRX = 0;
                    I2caRegs.I2CMDR.bit.STT = 1;
                    //  next state
                    i2c.state = READ_DATA;
                }
            }
            break;

        case READ_DATA:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    //  next state
                    i2c.state = DEVICE_NACK;
                }
                else
                {
                    read_data[i2c.trx_counter++] = I2caRegs.I2CDRR;
                    if ( i2c.trx_counter == i2c.n_reads )
                    {
                        //  next state
                        i2c.state = SEND_STOP;
                    }
                    else
                    {
                        //  next state
                        i2c.state = READ_DATA;
                    }
                }
            }
            break;

        case SEND_STOP:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    //  next state
                    i2c.state = DEVICE_NACK;
                }
                else
                {
                    I2caRegs.I2CMDR.bit.STP = 1;
                    //  next state
                    i2c.state = FINISH;
                }
            }
            break;

        case FINISH:
            if ( i2c.done )
            {
                i2c.done = false;
                i2c.cmd = I2C_NO_CMD;
                //  next state
                i2c.state = WAIT_FOR_CMD;
            }
            break;

        case WRITE_DATA:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    //  next state
                    i2c.state = DEVICE_NACK;
                }
                else
                {
                    I2caRegs.I2CDXR = write_data[i2c.trx_counter++];
                    if ( i2c.trx_counter == i2c.n_writes )
                    {
                        //  next state
                        i2c.state = WRITE_STOP;
                    }
                    else
                    {
                        //  next state
                        i2c.state = WRITE_DATA;
                    }
                }
            }
            break;

        case WRITE_STOP:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    //  next state
                    i2c.state = DEVICE_NACK;
                }
                else
                {
                    I2caRegs.I2CMDR.bit.STP = 1;
                    //  next state
                    i2c.state = FINISH;
                }
            }
            break;

        case START_WRITE_POOL:
            if ( i2c.done )
            {
                i2c.done = false;
                i2c.nack = false;
                i2c.retry = 0;
                I2caRegs.I2CMDR.bit.MST = 1;
                I2caRegs.I2CMDR.bit.RM = 1;
                I2caRegs.I2CMDR.bit.TRX = 1;
                I2caRegs.I2CSAR = i2c.sar;
                I2caRegs.I2CMDR.bit.STT = 1;
                //  next state
                i2c.state = WRITE_POOL;
            }
            break;

        case WRITE_POOL:
            if ( i2c.done )
            {
                i2c.done = false;
                if ( i2c.nack )
                {
                    i2c.retry++;
                    I2caRegs.I2CMDR.bit.MST = 1;
                    I2caRegs.I2CMDR.bit.RM = 1;
                    I2caRegs.I2CMDR.bit.TRX = 1;
                    I2caRegs.I2CSAR = sar;
                    I2caRegs.I2CMDR.bit.STT = 1;
                    //  next state
                    i2c.state = WRITE_POOL;
                }
                else
                {
                    I2caRegs.I2CMDR.bit.STP = 1;
                    //  next state
                    i2c.state = FINISH;
                }
            }
            break;

        case DEVICE_NACK:
            break;

        default:
            break;
        }
    }

  • Hi Luca,

    This issue is occurring anytime you send a STP bit command? I see your program has three cases that send a STP command.

    Can you try checking the I2CMDR and I2CSTR registers at different states of your program? Compare their values before and after sending a STP condition to see if you can acquire some insight into the issue. Also try checking the I2CISRC register for the INTCODE that's being set.

    Hope this helps,
    Kevin
  • Hi Kevin

    I solve the problem using another way to use the I2c... but I have problem if I receive a NACK it seems that I'm not able to recover correct communication after that. So which the best way to manage a NACK? Should I reset the I2c peripheral?

    Best Regards

  • Hi Luca,

    The I2C example in C2000ware may help you.

    Directory: C:\ti\c2000\C2000Ware_1_00_02_00\device_support\f2833x\examples\i2c_eeprom

    Something similar to the following portion of code may be what you're looking for:

        //
        // Interrupt source = Register Access Ready
        // This interrupt is used to determine when the EEPROM address setup 
        // portion of the read data communication is complete. Since no stop bit is
        // commanded, this flag tells us when the message has been sent instead of 
        // the SCD flag. If a NACK is received, clear the NACK bit and command a 
        // stop. Otherwise, move on to the read data portion of the communication.
        //
        else if(IntSource == I2C_ARDY_ISRC)
        {
            if(I2caRegs.I2CSTR.bit.NACK == 1)
            {
                I2caRegs.I2CMDR.bit.STP = 1;
                I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
            }
            else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
            {
                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
            }
        }

    There is another portion of the example code that handles NACKs if received after the initial slave addressing.

    Hope this helps,

    Kevin