Daily Archives: 10/14/2011

Arduino playground provides the WireLibraryDetailedReference

In seeking some more details on the inner workings of the Wire library for the Arduino, I chanced across this rather informative link on the Arduino Playground website:

Arduino playground – WireLibraryDetailedReference

Of particular interest to me was the description how requestFrom worked. It doesn’t just issue the request: it calls the low level twi_readFrom() command to read the bytes requested from the I2C device. Thus, in the case that troubled me before, the bytes are guaranteed to be there.

Or are they? What if you ask for too many? The documentation says the I2C slave will NACK the read request. Well, what happens there? Let’s see what the code looks like…

[sourcecode lang=”cpp”]
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
// clamp to buffer length
if(quantity > BUFFER_LENGTH){
quantity = BUFFER_LENGTH;
}
// perform blocking read into buffer
uint8_t read = twi_readFrom(address, rxBuffer, quantity);
// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = read;

return read;
}
[/sourcecode]

The twi_readFrom() call is from the underlying avr_libc library, which seems every bit as inscrutable. I haven’t dug deep enough to know for sure, but I suppose it is possible for twi_readFrom to return a value less than the number requested, or even zero in case of a NACK. In that case, the code that I was complaining about would still “work”, although it would call Wire.available() repeatedly (length times) to no avail, and leave the buffer empty.

It’s also good to note that the routine silently trims requests to match an internal buffer length. In theory, the AT24C1024 can write 256 bytes at a time, but the internal buffer lengths are set to 32.

Strange code in I2C code…

I noticed something while reading code that uses the Wire library for the Arduino, such as you might find below…

Arduino playground – I2CEEPROM

Check out this two line fragment from the read function:

    for ( c = 0; c < length; c++ )
      if (Wire.available()) buffer[c] = Wire.receive();

Is anyone else struck by the fact that it is, well, just wrong? The I2C device is expected to be sending "length" bytes. This loop checks to see if a byte is available, and if it is, then sticks it in the buffer. But what happens if it is not? Then the index increments, and when we try again, any particular byte we write will be placed at a strange location in the buffer.

The only way this code makes sense is if Wire.available() never fails. If it does, then it will leave an empty slot in the output array.

I'll have to step through the Wire library source to make sure, but this seems wrong to me. I'll let you know what I find.