# Multiplexing an I2C bus between two masters on a Xilinx FPGA

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. :)

• So, just to be clear. The instance of the I2C block you are using has a dedicated placement c/w pin locations and you can't add a mux in between the block and the pins to insert your own I2C bus master or you don't know how to write the code to grab those internal signals.? What is the name of the core that you are using? – placeholder Oct 29 '12 at 3:57
• No. The core MPD simply exposes only the implicit tristate signals, not the internal _I _O _T signals, and as a result if I try to put in a mux to those signals it complains that they're not in the MPD. If I manually add them to the MPD, the compiler is happy again, but this isn't ideal either as the MPD file (rarely) gets replaced when the core vendor releases an update. (The core is not an I2C core, it primarily does other things; it has some functions that use I2C but they're completely out of my control.) I want to insert a mux so that I can do some of my own control. – Miral Oct 29 '12 at 4:18
• My understanding is that since I2C is bidirectional it's not feasible to mux the tristate signals themselves within the FPGA, only the internal _I _O _T signals. The thing that bugs me is that with the default unedited MPD file the compiler obviously knows that the internal signals exist and maps them properly to the VHDL (which defines only the internal signals), but it won't let me specify them directly in the MHS file unless they're explicitly listed separately in the MPD. – Miral Oct 29 '12 at 4:22
• BUt you're saying that you know the state of the other controller so you know that it can't interfere, so yes it is entirely feasible. Whether the tools allow you to do it internally is another matter. – placeholder Oct 29 '12 at 5:35
• I2C is open 'collector', so if you can spare 2 pins you can create you own I2C pins and simply connect them to the core's I2C pins externally. – Wouter van Ooijen Oct 29 '12 at 8:34

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.)

If you can't solve the problem internally in the FPGA use transmission gates externally to gate two masters onto one external bus.

• No, there's definitely no need for external gates. This is purely an FPGA compiler problem. – Miral Oct 29 '12 at 8:59