Wire multibyte read is broken?

Trying to work around a glitching bug in the L3G4200D gyroscope, I ran into what looks like another bug, this time in Wire.

//  this is broken.  for some reason, trying to request two bytes at a time from wired messes up
int readRegister2_isbroken(int deviceAddress, byte address){
    Wire.beginTransmission(deviceAddress);
    Wire.write(address); // register to read
    Wire.endTransmission();
    Wire.requestFrom(deviceAddress, 2); // we want two bytes, little endian
    while(Wire.available() < 2) { delay(1); }
    byte b0 = Wire.read();
    byte b1 = Wire.read();
    return ((b1 << 8) | b0);
}

int readRegister2b(int deviceAddress, byte address){
    Wire.beginTransmission(deviceAddress);
    Wire.write(address);
    Wire.endTransmission();
    Wire.requestFrom(deviceAddress, 1);
    while(!Wire.available()) { delay(1); }
    byte b0 = Wire.read();
    Wire.beginTransmission(deviceAddress);
    Wire.write(address+1);
    Wire.endTransmission();
    Wire.requestFrom(deviceAddress, 1);
    while(!Wire.available()) { delay(1); }
    byte b1 = Wire.read();
    return ((b1 << 8) | b0);
}

The two above should be functionally equivelent, but the first one produces bad data.
I discovered this while trying to read all three registers (6 bytes) at once to possibly work around the glitch. (some suspect registers are being updated while I am trying to read them) Trying to read all six registers into an array in one swipe tends to produce six of the same number, though not always. Most of the time I get 253-255. Which is annoying, since that's also what the glitch tends to return. Sent me chasing my tail for a time.
(fyi the GY-81 schematic indicates mosfet level buffers with pull-ups on the I2C lines)
Just for laughs I tried reversing the b0/b1 reads to see if it was an endianness or stack-vs-fifo issue with Wire, but that didn't help.

Since Wire doesn't support a parameter in the Read function, I assume it's just never been intended to deal with more than one byte at a time, in single file? or is there something a little more subtle I'm missing here? This is a GY-81 tied ti an Arduino Micro, just the four wires and nothing else.

Which arduino version?

please try

int readRegister2_is_trial(int deviceAddress, byte address)
{
  Wire.beginTransmission(deviceAddress);
  Wire.write(address); // register to read
  int x = Wire.endTransmission();

  Serial.println(x, DEC);

  Wire.requestFrom(deviceAddress, 2); // we want two bytes, little endian
  while (Wire.available() < 2) 
  { 
    delay(1);
  }
  int b0 = Wire.read();
  int b1 = Wire.read();  // then I'm sure the shift works
  return (b1 << 8) | b0 ;
}

Wire.endTransmission(); has a return code that might indicate the cause of the failure.

FWIW, here's a snippit of the output of my gyro test sketch, showing the "glitch" several of us here in the forum have been trying to squash:

                   DEG = 20
-1  8  -5  
                   DEG = 20
-1  5  -3  
                   DEG = 20
-1  10  -5  
                   DEG = 20
1  6  -7  
                   DEG = 19
-4  10  -7  
                   DEG = 19
252  5  -6                      <<=== THAT
                   DEG = 19
-1  10  -6  
                   DEG = 19
-1  10  -6  
                   DEG = 19
-2  9  -4  
                   DEG = 19
-1  10  -4  
                   DEG = 19
-3  10  -7  
                   DEG = 19
-1  10  -2

That's with the gyro sitting peacefully on my desk. If a glitch happens on the Z axis, it will affect the position indicator (DEG)

do you have a link to the datasheet of the sensor?
Does it tell something about read latency?

robtillaart:
do you have a link to the datasheet of the sensor?
Does it tell something about read latency?

The gyro is a L3G4200D, http://www.pololu.com/file/0J491/L3G4200D.pdf

It has enough different timing options to make it difficult for me to figure out what if any latency is the issue here. I currently have it set to 200hz (slowest) and 12.5 cutoff. I've tried other ODR and cutoff without noticing any help.

One thing that really frustrates me is that it has a "status register" that looks like it might have precisely what I want, telling me if new data is available. I've even seen TWO sketches that use it to make sure data is available before reading. But to my surprise, ALL bits in that byte are always set. (255) So, data is always available, in every register, and is always overflowing. (and so it passed the other sketches' bit tests) Nothing I have tried has had any change in this, it's always 255 at all times in all cases. the data sheet specifically says that it will go high in BDU mode when all the data is good, and will only reset after you've read Z.

