Raspberry is great, and I2C is my favorite bus.
Unfortunately the two doesn’t mix well. See, I2C support a mode called “restart” where the bus remains occupied by the master and the adressed slave, between the write and the read part, so the operation is atomic, and there is no way of other devices interrupting an important command.
I like the atomic operations most because…you cannot spell PhotoAtomic without saying Atomic! Joking… i’m a fan because i’m obsessed with the fact of being always able to track down the causes of everything. Atomic operation are an easy clean and obvious way to do it.
Usually when I2C is in the game, the slave devices are very easy, less powerfull microcontroller, where you have only few KB of ROM for the entire program.
LOL, KB… we can’t store a single icon 14KB these days.
But beware, microcontroller are very capable device. The Pic i’m using is amazing, it has many many hardware peripherials onboard and two I2C port with hardware acceleration.
AND THEY WORKS DAMN WELL (if you spend a month debugging and learning all the details of I2C protocol)
I can’t say the same of Raspberry, and this drive me crazy.
My PIC costs less than a dollar, it has hardware I2C that are rock solid, they don’t miss a single bit, they support general call, clock stretching and restart. the full damn I2C protocol!
What i’ve discovered is that a 35$ Raspberry (v1, v2, v3, or v4) is not so compliant.
I’ve spent days in hunting a bug that i tought was in my code, and i’ve debugged everything down to the wire signal with logic analyzer and oscilloscope.
After all this work i’ve discovered that it wasn’t my PIC that doesn’t release the clock stretch, but instead the Raspberry state machine that is simply bugged as hell.
there are countless issue regarding the I2C clock stretching issue on the raspberry repo, start from this
I2C Broadcom bug workaround. · Issue #254 · raspberrypi/linux (github.com)
the issue seems to be in the silicon of the raspberry SoC. So hard to fix but com’on how many of this bugged chip have broadcom sold? it is tragic that they won’t fix them
Raspberry fundation should rise the voice. Raspberry sell millions of pieces, of a device that is bord for IoT.
in IoT sensors and peripherial are of 3 kind I2C, SPI, old serial. Forget the last that can be barely called “a protocol”
I2C is versatile, battle tested, cheap to implement (only 2 wires man!) it is a VERY IMPORTANT bus for IoT.
i cannot understand how the raspberry foundation is not ashamed of selling a device to “make” IoT that isn’t fully compliant with I2C specification.
there are several way to mitigate the issue.
1) if you are programming the slave, do not use clock stretching, this basically means no restart operation so no atomic operations.
this is because usually when you transfer a command the microcontroller is fast enough to not require any additional time to write the bytes in a buffer collecting all of them without asking for extra time.
but when the commandis completed, immagine a flash ram command, it can take some time to execute (flashing a ROM in a microcontroller requires a special bit “dance” to unlock memory block, plus the information you write usually must be block aligned, this means read flom the ROM as well…which is a quite slow operation. immagine multiply by 32 (my pic block size) and you easilly need to use clock stretching to keep the bus line busy line while performing this operations.
But Raspberry doesn’t undernstand clock stretching and simply cause its state machine to jam irreversibly. Sad, very sad, not epic, we need to SLAP broadcom for this.
So the workaround is to reprogram your device by working in an asynchronous way: the write and the read part of the atomic command must be decoupled, this means a more complex code, and some correlation id to be sent in order to understand which reply is for which command. Ugly in my opinion. i just have 14 precious kilobyte of RAM and i don’t want to waste them to adress an issue of a SoC with many Gigs of ram and as-many-as-yo-want storage in sd that are humongus these days … for 10$. This is very stupid.
2) another solution, if you cannot avoid clock stretching, is to lower the bus speed, this way you can be lucky enough to give the microprocessor enough time to process the command without the need to stretch the clock above it’s natural length. and the communication can occur…. untill you become unlucky.
so this is not a very robust solution
3) the real solution is to enable the good old bitbanging I2C driver on the raspberry. this is laughtable but it is the only way to have a reliable and compliant communication.
you can read details here i2c-bus/raspberry-pi-software-i2c.md at master · fivdi/i2c-bus (github.com)
basically you have to add to the device tree a virtual device editing the /boot/config.txt file and adding (in the [ALL] section at the end) the following line
dtoverlay=i2c-gpio,bus=3
The use the pins 16 and 18 as reported also here Adventures in I2C: clock stretching on the Raspberry Pi – Raspberry Pi Pod and micro:bit base (recantha.co.uk) instead of the 3 and 5
In my test the bitbanging driver is rock solid and is fully compliant with restart and bit stretching.
in conclusion: i think i’ll try to implement pic firmware with a mechanism that doesn’t require clock stretching, an asyncronous read-write which is in any case a stupid idea, because flashing rom required disabling interrupt, and therefore basically software removing and re-attaching at any time the microcontroller from the I2C bus, causing an all new sort of issue. while the clock stretching was a very elegant and convienent way that doesn’t require correlation ids or strong assumption to make the communication work.
But i want my device to be raspberry compatible out of the box as much as possible, so i’ll see if my small “David” PIC can fix the mess tha the dumb “Goliath” Raspberry have done on the bus.
Shame on you Raspberry, shame on you Broadcom!
Tags: