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.

CC1352P: I2C driver occasionally fails to read from slave device.

Part Number: CC1352P
Other Parts Discussed in Thread: INA226, , INA226EVM

I have a CC1352P-2 LaunchPad, Simplelink_cc13x2_26x2_sdk version 3.20.0.68, My project is based on the zed_switch example project.

I have my Launchpad connected to a Texas Instruments INA226. I'm using the I2C driver to read a register (register 0xFF) from the INA226. This 2-byte register contains the fixed value 0x2260. 95% percent of the time I read the correct value from the register.

Occasionally I read 0x22FF. I was able to see the transaction is a logic analyzer. When this problem occurs the INA226 returns only 1 byte, not 2. The CC1352P I2C driver doesn't give me an error it just fills the second byte with FF, so what I get back from the driver is 0x22FF.

In the logic analyzer I see the first byte (0x22) and an ack, but nothing following the ack. The second byte is not there, and the STOP is not there either. After the ack, the SDA and SCL lines stay low. This means the I2C driver (which is the master) stops driving the clock after it receives the first byte. This seems to be a problem with the I2C driver, not the INA226. I've attached a screen shot from the logic analyzer. Note the clock stops after the 0x22 and the ack.

Are you aware of any bugs in the I2C driver that would cause this?

Thanks,

