Skip to content

Tricks that are (almost) allowed

Koepel edited this page Oct 11, 2021 · 12 revisions

Reading the data in the loop() in a Target with empty onReceive handler.

When an Arduino is set as I2C Target, the interrupt function for receiving data is set with Wire.onReceive(). That interrupt function (the handler function) can be empty and the checking for received data can be done in the loop(). Thus assuming that the data is still available in the buffer after the interrupt function (the handler function) has finished.

This might work, although when new data is received it will replace the old data and in the loop() a mix of old and new data is processed.

The official Arduino Wire libraries clear the buffer when receiving data. That means the old data stays in the buffer and can indeed be used outside the interrupt function.

The main concern is the compatibility with other Wire libraries.

This does work at this moment with the official Arduino Wire libraries for the AVR boards. However, it is not explicitly mentioned in the documentation that this is supposed to be normal use of the Wire library.
It does not seem to work for the MKR/Zero boards: https://forum.arduino.cc/index.php?topic=660381.0

Writing 32 bytes in the Target onRequest handler, regardless how many the Controller will ask.

When the Arduino is set as a Target, it does not know how many bytes the Controller wants when the Controller does a Wire.requestFrom(). In the onRequest handler in the Target it is allowed to completely fill the buffer. The buffer size is 32 bytes for an Arduino Uno. The Controller could request just 1 or 2 bytes and might stop the I2C bus transaction after that.
This is allowed and will do no harm.

Using the size of the data in the onReceive handler to identify which data it is.

When the Arduino is set as a Target, the parameter of the onReceive handler tells how many bytes are received. When different kind of data sets are written to the Target and the data packets have different sizes, then a identifier is not needed and the Target can use the size to distinguish between the data packets.

Don't try a multi-Controller I2C bus

Since 2018 the Wire library for the Arduino Uno can detect a bus collision. That error is processed by the Wire.endTransmission() and Wire.requestFrom(). The experienced Arduino users stay away from a multi-Controller I2C bus, because it has many consequences. It is hard to predict when it still works reliable and when there are too many Controllers on the bus. Don't be the first one to attempt to make a multi-Controller I2C bus.

Be careful with I2C level shifters

I am a big fan of I2C level shifters when 3.3V sensors are connected to 5V Arduino boards. However they have disadvantages.
The normal I2C bus for 100 kHz to 400 kHz has weak signals because the signal is pulled high with pullup resistors. A level shifter to connect a 5V I2C bus to a 3.3V I2C bus makes the signal even weaker. Be careful when using long wires (1 or 2 meters is long for a I2C bus) and also a level shifter.
Sometimes a sensor module has onboard I2C level shifters. Do not use another I2C level shifter for those modules, because then the signals gets disturbed too much. The low level has to go through two diodes.
If possible, try to use a newer Arduino board with a 3.3V processor to avoid the problems with level shifters.