It can trigger an interrupt pin when data is ready, but the GY-81 doesn't implement that pin. (I'd much prefer to poll a register anyway)

My next avenue is to explore getting it out of bypass mode and into fifo and see if the data it pops off the fifo is reliable. Considering its high polling speed, I may just flat out give up and fine tune my "glitch filter". Reads seems to occur in under 2ms, so I have been reading, and test for 1111xxxx in LSB. if those three bits are set, I read again. That seems to work fairly well. But I've seen a 230 glitch sneak by at least twice. (changed filter to 111xxxx)

sigh… I thought a cold reset had fixed it. then scroll 20 pages and...

                   DEG = -11
-3  11  -2  
                   DEG = -11
-4  10  -4  
                   DEG = -11
253  6  -5                      NOPE!
                   DEG = -11
-5  6  -7  
                   DEG = -11
-2  6  -4  
                   DEG = -11

at this point I think i't safe to say that the glitches in the LSB are caused by one byte being read (MSB/LSB), then the register being updated, then the other being read.

Since the data is in 2's complement, -3 is FF FD and +2 is 00 02

so if the value is changing from +2 to -3 (which it does when the gyro is stable), and if I read a byte, then it updates, then I read the other, I will either get FF 02 (-254) or 00 FD (253), depending on the order I read the bytes in.

I just modified my read function to read the MSB first (out of the proper address, yes) and found that I was still getting 254 ish as a glitch, not -32520 etc, so the wire function appears to be grabbing the data properly, but it's in an inconsistent state in the device's register, for long enough for me to sneak in.

I need to find a way to either time my reads (by detectin when data is stable) or force it to stay stable long enough for me to read it.

(one more edit)

do {
(read a register)
} while ((constrain(v,224,255) == v) || (constrain(v,-256,-225) == v));
// after rather extensive testing, that appears to weed out all the glitches. 00E0-00FF and FF00-FF1F

That solves the gyro issue entirely. Judging by the byte-placement disparity in the two groups, I'd say that even if I had a Wire that could read two bytes at a time, it woudn't have helped. This gyro appears to just plain have issues. The above loop was never seen executing more than twice, although considering the relative uncommonness of the glitches, it's possible it may have to make a 3rd or even a 4th attempt in some very uncommon cases.

If you read the datasheet - page 23 / 42

It is clear that the device makes a difference between single byte - table 16 -
and multiple byte reading. - table 17 -

In order to read multiple bytes, it is necessary to assert the most significant bit of the subaddress field. In other words, SUB(7) must be equal to 1, while SUB(6-0) represents the address of the first register to be read.

This bit is probably a bit that says "block the update until all bytes read"

What was the register address you used?

This means that code to read multiple bytes should look like:

int readRegister2_isbroken(int deviceAddress, byte address )
{
    multiByteSubAddress = address  | 0x80;  // FORCE BIT SUB(7) TO 1

    Wire.beginTransmission(deviceAddress);
    Wire.write(multiByteSubAddress ); 
    Wire.endTransmission();

    Wire.requestFrom(deviceAddress, 2);
    while(Wire.available() < 2) { delay(1); }
    byte b0 = Wire.read();
    byte b1 = Wire.read();
    return ((b1 << 8) | b0);
}

Can you give this a try?

robtillaart:
Can you give this a try?

I thought I'd already tried it awhile ago, but I gave it another shot just now. I also made sure to set the BDU bit on the control register. (I've read the datasheet, but I don't have 100% comprehension, especially when they're getting into FIFO access)

Still glitches :frowning: I also have discovered it gets worse as time goes on. I have to unplug power from it to reset it. If it's been on for an hour or more, it's very difficult to get a reading free of glitches. I'm starting to wonder if I got a defective unit or if maybe it's a quality or design issue? Ive looked up this gyro and it shows discontinued, "has been replaced with a newer design that uses a higher sampling frequency" or something like that. No mention of other issues with this model. I bought two, I'll try to swap it out with the other I have. But I've already ran into THREE people that are experiencing this glitching, so I'm expecting similar results with my other GY-81. It's looking more and more like I just have to work around the glitches. My code has gotten fairly robust, but it's hands are tied if the hardware just refuses to supply plausible data after numerous requests.

And a bit more on topic, so have we decided it's impossible to read two bytes in one operation with Wire? (and get correct data)

And a bit more on topic, so have we decided it's impossible to read two bytes in one operation with Wire? (and get correct data)

Agree for this sensor (version)

As other wire devices e.g. RTC's do not have this bug, the conclusion is: This sensor has probably a serious flaw.