6 Replies Latest reply on Jun 27, 2017 12:20 PM by user_376040860

    I2C question

    user_376040860

      I'm working with a proc 4 device and a LIS3DH accelerometer. I've stripped down my code to do the most basic thing to demonstrate my problem. I read the "who am I" register (0x0F) of the accelerometer. The response is 0x33 and that's just what I get if I let the psoc read it once, twice or even 10 times. But if I read it (or other registers more than ten times the proc hangs. I'm watching everything on the I2C bus with a logic analyzer. I can tell it hangs because it doesn't get to the LED section at the end.

         

      Thanks for any help with this...

         

      Kevin

         

      #include <project.h>

         

      uint32 i;
      uint8 userArray[6] = {0x01,0x02,0x03,0x04,0x05,0x06};
      uint8 status;
      uint8 I2C_WRITE_XFER_MODE = 0x00u;
      uint8 I2C_I2CMSTR_NO_ERROR;
      uint32 LIS3DH_ADDRESS = 0x18 ;

         


      int main()
      {   CyGlobalIntEnable;
          LED_Green_Write(0);

         

      //    UART_Start();
      //    UART_UartPutString("The first words out...");
          
         I2C_Start(); //Start the I2C component
                

         

          
          I2C_I2CMasterSendStart(LIS3DH_ADDRESS, I2C_I2C_WRITE_XFER_MODE);
          
       //   I2C_I2CMasterWriteByte(0x20);
       //   I2C_I2CMasterWriteByte(0x97);
       //   I2C_I2CMasterSendStop();
          
          
          
          for(i=0; i<10; i++)
              {
               
               I2C_I2CMasterSendStart(LIS3DH_ADDRESS, I2C_I2C_WRITE_XFER_MODE);
               I2C_I2CMasterWriteByte(0x0F);
               I2C_I2CMasterSendStop();

         

               I2C_I2CMasterSendStart(LIS3DH_ADDRESS, I2C_I2C_READ_XFER_MODE);
               userArray[i] = I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA);
               I2C_I2CMasterSendStop();

         

              }
              
          LED_Blue_Write(0);
          LED_Green_Write(1);
              
          I2C_I2CMasterSendStop(); /* Send Stop */
          
         
          
          
      }

         

      /* [] END OF FILE */

        • 1. Re: I2C question
          e.pratt_1639216

          Your data array "userArray" is only 6 bytes of data length, but you write to it using the i variable from the for loop; This will buffer-overflow the pointer and start writing to an unknown address causing data corruption/crashing; I would suggest changing the size of the userArray to 10+ and see if that fixes the issue.

             

          Otherwise, it could be the accelerometer is communicating too slowly/quickly or something.

          • 2. Re: I2C question
            user_376040860

            Oh, bloody hell. Thanks very much e.pratt. It was the array size.

               

            Regards,

               

            Kevin

            • 3. Re: I2C question
              e.pratt_1639216

              Glad it worked out easily :)

              • 4. Re: I2C question
                user_376040860

                Yes, easy this time thanks to a fresh set of eys thank you. I can't help but think that my code is also way too detailed, there must be an easier way to do this. Should I have to use so much start/stops and addressing?

                   

                Regards,

                   

                Kevin

                • 5. Re: I2C question
                  graa

                  Yes. There are some high level APIs that can perform multiple byte read and write.  Here is a sample code that uses these APIs.

                     

                  In the below code, the first write operation writes one byte of data from the write buffer. This byte is the register address that you want to read from the slave.  The write can be performed in two modes, either the COMPLETE_XFER, or the NO_STOP.  When NO_STOP is used, the Master, after completing the write, will not issue a Stop on the I2C bus.  If COMPLETE_XFER is used, the Master completes the transfer with a Stop.

                     

                  The next read operation reads 8 bytes of data from the slave into the ReadBuffer.  The first byte of data will come from register address 0x0F followed by data from subsequent addresses.  The REPEAT_START mode tells the master to issue a repeat start instead of a normal start.  This is because the previous operation ended with a no stop.

                     

                  Hope this helps.

                     
                      
                  #define LIS3DH_ADDRESS  (0x18)  uint8 ReadBuffer[10];  uint8 WriteBuffer[8];   int main()  {        I2C_Start();               /* Register address to be read */        WriteBuffer[0] = 0x0F;               /* Initiate a write transfer and wait for the write to complete              Usually I2C slaves that need an address write first followed by read              do not need a stop in between.  For these slaves use the I2C_I2C_MODE_NO_STOP mode.              If the slave does not support no stop, use the I2C_I2C_MODE_COMPLETE_XFER */        I2C_I2CMasterWriteBuf(LIS3DH_ADDRESS, WriteBuffer, 1, I2C_I2C_MODE_NO_STOP);               /* Wait for write to complete, and clear the status */        while(!(I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT));        I2C_I2CMasterClearStatus();               /* Initiate a read transaction.  If the previous transaction use the I2C_I2C_MODE_NO_STOP, use the              I2C_I2C_MODE_REPEAT_START mode.  Otherwise, use the I2C_I2C_MODE_COMPLETE_XFER mode */        I2C_I2CMasterReadBuf(LIS3DH_ADDRESS, ReadBuffer, 8, I2C_I2C_MODE_REPEAT_START);         /* Wait for read to complete, and clear the status */        while(!(I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT));        I2C_I2CMasterClearStatus();  }
                     
                  • 6. Re: I2C question
                    user_376040860

                    I'll give this a try, thank you very much graa.

                       

                    Regards,

                       

                    Kevin