I2C Implementation Writing Extra Bytes

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Hi all,

I'm using the I2C on a CY8C5267LTI-LP089 chip and I've implemented a solution that talks to a slave that manages a battery in my device.

My code is below.

The short story of it is that I write a single command byte, read the return date (either 2 or 4 bytes), then store that data to be sent out on USB, then repeat for the next command byte.

void Internal_BAT_I2C(void) //This function is called in the main loop amongst other things

{

    static uint8 Internal_Gas_Gauge_Address[40] = {0x00,0x08,0x09,0x0A,0x0D,0x0E,0x11,0x12,0x13,0x16,0x17,0x4F,0x01,0x02,0x03,0x0B,0x0C,0x0F,0x10,0x1B,0x3C,0x3D,0x3E,0x3F,0x14,0x15,0x18,0x19,0x1A,0x1C,0x60,0x61,0x62,0x55,0x56,0x50,0x51,0x52,0x53,0x54};

    static uint8 Internal_I2C_Command[1]; // i2C write pointer

    static uint8 Internal_BAT_I2C_Step = 1 ; //internal bat i2c step

    static uint8 I2C_Internal_BAT_CMD_SEQ = 0; //used for incrementing the I2C address

    static uint8 Internal_BAT_I2C_READ_BYTE_COUNT;

    static uint8 Internal_BAT_I2C_WRITE_BYTE_COUNT;

    static uint8 Internal_I2C_buffer[5]; //I2c read buffer pointer

   

   

    if (Internal_BAT_I2C_Step == 1) // I split the I2C transaction into steps so that other parts of the firmware can run while it resolves.

    {

        I2C_INTERNAL_BAT_MasterClearStatus();            

        Internal_BAT_I2C_WRITE_BYTE_COUNT =  1; // Write single byte to I2C -command byte of gas gauge

        Internal_I2C_Command[0]= Internal_Gas_Gauge_Address[I2C_Internal_BAT_CMD_SEQ]; // = 0x20;

        I2C_INTERNAL_BAT_MasterWriteBuf(0x0B, (uint8*)Internal_I2C_Command, Internal_BAT_I2C_WRITE_BYTE_COUNT, I2C_INTERNAL_BAT_MODE_NO_STOP);

        Internal_BAT_I2C_Step  = 2; //Write is done so proceed to read step on next loop

    }

    // If the write is finished then

    if (((I2C_INTERNAL_BAT_MasterStatus() & I2C_INTERNAL_BAT_MSTAT_WR_CMPLT)!=0u) && (Internal_BAT_I2C_Step  == 2) && ((I2C_INTERNAL_BAT_MasterStatus() & I2C_INTERNAL_BAT_MSTAT_ERR_XFER) != 0u))

    {

         I2C_INTERNAL_BAT_MasterClearStatus();

        if (Internal_I2C_Command[0] == 0x50 || (Internal_I2C_Command[0] == 0x51) ||(Internal_I2C_Command[0] == 0x52) ||(Internal_I2C_Command[0] == 0x53) || (Internal_I2C_C

ommand[0] == 0x54) ||(Internal_I2C_Command[0] == 0x60) || (Internal_I2C_Command[0] == 0x61) ||(Internal_I2C_Command[0] == 0x62) ||(Internal_I2C_Command[0] == 0x55) || (Internal_I2C_Command[0] == 0x56) )        {

            Internal_BAT_I2C_READ_BYTE_COUNT = 5;

        }

        else

        {

            Internal_BAT_I2C_READ_BYTE_COUNT = 2;

           

        }

        

        I2C_INTERNAL_BAT_MasterReadBuf(0x0B, (uint8*)Internal_I2C_buffer, Internal_BAT_I2C_READ_BYTE_COUNT, (I2C_INTERNAL_BAT_MODE_COMPLETE_XFER|I2C_INTERNAL_BAT_MODE_REPEAT_START));

        Internal_BAT_I2C_Step  = 3;

       

    }

// if the read is finished then store data to be sent to USB

    if (((I2C_INTERNAL_BAT_MasterStatus() & I2C_INTERNAL_BAT_MSTAT_RD_CMPLT)!=0u) && (Internal_BAT_I2C_Step  == 3) && ((I2C_INTERNAL_BAT_MasterStatus() & I2C_INTERNAL_BAT_MSTAT_ERR_XFER) != 0u) )

    {

        if (Internal_BAT_I2C_READ_BYTE_COUNT == 2)

        {

            Internal_Gas_Gauge_Data_B0[I2C_Internal_BAT_CMD_SEQ]=Internal_I2C_buffer[0];

            Internal_Gas_Gauge_Data_B1[I2C_Internal_BAT_CMD_SEQ]=Internal_I2C_buffer[1];

        }

        if (Internal_BAT_I2C_READ_BYTE_COUNT == 5)

        {

           Internal_Gas_Gauge_Data_B0[I2C_Internal_BAT_CMD_SEQ]=Internal_I2C_buffer[1];

           Internal_Gas_Gauge_Data_B1[I2C_Internal_BAT_CMD_SEQ]=Internal_I2C_buffer[2];   

           Internal_Gas_Gauge_Data_B2[I2C_Internal_BAT_CMD_SEQ]= Internal_I2C_buffer[3];

           Internal_Gas_Gauge_Data_B3[I2C_Internal_BAT_CMD_SEQ]= Internal_I2C_buffer[4];

        }

   //This section of code selects the next command byte to be sent. We just iterate through the entire list

        Counter_1_Start();  //using counter to add 20msec delay between each commands - start the counter

        if (Counter_1_ReadCounter() <= 59980) //wait for 20msec or more (Scope measured ~80ms delay with USB connection and ~40ms with no USB connection)

        {

            Counter_1_Stop();                  //stop the counter

            Counter_1_WriteCounter(60000);     //reset the counter back to its orginal

          

            if (I2C_Internal_BAT_CMD_SEQ == 39)//if we've reached the last command then reset to the first

            {

                Counter_2_Start();

                if (Counter_2_ReadCounter() <= 59000)  //wait for at least 2sec before reading the same command again

                {

                    Counter_2_Stop();                  //stop the counter

                    Counter_2_WriteCounter(60000);

                    I2C_Internal_BAT_CMD_SEQ = 0;

                    Internal_BAT_I2C_Step  = 1;

                }

            }   

            else

            {

               ++I2C_Internal_BAT_CMD_SEQ;

                Internal_BAT_I2C_Step  = 1;

            }

       }

    }

}

