2

I have put together a system that uses multiple Arduinos and a couple of 20x4 LCD displays to monitor my PV sun tracker and a weather station. I am using I2C to link them all together. One of the LCDs has been modified to have a different address (0x3b) so as to not conflict with the first one (0x3f). So far, so good. The sun tracker shows its display on the yellow one and the weather station shows its data on the blue one.

In order to connect this together I am using the Mayhew I2C&Power devices, so one power source energizes the entire system. I send 12 Volts on the wire, then at each node I use a 12v to 5v converter to provide power for the I2C&Power board and the Nanos. (The anemometer on the WX needs 12V to operate so that's a plus)

Each Arduino has a unique I2C address - there is no master in the system.

I have learned to set the screen updates to be quick (take readings and do any calculations before writing to the LCD in one swell foop), and to stagger the display update timings (the WX info updates every 65050 ms (full display update) and the PV info updates every 67050 ms (4 characters) and 605550 ms (full display refresh). I chose these (arbitrarily random) values to make it less likely that they would try to update at the same time, because when both systems try to update their respective displays at the same time it causes some very interesting results - basically wiping out one or both displays. It works most of the time but eventually one or the other screen will get wiped out.

Question: Is there any way to implement collision detection on the I2C bus to prevent transmitting while other devices are communicating? Something like CSMA/CD (Carrier Sense Multiple Access with Collision Detection) on Ethernet..

  • What are the physical distances involved with your interconnections? – jose can u c Nov 8 '16 at 16:18
  • Less than 50 feet for the longest one. If the I2C&Power over Ethernet cable doesn't do the trick (They claim 300 feet - but the time delays could become an issue) then I will need to put a Pi out there to put up a value somewhere, like the way people Tweet parameters. – SDsolar Dec 12 '16 at 3:52
  • I did find this little gadget that provides interrupts so I could have dual I2C buses feeding into a single device without having them actually collide: ebay.com/itm/401208338113 – SDsolar Jan 22 '17 at 20:20
1

Collision detection on I2C is fully supported (See I2C Multi-Master). It works basically by attempting to transmit something and reading what is being transmitted at the same time. If what is read matches what is transmitted then the transmission worked. If it didn't match then there was a collision.

It is usually performed on a per-bit basis:

  1. If a 0 then pull the data line LOW. If a 1 then let the resistor pull the data line HIGH.
  2. Read the data line. If you want a 1 and get a 0 then some other device is pulling the data line low for a 0.
  3. If the value was wrong then stop your transmission and back off by a random amount. Retry again. (note: both ends may retry, so you need good random numbers).

There is no support in the Wire library for collision detection, though, so you will have to implement it yourself. Section 22.4 of the datasheet gives you more information about how to implement it.

  • Thank you, @Majenko. I'll follow up on this one for sure. I am not using any pull-ups at all right now, (though I suspect some of my devices on the line, like the RTC, might have their own). But this is very intriguing. – SDsolar Nov 8 '16 at 18:57
  • 1
    The Wire library turns on the internal pullups on the I2C pins for you. It really shouldn't, since they are too big (by about 10x). You should use external ones at about 3.3kΩ. – Majenko Nov 8 '16 at 18:58
  • Upon more experimentation I have discovered that my I2C bus (extended by Mayhew I2C&Power modules) only works so well because of the presence of the RTC module. It can be anywhere on the bus - at the display or out at the sensors with the Nano. If I remove it, the bus quits working. So I presume it is doing the job for me. – SDsolar Nov 11 '16 at 2:49
  • I will be multi-master, per se. But will designate a primary system that can have one byte to say which system is currently allowed to transmit. After determining that the bus is not busy I will read that one byte and if zero then will put my node number in and then read it back to confirm. Then open the connection then set it back to zero when I am done. If nonzero I will know either a part failed in the middle of a write operation or the bus-busy failed. So will wait and try again. If the problem persists then I will write a FF to signal the primary to do a poll for missing nodes. – SDsolar Dec 12 '16 at 3:20
  • That link to the datasheet is quite interesting. It is clear that there needs to be a software solution. I like the idea of opening and writing a byte then checking to see if it went through. The other nodes will have to honor that and wait their turn. I'll be sending short messages from all of them, so a too-long delay in releasing the channel will mean a node failed to clear the byte. – SDsolar Dec 12 '16 at 3:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.