3 Replies Latest reply on May 3, 2018 11:32 AM by bob.marlowe

    I2C Implementation Writing Extra Bytes

    user_436896257

      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.

       

      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

        • 1. Re: I2C Implementation Writing Extra Bytes
          bob.marlowe

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

           

          Bob

          • 2. Re: I2C Implementation Writing Extra Bytes
            user_436896257

            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?

            • 3. Re: I2C Implementation Writing Extra Bytes
              bob.marlowe

              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