While adding an I2C communication bus to an embedded power supply for a client, I recently reviewed the datasheet for an I2C bus switch, a PCA9546A by NXP. This particular switch allows one or more downstream I2C buses to be switched into one upstream I2C bus.
The PCA9546A switch is cleverly designed to operate as an I2C node. The upstream bus master simply addresses the switch via the bus and writes to a register on the switch to select the desired downstream bus or buses. The upstream bus master can then address downstream nodes on the selected buses. Likewise, any masters on the downstream buses can address notes on the upstream bus and other downstream buses. And since the switch is just another node on the bus, there’s no need for dedicated control lines between the bus master and the switch.
However, an application note for the PCA9546A switch cautions:
The PCA954X products however do not have the capability to detect activity on a downstream bus before the upstream master enables it. Therefore, care must be taken when switching buses if there is a master device on the downstream bus. The master on the downstream bus must be idle when the upstream master enables that channel in order to avoid data corruption.
This poses a chicken and egg problem: How can we know whether or not a downstream master is idle without switching to that bus to check its activity? If we could sniff the current levels of the two I2C signal lines on the downstream bus, we could detect activity on that bus without risking data corruption. A simple improvement to the switch would be to add a register that returns the current levels of the two signal lines for each port on the switch.
Being able to sniff the current levels on each port helps, but we still have to know what to do with that information. If either signal is low, then we know the bus is busy. However, just because both signals are high does not mean that the bus is idle, so we should sample the signals a few times to make sure they both stay high. But sampling puts a burden on the firmware of the upstream bus master – how often and how many times should it sample the signals before it can safely call the bus “idle”?
We can solve this problem with another improvement to the switch: Add a simple state machine to track the state of the each downstream I2C bus–active or idle–as indicated by start and stop bits. In I2C, the start and stop bits are very easy to detect. The start bit is indicated by a 1 to 0 transition on the data line while the clock line stays high. The stop bit is indicated by a 0 to 1 transition on the data line while the clock line stays high.
Using this state machine, the switch could indicate in a register the current state of each downstream bus. The upstream master could read this register to get the current activity state of each downstream bus whether or not any downstream buses are selected by the switch. This example shows how a little bit of logic in a chip can go a long way to provide necessary information that would otherwise be a significant burden on firmware to obtain.
Until the next switch…