Multiplex 2 external I2C signals to one FPGA internal signal

H

hhanff

Hello world!

I have a problem concerning tri-state signals. Basically I have the
folliwing design:

library IEEE;

use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;

library work;
use work.config.all;

entity tri_state_design is
port(
-- currently running on 18.5 Mhz clock
clk : in std_logic;
-- clock is active low
nrst : in std_logic;
-- pins for i2c signal 1
i2c_scl_1 : inout std_logic;
i2c_sda_1 : inout std_logic;
-- pins for i2c signals 2
i2c_scl_2 : inout std_logic;
i2c_sda_2 : inout std_logic;
);
end tri_state_design;

architecture behavioral of tri_state_design is

component i2c_wrapper
port (
sys_clk : in std_logic;
nrst_i : in std_logic;
sda : inout std_logic;
scl : inout std_logic);
end component;

signal sda_s : std_logic;
signal scl_s : std_logic;

signal mux_s : std_logic;
signal mux_cnt_s : natural; -- needed to multiplex the 2
different tmp sensors to one i2c mudule

i2c_wrapper_1 : i2c_wrapper
port map (
sys_clk => clk,
nrst_i => rst,
sda => sda_s,
scl => scl_s);

-- purpose: This process sets up a counter to multiplex the two
different i2c signals
-- every 500 ms to share the same i2c instance
-- type : sequential
-- inputs : clk, rst
-- outputs:
mux : process (clk, rst)
begin -- process mux
if rst = '1' then -- asynchronous reset (active
high)
mux_cnt_s <= 0;
mux_s <= I2C_1;
elsif clk'event and clk = '1' then -- rising clock edge
if to_integer(to_unsigned(mux_cnt_s, 32)) = 10000 / 2 then
case mux_s is
when I2C_1 =>
mux_s <= I2C_2;
when I2C_2 =>
mux_s <= I2C_1;
when others => null;
end case;
mux_cnt_s <= 0;
else
mux_cnt_s <= mux_cnt_s + 1;
end if;
end if;
end process mux;

-- i2c signals are multiplexed here
i2c_sda_1 <= sda_s when mux_s = I2C_1 else 'Z';
i2c_scl_1 <= scl_s when mux_s = I2C_1 else 'Z';
i2c_sda_2 <= sda_s when mux_s = I2C_2 else 'Z';
i2c_scl_2 <= scl_s when mux_s = I2C_2 else 'Z';


----purpose : Process for multiplexing the I2C signals
----type : sequential
----inputs : sys_clk, rst_s
----outputs :
--mux_p : process (clk, rst)
--begin -- process control_write_p
-- if (rst = '1') then -- asynchronous reset
(active high)
-- i2c_sda_2 <= 'Z';
-- i2c_scl_2 <= 'Z';
-- i2c_sda_1 <= 'Z';
-- i2c_scl_1 <= 'Z';
-- elsif clk'event and clk = '1' then -- rising clock edge
-- case mux_s is
-- when I2C_1 =>
-- i2c_sda_2 <= 'Z';
-- i2c_scl_2 <= 'Z';
-- i2c_sda_1 <= sda_s;
-- i2c_scl_1 <= scl_s;
-- when I2C_2 =>
-- i2c_sda_2 <= sda_s;
-- i2c_scl_2 <= scl_s;
-- i2c_sda_1 <= 'Z';
-- i2c_scl_1 <= 'Z';
-- when others =>
-- i2c_sda_2 <= 'Z';
-- i2c_scl_2 <= 'Z';
-- i2c_sda_1 <= 'Z';
-- i2c_scl_1 <= 'Z
-- end case;
-- end if;
--end process mux_p;

end behavioral;

As you can see 2 external i2c signals shall be multiplexed to one i2c
instance. I tried to implement the multiplexer in both a concurrent an
synchronous way but none of them is OK for my Spartan 3 design.

In most cases it seems that the active i2c sda line is forced to '1'
when a 'Z' is desired (e.g. during the achnowledge phase).

Can you help me?

Greetings,

Hendrik
 
T

Tricky

Hello world!

I have a problem concerning tri-state signals. Basically I have the
folliwing design:

library IEEE;

use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;

library work;
use work.config.all;

entity tri_state_design is
  port(
    -- currently running on 18.5 Mhz clock
    clk           : in    std_logic;
    -- clock is active low
    nrst          : in    std_logic;
    -- pins for i2c signal 1
    i2c_scl_1       : inout std_logic;
    i2c_sda_1       : inout std_logic;
    -- pins for i2c signals 2
    i2c_scl_2 : inout std_logic;
    i2c_sda_2 : inout std_logic;
    );
