I have an RPI which is only booted to collect and transmit sensor data periodically, connected to an Arduino Nano via serial. The serial communication is OK via an interface I’ve created on the Nano, but I’d like to move it to i2c for better reliability.
The RPI will always be an i2c master - reading from i2c sensors and from the Arduino.
The Arduino will be an i2c slave - but also needs to be a master to read Voltage readings from an INA219 and determine when to boot the RPI.
I’ve read this topic:
But won’t there be a conflict if the RPI i2c master is reading from the bus at the same time the Arduino does its:
Is there a better way for the Arduino to detect whether the RPI is reading/writing to i2c?
Yes, that's called a bus conflict. That's is why you cannot have two masters that are not synchronized in some way. The easiest way that comes to mind would to use a gpio pin on the Rpi connected to a nano digital in that tells the nano the Rpi owns the bus during writes to avoid the conflict.
I'm not sure I understand your configuration enough to know which device (Rpi or nano) is the busier one. The key is that the additional i/o needs to be set up in such a way that the device that needs to write most i2s data should be the device that outputs the busy signal to the input of the lower thruput device.
I2C supports multiple masters, it is part of the protocol. The question becomes do the devices that are master support multi-master mode?
I believe that the AVR twowire h/w does, not sure about the rPI.
At least the Arduino can not issue its own I2C data collection when it's currently addressed by the Rpi. Once an I2C transmission has started, it can not be interrupted by another I2C transmission.
In code the results of each I2C function call have to be inspected for error conditions, resulting from possibly concurrent bus access. When a transmission should start while another transmission is active, just that call should return an error.
In the case of Wire.requestFrom() the returned number of bytes should be zero on a bus collision. Then a delay should be inserted, to allow the ongoing transmission to terminate, then the request should be retried until bytes have been received.
In my design, the Arduino will be performing a read (as master) of the INA219 every 10 seconds for charge voltage. The RPi performs a read (as master) every 10 minutes of all other i2c devices on the bus. The Arduino will also be acting as a slave, for these reads from the RPi.
The chances of a collision are minimal, but possible. Only if the RPi initiates a read when the Arduino is already reading voltage from the INA219.
Maybe this is more of a question on how i2c master assertion is implemented on the RPi. i.e. what happens on the RPi when it tries to perform a read as master, when the bus is busy?
I'd like to avoid having to program for master-master priority using RPi GPIO and Arduino digital lines.
If the Arduino is using a slave that the rpi is not accessing and you have two spare pins, then the Arduino could use SoftwareWire on to talk to that slave on a different bus.
This would avoid any multi master issues as the AVR could be a master on one bus using SoftwareWire and a slave on the other using the AVR twowire h/w and the Wire library.