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 Doesn't work correctly



Hi Folks,

I'm using an LM4F120H Evaluation kit board. Trying to do a REAL simple test of the I2C bus, using I2C0, with Master and slave in loopback mode. Send a single character and print it to a console is the aim of the game. I have two issues: 1) The Master is always busy if I perform the while (I2CMasterBusy(ulBase)) { } test and 2) I do not get the correct data (all zeroes). Attached is the following. They are heavily based off the example loopback code, plus interesting and useful diversions which I really wish to heck had been shoved more in front of my face, like the golden nugget of GPIOPinTypeI2CSCL() which only exists in these forums and not even on the datasheet.

I also am making the following assumptions (which may very well be where the problem lies!):

1) SLAVE_ADDRESS 0x40 is valid. I know about the 7 bit address + R/W bit caveat. This should be "1000 000x" where x = 0 to read and 1 to write if its bit-shifted.

2) Using ROM_ variant of a function is equivalent to its API equivalent, only that the API program code has been hardcoded and the ROM_ is an alias to that physical ROM memory to save space for application code in flash.

3) I use both the master and slave of the same module to do loopback

4) GPIOPinTypeI2CSCL() looks like an afterthought, but even the weak pullup should be strong enough for internal usage.

Thanks in advance for your help, as I'm only just a beginner really.

Rik

1) Function to perform single byte write:

unsigned long I2CMasterTxSingle(unsigned long ulBase,unsigned long ulSlaveAddr,
unsigned char *ucDataTx) {

//1. Set the slave address to talk to and the receive parameter = false (i.e. send)
I2CMasterSlaveAddrSet(ulBase, ulSlaveAddr, false);

//2. Wait until bus is not busy
//DEBUG: UARTwrite("Waiting for bus", 15);
while (I2CMasterBusBusy(ulBase)) {
}

//3. Place the data to be sent in the data register
I2CMasterDataPut(ulBase, *ucDataTx);

//4. Initiate send of data from the master.
I2CMasterControl(ulBase, I2C_MASTER_CMD_SINGLE_SEND);

//5. Wait until master is not busy
//DEBUG: UARTwrite("Waiting for master", 18);
while (I2CMasterBusy(ulBase)) { //Why does master not go to idle?
}

//5. Return any errors
return (I2CMasterErr(ulBase));

}

2) Test Environment for function

int32_t Cmd_I2CMasterTxSgl(int16_t argc, char*argv[]) {
unsigned long ulDataRx[NUM_I2C_DATA];
unsigned long ulindex;
unsigned long ulBase = I2C0_MASTER_BASE;
unsigned long ulClock = SysCtlClockGet();

/*Announce start of test*/
UARTprintf("Sending packets individually:\n\r");

/*Initialize the receive buffer.*/
for (ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++) {
ulDataRx[ulindex] = 0;
}

/*Indicate the direction of the data.*/
UARTprintf("Transferring from: Master -> Slave\n");

/*Send 3 pieces of I2C data from the master to the slave.*/
for (ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++) {
/*Display the data that the I2C0 master is transferring.*/
UARTprintf(" Sending: '%c' . . . ", ucDataTx[ulindex]);

/*Place the data to be sent in the data register*/
I2CMasterTxSingle(I2C0_MASTER_BASE,SLAVE_ADDRESS, &ucDataTx[ulindex]);

/*Wait until the slave has received and acknowledged the data.*/
while (!(I2CSlaveStatus(ulBase) & I2C_SCSR_RREQ)) {
}

/*Read the data from the slave.*/
ulDataRx[ulindex] = I2CSlaveDataGet(I2C0_SLAVE_BASE);

/*Display the data that the slave has received.*/
UARTprintf("Received: '%u'\n", ulDataRx[ulindex]);          //Why is data bad?

SysCtlDelay(ulClock / 30000);
}

/*Tell the user that the test is done.*/
UARTprintf("\nDone.\n\n");

/*Return no errors*/
return (0);

}

3) Setup Function

/*Initialize both the physical module and the functionality*/
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL);
ROM_GPIOPinConfigure(GPIO_PB3_I2C0SDA);

GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2); // I2CSCL special function for M4F, select M3
ROM_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. For this example we will use a data rate of 100kbps.*/
ROM_I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), bFast);

HWREG(ulBase + I2C_O_MCR) |= 0x01;

/* Enable the I2C0 slave module. This module is enabled only for testing
purposes. It does not need to be enabled for proper operation of the
I2Cx master module.*/
ROM_I2CSlaveEnable(ulBase);

/* Set the slave address to SLAVE_ADDRESS. In loopback mode, it's an
arbitrary 7-bit number (set in a macro above) that is sent to the
I2CMasterSlaveAddrSet function.*/
ROM_I2CSlaveInit(ulBase, ulSlaveAddr);

  • Hmmmm good question...

    /5. Wait until master is not busy
    //DEBUG: UARTwrite("Waiting for master", 18);
    while (I2CMasterBusy(ulBase)) { //Why does master not go to idle?
    }

    I have seen that from time to time...

  • Hi Rik,

    I compared your code to the I2C master_slave_loopback.c code and found there are many problems in your implementation.  I have listed a few examples below, but you should really go back and compare your code with this example line by line.

    1. ROM_I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), bFast);
      should be
      ROM_I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);
    2.  I don't see where you are initializing the data to send. The example code has:

      //
      // Initalize the data to send.
      //
      ulDataTx[0] = 'I';
      ulDataTx[1] = '2';
      ulDataTx[2] = 'C';

       
    3. You use 
      /*Place the data to be sent in the data register*/
      I2CMasterTxSingle(I2C0_MASTER_BASE,SLAVE_ADDRESS, &ucDataTx[ulindex]);
      I don't think I2CMasterTxSingle is a valid API.  The example uses
      I2CMasterDataPut(I2C0_MASTER_BASE, ulDataTx[ulindex]); 
    4. You don't have the I2CMasterControl function to actually send the data.
       
    That's as far as I went.  It's great that you properly identified the items needed for the LM4F implementation, but a careful comparison to the example would be very helpful.
    Regards,
    Sue
  • Thanks for your quick response Sue. Unfortunately your observations are more my fault for not pasting all the code more clearly.

    1) bFast is a boolean variable, set to false in the code, not shown above. Above is shown the function, but here is where it is called in main():

    int
    main(void)
    {
    /*System configuration*/
    SystemSetup();

    /*Setup the UART interrupt first */
    UARTCmdLineSetup();

    /*Now initialize other peripherals*/
    /*Test I2C 0 using loopback mode*/
    I2CSetup(0,false);
    I2CLoopbackSetup(0,false,SLAVE_ADDRESS);

    Cmd_I2CMasterTxSgl(0,NULL);
    /*Do useful work here*/
    while(1)
    {
    CmdLineIntProcess();
    }
    }

    2) ulDataTx is set in the code, not shown above

    3) I2CMasterTxSingle() is my function, not the library. It is listed in under "1) Function to perform single byte write:" above.

    4) I believe that in the I2CMasterTxSingle() function above, I used:

    //4. Initiate send of data from the master.
    I2CMasterControl(ulBase, I2C_MASTER_CMD_SINGLE_SEND);

    Thanks for taking your time to try and help. Would it be better if I just zipped the project or c files and sent them to you? 

    Rik