Contrlloing multiple identical I2C devices in parallel (cheaply...) - Page 1
Forum section: electronics / projects

author: Gabri74
author_rank: Regular Contributor
timestamp: May 30, 2019, 08:32:35 am
content: I need to control 16 I2C oled controllers which are on the same I2C address.The main problem is that I need to drive them fast and at the same time to have them refresh synchronously.And the cost must be realllly low... i.e. I cannot use a 2$ chip per oled, it's too much.I thought of different solutions but none are able to satisfy all requirements:1. 16 SPI->I2C bridges connected to a single MCU via multiple chip select. I found several SPI->I2C bridges but they are too expensive2. Use 2 I2C 8 channels expander. Cheap but this still allows me to drive only one I2C slave at a time3. 16 low end MCUs to act as SPI->I2C bridge connected to a single master via SPI/UART. This will probably be cheaper than solution 2. but I will need to program 16 MCU in production or connect them in daisy chain and use embedded UART bootloader and boot pin to batch program them.4. Use a MCU with al lot of GPIO and implement all the I2C via bitbang. Can do easily but this will not allow me to drive all the slaves at the same time, I will still need to drive one at a time5. Use a cheap CPLD/FPGA to act as an SPI-> 16 I2C bridge. This way I can multiplex all the I2C commands on a fast SPI and have them deserialized and sent to individual devices. Best solution so far but VHDL is not my strongest skill and I'm worried I'll spend to much time writing/debugging this code.So... does anyone have some device to suggest ? Like a SPI->16 I2C bridge ? Does something like this exist? I couldn't find any...Also this is a simple and common problem and it seems strange that I cannot find an already existing device to accomplish this.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 30, 2019, 08:40:22 am
content: Quote from: Gabri74 on May 30, 2019, 08:32:35 amWhy not at the same time?If they are displays and you send them similar (same length) messages, consider tying SCLs together, then dedicating 1 full 16-bit GPIO port for the SDA lines - you'll synchronously write one bit to all 16 displays at a time, with one GPIO port write operation.Depending on what you actually need, you may not be able to pull this off, but this would be fairly simple, and wouldn't be any more demanding for the software than bitbanging a single I2C would.If your simultaneous messages are of different length or structure (w.r.t. read/write), then the software logic would be more complex, but should be still doable.

author: mikerj
author_rank: Super Contributor
timestamp: May 30, 2019, 09:49:33 am
content: Quote from: Siwastaja on May 30, 2019, 08:40:22 amExactly my thoughts, if the message lengths are the same then it's relatively trivial to clocking out bits simultaneously. Use of a fast micro with bit banding (ARM Cortex) should speed up the operation of combining multiple bits from 16 words into a single 16 bit word. Squeezing out 400kbit/s might be an interesting challenge, but should be doable with one of the higher clocked devices, maybe running from SRAM as well.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 30, 2019, 11:22:03 am
content: Itmightbe possible to even utilize DMA, by configuring one timer in PWM mode to output the SCL waveform, and another synchronized timer channel to generate DMA triggers, the DMA target being the GPIO port, and the full bit sequences pre-calculated (you'd likely need two bits per actual bit, so you can generate the start/stop conditions automatically).If it is a display, you'd likely simply want to ignore ACK/NACK, as all you can do in a fault condition anyway is to do the next refresh as usual.

author: Rerouter
author_rank: Super Contributor
timestamp: May 30, 2019, 12:28:15 pm
content: Another recommending bulk bit banging, with a common SCL line, find a 16 or 32 bit micro so you have atleast 16 pins on the same port (not all micros expose all of those pins conveniently, and just write and read at a port level, this is much easier if you can precompute the patterns, that way you just need to use very few cycles to just copy a state to the port and toggle the SCL pin twice.If you need to generate everything on the fly, well its not hard, just ugly to make as fast as possible, as you have 16 LED's with a byte of data you want to send, that you need to rotate into 16 bit slices for each bit of those bytes, so its mainly going to be using the bit manipulation e.g. ADDRESS |= (1<<BIT) handle each bit in 2-3 clock cycles, ironically this would result in almost perfect utilization of say a 16MHz AVR, if instead of running at a hard 400KHz you settled on like 380Khz, you would even have cycles left to say read in external data via SPI, but yes, it would be as bare metal coding as you can manage.

author: Gabri74
author_rank: Regular Contributor
timestamp: May 30, 2019, 01:03:39 pm
content: Thanks for all the suggestionsUsing a single SCL line and group together in one single port SDA lines is indeed a clever idea that I didn't think ofI see only to possible pitfalls:1. Clock stretching. If the controller supports it (and I'm not sure yet) every device could mess up all the transmission. Obviously if the devices are all the same this is highly improbable, but it's a thing to take into account2. You can never address a single device, to change one display you have to refresh them all (not a big problem)A possible approach could be to use a 16bit port so SCL also. This way no device can alter the clock or another and also it would be possible to refresh only some devices at a time.The project is in the feasibility stage and I'm not sure yet if the mechanical constraints will allow to use one single PCB for all the displays. If a single PCB is possible, I'll go the way you suggested.If I'll need to user separate PCBs I'm afraid I'll have to use a separate MCU per display and control them via SPI.

author: ejeffrey
author_rank: Super Contributor
timestamp: May 30, 2019, 05:43:24 pm
content: Clock stretching shouldn't be a problem assuming you actually detect it on the master. If any single device does clock stretching, the master would simply wait until all of them released the SCK line before proceeding. I wouldn't bother implementing it at all unless you know the devices support/require it.That said, provisioning individual IO for the clocks doesn't seem too onerous. 32 GPIO pins isn't a crazy amount, and the ability to individually select devices seems like a good future proofing decision.

author: MustardMan
author_rank: Contributor
timestamp: March 04, 2021, 08:12:17 am
content: Quote from: Gabri74 on May 30, 2019, 01:03:39 pmI don't know if this is actually true.According to the I2C specifications, an I2C bus is ONLY started when SDA goes low while SCL is high. Following from that if the channels you did not want to receive a command left SDA high for just the first bit (letting all other SDA toggles occur as per usual, which is when SCL is low). However, that does rely on the slaves following the spec!However, you could only allow the channel you wanted to 'address' (out of the 16) toggle SDA, while all the others remain untouched (high) for the entire command string, and that should work. I can't see anything in the spec that says randomly toggling SCL with SDA staying high will cause any issue.I originally found this with a forum search, and although old, is related to my particular problem... an issue I will soon raise in a new thread.Cheers,