end tri_state_design;

architecture behavioral of tri_state_design is

  component i2c_wrapper
    port (
      sys_clk      : in    std_logic;
      nrst_i       : in    std_logic;
      sda          : inout std_logic;
      scl          : inout std_logic);
  end component;

  signal sda_s        : std_logic;
  signal scl_s        : std_logic;

  signal mux_s        : std_logic;
  signal mux_cnt_s    : natural;  -- needed to multiplex the 2
different tmp sensors to one i2c mudule

  i2c_wrapper_1 : i2c_wrapper
    port map (
      sys_clk      => clk,
      nrst_i       => rst,
      sda          => sda_s,
      scl          => scl_s);

  -- purpose: This process sets up a counter to multiplex the two
different i2c signals
  --          every 500 ms to share the same i2c instance
  -- type   : sequential
  -- inputs : clk, rst
  -- outputs:
  mux : process (clk, rst)
  begin  -- process mux
    if rst = '1' then                   -- asynchronous reset (active
high)
      mux_cnt_s <= 0;
      mux_s     <= I2C_1;
    elsif clk'event and clk = '1' then  -- rising clock edge
      if to_integer(to_unsigned(mux_cnt_s, 32)) = 10000 / 2 then
        case mux_s is
          when I2C_1 =>
            mux_s   <= I2C_2;
          when I2C_2 =>
            mux_s   <= I2C_1;
          when others => null;
        end case;
        mux_cnt_s <= 0;
      else
        mux_cnt_s <= mux_cnt_s + 1;
      end if;
    end if;
  end process mux;

  -- i2c signals are multiplexed here
  i2c_sda_1 <= sda_s when  mux_s = I2C_1 else 'Z';
  i2c_scl_1 <= scl_s when  mux_s = I2C_1 else 'Z';
  i2c_sda_2 <= sda_s when  mux_s = I2C_2 else 'Z';
  i2c_scl_2 <= scl_s when  mux_s = I2C_2 else 'Z';

  ----purpose : Process for multiplexing the I2C signals
  ----type    : sequential
  ----inputs  : sys_clk, rst_s
  ----outputs :
  --mux_p : process (clk, rst)
  --begin  -- process  control_write_p
  --  if (rst = '1') then                 --  asynchronous reset
(active high)
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z';
  --  elsif clk'event and clk = '1' then  -- rising clock edge
  --    case mux_s is
  --      when I2C_1 =>
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= sda_s;
  --        i2c_scl_1 <= scl_s;
  --      when I2C_2 =>
  --        i2c_sda_2 <= sda_s;
  --        i2c_scl_2 <= scl_s;
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z';
  --      when others =>
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z
  --    end case;
  --        end if;
  --end process mux_p;

end behavioral;

As you can see 2 external i2c signals shall be multiplexed to one i2c
instance. I tried to implement the multiplexer in both a concurrent an
synchronous way but none of them is OK for my Spartan 3 design.

In most cases it seems that the active i2c sda line is forced to '1'
when a 'Z' is desired (e.g. during the achnowledge phase).

Can you help me?

Greetings,

     Hendrik

Are these tristates signals connected to pins, or are they meant to be
internal signals?
You cannot use internal tri-states. They get converted to muxes.
 
A

Andy

Hello world!

I have a problem concerning tri-state signals. Basically I have the
folliwing design:

library IEEE;

use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;

library work;
use work.config.all;

entity tri_state_design is
  port(
    -- currently running on 18.5 Mhz clock
    clk           : in    std_logic;
    -- clock is active low
    nrst          : in    std_logic;
    -- pins for i2c signal 1
    i2c_scl_1       : inout std_logic;
    i2c_sda_1       : inout std_logic;
    -- pins for i2c signals 2
    i2c_scl_2 : inout std_logic;
    i2c_sda_2 : inout std_logic;
    );
end tri_state_design;

architecture behavioral of tri_state_design is

  component i2c_wrapper
    port (
      sys_clk      : in    std_logic;
      nrst_i       : in    std_logic;
      sda          : inout std_logic;
      scl          : inout std_logic);
  end component;

  signal sda_s        : std_logic;
  signal scl_s        : std_logic;

  signal mux_s        : std_logic;
  signal mux_cnt_s    : natural;  -- needed to multiplex the 2
different tmp sensors to one i2c mudule

  i2c_wrapper_1 : i2c_wrapper
    port map (
      sys_clk      => clk,
      nrst_i       => rst,
      sda          => sda_s,
      scl          => scl_s);

  -- purpose: This process sets up a counter to multiplex the two
