Electronic – Multiplexing an I2C bus between two masters on a Xilinx FPGA

fpgai2cvhdlxilinx

I have a single external I2C bus (SDA and SCL pins). This is currently controlled by a third-party IP core which provided "implicit" inout ports in the MPD, specifically:

PORT IIC_DATA = "", DIR = IO, THREE_STATE=TRUE
PORT IIC_CLOCK = "", DIR = O, THREE_STATE=TRUE

I've hit a situation where I want to be able to talk to a device on that bus independently of the IP core (at a time when the IP core itself can be held in reset so that I know it cannot interfere). I've tried creating a separate axi_iic master and connecting it to the same external ports, but this doesn't work as it gets upset about multiple output drivers connected together.

So I think I need a simple I2C multiplexer as glue logic between the two masters, and I think I know how to do that in terms of the internal _I, _O, _T signals of each master, but I'm not sure how to "extract" those internal signals for the existing core given the MPD above (they are present in the underlying VHDL).

For the moment I've just manually modified the MPD file to expose these signals, but I was wondering if there's a better way to do this (either getting at the signals without changing the MPD file, or doing the whole I2C multi-master thing); while the manual edit is workable, the changes to the MPD file may get lost when the core is updated, so it's error-prone.

Another solution that I've considered (but I'm not sure if I like, though it's still possible since the FPGA pinout isn't final yet) is to double-route the external bus (so the external SDA goes to two separate FPGA pins, one for the third-party core and one for the new core). This seems fairly ugly and wasteful though, but then I'm not an expert. 🙂

Best Answer

Just for the sake of completeness (since I was recently reminded about this question) I'll restate the answer that I finally settled on:

Given the following MPD snippet provided by the core vendor:

PORT IIC_DATA = "", DIR = IO, THREE_STATE=TRUE
PORT IIC_CLOCK = "", DIR = O, THREE_STATE=TRUE

I replace it with the following:

PORT IIC_DATA_I = "", DIR = I
PORT IIC_DATA_O = "", DIR = O
PORT IIC_DATA_T = "", DIR = O
PORT IIC_DATA = "", DIR = IO, THREE_STATE=TRUE, TRI_I = IIC_DATA_I, TRI_O = IIC_DATA_O, TRI_T = IIC_DATA_T
PORT IIC_CLOCK_O = "", DIR = O
PORT IIC_CLOCK_T = "", DIR = O
PORT IIC_CLOCK = "", DIR = O, THREE_STATE=TRUE, TRI_O = IIC_CLOCK_O, TRI_T = IIC_CLOCK_T

This works fine (as the underlying signals were defined in the VHDL anyway). It's a little bit of a hassle as I have to remember to do this each time I get an updated core from the vendor, but this is infrequent enough to not be a big deal. (I've been trying to persuade the vendor to add it themselves, but haven't had much luck thus far.)

Related Topic