1
$\begingroup$

The beaglebone black which I work on has only 2 i2c busses. Say for some crazy reason, i need to use 8 i2c busses. I dont want to chain any of the devices. The idea is to have every device's SDA line separated and use a shared SCL line so i can use the same clock and have as many SDA lines as i want. Since the SCL clock is hardware controlled there wont be any major issues here. The GPIO can do around 2.5mhz of switching so I am happy with that.

If that works out, i can spawn 8 threads to talk on 8 i2c Lines making my solution faster!

Do you think its doable? I would like to hear from you guys as this idea of using 1SCL and GPIO as SDA just popped in my head and i thought of sharing it with you guys.

Cheers!

| improve this question | | | | |
$\endgroup$
4
$\begingroup$

Unless your I2C hardware components have the ability to use an external clock to drive the clock line of the buses (none that I've heard of), you wouldn't be able to do this by hardware.

You could do this by manually driving the buses. This is called bit-banging. If you do that, you can carefully craft your software driving GPIO pins that act as I2C buses and manage all 8 buses in parallel. You would most likely want to do the bit banging by interrupts.

You can have your piece of software having 8 (global) variables (of a struct) that tell if and what needs to be written to each I2C and if and how much needs to be read as response. Regardless of hardware I2C or software-emulated, this step is actually necessary anyway.

In your bit-banging piece of software, here are some things to look out for:

  • If at least one bus needs to read/write data, drive the clock.
  • If parallel threads want to write to the variables, make sure to write them in the correct order and take care of synchronization.

    • For example:

      /* bus 3 wants to write and read something */
      i2c_data[3].address = some_address;
      memcpy(i2c_data[3].to_write, whatever, 10);
      i2c_data[3].expect_to_read = 5;
      atomic_set(i2c_data[3].new_data);
      

      where new_data, a flag that the I2C emulation software checks for to know if there is something new to do, is written last and atomically.

  • If any of the buses wants to start or stop, generate their respective start or stop condition and make sure there is enough setup and hold time before you continue clocking.
  • If any bus results in a NACK, make sure to at least note it, if not stopping that particular bus.

Of course, this is to make 8 parallel unrelated I2C buses. If your application needs to talk with 8 of the same kind of device, then your bit-banging software would be simpler, since they all start and stop at the same time, even if their data and ACKs are managed separately.

Note that the I2C emulation software is not replicated per thread, but is one managing all of them at the same time.


While I'm always up for using the hardware in ways beyond most people's wildest imagination to get it to do something better or faster, I'd advise you to study your problem a bit more, do some calculations to make sure you actually want to do this.

Emulating hardware through software is very error-prone and slower by an order, there are very many edge cases and needs thorough testing. In short, it's a time-consuming job. Being slower than hardware also means that there is a point where it starts to become beneficial and you need to find that point. Since you have 8 devices and 2 I2C hardware components, you can attach 4 devices to each bus and you need to study if your implementation would actually be faster than that.

You may also think of changing your hardware. A Cypress PSoC for example lets you put as many components as you want (and there is space and resources on the chip) so for example you could put 4 I2C buses (if 8 wasn't possible) and attach 2 devices to each bus. With a PSoC and knowledge in verilog, you can also write your own 8-device I2C bus component implemented in hardware.

Alternatively, you could also think of changing your bus. I2C is a very strict protocol designed to ensure error handling with each byte as well as prevent component cross-talk. You might not need that much restriction and for example you could check the data with CRC so you may not care for intermediate errors.

You could use an SPI bus, which is much simpler and thus easier to emulate. As a bonus, you don't need to be working with an open-drain data bus (as in I2C) which means you can get to speeds that are much higher than I2C. Common support for I2C buses go up to 400Kbps (newer ones go higher) but common devices supporting SPI bus can easily go up to 4Mbps.

That said, talking serially to 8 devices on an SPI bus @4Mbps could indeed be faster than talking to 8 devices in parallel on I2C buses @400Kbps (depending on the protocol). Again, this is something you would need to assess to see which option is more beneficial to you.

| improve this answer | | | | |
$\endgroup$

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.