different i2c signals
  --          every 500 ms to share the same i2c instance
  -- type   : sequential
  -- inputs : clk, rst
  -- outputs:
  mux : process (clk, rst)
  begin  -- process mux
    if rst = '1' then                   -- asynchronous reset (active
high)
      mux_cnt_s <= 0;
      mux_s     <= I2C_1;
    elsif clk'event and clk = '1' then  -- rising clock edge
      if to_integer(to_unsigned(mux_cnt_s, 32)) = 10000 / 2 then
        case mux_s is
          when I2C_1 =>
            mux_s   <= I2C_2;
          when I2C_2 =>
            mux_s   <= I2C_1;
          when others => null;
        end case;
        mux_cnt_s <= 0;
      else
        mux_cnt_s <= mux_cnt_s + 1;
      end if;
    end if;
  end process mux;

  -- i2c signals are multiplexed here
  i2c_sda_1 <= sda_s when  mux_s = I2C_1 else 'Z';
  i2c_scl_1 <= scl_s when  mux_s = I2C_1 else 'Z';
  i2c_sda_2 <= sda_s when  mux_s = I2C_2 else 'Z';
  i2c_scl_2 <= scl_s when  mux_s = I2C_2 else 'Z';

  ----purpose : Process for multiplexing the I2C signals
  ----type    : sequential
  ----inputs  : sys_clk, rst_s
  ----outputs :
  --mux_p : process (clk, rst)
  --begin  -- process  control_write_p
  --  if (rst = '1') then                 --  asynchronous reset
(active high)
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z';
  --  elsif clk'event and clk = '1' then  -- rising clock edge
  --    case mux_s is
  --      when I2C_1 =>
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= sda_s;
  --        i2c_scl_1 <= scl_s;
  --      when I2C_2 =>
  --        i2c_sda_2 <= sda_s;
  --        i2c_scl_2 <= scl_s;
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z';
  --      when others =>
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z
  --    end case;
  --        end if;
  --end process mux_p;

end behavioral;

As you can see 2 external i2c signals shall be multiplexed to one i2c
instance. I tried to implement the multiplexer in both a concurrent an
synchronous way but none of them is OK for my Spartan 3 design.

In most cases it seems that the active i2c sda line is forced to '1'
when a 'Z' is desired (e.g. during the achnowledge phase).

Can you help me?

Greetings,

     Hendrik

As far as I can see, you only have an output mux (for signal flow from
i2c_wrapper to the two external i2c interfaces.)

What about the intput mux? How is i2c_wrapper going to receive clock
and data from the external interfaces?

Andy
 
H

hhanff

Are these tristates signals connected to pins, or are they meant to be
internal signals?
You cannot use internal tri-states. They get converted to muxes.

These signalse are connected to pins:
-- pins for i2c signal 1
i2c_scl_1 : inout std_logic;
i2c_sda_1 : inout std_logic;
-- pins for i2c signals 2
i2c_scl_2 : inout std_logic;
i2c_sda_2 : inout std_logic;

The signals
sda : inout std_logic;
scl : inout std_logic;
are internal signals and thus converted to muxes.
It is OK for me if they are converted to muxes and the whole design is
fully functional as long as I do not manually multiplex the external
i2c signals to the i2c_wrapper.

In other words:
If I would avoid the manual multiplexing of the two external ic2
signals by using two i2c_wrapper components there wouldn't be any
problem.

Or:
If I would only have one external i2c signal and connect this to the
i2c_wrapper, there would also be no problem.

Why???
 
H

hhanff

Might be irrelevant but where is I2C_1 defined ?

Michael Kellett

Sorry! Both I2C_1 and I2C_2 are defined in a package which I didn't
include in this thread for reasons of simplicity.

I2C_1 = '1' and I2C_2 = '0'...
 
H

hhanff

As far as I can see, you only have an output mux (for signal flow from
i2c_wrapper to the two external i2c interfaces.)

What about the intput mux? How is i2c_wrapper going to receive clock
and data from the external interfaces?

Andy

For my understanding the synthesis tool should insert muxes for
resolving input and output signals automatically during synthesis.
The mux that was inserted by me has the intention to multiplex the two
external i2c signals to one internal i2c component. Reason: I would
like to save resources...
 
H

hhanff

Hello world!

I have a problem concerning tri-state signals. Basically I have the
folliwing design:

library IEEE;

use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;

library work;
use work.config.all;

entity tri_state_design is
  port(
    -- currently running on 18.5 Mhz clock
    clk           : in    std_logic;
    -- clock is active low
    nrst          : in    std_logic;
    -- pins for i2c signal 1
    i2c_scl_1       : inout std_logic;
    i2c_sda_1       : inout std_logic;
    -- pins for i2c signals 2
    i2c_scl_2 : inout std_logic;
    i2c_sda_2 : inout std_logic;
    );
