i2c (wire) debugging (hack/patch)

Hello all,

I have been having a hard time getting the TMC222 microstepping controller to work with the Arduino using the Wire library.

One of the main deficiencies in the Wire library is, in my opinion, it's lack of reporting error conditions (like missing ACKs from the slave) back to the Arduino sketch - though they are all handled internally by interrupt masks. This makes debugging I2C problems even more difficult that it has to be.. (for example: if the device does not respond to the beginning of a message - Arduino is master - the output buffer is returned again in the following receive() calls, further adding some confusion..)

I unfortunately don't have time to do a proper fix for all this, but as a quick hack I added a function that makes it able to retrieve the last interrupt indicating an error (like all the different NACKs, illegal start/stop sequence, ..). You can find the patch on http://gottfriedhaider.com/texts/show/2008/03/23/arduino-vs-i2c, together with some additional comments.. Maybe this can be useful for someone, or be the starting point for some better rework of the Wire library.

Note that I would also advocate for changing the format of the 7-bit slave address: In stock Arduino 010, you have to provide the slave address of the device in the lower seven bits of the parameter to various Wire functions - internally it is being left-shifted by one bit and (in case of reading) the read bit appended. This is, however, not reflected in the user documentation and unlike the format used in most of the slave devices' documentation material (where they suggest writing to 0xC0, reading from 0xC1. I think this should be changed (as it is now in this experimental patch above), or at least reflected in the documentation!

Thank you for this great development platform, btw :) gohai

Hi gohai,

I downloaded the patched code since I will be using I2C for my next project. In the description for the patch you say :

If you want to monitor the success of a master transfer, you have to put it after the call to endTransmission() as the library doesn't do any communication over the wire before that.

If I have to do that anyway, why can't the error-condition be returned directly from the endTransmission() call. Currently this function has not return value, so this small change should not effect already existing code. But new projects could benefit from the error-checking.

This is a patch that would probably accepted by the arduino-team. The automatic bit-shifting on the address will surly be rejected. The library has been used on too many projects. Maybe the documentation for the lib needs to be rewritten on the arduino-Playground pages.


Thanks for the patch

There is effectively this problem that if your command has had no reply the library still returns what you have sent to the device (i.e. it doesnt clean the buffer..) makin you thing tht the device has somehow responded... I've lost half a day trying to figure this out. I'll ask nick to add it to the library

the address shifting just needs some better documentation.



Dear Eberhard|massimo,

thanks for your suggestions.. I redid the patch completely, you can find it here: http://gottfriedhaider.com/texts/show/2008/03/29/arduino-vs-i2c.

I removed the change how the slave address is being handled (but please put this in the documentation), so what remains:

endTransmission() returns
  0  ..  success
  1  ..  data to send exceeds output buffer size
  2  ..  send slave address, NACK received
  3  ..  send data byte, NACK received
  4  ..  other error occured (lost bus arbitration, bus error, ..)
requestFrom() returns
  number of bytes actually read from device

also, requestFrom() sets rxBufferLength to the number of bytes actually read, which means that available() does not just return the number of bytes requested anymore and receive() does not return the data you send yourself in this case.

.. hope this can be included in a future release of the Arduino software!

best, gohai

Looks good, I'll put it in Arduino 0012.

Just to check: you only changed existing return values in the internal functions right? (Not counting the return values you added to functions that used to return void.)

Hi mellis,

I've looked through it once again: the only changes that touch existing code are those:

  • rxBufferLength in requestFrom() is set to the returned value of twi_readFrom (i.e. twi_masterBufferIndex) instead of the number of bytes requested in the argument.. this means that available() and received() behave more consistently (only returning bytes actually read!)

  • twi_readFrom() returns 0 instead of the error value 1 in case the number of bytes requested exceeds the internal buffer size, as the function now returns the number of bytes read

  • in twi_readFrom(), only the number of bytes actually received (twi_masterBufferIndex) is being copied from the internal to the outer buffer passed as an argument, instead of hardcoding it to the number of bytes requested (byte from previous transmission would be also copied to the outer buffer in case the device responded with fewer bytes that expected - clearly confusing!)

.. just spotted a small bug: if (at the end of the transaction in twi_readFrom) the twi_masterBufferIndex is greater that the number of bytes requested (quantity), the loop would silently overflow the outer buffer - so this should clearly be min(twi_masterBufferIndex, quantity), and this value also returned! I'll fix this up asap and also do some additional testing, but I do have a good feeling with all those changes :)

cheers! Gottfried

Hello all,

I just fixed the bug mentioned above - you find the updated patch or tarfile on the same location..

So would be ready for inclusion (or more testing) imho.

greetings Gottfried

gohai: can you repost the patch? I downloaded the original version, but not the updated one, and now it appears that your website is down.

Hello mellis,

the server is down, unfortunately, but I'll send you the patch in a second via email..


Awesome, thanks.

Hi! I have the same problems could you send me the patch?

I’ll infinitely grateful to you!