Go Down

Topic: I2C multi-master question (Read 4015 times) previous topic - next topic

olesk

Hi!

I'm setting up a system with two masters (Arduino + Peggy2 from Evil Mad Science) and multiple slaves (external clock, some sensors etc.). I should quickly add in case someone feel like suggesting that I consolidate on one master that I'm doing this as a learning/experimentation projects, so I'm on purpose making things a little more tricky than strictly speeking necessary.

I've been looking at the/one I2C FAQ http://www.esacademy.com/en/library/technical-articles-and-documents/miscellaneous/i2c-bus/general-introduction/bus-arbitration.html, and it *seems* to me that arbitration between two masters is not all that tricky. From the FAQ:
Quote
Therefore the general rule of thumb is: If a master can't get a certain line to go high, it lost arbitration and needs to back off and wait until a stop condition is seen before making another attempt to start transmitting.


That seems deceptively simple to a newbie like me: if one of the two masters trying to get a line high can't, it needs to cancel, wait and retry later. But since I've seen quite a few confused posts about this on these forums and no one stating that they've done this successfully (feel free to slap me if I've missed something), except on systems with *only* two masters, I guess I'm missing some finer point here. I'm not a particularly experienced C programmer (my background is sysadmin with Perl & other scripting), but it seems like adding this functinality to the Wire library should be managable, or...?

wayneft

Actually the Wire library handles the arbitration issue fairly well...a little too well and that's where the problem comes in.  As you stated, the master should wait for a stop condition before attempting to gain control of the bus which Wire will do.  The real problem comes into play because the Wire library does not support the use of a repeated start between write/read transactions.  A typical scenario when reading data from a slave device, using the Wire library, is to initiate a write cycle to the slave address (set the address pointer), send a stop bit, send a start bit and finally read back the data beginning from the address pointer.  In a single master system, and for most I2C devices, this setup works just fine.

When you add a second master to the bus, again using the Wire library, the second master will watch the bus and will wait for the stop condition before initiating it's transaction.  Unfortunately the first stop condition takes place between the write and read cycles on the first master's transaction.  So what ends up happening is the first master ends up with the second master's requested data and the second master ends up with the incorrect data.  Here's the sequence of what happens:

Master1 sets address pointer: Master1 sends stop bit: Master2 sees stop bit (bus free): Master2 sets address pointer (Master1 is now waiting for bus to free up): Master2 sends stop bit: Master1 sees bus free and reads back data (data is read from Master2's address pointer): Master1 finishes reading data and sends stop bit: Master2 sees the bus is free and reads the data from the slave device. If the slave device supports autoincrement reads, the data read back from slave for Master2 will start at the address location following the last read from Master1.

The only way to fix this problem is to use a repeated start between write/read cycles which the current version of the Wire library does not support (the developers are working on a patch for this issue). A repeated start takes the place of the stop then start bits so the bus never frees up between write/read cycles so each master can finish it's transaction completely.

borref

Credo to wayneft for his excellent explanation on why repeated-start is needed in a multiple master setup.

Another shortcoming in the wire library is lack of bus-fault tolerance. The wait-for-ready logic is implemented as simple loops that will block indefinitely and lock up your system in case of bus issues. This behavior is likely to be unacceptable in real-life systems and also difficult to trace and debug.

There is also a hardware issue with the way Atmel implemented TWI for the AtMega core in terms of multiple masters. An explanation of this issue is available here:

http://www.robotroom.com/Atmel-AVR-TWI-I2C-Multi-Master-Problem.html

Implementing repeat-start and adding recovery from bus issues is not all that difficult, so perhaps you should look into rewriting the wire library as part of your I2C project.


olesk

Hi and thank you both for very helpful answers! :)
As I'll have pretty tight timing requirements for this project it seems I'm better off restructuring the project as a single master project, at least for the time being. Too bad, but I'm grateful you told me before I started tearing all my hair out on a somewhat doomed approach...

Go Up