Go Down

Topic: Wire.available() necessary? (Read 6839 times) previous topic - next topic

_Leo_

Hi all,

I've been asking myself for a long time why Wire.available() is needed.

E.g. I see programs even using it in while-loops. Why?

My thinking is that when the Wire.requestFrom() function is called it should have the number of requested bytes every time and completely finished. After that it should be safe to call Wire.read() without having to check if in fact bytes are in the buffer. If that would be not that case then IMO something is terribly wrong in the hardware.

Any thoughts on this?

Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

Delta_G

Does requestFrom guarantee that the other piece will actually respond?
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

KeithRB

At some point you might do the transfer in hardware and requestFrom() would just set things up and immediately return. Then you would use available() to see if any data came back.

bperrybap

#3
May 13, 2016, 09:48 pm Last Edit: May 13, 2016, 09:56 pm by bperrybap
I've
Does requestFrom guarantee that the other piece will actually respond?
Tecnically no.
However, if the slave didn't respond during the address phase (which is an i2c write), that would be considered an error and terminate the requestFrom() and reaturn 0 (no bytes read).
Slaves set the ack/nack bit during i2c writes since they are in charge of the SDA signal during that bit time. A non responding slave will not touch the SDA signal so it will be high which is a NAK. A slave should pull SDA low (ACK) after the address to indicate that it is responding to that address.


On reads the Master sets the ack/nack bit since it is in charge of the SDA signal during that bit time.
A high SDA (nack) tells the slave that there are no more data bytes to read.
I don't think the slave has any way to reject a read.
So a non responding slave during the 8 bit times of the data bit transfer would be seen by the master as a 0xff as the SDA line would be pulled up by the resistors on the SDA signal.

At some point you might do the transfer in hardware and requestFrom() would just set things up and immediately return. Then you would use available() to see if any data came back.
I'm assuming by "you might" you mean the "the library might" and that would explain the need for available()
There is another reason for available() - see below.



Since the master is always in charge including during reads, there is no way for a slave to pre-terminate a twi multi-read operation. So if the master is wanting 6 bytes it will read 6 bytes.
HOWEVER..... there is something that can cause a requestFrom() to terminate early before all bytes are read from the slave.
And that is a loss of bus arbitration.
This would normally happen if there were another master. The other master could jump in and cause the current multi-read operation to terminate. This would cause requestFrom() to terminate before all the bytes were transferred.


The only reason I'm so familiar with this is that for the past few days, I've been tracking down a twi  issue where the AVR master hangs.
After long hours with a logic analyzer it turns out in this case it is due to a misbehaving slave device that is acking reads, which is not allowed since the master controls this status bit during reads.
It appears that the slave does not support reads but incorrectly responds as if they were writes.
But the bigger issue is that when this occurs, the AVR master thinks there is another master on the bus and drops off the bus due to thinking it has a loss of bus arbitration.
The issue at that point is that the twi code never recovers and will hang if any additional i2c requests are done. (reads or writes)

The stop for the current operation is never sent and the AVR will not start any more i2c requests.

I know what is happening, now I just need to figure out how to fix the twi code to deal with this.
My guess is that the twi code was never tested very much with multiple masters and for sure not this specific condition.
I think the AVR may have flipped from master into slave mode, but I'm still going through the AVR docs to figure out how to get it going again.


--- bill

_Leo_

@Bill: Thanks for the detailed explanation!

I'm looking at it on the pragmatic side. I'm counting on that the bytes requested are ready after requestFrom() was called and therefore don't need to check again with available().
If I have a device (e.g. quadcopter or model rocket) that is 100% dependent on reliable readings I can't afford having misreading's and needing to check via available() to take appropriate actions. By then it's too late.

Using available() for debugging purposes is something I can understand.
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

nickgammon

