-
-
Notifications
You must be signed in to change notification settings - Fork 7k
I2C/TWI Library: Buffer Overflow #1354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I just checked the source and I guess the error is in the file libraries/Wire/Wire.cpp: // copy twi rx buffer into local read buffer I guess it should be I'll test that tomorrow. |
Nope, this didn't help. I also checked the twi.c file but didn't spot the error. any hints about this? |
To me it looks like the code you mentioned is indeed susceptible to overflow. However, the twi.c file also keeps a buffer, so if those buffers are the same length, I guess this code shouldn't trigger a problem, but it's still good to fix it. I would however fix it by putting the following two lines before the loop, instead of the change you proposed:
This makes sure rxBufferLength gets set to the proper (truncated) value. However, twi.c also performs correct buffer checks, and both buffer sizes are equal, so it is unlikely this is the cause for your problem. Looking at twi.c, I see the following code in the interrupt handler:
This means that the code sends a NAK when the received data would overflow the buffer. Perhaps this somehow messes up the state of the i2c hardware causing a deadlock? You'd have to check the datasheet to be sure, I don't know how the i2c hardware is supposed to work. |
Thanks for your reply. Well I also added a check like:
However this didn't resolve the issue. As there are 4 other buffers used for the i2c data, the error must be somewhere else. About the i2c reply, someone knows more about this? Maybe this helps: http://processors.wiki.ti.com/index.php/I2C_Tips#Detecting_and_handling_NACK Edit: |
I just had a look at your blogpost, seems like your Arduino sketch isn't doing anything else except reading i2c data. You are saying the "arduino just freeze", but are you sure the Arduino is really frozen, or is just the i2c hardware no longer receiving. You can check by adding a serial print in the loop, for example. It seems more likely to me that the i2c hardware is somehow ending up in an undefined state. I wonder if the problem might be with the rpi instead of the Arduino. Perhaps the rpi is not properly freeing the bus (sending a STOP signal) after receiving the ack from the Arduino? This is just a guess, though. |
what I did was a "i2cdetect -y 1" on the RPI. after sending more bytes than the i2c buffer on the arduino can h andle the arduino was not longer visible via i2c. yes maybe just the i2c is in a fancy state. I'll try to add serial debug output and see if the arduino itself is just alive. thanks for the idea. I think this would relate to the other links I posted. It looks like the arduino is waiting infinitely in a while loop. http://arduino.cc/forum/index.php/topic,19624.0.html:
if this is the case, the serial output would also stop and the arduino would be blocked. |
Looking at the code and the datasheet, I think that the NAK condition is
Not sure if this is a proper fix, but it could work. (PS: Better not to edit your comments after submitting them, since edits |
Bingo! Thanks for that, this fixed the issue. I created a pull request (#1363). I sended 8 times 32 bytes: everything ok. then Thanks again for your help! |
One more thing I noticed in the code: It seems that the twi library is one byte "late" with signalling a NAK. If I'm right about this sending a 33 byte message would cause 32 bytes to be received without error, with the last byte being silently dropped (I suspect this happens with and without my patch above). Could you see if this is indeed the case? |
I just took some time to hook up my own rpi to my Arduino and managed to reproduce your problem here. I also tested writing 33 bytes and as I expected that works, while silently dropping the 33rd byte. I'll see if I can improve the code a bit now I have a test environment. For future reference, here is the C test program I'm using on the rpi.
|
Hi, I am chasing this bug for days now, so glad I found this post. Unfortunately my arduino uno is still crashing, even if I send less than 32 bytes using the test program above :( My arduino is directly wired to the rpi, no extra pull-up resistors (wired like here: http://neophob.com/2013/04/i2c-communication-between-a-rpi-and-a-arduino/). The arduino is running the following test code (compiled with the bugfix introduced here) : #include <Wire.h>
void setup() {
Wire.onReceive(onReceive);
Wire.begin(4);
Serial.begin(9600);
}
void loop() {
}
void onReceive(int numBytes) {
while (Wire.available()) {
Serial.println(Wire.read());
}
} With this code I can repeatedly write 21 bytes without crashing the arduino uno. Any more bytes will always crash it (arduino appears hanging, i2cdetect fails to detect any devices, test programm reports "Wrote 22 bytes" but on the next attempt writes "Wrote -1 bytes"). Interesting for me: Introducing a Serial.println("LOOP") inside the loop will crash it immediately on the first byte. I have tested this with multiple Arduino Unos and they all behave the same. I am not sure if this problem is related to my setup/code or a flaw in the Wire library - I'm a bloody beginner I have to admit. Hope someone can guide me into the right direction... |
@mofux, you're not seeing a problem inside the i2c library, but in the Serial library (and/or a side effect of the way you wrote your test program). I you use the test program from the article at neophob.com), things will work as expected. What happens is that onReceive runs from the interrupt servicing routines, with interrupts disabled. When you write to Serial, its buffer fills up. Once the buffer is full, Serial.println() will wait for some space to appear in the buffer, but this never happens (since the "byte sent" interrupt from the serial hardware never triggers). The limit of 21 bytes comes from the Serial buffer size of 64 bytes (I suspect you're sending one digit and a CRLF, so three bytes through Serial per received byte through I2C, and 21 * 3 = 63, but 22 * 3 = 66 == buffer full). See #672 which describes this particular issue in detail and offers some suggestions for fixes that could be implemented. |
I just replaced the Serial.println(...) by Serial.print(...) and bam, no more crashes. Thanks for pointing this out and for the detailed explanation. You really made my day. |
@mofux @matthijskooijman are there any action items or can we close this issue? |
I am not entirely sure, but so far as I can tell, the patch in question (1) is actually needed, (2) is not present in arduino 1.8.1's copy of that library yet. |
Tested on Arduino v1.0.3, Using Arduino Duemillanove/Seeeduino
I did some I2c testing between RPI and Arduino (http://neophob.com/2013/04/i2c-communication-between-a-rpi-and-a-arduino/) and observed that when a I2C master (RPI) sends data to an Arduino I2C slave device that is larger than the default buffer (32 bytes) the Arduino just freeze. After sending a i2c packet larger than the default buffer a i2cdetect scan shows no more devices on the bus.
The Arduino needs a reset after this event.
The text was updated successfully, but these errors were encountered: