Wire.write(constants) Hair Pulling

I just spent all morning trying control a new I2C sensor. It is the AS5601 Hall Effect Rotation Encoder.

It is a nice chip, simp 3.3v or 5.v Vcc, I2C interface with A B Encoder outputs.

my problem: I could not get reliable Writes and Reads. Some would work, others would fail.

The AS5601 can almost be sequentially accessed. Unless you specifically set the 'register pointer' a couple of pot holes.

Basically, if you directly access register 0x0C, 0x0E, 0x1B the chip will loop the register point in a special manner. If you specify 0x0C, it will automatically increment to 0x0D then automagically back to 0x0C. If you specifiy 0x00 to 0x0B it will respond differently; It will NOT automagically loop! The same pattern exists of 0x0E and 0x1B.

#rant ON
Now the REAL hair puller. Say I want to write the value 0x09fA into register 0x01:

Wire.begintransmission(EncoderAddress);
Wire.write(0x01);
Wire.write(0x09);
Wire.write(0xFA);
Wire.endTransmission();

does Anyone see the problem here? The device uses an 8bit address pointer, so Everything looks good right?

Well, This stupid GCC compiler decide my constants are WORDS and the Wire.h library kindly has many overloaded write() members.

This is the one that KILLED my MORNING!

    inline size_t write(int n) { return write((uint8_t*)&n,sizeof n); }

Since the compiler decided my constant was a word (2 bytes) it amplified my single Wire.write() call into effectively two **Wire.write()**calls.

The I2C buss had this stream on it.

[EncoderAddress] 1 0 9 0 FA 0

It is no wonder that my Encoder was going crazy!

So the moral of the story is always Type Cast constants!

Wire.begintransmission(EncoderAddress);
Wire.write((uint8_t)0x01);
Wire.write((uint8_t)0x09);
Wire.write((uint8_t)0xFA);
Wire.endTransmission();

#rant Off

Chuck

Dear Chuck,
You have created you own buggy terrible Wire library, which is not compatible with the Arduino Wire library and does break the way the Wire.write() is used. Now you complain that your own Wire library has a bug, and you bother us with a problem that does not even exist.

The avr gcc compiler uses default 16-bit integers for 8-bit AVR chips.
The Wire.write() should use a byte. Anything else breaks the way Wire.write() is used.
http://www.arduino.cc/en/Reference/WireWrite : value: a value to send as a single byte.

Someone tried to introduce that bug here : http://forum.arduino.cc/index.php?topic=323119.msg2236312#msg2236312

But the real trouble begins here, when you create your own library with that bug : http://forum.arduino.cc/index.php?topic=331268.msg2286241#msg2286241

Apologize to all users of this forum and the Arduino team please.

Koepel:
Dear Chuck,
You have created you own buggy terrible Wire library, which is not compatible with the Arduino Wire library and does break the way the Wire.write() is used. Now you complain that your own Wire library has a bug, and you bother us with a problem that does not even exist.

The avr gcc compiler uses default 16-bit integers for 8-bit AVR chips.
The Wire.write() should use a byte. Anything else breaks the way Wire.write() is used.
http://www.arduino.cc/en/Reference/WireWrite : value: a value to send as a single byte.

Someone tried to introduce that bug here : http://forum.arduino.cc/index.php?topic=323119.msg2236312#msg2236312

But the real trouble begins here, when you create your own library with that bug : http://forum.arduino.cc/index.php?topic=331268.msg2286241#msg2286241

Apologize to all readers of this forum and the Arduino team please.

I stand by my conjecture. The compiler promotes constants to int values. if the compiler did not promote a byte value to an int, this error would not have happened.

I agree that I am culpable for making write(int) actually write an int.

I have always thought that a machine should do what you tell it to do. I have never believed that a machine could be omniscient.

If I tell the compiler to write a int value I would not expect it to write a byte value.

Why should the following code work:

int i=0x103;
Wire.beginTransmission(sensor);
Wire.write(i); // only sends 0x03, does not actually do was was instructed.
Wire.endTransmission();

long L = 0x99991234;
Wire.beginTransmission(sensor);
Wire.write(L); // sends 0x34
Wire.endTransmission();

Wire.h Source on GitHub

    inline size_t write(unsigned long n) { return write((uint8_t)n); }
    inline size_t write(long n) { return write((uint8_t)n); }
    inline size_t write(unsigned int n) { return write((uint8_t)n); }
    inline size_t write(int n) { return write((uint8_t)n); }

if none of these oversized write()'s existed, the error would be caught by the compiler, or

Wire.write((uint8_t)L); // if you actually want to use a Long to contain a byte value.

Chuck.

That is not an apology.