Search code examples
c++performancearduinoi2c

arduino low i2c read speed;


I'm currently working on a project using the genuino 101 where i need to read large amounts of data trough i2c, to fill an arbitrarily sized buffer.from the following image i can see that the read requests themselves only take about 3 milliseconds and the write request about 200 nanoseconds.

Read Transactions

however there is a very large time (750+ ms) between read transactions in the same block

#define RD_BUF_SIZE 32
void i2cRead(unsigned char device, unsigned char memory, int len, unsigned char * rdBuf)
{
     ushort bytesRead = 0;
     ushort _memstart = memory;
     while (bytesRead < len) 
     {
         Wire.beginTransmission((int)device);
         Wire.write(_memstart);
         Wire.endTransmission();
         Wire.requestFrom((int)device, BLCK_SIZE);
         int i = 0;
         while (Wire.available()) 
         {
              rdBuf[bytesRead+i] = Wire.read();
              i++;
         }
         bytesRead += BLCK_SIZE;
         _memstart += BLCK_SIZE;
     }
}

from my understanding this shouldn't take that long, unless adding to memstart and bytesRead is taking extremely long. by my, arguably limited, understanding of time complexity this function has a time complexity of O(n) and should, in the best case only take about 12 ms for a 128 byte query

Am i missing something?


Solution

  • Those 700ms are not caused by the execution time of the few instructions in your function. Those should be done in microseconds. You may have a buffer overflow, or the other device might be delaying transfers, or there's another bug not related to buffer overflow.

    This is about how I'd do it:

    void i2cRead(unsigned char device, unsigned char memory, int len, unsigned char * rdBuf, int bufLen)
    {
         ushort _memstart = memory;
         if ( bufLen < len ) {
             len = bufLen;
         }
         while (len > 0) 
         {
             Wire.beginTransmission((int)device);
             Wire.write(_memstart);
             Wire.endTransmission();
    
             int reqSize = 32;
    
             if ( len < reqSize ) {
                 reqSize = len;
             }
    
             Wire.requestFrom((int)device, reqSize);
    
             while (Wire.available() && (len != 0)) 
             {
                  *(rdBuf++) = Wire.read();
                  _memstart++;
                  len--;
             }
         }
    }