See my page about I2C. The requestFrom will either return 0 (the slave didn't respond) or the number of bytes you requested (as Bill said). Therefore doing a Wire.available() isn't particularly useful, although it also doesn't do a great deal of harm. The alternative would be to check for a zero response, and then just iterate in a loop for the number of bytes you requested.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Koepel

#6
May 14, 2016, 01:35 pm Last Edit: May 14, 2016, 01:40 pm by Koepel
KeithRB, it is not like that.
The Wire.requestFrom() is a complete I2C transaction on its own.
The Wire library uses interrupts, but the Wire.endTransmission() and Wire.requestFrom() wait until everything has finished.
If there would be new function that does not wait, then Wire.available() is not enough. Because the I2C transaction could be aborted without data, or data is not ready yet.
It is of course a waste of time if a M0+ processor has to wait for a full millisecond for a few bytes. For an embedded system I highly prefer that there was no waiting for the I2C transaction to finish (for example with a call-back function) but with the Wire library, that is not possible.
The others are correct.

bperrybap, do you use the newest Arduino IDE 1.6.9 ?
The I2C was improved with version 1.6.6 for collisions and timing. Since 1.6.6 I can use I2C without problems between two Arduino boards.
A I2C device that ACKs when the Master is reading is nuts. I don't blame the Wire library if the Wire library goes haywire.
I have a newer and working development version of SoftwareWire, it is a drop-in replacement for the Wire library. You could use that and fix it for the that device.

_Leo_, there are many wrong example online with Wire.available. The Wire.available() is useful when writing data to the serial monitor for example. It is a useful function, and has nothing to do with debugging or not.
For myself, I often use the return value of Wire.requestFrom().
Code: [Select]

byte buffer[6];
int n = Wire.requestFrom( i2caddress, 6);
if( n == 6)    // did we receive the number of requested bytes ?
{
  Wire.readBytes( buffer, n);
}


For a reliable I2C, always use level shifters when connecting a 5V Arduino board to a 3.3V sensor. Never put SDA and SCL next to each other in a flat ribbon cable. Keep the wires short. Calculate the total pullup value of all the modules for SDA and SCL.

RayLivingston

The only reason I'm so familiar with this is that for the past few days, I've been tracking down a twi  issue where the AVR master hangs.
After long hours with a logic analyzer it turns out in this case it is due to a misbehaving slave device that is acking reads, which is not allowed since the master controls this status bit during reads.
It appears that the slave does not support reads but incorrectly responds as if they were writes.
But the bigger issue is that when this occurs, the AVR master thinks there is another master on the bus and drops off the bus due to thinking it has a loss of bus arbitration.
The issue at that point is that the twi code never recovers and will hang if any additional i2c requests are done. (reads or writes)

The stop for the current operation is never sent and the AVR will not start any more i2c requests.

I know what is happening, now I just need to figure out how to fix the twi code to deal with this.
My guess is that the twi code was never tested very much with multiple masters and for sure not this specific condition.
I think the AVR may have flipped from master into slave mode, but I'm still going through the AVR docs to figure out how to get it going again.


--- bill
I would be very interested in hearing what you find there.  I think I may be having the same problem recently.  Is this perhaps on a Due?

Regards,
Ray L.

bperrybap

#8
May 14, 2016, 07:05 pm Last Edit: May 14, 2016, 07:07 pm by bperrybap
In terms of how to handle requestFrom() and available(), the issue I see is that there is no API documentation that defines how requestFrom() is supposed to behave.
All it says is that it returns: "the number of bytes returned from the slave device"
It does not specify if it is normally the requested number of bytes or even if the call is synchronous/blocking until the expected data arrives.
This is incomplete and should be updated to further define the behavior.

In a single master environment, with the existing AVR code (not sure how it is handled in the other cores), it should always be the number of bytes requested.
But even with current AVR code that "waits" for all the bytes, in multi master (assuming the library can really handle multi masters) it can return early with less than the requested bytes if another master jumps in and uses the bus.
And if in a multi-master environment, even though the requestFrom() will return early, eventually the remaining bytes will still come in. (they will be handled by the ISR and stuffed into the twi private RX buffer).

So the value of available() is really in multi-master environments, where requestFrom() can return early but the rest of the bytes will eventually come in.
This will be the only way to know when the rest of the bytes from a premature return of requestFrom() actually arrive.

I would actually prefer that the Wire library - which sits on top of the twi code, was smarter and would hide this early twi code return and issue another request to the twi code to complete the read so that even in a multi-master environment, the Wire.requestFrom() never returned until all the bytes were received.
This would ensure that the behavior is consistent regardless of whether being used in multi-master environment.

In other words there should be some way through the API to tell the Wire code to not return back until either all the bytes were received or there was a fatal error.
Losing the bus in a multi-master environment is not a fatal error and should be hidden from the application.




I would be very interested in hearing what you find there.  I think I may be having the same problem recently.  Is this perhaps on a Due?

Regards,
Ray L.
It is AVR.

bperrybap, do you use the newest Arduino IDE 1.6.9 ?
The I2C was improved with version 1.6.6 for collisions and timing. Since 1.6.6 I can use I2C without problems between two Arduino boards.
I was using 1.6.7
While I could have missed it, I looked at the githib repo and didn't see any code updates that looked related to this specific condition.
I'll go back and take another look and even try the latest 1.6.9 IDE.
The state status is: TW_MR_ARB_LOST, which is the same state value as TW_MT_ARB_LOST
The current code doesn't really handle TW_MR_ARB_LOST (which is lost arbitration during relieves) and handles it the same way as lost arbitration during transmits. And that may be part of the problem.
I'm assuming that the AVR dropped off the bus and flipped into slave mode and is now waiting to see a STOP from the "other master" before it will ever jump back on the bus.
The issue is that a STOP will never occur in this case.
In 1.6.0 and later I can recover by doing an end() then begin() and then a dummy address phase.
But I'm looking for a solution in the actual library.

Quote
A I2C device that ACKs when the Master is reading is nuts. I don't blame the Wire library if the Wire library goes haywire.
The device is an i2c LCD:

I see this as an issue.
The current code will hang and lock up the AVR in this situation and never recover.
I don't like code that does not gracefully handle and recover from errors.
Seems like there should be sort of timeout that should allow recovery from this condition.
Either the h/w or the s/w is broken and so the s/w would need to be updated to handle this situation


I need to start another thread on this but I don't know where to put it.
Any suggestions?

--- bill


RayLivingston

The device is an i2c LCD:

I see this as an issue.
The current code will hang and lock up the AVR in this situation and never recover.
I don't like code that does not gracefully handle and recover from errors.
Seems like there should be sort of timeout that should allow recovery from this condition.
Either the h/w or the s/w is broken and so the s/w would need to be updated to handle this situation


I need to start another thread on this but I don't know where to put it.
Any suggestions?

--- bill


That is EXACTLY what I'm seeing on the Due, so this is likely not an AVR-specific problem.  At some point, the I2C accesses to a 4x20 LCD start taking an eternity, and the whole system runs at a snails pace.  When I put a scope on the I2C lines,  I see the SAM is not even issuing clocks any more.  Nothing I do in firmware makes any difference at all - it takes a hardware reset to get it working again.  Re-initializing the Wire and LCD objects does nothing at all.  It's bad enough,  I've just gone to the ridiculous extreme of putting a ProMini with an RS232 connection between the Due and the LCD, and that seems to work perfectly, so the Due no longer drives the LCD directly.

Regards,
Ray L.

Koepel

@bperrybap, the bytes do not come in after the Wire.requestFrom() with multi-master. When the Arduino is busy, the other Master should wait. Suppose it does not wait, and jumps in, then the Arduino detects that, and the I2C transaction fails, it should return with a number that is less than the number of bytes that was requested.

I think every I2C device (sensor, eeprom, rtc) will not continue after it sees a start or stop from another Master during a I2C transaction.

I don't like it, but the whole Wire library will only work, when the Wire.endTransmission() and Wire.requestFrom() are waiting.

Please start a new topic ( for example "I2C LCD not conform I2C standard" ) in the Network/I2C section ( https://forum.arduino.cc/index.php?board=11.0 ) and refer to this topic.

bperrybap

Moderator:
I would like to move the detail discussion of this i2c stuff out of this thread, but don't know which section to put it in. Can you suggest something and perhaps split the thread?
--- bill




That is EXACTLY what I'm seeing on the Due, so this is likely not an AVR-specific problem.  At some point, the I2C accesses to a 4x20 LCD start taking an eternity, and the whole system runs at a snails pace.
Doesn't sound quite the same.
In this situation, the AVR is a in a tight loop waiting on a twi status.
This isn't a situation of running slow. The AVR is hung in a loop.
What i2c interface is being used? Is it a i/o expander like a PCF8574 or something else?
And are voltage shifters involved?

This is the LCD I'm using:http://www.seeedstudio.com/wiki/images/0/03/JHD1214Y_YG_1.0.pdf


Quote
When I put a scope on the I2C lines,  I see the SAM is not even issuing clocks any more.  Nothing I do in firmware makes any difference at all - it takes a hardware reset to get it working again.  Re-initializing the Wire and LCD objects does nothing at all.  It's bad enough,  I've just gone to the ridiculous extreme of putting a ProMini with an RS232 connection between the Due and the LCD, and that seems to work perfectly, so the Due no longer drives the LCD directly.
Sounds like the processor is still running so this is not the same thing.
Make sure you have external pullups on the SCK and SDA signals as that creates all sorts of strange issues if missing.
On the AVR, if you get less than the number of bytes you expected from Wire.requestFrom(), then the next attempt to use the i2c will hang the processor.
When i detect the condition,
The only sequence that I've found that can get things going again on the avr is.
Code: [Select]
Wire.end();
Wire.begin();
Wire.beginTransmission(i2caddr);
Wire.endtransmission();


If you attempt to do a read or write without doing this "dummy" address phase, even after doing end() and begin() the library will hang.
So clearly end() and begin() are not really cleaning things up to a clean state after this condition occurs.

--- bill

bperrybap

The Wire bus arbitration discussion is continued over here:
http://forum.arduino.cc/index.php?topic=400643.0
--- bill

nickgammon

Moderator:
I would like to move the detail discussion of this i2c stuff out of this thread, but don't know which section to put it in. Can you suggest something and perhaps split the thread?
--- bill
I thought it was all pretty relevant. After all, the whole question is about I2C.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Go Up