Tim

  • Hi Timothy,

    I'm not aware of any such issues, you might be quick to jump to the conclusion that it is the I2C driver in this case. I assume the driver is asked to receive 2 bytes of data. This means it should drive the clock to the slave for the second byte which it does not (as you noted). This could be due to the INA device possibly stretching the clock (or something else is pulling it low).

    Could you maybe share some code showing how you set up the transfers as well as how the I2C driver is configured? If you have the debugger attached at this point you could also try to read out the I2C MSTAT register and tell me the value of this when this occur. Also, what is the state of the application running, does the I2C transaction finish or do it remain active (as one would expect in this case)?

  • Here is my code.

    static I2C_Handle i2cHandle;

    // Initialization function, called once when my application starts.
    void initalizeI2C()
    {
      // One-time initialization of I2C driver
      I2C_init();

      // Initialize I2C bus parameters
      I2C_Params params;
      I2C_Params_init(&params);
      params.bitRate = I2C_100kHz;

      // Open I2C driver
      i2cHandle = I2C_open(Board_I2C0, &params);
      if (i2cHandle == NULL)
        printf("Error opening I2C driver\n");
    }

    // Read value from the INA226 evaluation board. I call this every 10 seconds.
    uint16_t readINA226(uint8_t address)
    {
      uint8_t readBuf[2];
      uint8_t writeBuf[1];
      bool status;

      //writeBuf[0] = 0xFE; // INA226 manufacturer ID register, value read from this register contains 0x5449
      writeBuf[0] = 0xFF; // INA226 die ID register, value read from this register contains 0x2260

      // Initialize slave address of transaction
      I2C_Transaction transaction = {0};
      transaction.slaveAddress = address;

      // Write and read in a single transaction.

      transaction.writeBuf = writeBuf;
      transaction.writeCount = 1;
      transaction.readBuf = readBuf;
      transaction.readCount = 2;
      status = I2C_transfer(i2cHandle, &transaction);
      if (status == false)
        printf("I2C_transfer failed\n");

      return ( (uint16_t) readBuf[0] << 8 | (uint16_t) readBuf[1] );
    }

    Yes, I ask the driver to read 2 bytes. When this error occurs, the I2C_transfer() function finishes and returns the value 0x22FF, The 0x22 comes from the INA226 and I'm assuming the driver is filling in the second byte (0xFF) because as can be seen on the logic analyzer only one byte is coming from the INA226.

    When this error occurs, the I2C MSTAT regsiter contains 0x00000020.

    I hope this helps. Please let me know what you think.

    A screenshot of the MSTAT register.

  • M-W,

    I forgot to say in my previous post. I'm using the Texas Instruments INA226EVM evaluation board. This board has resistors R3 and R4 on the SDA and SCL lines.

    Each resistor pulls it's line high, unless something actively pulls it low, like the CPU while it’s driving the clock. So to me, the CC1352P just stops clocking. We looked at the signals on a scope and they’re pretty square and they are the right levels. The signals look good (3.3 volts when pulled up, down to ground when being actively clocked, pretty square edges). I'm running I2C at 100 kHz.

    So it seems like, when this error occurs, the CPU just stops clocking after receiving the first byte. What would make it stop?

    Thanks,

    Tim

  • M-W,

    Here's an update.The code I posted above does the read and write in a single I2C transaction.

    So just as an experiment, I changed my code to do two separate I2C transactions - a write transaction followed by a read transaction. I started this code in the debugger about 9:00 this morning and let it run all day. It's still running now, 9 hours later, and no errors have occurred. It reads from the INA226 correctly every time.

    So the problem is somehow related to doing the write and read in a single I2C transaction. It sure sounds like a driver bug.

    Here is my code that does 2 transactions.

      // Write to the slave device

      transaction.writeBuf = writeBuf;
      transaction.writeCount = 1;
      transaction.readBuf = NULL;
      transaction.readCount = 0;
      status = I2C_transfer(i2cHandle, &transaction);
      if (status == false)
        printf("I2C_transfer write failed\n");

      // Read from the slave device

      transaction.readBuf = readBuf;
      transaction.readCount = 2;
      transaction.writeCount = 0;
      transaction.writeBuf = NULL;
      status = I2C_transfer(i2cHandle, &transaction);
      if (status == false)
        printf("I2C_transfer read failed\n");

  • Hi Timothy,

    Could you maybe provide a trace of the error again including the full transaction (with that I mean the logic trace for write of 0xFF to read of responds)? What I'm curious about is the repeated start condition that should happen in the first case where you issue write + read and that will not happen in example two. As for the pull-ups, could you check if the pull-ups on the launchpad is also mounted (two parallel resistors in the down left IO header corner) and if they are, try to remove them so that you only have a single set of them mounted?

  • Hi M-W,

    There are 2 resistors on the launchpad connected to the SDA line. Are you asking me to remove one or both resistors?

    I will try to get the logic analyzer screen capture for you and I will post it soon.

    Thanks

    Tim

  • Hi Tim,

    My point was really to have you remove any additional set up pull-ups on the lines, if you do it on the LP or the EVM board does not really matter :)

  • M-W

    Thanks for your help

    I'm out of the office. On Friday I will try removing the resistors on the INA226EVM board. What would you like me to send you? Maybe oscilloscope screenshots before and after removing the resistors?

    Here are the screenshots you requested

    This image is a single I2C transaction with no error (I2C_transfer returned 0x2260 as expected). Note that the light blue element (the element just before the orange address element) is the start element. The remaining element colors you can figure out by looking at the packet list at the bottom of the image. Note that there are two start elements and two address elements, one at the start of the write and one at the start of the read.

    This image is a single I2C transaction with error (I2C_transfer returned 0x22FF). Note that there are two start elements and two address elements. This graph is identical to the first graph above, except in this graph the MCU stops toggling the clock line - I think this is why the final byte (the 0x60) is not returned from the INA226EVM.

    And finally this image is two I2C transactions - at write transaction followed by a read transaction. Note there is a start and a stop element in each transaction. These transactions worked with the second I2C_transfer returning 0x2260 as expected.

     

  • Hi Tim,

    If you have access to the board SW for testing, there is something I would like you to test out to see if it solves the issue you are seeing.

    It requires you to add the driver source file to the project as I want you to remove a check condition in the I2C ISR. What you need to do is the following:

    1) Add the I2CCC26XX.c file to the project (to override the library version).

    2) Find the HWI function - I2CCC26XX_hwiFxn()

    3) Comment out the master busy check in the start of it:

       if (I2CMasterBusy(hwAttrs->baseAddr)) {
            return;
        }

    An alternative to 3) is to comment out the return and simply add a counter for this instead (or a GPIO toggle if you would like to correlate the potential occurrence with the I2C transaction).

    The GPIO approach would be favorable if you have the time. Even better is leaving the if-statement as it is today and only add the toggle so we could for sure see if it correlates with your issue.

    This if statement is the only reason I could figure your case failing. It is unclear on why this would be. I would assume the MSTAT to be valid when the interrupt is received, which means I would not expect to hit it at all. If you do hit it, I would assume you could end up getting stalled in some cases and I would need to figure out why there is an interrupt without a valid MSTAT register.

  • Hi M-W

    I attempted to make your suggested changes to I2CCC26XX_hwiFxn(), but there is no call to I2CMasterBusy(), In fact, there is no call to I2CMasterBusy() anywhere in the file. There is a call to I2CMasterBusBusy(), but it's called from function I2CCC26XX_primeTransfer().

    I did a search of all the SDK source code. There is a function I2CMasterBusy() in file C:\ti\simplelink_cc13x2_26x2_sdk_3_20_00_68\source\ti\devices\cc13x2_cc26x2\driverlib\i2c.h, but there is no call to this function anywhere in the source code.

    Do you have different source code than I do? I have Simplelink_cc13x2_26x2_sdk version 3.20.0.68.

    What should I do?

    Also, I noticed debug statements in the file, similar to the following.

    DebugP_log2(
        "I2C:(%p) Starting transaction to slave: 0x%x",
        hwAttrs->baseAddr,
        object->currentTransaction->slaveAddress);

    How do I turn on debugging so that I can see these statements? And where do the statements appear? In the CCS console?

    Thanks,

    Tim

  • Hi Tim,

    Turning on the debugging is a effort I would not recommend taking but basically it means you should add the driver to the project, set the Debug define and make sure to configure TI-RTOS to handle the "Log" statements which is used bu the DebugP layer.

    As for the driver, you are right, I was looking at a newer version of it from the 4.10 SDK (my bad). I have attached it to the post so that you could try add it to your project and see if it solves your issue (it should be plug and play but let me know if there is any compile errors).

    /cfs-file/__key/communityserver-discussions-components-files/158/I2CCC26XX.c

  • Hi M-W

    I get 62 compiler errors. Most of them refer to struct I2CCC26XX_Object having field names that the compiler doesn't recognize. Maybe some fields were renamed between my SDK and yours. It also complains about #defines that it doesn't recognize, such as I2C_STATUS_CANCEL and many others.

    And I get this error:

    #145-D a value of type "int_fast16_t (*)(I2C_Handle, I2C_Transaction *, uint32_t)" cannot be used to initialize an entity of type "I2C_TransferFxn" I2CCC26XX.c /rit_end_device_P2/Application line 109

    So it looks like I can't simply drop the new file into my project. 

    I could upgrade to the latest SDK. I have resisted doing that because the last time I upgraded, my project files would not compile and it took FOREVER to fix the errors. I have two projects that are based on zed_switch and zc_light example projects. To fix my problems I had to import these projects again from the new SDK and then copy all of my code changes (a lot) from my old projects to the newly imported projects.

    But I will upgrade if it will help. Are you aware of any I2C fixes that were made between 3.20 SDK and 4.10 SDK? 

    How do you want to proceed?

  • Hi Timothy, 

    Seems it was a bit more changes that one would have wished for in order to be a plug-and-play fix. Generally, I would advice doing the migration if you feel you have time for it, the more frequency the migration is done the less potential errors you should encounter. You are currently two SDK versions behind so I don't know the exact impact this would have on your project.

    No matter if you do the migration or not, you would likely need to update the and fix the compile errors you see. Assuming the addition of the I2C status field in the callback, this would need to be updated in your application even if you simply port the driver or if you choose to do the full migration.

    I attached all the I2C related files to this post (including headers), it should help with some of those compile issues such as Object fields etc:

    /cfs-file/__key/communityserver-discussions-components-files/158/0045.I2C.c

    /cfs-file/__key/communityserver-discussions-components-files/158/2313.I2C.h

    /cfs-file/__key/communityserver-discussions-components-files/158/I2CCC26XX.h

    To have an easier time doing "just" the I2C part of the migration, I would advice to backup the I2C files from the SDK and first place these into the SDK directory and then add them to the project from there. This to assure he project picks up the correct header files as it will look at the SDK drivers directory for this. 

  • Hi M-W

    I will upgrade the latest SDK today or tomorrow and then run your test. I'll let you know the results.

    Tim

  • M-W,

    I upgraded to the latest SDK (4.10) and it solved my I2C problem.

    I did the test you suggested.

    1) Add the I2CCC26XX.c file to the project (to override the library version).

    2) Find the HWI function - I2CCC26XX_hwiFxn()

    3) Find the master busy check in the start of it:

    if (I2CMasterBusy(hwAttrs->baseAddr)) {
       LED_toggle(gRedLedHandle);
       return;
    }

    I added a call just before the return statement that turns on an LED. That LED never turned on!

    I ran my code for several hours. My code reads from the INA226 eval board every 10 seconds and it read the correct value every time.

    So there must have been a problem with the I2C driver in the old SDK that was fixed in the new SDK.

    Tim

  • Hi Tim, 

    Great news :) I will then consider the case close!