I2C bus multiplexing inside CPLD

T

Thomas

Hi all,

I need to design (VHDL) a I2C bus multiplexer to control 4 clock I2C
slave devices that have the same slave address. My CPLD receives an on-
board I2C bus and needs to route it to 4 I2C devices thru an I2C mux
depending on the slave that i need to configure. No matter what I've
tryed, it doesn't work....

Any help/idea?

Thank you.

My design looklike:

entity I2c_Bus_Mux is
port( onboard_i2c_SCL : inout std_logic;
onboard_i2c_SDA : inout std_logic;
control_vector : in std_logic_vector(1 downto 0);
Slave0_SCL : inout std_logic;
Slave0_SDA : inout std_logic;
Slave1_SCL : inout std_logic;
Slave2_SDA : inout std_logic
---------------------etc-------------------);
end I2c_Bus_Mux;


process (----sensitivity list containing all involved signals)
begin
case control_vector is
when "00" =>
Slave0_SCL <= onboard_i2c_SCL ;
Slave0_SDA <= onboard_i2c_SDA;
onboard_i2c_SCL <= Slave0_SCL;
onboard_i2c_SDA <= Slave0_SDA;
when "01" =>
.......etc.....
 
D

David Spencer

Thomas said:
Hi all,

I need to design (VHDL) a I2C bus multiplexer to control 4 clock I2C
slave devices that have the same slave address. My CPLD receives an on-
board I2C bus and needs to route it to 4 I2C devices thru an I2C mux
depending on the slave that i need to configure. No matter what I've
tryed, it doesn't work....

Any help/idea?

Thank you.

My design looklike:

entity I2c_Bus_Mux is
port( onboard_i2c_SCL : inout std_logic;
onboard_i2c_SDA : inout std_logic;
control_vector : in std_logic_vector(1 downto 0);
Slave0_SCL : inout std_logic;
Slave0_SDA : inout std_logic;
Slave1_SCL : inout std_logic;
Slave2_SDA : inout std_logic
---------------------etc-------------------);
end I2c_Bus_Mux;


process (----sensitivity list containing all involved signals)
begin
case control_vector is
when "00" =>
Slave0_SCL <= onboard_i2c_SCL ;
Slave0_SDA <= onboard_i2c_SDA;
onboard_i2c_SCL <= Slave0_SCL;
onboard_i2c_SDA <= Slave0_SDA;
when "01" =>
.......etc.....

The problem is that I2C signals (SCL and SDA) are bidirectional, which makes
any form of I2C repeater/switch within an FPGA very hard to implement.
Assuming that you only have a single I2C master then you don't need to worry
about arbitration and you may be able to make it work with some careful
thinking, but it is non-trivial.

An easier solution is to implement an I2C device within your FPGA to act as
a control register for an external analog mux (Quickswitch type thing).
Alternative, just buy an I2C mux from NXP (Philips as was), which will do
the job for you.
 
T

Thomas

The problem is that I2C signals (SCL and SDA) are bidirectional, which makes
any form of I2C repeater/switch within an FPGA very hard to implement.
Assuming that you only have a single I2C master then you don't need to worry
about arbitration and you may be able to make it work with some careful
thinking, but it is non-trivial.

An easier solution is to implement an I2C device within your FPGA to act as
a control register for an external analog mux (Quickswitch type thing).
Alternative, just buy an I2C mux from NXP (Philips as was), which will do
the job for you.

Hi,
I agree with you but it's too late for us, the PCB is made and I have
to find a solution for that

Thanks

Thomas
 
B

Brad Smallridge

You should be able switch your signals, if you can
get at the IOs before they are combined into inouts.
Can you do that? Or is there some sort of proprietary
code problem?

What tools are you using and what is your target CPLD?

Brad Smallridge
AiVision
 
D

David Spencer

Brad Smallridge said:
You should be able switch your signals, if you can
get at the IOs before they are combined into inouts.
Can you do that? Or is there some sort of proprietary
code problem?

What tools are you using and what is your target CPLD?

Brad Smallridge
AiVision

The problem is that I2C signals are open-drain and inherently bidirectional.
Any sort of I2C buffering or switching requires a low-level on either side
to be propagated to the other side. This is virtually impossible to do in a
100% digital device since either or both sides can pull the signal low at
any time.
 
T

Thomas

You should be able switch your signals, if you can
get at the IOs before they are combined into inouts.
Can you do that? Or is there some sort of proprietary
code problem?

What tools are you using and what is your target CPLD?

Brad Smallridge
AiVision


Well to Brad,

