I²C issue on Raspberry Pi - Page 1
Forum section: electronics / beginners

author: Blaffetuur
author_rank: Regular Contributor
timestamp: January 06, 2018, 09:14:44 am
content: Hi all,I'm trying to get I²C communication going between a Raspberry Pi (master) and Arduino Uno (slave). Have a look at the PDF in the attachment, there I descirbe the problem in more detail.I have 3 python scripts:1. Request data from the slave: works fine2. Send data to slave: works fine3. Send data to slave and then read data from slave: gives me troubles.Any help would be appreciated, Thanks!-Robin

author: frozenfrogz
author_rank: Frequent Contributor
timestamp: January 06, 2018, 10:10:00 am
content: Might very well be a stretching issue, you can read more about it here:http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.htmlThere are also some suggested workarounds.Maybe, you could dump I2C in favor of SPI?Edit:Here is also an informative write-up for the I2C interface.https://aticleworld.com/i2c-bus-protocol-and-interface/

author: paulca
author_rank: Super Contributor
timestamp: January 06, 2018, 01:13:07 pm
content: This is usually an anti-pattern that will burn you.Code:void receiveEvent(int howMany){while (Wire.available()){data = Wire.read();}rec = true;}Typically available() methods on streams or sockets tells you if there is something available to read "right now", ie. sitting in the read buffer. available() returning 0 does not mean the transmission has finished. I see people making this mistake quite a lot and in 99% of cases it will work fine, but when it doesn't it will be a pig to find out why.It is better to communicate how the long the message is in the first few bytes, message header, and then wait on that many bytes arriving or timeout. Or if you know how many bytes you are going to receive then check you have received that many. Timeouts and blocking versus non blocking IO stuff would go here.You appear to be only reading/writing one byte though, so it's academic. However, you are depending on the Wire event model to know there is a byte available. If available returns 0 your code will exit that function without actually reading a byte.Don't run python as root. Ignore what the idiots at Adafruit etc. tell you. Add yourself to the relevant groups, logout and in again. If you find a library which outputs "Expecting to run as root", edit it, delete that code. It's dumb. There are VERY few circumstances were you 'need' to run basic user scripts as root. Those would include system administration or access system files... which is why you don't run scripts that don't need to do those things as root, because if they go wrong they can trash your system. The reason why Adafruit et al suggest it is laziness and not bothering newbies with groups and chmod/chown etc.https://www.raspberrypi.org/forums/viewtopic.php?f=44&t=88718And don't set files to 777 ever.The only potentially relevant exception to this is if you need near-realtime priority for timing. I do not believe this is require for I2C as the PI is more than fast enough.As to your actual problem. The clock pulse on the start of the data word appears mangled on the scope. That is the bit the PI is reading wrong which suggests it's being intercepted incorrectly, potentially due to the mangled clock pulse.

author: paulca
author_rank: Super Contributor
timestamp: January 06, 2018, 01:52:41 pm
content: So I did a bit of digging and that mangled clock pulse is almost certainly the ATMega trying to slow the master down because the Wire library has not responded yet by setting a flag that it received the data.See:https://www.reddit.com/r/arduino/comments/2jip7s/are_there_ways_to_disable_clock_stretching_for/The only viable options seem to be:Slow the I2C clock down.Make the Arduino masterBit bang the hardware I2C yourself to set the TWINT flag as fast as possible.

author: Blaffetuur
author_rank: Regular Contributor
timestamp: January 07, 2018, 08:49:04 am
content: Quote from: paulca on January 06, 2018, 01:52:41 pmThanks for the tips ! I'm definitely going to look into the wire library some more and I never gave a second tought about running my scripts as root. Two thing added to my to do listQuoteMan I saw this tooI was so focused on the aknowledging part that I didn't added this to my list of possible causes.As for the posibble solutions, I chose to slowing the clock down first:Tried thishttp://www.mindsensors.com/blog/how-to/change-i2c-speed-with-raspberry-pisite first without much succes. The instructions used the don't appear to be effective in Raspbian Jessee.By adding the folowing line to /boot/config.txt I was able to change the baud rate of the I²C busCode:dtparam=i2c_arm_baudrate=10000I arbitrarily chose 10kpbs and it seems to be working fine. Did not yet tried at which speed it stops working.

author: Blaffetuur
author_rank: Regular Contributor
timestamp: January 07, 2018, 09:36:06 am
content: Quote from: frozenfrogz on January 06, 2018, 10:10:00 amYeah I see it now, thanks for the great articleit gives a really good explenation of what's happening. One of the suggestions is slowing down the I²C clock and thats exactly what I've done to solve it.

author: paulca
author_rank: Super Contributor
timestamp: January 07, 2018, 10:01:53 am
content: Quote from: Blaffetuur on January 07, 2018, 08:49:04 amI recall that some of the Adafruit python libraries attempt to do a "modprobe", for example, "modprobe i2c-dev". They need root for that to work.However, again, it's a bit dumb doing this in a user script which shouldn't be changing kernel modules. They tend to run the python script as root so it can do this.The correct way is to set those up with either raspb-config or /boot/config.txt or the traditional /etc/modprobe.d/ entries.