05-11-2018 12:24 AM
Hi everyone,
Currently,Our hardware board have a I2C host controller with 1.8v standard i2c signal(sdc1.8,sda1.8), and a I2C slave memory device(sdc3.3,sda3.3) with 3.3v standard signal.We connected sdc1.8,sda1.8,sdc3.3,sda3.3 to FPGA banks.
And I configure FPGA pins sdc1.8 as input LVCMOS18,sda1.8 as inout LVCMOS1.8,sdc3.3 as output LVCMOS33,sda3.3 as inout LVCMOS33. Actually, FPGA as a Voltage converter,sda and sdc bypass fpga logic.
I don't know if it's right.I am not sure i2c be able to work either. anyone knows?
05-16-2018 05:55 AM
Here’s my submission for “most expensive I2C-bypass circuit” … and it may even work.
I have shown only the bidirectional sda-line, but the same circuit could be used for a bidirectional scl-line. Note that I2C clock speeds are typically well below 1 MHz.
CTRL_LOGIC: process(clk100) begin if rising_edge(clk100) then if(rst100 = '1') then O1 <= '0'; O2 <= '0'; i2c_state <= s0; else case i2c_state is when s0 => --s0: wait for I1 or I2 to be pulled low T1 <= '1'; --both OBUFT in high-impedance state T2 <= '1'; if(I1 = '0') then T2 <= '0'; --sda driven by O2 is now low i2c_state <= s1; elsif(I2 = '0') then T1 <= '0'; --sda driven by O1 is now low i2c_state <= s2; else i2c_state <= s0; end if; when s1 => --s1: wait for I1 to go high if(I1 = '1') then i2c_state <= s0; else i2c_state <= s1; end if; when s2 => --s2: wait for I2 to go high if(I2 = '1') then i2c_state <= s0; else i2c_state <= s2; end if; when others => --others: bad state i2c_state <= s0; end case; end if; end if; end process CTRL_LOGIC;
05-11-2018 03:38 AM
maybe draw us a high level diagram of it.
My main concern is the propagation delay added by this route through you have in the FPGA.
05-11-2018 10:32 AM
-also, using IOBUF for the bidirectional data (sda) line will be a problem since you have no easy way to control the 3-state-input, T, of the IOBUF.
05-13-2018 05:38 AM - edited 05-13-2018 07:27 AM
I don't think you can do an I2C passthrough. Say a device at the 1.8V end pulls the bus down. Then the correct reaction from the FPGA is to pull the 3.3V side of the bus down too. Since the 3.3V side is now low (and the FPGA has no way to know whether this is just because it's pulling down, or because a 3.3V device is also pulling the bus down) the correct action is to pull the 1.8V side down too. The result is that the FPGA ends up permanently holding both sides low, so nobody can talk. Very fancy systems can pull the bus down to maybe 0.5V instead of 0V, so then they can detect when something else is holding the bus too - but FPGAs don't have that sort of output buffer, nor do they have ADCs on every pin to detect the difference.
Realistically, if you want I2C level translation, there are far better ways to do it. There's a single-MOSFET version (well, one MOSFET per line, so two for I2C) that works nicely. Or there are a range of "smart" level shifters that hold the bus with a very low current (ie microamps) so that any input can overpower them.
05-13-2018 06:43 PM
I think FPGA can convert 1.8v input to 3.3v output. But I'm not sure about Bi-directional I2C signal could bypass through FPGA.
05-13-2018 06:49 PM
Hi,
Your are right. It's too hard to control 3-state-input,T,of IOBUF.After implement,I noticed there are not any IOBUF insert to sda18 and sda33 IO in FPGA.
05-13-2018 06:59 PM
Hi,
Thanks for you replay. We insert MOSFET to I2C signal and works nicely before. Now, we want remove MOSFET and relpaced by FPGA.
05-16-2018 05:55 AM
Here’s my submission for “most expensive I2C-bypass circuit” … and it may even work.
I have shown only the bidirectional sda-line, but the same circuit could be used for a bidirectional scl-line. Note that I2C clock speeds are typically well below 1 MHz.
CTRL_LOGIC: process(clk100) begin if rising_edge(clk100) then if(rst100 = '1') then O1 <= '0'; O2 <= '0'; i2c_state <= s0; else case i2c_state is when s0 => --s0: wait for I1 or I2 to be pulled low T1 <= '1'; --both OBUFT in high-impedance state T2 <= '1'; if(I1 = '0') then T2 <= '0'; --sda driven by O2 is now low i2c_state <= s1; elsif(I2 = '0') then T1 <= '0'; --sda driven by O1 is now low i2c_state <= s2; else i2c_state <= s0; end if; when s1 => --s1: wait for I1 to go high if(I1 = '1') then i2c_state <= s0; else i2c_state <= s1; end if; when s2 => --s2: wait for I2 to go high if(I2 = '1') then i2c_state <= s0; else i2c_state <= s2; end if; when others => --others: bad state i2c_state <= s0; end case; end if; end if; end process CTRL_LOGIC;
07-03-2019 09:24 AM
I haven't analyzed the code above, and it may work under limited conditions, but take a look at the following links that describe why you do not want to do an I2C MUX in an FPGA.
https://forums.xilinx.com/t5/Welcome-Join/joining-bidirectional-pins/m-p/300045#M3448
Avrum