Its Altear MAX II CPLD and I am using Quartus II 7.2sp3 tool.
I've discussed this morning with some senors at work and they seems to
say the same thing as David is saying here. But, giving the situation,
I am working on it trying to find some work around. It could be not
realy nice design but if it works we will be happy here.
So any other suggestions are more then welcome. I am sure that I am
not the first person that had this issue.

Thoms
 
D

David Spencer

Thomas said:
Well to Brad,

Its Altear MAX II CPLD and I am using Quartus II 7.2sp3 tool.
I've discussed this morning with some senors at work and they seems to
say the same thing as David is saying here. But, giving the situation,
I am working on it trying to find some work around. It could be not
realy nice design but if it works we will be happy here.
So any other suggestions are more then welcome. I am sure that I am
not the first person that had this issue.

Thoms

The fundamental problem with bridging I2C is its inherent bidirectional
nature. Essentially, you are connecting side A to side B and if either side
pulls the signal low you need to repeat that low on the other side. However,
you then need to make sure you don't try to repeat the destination low (that
you are driving) on the source side otherwise you just latch up. Custom I2C
repeaters and muxes tend to use a low value series resistor and measure the
voltage drop across that to determine which side is the driving side. Of
course, you can't do this in an FPGA.

One way that may work is to have a state machine for each signal that keeps
track of which side is driving the signal low. In other words, when you
detect one side driving low, you remember which side it is and enter a state
that drives the other side low. When the source side stops driving you
release the other side. You will almost certainly need some form of delay to
allow the signal time to go high again otherwise you might detect a low on
the destination side immediately after you stop driving it.
 
B

Brad Smallridge

Its Altear MAX II CPLD and I am using Quartus II 7.2sp3 tool.
I've discussed this morning with some senors at work and they seems to
say the same thing as David is saying here.

So, you don't have the code to the I2C module?
 
N

Nicolas Matringe

Thomas a écrit :
Its Altear MAX II CPLD and I am using Quartus II 7.2sp3 tool.
I've discussed this morning with some senors at work and they seems to
say the same thing as David is saying here. But, giving the situation,
I am working on it trying to find some work around. It could be not
realy nice design but if it works we will be happy here.
So any other suggestions are more then welcome. I am sure that I am
not the first person that had this issue.


Hello
I think I have found a way.
As David Spencer explained you need to know which side is driving the
bus low. Your mux must therefore never be able to drive both sides low
at the same time otherwise you're deadlocked.

The basic element is this :

entity i2c_mux_elem is
port (
pad : inout std_logic;
input : out std_logic;
output : in std_logic);
end i2c_mux_elem;

architecture rtl of i2c_mux_elem is
signal i_in : std_logic;

begin -- rtl

i_in <= to_x01(pad);
pad <= '0' when output = '0' else 'Z';
input <= i_in or not output; -- Mask i_in when driving the pad low

end rtl;

Now all you need to do is connect 5 of these elements together through a
standard mux
The tool will complain about combinatorial loops but that shouldn't be a
problem.

Anyone please comment if you see problems I have overlooked :)

Nicolas
 
T

Thomas

Thomas a écrit :


Hello
I think I have found a way.
As David Spencer explained you need to know which side is driving the
bus low. Your mux must therefore never be able to drive both sides low
at the same time otherwise you're deadlocked.

The basic element is this :

entity i2c_mux_elem is
port (
pad : inout std_logic;
input : out std_logic;
output : in std_logic);
end i2c_mux_elem;

architecture rtl of i2c_mux_elem is
signal i_in : std_logic;

begin -- rtl

i_in <= to_x01(pad);
pad <= '0' when output = '0' else 'Z';
input <= i_in or not output; -- Mask i_in when driving the pad low

end rtl;

Now all you need to do is connect 5 of these elements together through a
standard mux
The tool will complain about combinatorial loops but that shouldn't be a
problem.

Anyone please comment if you see problems I have overlooked :)

Nicolas

Nicolas,

It's not easy as that. You risk to latch-up....

Finaly I've found a way around it by adding a slightly modified slave
that will listen on the same slave address that the reel one would but
it will not send a data, just listen to the bus. It will act as a sort
of controller/arbiter by controlling the tri-state buffers. The idea
is to have an I2C controller that listen to the bus, knows ho needs to
talk and gives it the access. It's tweaky but works fin for us.
Lesson learned here: never try to do this in FPGA/CPLD, instead add
external analog Mux.

Thank you all for participating in this post

Thomas.
 
N

Nicolas Matringe

Thomas a écrit :
It's not easy as that. You risk to latch-up....

I've looked at the problem in every posible direction I could think of
and still fail to see how this can latch-up.

Nicolas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top