end tri_state_design;

architecture behavioral of tri_state_design is

  component i2c_wrapper
    port (
      sys_clk      : in    std_logic;
      nrst_i       : in    std_logic;
      sda          : inout std_logic;
      scl          : inout std_logic);
  end component;

  signal sda_s        : std_logic;
  signal scl_s        : std_logic;

  signal mux_s        : std_logic;
  signal mux_cnt_s    : natural;  -- needed to multiplex the 2
different tmp sensors to one i2c mudule

  i2c_wrapper_1 : i2c_wrapper
    port map (
      sys_clk      => clk,
      nrst_i       => rst,
      sda          => sda_s,
      scl          => scl_s);

  -- purpose: This process sets up a counter to multiplex the two
different i2c signals
  --          every 500 ms to share the same i2c instance
  -- type   : sequential
  -- inputs : clk, rst
  -- outputs:
  mux : process (clk, rst)
  begin  -- process mux
    if rst = '1' then                   -- asynchronous reset (active
high)
      mux_cnt_s <= 0;
      mux_s     <= I2C_1;
    elsif clk'event and clk = '1' then  -- rising clock edge
      if to_integer(to_unsigned(mux_cnt_s, 32)) = 10000 / 2 then
        case mux_s is
          when I2C_1 =>
            mux_s   <= I2C_2;
          when I2C_2 =>
            mux_s   <= I2C_1;
          when others => null;
        end case;
        mux_cnt_s <= 0;
      else
        mux_cnt_s <= mux_cnt_s + 1;
      end if;
    end if;
  end process mux;

  -- i2c signals are multiplexed here
  i2c_sda_1 <= sda_s when  mux_s = I2C_1 else 'Z';
  i2c_scl_1 <= scl_s when  mux_s = I2C_1 else 'Z';
  i2c_sda_2 <= sda_s when  mux_s = I2C_2 else 'Z';
  i2c_scl_2 <= scl_s when  mux_s = I2C_2 else 'Z';

  ----purpose : Process for multiplexing the I2C signals
  ----type    : sequential
  ----inputs  : sys_clk, rst_s
  ----outputs :
  --mux_p : process (clk, rst)
  --begin  -- process  control_write_p
  --  if (rst = '1') then                 --  asynchronous reset
(active high)
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z';
  --  elsif clk'event and clk = '1' then  -- rising clock edge
  --    case mux_s is
  --      when I2C_1 =>
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= sda_s;
  --        i2c_scl_1 <= scl_s;
  --      when I2C_2 =>
  --        i2c_sda_2 <= sda_s;
  --        i2c_scl_2 <= scl_s;
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z';
  --      when others =>
  --        i2c_sda_2 <= 'Z';
  --        i2c_scl_2 <= 'Z';
  --        i2c_sda_1 <= 'Z';
  --        i2c_scl_1 <= 'Z
  --    end case;
  --        end if;
  --end process mux_p;

end behavioral;

As you can see 2 external i2c signals shall be multiplexed to one i2c
instance. I tried to implement the multiplexer in both a concurrent an
synchronous way but none of them is OK for my Spartan 3 design.

In most cases it seems that the active i2c sda line is forced to '1'
when a 'Z' is desired (e.g. during the achnowledge phase).

Can you help me?

Greetings,

     Hendrik

Yesterday I found an article which seems to adress my problem:
http://cdserv1.wbut.ac.in/81-312-0257-7/Xilinx/files/Xcell Journal Articles/xcell_47/xc_synpro47.pdf

The paragraph "Mapping to Spartan-3 without TBUF" adresses what I'm
trying to implement... unfortunately I do not understand what is
described... can anybody help me???
 
A

Andy

Synthesis' job is to produce hardware that will act like the source
code simulates (within limitations). If you simulate your code (highly
recommended!), you will see that anything externally driving your two
I2C interfaces will not get back to the i2c_wrapper component.
Continuous signal assignments are not bidirectional relationships.
(not to be confused with port assignments on inout ports) You won't
get a bidirectional HW interface from a single continuous assignment.

If you want the synthesis tool to implement something, you have to
describe the behavior you want implemented.

One more hint: do not use "clk = '1' and clk'event" for detecting a
rising clock edge. Use "rising_edge(clk)" instead. It reliably handles
transitions like '0' -> 'H', which might be critical in this design.
Both implement the same hardware, but the former does not simulate
correctly.

Andy
 
H

hhanff

Just for completeness: I changed my design and removed all internal
tristates. Now it's fine.
 

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,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top