The problem I'm running into is that despite giving I2C_MasterWriteBuf() only a single byte it will randomly send an extra 2 bytes. My I2C bus locks up and won't recover until the the system is power cycled. At the same time the I2C bus locks up I've noticed that the USB sending data to Windows from Cypress also disappears and shows as an unknown device in Device Manager so I think the chip itself may also be locking up.

Here's a capture of the failure with my I2C sniffer.

pastedImage_6.png

Can someone comment on this? I can't see a reason why my code would cause or allow extra bytes to be sent. I also can't explain the relation between the USB failing in conjunction with the I2C.

Cheers

Kevin

0 Likes
1 Solution

I2C_INTERNAL_BAT_MasterWriteBuf() is a function which implementation you can find (right click on the name, select definition). At the first executable statement you can set a breakpoint. Left click on the BP symbol and set the required condition (count != 1). When the execution stops you have the choice to see the call stack to see where the wrong data come from. Of course you may inspect (and even set) variables when debugging. Check for stack overflow, bad pointers etc.

Bob

View solution in original post

0 Likes
3 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Debug your project and check at I2C_INTERNAL_BAT_MasterWriteBuf() for count != 1. You may set the breakpoint condition accordingly.

Bob

0 Likes
Anonymous
Not applicable

Hey Bob, thanks for the response.

I'm not sure how to check the count - as far as I know MasterWriteBuf() doesn't return a count for the number of bytes it sends. The Internal_BAT_I2C_WRITE_BYTE_COUNT I use in the MasterWriteBuf() is hard set to 1 and never changes.

Also I apologize if this is a silly question.. How would the breakpoints help me debug this in an embedded system? I'm not very experienced with developing for embedded chips - but from my understanding I'd still be unable to read any of the data right?

0 Likes

I2C_INTERNAL_BAT_MasterWriteBuf() is a function which implementation you can find (right click on the name, select definition). At the first executable statement you can set a breakpoint. Left click on the BP symbol and set the required condition (count != 1). When the execution stops you have the choice to see the call stack to see where the wrong data come from. Of course you may inspect (and even set) variables when debugging. Check for stack overflow, bad pointers etc.

Bob

0 Likes