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.

Tiva I2C status issue

Other Parts Discussed in Thread: TM4C129XNCZAD

On a Tiva (Texas Instruments Cortex M4F ARM) TM4C129XNCZAD I have a problem with I2C interface. I have employed 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 the master sends 3 bytes to the slave within "Master Send" mode as a request and then the master switches into "Master Receive" mode and the master receives 3 bytes from the slave. There is an issue however. After the master receives data from the slave, in spite of the master sets a STOP bit within an I2C MCS register, the master module persists in the "Master Receive" mode and the I2C MCS register polling indicates the I2C bus is busy. Because of that there is impossible to set a new slave address and to enter to new cycle. Has anybody any idea how to fix this issue?

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 0x2C
#define NUM_I2C_DATA 3

#define RUN     1 
#define START   2
#define STOP    4
#define ACK     8
#define QCCMD   0x20
#define BURST   0x40

uint32_t  ui32Index;
uint32_t pui32DataRx[NUM_I2C_DATA];
uint32_t pui32DataTx[NUM_I2C_DATA];

int test(void)
{
    while(1)
    {
        for(ui32Index = 0; ui32Index < NUM_I2C_DATA; ui32Index++)
        {
                pui32DataRx[ui32Index] = 0;
                pui32DataTx[ui32Index] = 0;                 
        }
        while(I2CMasterBusBusy(I2C4_BASE));             
        I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);         
/*-------------------------------------------------------------*/
        I2CMasterDataPut(I2C4_BASE, '1');
        I2CMasterControl(I2C4_BASE, START | RUN);   // I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ)); // Wait until the slave has received and acknowledged the data.           
        pui32DataRx[0] = I2CSlaveDataGet(I2C6_BASE);  // Read the data from the slave.
        while(I2CMasterBusy(I2C4_BASE));            
/*-------------------------------------------------------------*/           
        I2CMasterDataPut(I2C4_BASE, '2');
        I2CMasterControl(I2C4_BASE, RUN);   // I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));           
        pui32DataRx[1] = I2CSlaveDataGet(I2C6_BASE);
        while(I2CMasterBusy(I2C4_BASE));                
/*-------------------------------------------------------------*/   
        I2CMasterDataPut(I2C4_BASE, '3');
        I2CMasterControl(I2C4_BASE, STOP | RUN);    //I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));           
        pui32DataRx[2] = I2CSlaveDataGet(I2C6_BASE);
        while(I2CMasterBusy(I2C4_BASE));                            
/*-------------------------------------------------------------*/               
        I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, true);
/*-------------------------------------------------------------*/                   
        I2CMasterControl(I2C4_BASE, RUN | START | ACK); // I2C_MASTER_CMD_BURST_RECEIVE_START);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));
        I2CSlaveDataPut(I2C6_BASE, 'A');
        while(I2CMasterBusy(I2C4_BASE));    
        pui32DataTx[0] = I2CMasterDataGet(I2C4_BASE);
/*-------------------------------------------------------------*/       
        I2CSlaveDataPut(I2C6_BASE, 'B');
        I2CMasterControl(I2C4_BASE, RUN | ACK);//I2C_MASTER_CMD_BURST_RECEIVE_CONT);
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));
        while(I2CMasterBusy(I2C4_BASE));    
        pui32DataTx[1] = I2CMasterDataGet(I2C4_BASE);
/*-------------------------------------------------------------*/
        I2CSlaveDataPut(I2C6_BASE, 'C');
        I2CMasterControl(I2C4_BASE, RUN | ACK); // I2C_MASTER_CMD_BURST_RECEIVE_CONT);
// Missing an ACK causing I2CSlaveStatus stays clear.               
        while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));
        while(I2CMasterBusy(I2C4_BASE));    
        pui32DataTx[2] = I2CMasterDataGet(I2C4_BASE);
/*
When the I2C module operates in Master receiver mode, the ACK bit is normally
set, causing the I2C bus controller to transmit an acknowledge automatically after each byte. This
bit must be cleared when the I2C bus controller requires no further data to be transmitted from the
slave transmitter.

b. In Master Receive mode, a STOP condition should be generated only after a Data Negative Acknowledge executed by
the master or an Address Negative Acknowledge executed by the slave.
*/
        I2CMasterControl(I2C4_BASE, STOP);  // I2C_MASTER_CMD_BURST_SEND_STOP);
        while(I2CMasterBusy(I2C4_BASE));
    }
}
  • Hello Marek,

    The Last Receive Transaction should be

    I2CMasterControl(I2C4_BASE, RUN | STOP)

    instead of

    I2CMasterControl(I2C4_BASE, RUN | ACK)
    I2CMasterControl(I2C4_BASE, STOP)

    The reason, is that the ACK bit would have been sent already and the Slave will be holding the line expecting another transfer to be made. You can check that in the master I2CMBMON register the SCL or SDA would be 0.

    Regards

    Amit

  • Hello Amit,
    I tried the solution you recommend as a first, but without ACK the slave returns status zero. The slave then get stuck at polling I2CSlaveStatus();


           I2CSlaveDataPut(I2C6_BASE, 'C');
           I2CMasterControl(I2C4_BASE, RUN | STOP);   // Missing an ACK is causing I2CSlaveStatus stays clear.               
           while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));

    Regards

    Marek

  • Hello Marek,

    In the original code, when the Master get's stuck in the busy did you check the I2CMBMON register through the debugger to see what the state of the SCL and SDA line's are?

    In the meantime let me check for an example on my side.

    Regards

    Amit

  • Hello Amit,

    I have append a SDA & SCL (I2CMBMON) reading thru I2CMasterLineStateGet(). 1st and second result was 0, remaining one was 2.

    /*-------------------------------------------------------------*/
            mon = I2CMasterLineStateGet(I2C4_BASE);    // mon = 0
            I2CSlaveDataPut(I2C6_BASE, 'C');
            I2CMasterControl(I2C4_BASE, RUN | ACK);
            while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_TREQ));
            while(I2CMasterBusy(I2C4_BASE));    
            pui32DataTx[2] = I2CMasterDataGet(I2C4_BASE);
            mon = I2CMasterLineStateGet(I2C4_BASE); // mon = 0
    /*-------------------------------------------------------------*/
            I2CMasterControl(I2C4_BASE, RUN | STOP); // there is the result with RUN and without RUN
            while(I2CMasterBusy(I2C4_BASE));
            mon = I2CMasterLineStateGet(I2C4_BASE);    // mon = 2

    Regards Marek

    P.s. Next week I have a vacation.

    P.s. There are not stable results. A tracing gives mon = 2, but real time run gives mon = 0.

    3rd P. S. After inserting of small delay,  mon = 2 (stable)