03-04-2014 12:35 PM
03-04-2014 02:02 PM
What exactly do you want to do with the serial EEPROM's? It's not clear what you mean by "control" serial EEPROM's, since normally you'd just eithe read or write data to them.
In essence, the I2C protocol itself is fairly simple. So without a processor, how you set about designing an interface to I2C depends on what exactly you want to accomplish. There is code available on opencores for this (haven't tried it myself so I won't rate its usefulness). I have written code for dealing with simple I2C slaves with 7-bit I2C address and no more than 1 address byte (like a 2Kbit EEPROM, and typical of I/O expanders and video devices that use I2C for setup of internal registers).
03-04-2014 03:46 PM
@fatihdag wrote:
Hi,
I need a I2C Core to control serial eeprom's. In most of the I2C examples on the web, microprocessors are used. But I want use only FPGA. How can i do that? and Does anyone have I2C controller which doesn't require processor or microcontroller?
Thanks.
I would start with the I2C spec, available from the NXP web site.
Since your master is dealing only with known slaves, it greatly simplifies the problem. You don't need to worry about multi-master arbitration, and you probably don't have to deal with wait states.
Basically, it boils down to a state machine and a couple of shift registers.
03-05-2014 01:43 AM
First of all thank you for your interest.
Firstly I just want to write one byte data to an eeprom until getting the experience. Most of the examples from opencores includes mp or wishbone controller signal. It comes more complicated to me. I couldn't write my own i2c codes at the moment. So I try the work on existed codes. I'have worked i2c theory. Also I studied on the datasheet of the eeprom. I just want to send totally 35 bits (start-device type identifier-ack-byte adress-ack-data byte-ack-stop) with i2c protocol.
Thanks.
03-05-2014 02:15 PM
03-11-2014 12:25 PM
Thanks for your interest. I found a video about the i2c master. It could be helpfull for the beginners like me.
03-12-2014 03:27 PM
Dear all,
I fairly new to fpgas and for learning porpuses I am developing a I2C Module in VHDL.
I am having trouble with the i2c clock because it is not in phase with a signal that I created and I don't know why.
I will put the code in here as well as a screenshot of the ISim wave in hope that someone could give a hint on what I am doing wrong. I know that the module is not ready..
library IEEE; use IEEE.STD_LOGIC_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity i2c is Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; i2c_sda : out STD_LOGIC; i2c_scl : out STD_LOGIC); end i2c; architecture Behavioral of i2c is constant IDLE : std_logic_vector :="000"; constant START : std_logic_vector :="001"; constant ADDRESS : std_logic_vector :="010"; constant RW : std_logic_vector :="011"; constant ACK : std_logic_vector :="100"; constant DATA : std_logic_vector :="101"; constant ACK2 : std_logic_vector :="110"; constant STOP : std_logic_vector :="111"; signal addr: std_logic_vector (6 downto 0) := (others => '0'); signal dat: std_logic_vector (6 downto 0) := (others => '0'); signal i2c_scl_signal: std_logic; signal state: std_logic_vector (2 downto 0); begin I2C: Process(clk) variable Counter : integer range 0 to 7; begin if falling_edge(clk) then if reset = '1' then i2c_scl_signal <= '1'; elsif state = IDLE or state = START or state = STOP then i2c_scl_signal <= '1'; else i2c_scl_signal <= not i2c_scl_signal; i2c_scl <= i2c_scl_signal; end if; end if; if rising_edge(clk) then if reset = '1' then state <= IDLE; i2c_sda <= '1'; i2c_scl <= '1'; addr <= "0110000"; dat <= "0011100"; Counter := 0; end if; case state is when IDLE => i2c_sda <= '1'; state <= START; when START => i2c_sda <= '0'; state <= ADDRESS; Counter := 6; when ADDRESS => i2c_sda <= addr(Counter); if Counter = 0 then state <= RW; else Counter := Counter -1; end if; when RW => i2c_sda <= '1'; state <= ACK; when ACK => state <= DATA; Counter := 7; when DATA => i2c_sda <= dat(Counter); if Counter = 0 then state <= ACK2; else Counter := Counter - 1; end if; when ACK2 => state <= STOP; when STOP => i2c_sda <= '1'; state <= IDLE; when others => state <= IDLE; end case; end if; end Process I2C; end Behavioral;
To be more specific, when I enter in the Address state, at the falling edge of the clock, both i2c_scl and i2c_scl_signal should go from 1 to 0 (where the yellow mark is) but the signal does that and the i2c_scl doesn't. This last wave waits one period to go from 1 to 0..why? I put some of the code in bold to be easier for you to track the problem.
Thank you in advance for your help!
03-12-2014 04:20 PM
> both i2c_scl and i2c_scl_signal should go from 1 to 0 (
You are using a non-blocking assigments so this will i2c_scl will always be one falling edge clock cycle behind i2c_scl_signal (if you didn't want this then why did you write it this way). Except for when it runs into a contention with a reset in the rising_edge.
You need to use a single clock edge in your design as the code that you wrote is not synthesizable.
03-12-2014 04:59 PM
>You are using a non-blocking assigments so this will i2c_scl will always be one falling edge clock cycle behind i2c_scl_signal (if you didn't want this then why did you write it this way). Except for when it runs into a contention with a reset in the rising_edge.
Well I didn't do it on purpose. After reading your post I read about blocking and non-blocking assigments. As far as I understood, and please correct me if I am wrong, signals are assigned using "<=", and they are always non-blocking and variables, for instance, are assigned using ":=" this assignment is blocking. As I am trying to use the same signal twice on the same clock edge, one of the assignments will be done one clock later.
So, so solve this I believe that could set the i2c_scl_signal as variable instead of signal however ISim doesn't allow to plot variables, useful for debugging. There is any alternative solution or I really have to use variables in this case?
>You need to use a single clock edge in your design as the code that you wrote is not synthesizable.
Didn't know that. You mean never or for any specific reason in my code? What for instance if I were using rising_edge(clk) and falling_edge(clk2)...different clocks..is this valid?
03-12-2014 05:32 PM
nnunes wrote:Didn't know that. You mean never or for any specific reason in my code? What for instance if I were using rising_edge(clk) and falling_edge(clk2)...different clocks..is this valid?
The real reason your code is not synthesizable is because you assign to i2c_scl in two processes, the rising edge and the falling edge.
I don't understand why you feel the need to use the falling-edge logic at all. While it is certainly legal to clock stuff on whichever edge of the clock, in generally you just pick one edge. There is no advantage to clocking something on the rising edge and having the following flop clock the first flop's output on the falling edge. That just cuts your max period in half.
Anyways, a much larger problem is that you've got i2c_sda declared in the port list as an output. It must be a bidirectional; a slave acknowledges a byte transfer by pulling down sda. A slave can't do that with the master always driving.
As for the blocking (variable) vs non-blocking (signal) assignment, in general unless you have a Real Good Reason you use signal assignments.
03-12-2014 05:34 PM
The ":=" is a VHDL construct and in Verilog the "=" is a block assignment. If you wrote:
i2c_scl_signal = not i2c_scl_signal;
i2c_scl = i2c_scl_signal;
it would be the same as writing:
i2c_scl_signal <= not i2c_scl_signal;
i2c_scl <= not i2c_scl_signal
This page has a decent example on the use of blocking vs non-blocking.
> You mean never or for any specific reason in my code?
I meant never. You can write a process and use the positive edge of a clock and you can write a process and use the negative edge of a clock and these will synthesis to a register with or without an invertor on the clock pin, but there is no resource in the FPGA that supports both negative and postive clocks. This isn't just a FPGA limitation, you also won't find a dual edge register in an ASIC or your digital circuit books.
Note: There is a resource in the FPGA that behaves as a dual-edge register and this is the ODDR for the DDR I/O's. While this looks like a dual-edge register in reality there are two registers with one on the positive edge and one on the negative edge and the clock level is used for a mux select to determine which will be sent to the output. Synthesizer will not infer these blocks and they must be instantiated in the code.
03-13-2014 03:28 PM
@bassman59 wrote:
The real reason your code is not synthesizable is because you assign to i2c_scl in two processes, the rising edge and the falling edge.
I don't understand why you feel the need to use the falling-edge logic at all. While it is certainly legal to clock stuff on whichever edge of the clock, in generally you just pick one edge. There is no advantage to clocking something on the rising edge and having the following flop clock the first flop's output on the falling edge. That just cuts your max period in half.
Well, I'll try to explain why I did it. Look for instance at the i2c start condition: It is expected to have the scl high and sda on falling edge..it was pretty much these situations that I was trying to achieve. Can I do the start of i2c if scl is on its rising edge and sda on its falling edge?
@bassman59 wrote:
Anyways, a much larger problem is that you've got i2c_sda declared in the port list as an output. It must be a bidirectional; a slave acknowledges a byte transfer by pulling down sda. A slave can't do that with the master always driving.
Oh you're right! Thank you for pointing that out. I'll correct it.
@mcgett wrote:
@the ":=" is a VHDL construct and in Verilog the "=" is a block assignment. If you wrote:
i2c_scl_signal = not i2c_scl_signal;
i2c_scl = i2c_scl_signal;
it would be the same as writing:
i2c_scl_signal <= not i2c_scl_signal;
i2c_scl <= not i2c_scl_signal
This page has a decent example on the use of blocking vs non-blocking.
Understood. I really wasn't aware of the existance of blocking and non-blocking assignments. The link you posted was also useful to understand the concept.
@mcgett wrote:
I meant never. You can write a process and use the positive edge of a clock and you can write a process and use the negative edge of a clock and these will synthesis to a register with or without an invertor on the clock pin, but there is no resource in the FPGA that supports both negative and postive clocks. This isn't just a FPGA limitation, you also won't find a dual edge register in an ASIC or your digital circuit books.
Note: There is a resource in the FPGA that behaves as a dual-edge register and this is the ODDR for the DDR I/O's. While this looks like a dual-edge register in reality there are two registers with one on the positive edge and one on the negative edge and the clock level is used for a mux select to determine which will be sent to the output. Synthesizer will not infer these blocks and they must be instantiated in the code.
Ok didn't knew that either. Shouldn't ISE give me an error when I try to Synthesize the code I posted before?
03-13-2014 04:11 PM
> Shouldn't ISE give me an error when I try to Synthesize the code I posted before?
Yes, it should result in an ERROR condition.
03-13-2014 04:51 PM
@nnunes wrote:
Well, I'll try to explain why I did it. Look for instance at the i2c start condition: It is expected to have the scl high and sda on falling edge..it was pretty much these situations that I was trying to achieve. Can I do the start of i2c if scl is on its rising edge and sda on its falling edge?
You have a high-speed FPGA clock to which everything is synchronous. Say it's 50 MHz. It's easy enough to assert the START and other I2C bus states when your timing granularity is 20 ns!
03-13-2014 05:24 PM
@mcgett wrote:
> Shouldn't ISE give me an error when I try to Synthesize the code I posted before?
Yes, it should result in an ERROR condition.
It doesn't. I got some warnings but I believe that they are not related with the rising/falling edge because I putted all in the rising edge and the warning are the same.
03-13-2014 05:29 PM
Did you take it place and route? At the very least I would expect that you get a multi-source error.
03-14-2014 06:18 AM
@mcgett wrote:
Did you take it place and route? At the very least I would expect that you get a multi-source error.
I hadn't but now I did and I'm still not getting any error.
04-06-2014 10:34 AM
Hello again :) ,
I'm trying not to bore you too much but I need your help again.
I am trying to push this to a new level and implement the i2c module in a really i2c IC. I look around and I found a TMP421 resting so I decided to try reading it. http://www.ti.com/lit/ds/sbos398c/sbos398c.pdf
As I don't have a logic analyzer avaiable, I'm trying to use chipscope to read the values from the sensor.
Below, the current vhdl code:
---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 17:45:53 03/09/2014 -- Design Name: -- Module Name: i2c - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity i2c is Port ( CLK_27MHz : in STD_LOGIC; reset : in STD_LOGIC; i2c_sda : inout STD_LOGIC; i2c_scl : out STD_LOGIC); end i2c; architecture Behavioral of i2c is constant IDLE : std_logic_vector :="0000"; constant START : std_logic_vector :="0001"; constant ADDRESS : std_logic_vector :="0010"; constant RW : std_logic_vector :="0011"; constant ACK : std_logic_vector :="0100"; constant DATA : std_logic_vector :="0101"; constant ACK2 : std_logic_vector :="0110"; constant DATA2 : std_logic_vector :="0111"; constant NACK : std_logic_vector :="1000"; constant STOP : std_logic_vector :="1001"; signal clk: std_logic := '0'; signal Counter: std_logic_vector (6 downto 0); signal addr: std_logic_vector (6 downto 0) := (others => '0'); signal dat: std_logic_vector (6 downto 0) := (others => '0'); signal dat2: std_logic_vector (6 downto 0) := (others => '0'); signal i2c_scl_signal: std_logic; signal state: std_logic_vector (3 downto 0); begin Prescaler: process (CLK_27MHz) begin if rising_edge(CLK_27MHz) then if Counter < "1000011" then Counter <= Counter + 1; else clk<=not clk; Counter <= (others=>'0'); end if; end if; end process Prescaler; I2C: Process(clk) variable Counter : integer range 0 to 7; begin if rising_edge(clk) then if reset = '1' then state <= IDLE; i2c_sda <= '1'; i2c_scl <= '1'; addr <= "1001100"; -- dat <= "0001010"; Counter := 0; elsif state = IDLE or state = START or state = STOP then i2c_scl_signal <= '1'; else i2c_scl_signal <= not i2c_scl_signal; i2c_scl <= not i2c_scl_signal; end if; case state is when IDLE => i2c_sda <= '1'; state <= START; when START => i2c_sda <= '0'; state <= ADDRESS; Counter := 6; when ADDRESS => i2c_sda <= addr(Counter); if Counter = 0 then state <= RW; else Counter := Counter -1; end if; when RW => i2c_sda <= '1'; state <= ACK; when ACK => if i2c_sda = '0' then state <= DATA; Counter := 6; end if; when DATA => dat(Counter)<=i2c_sda; if Counter = 0 then state <= ACK2; else Counter := Counter - 1; end if; when ACK2 => if i2c_sda = '0' then state <= DATA2; Counter := 6; end if; when DATA2 => dat2(Counter)<=i2c_sda; if Counter = 0 then state <= NACK; else Counter := Counter - 1; end if; when NACK => i2c_sda <= '1'; state <= STOP; when STOP => i2c_sda <= '1'; state <= IDLE; when others => state <= IDLE; end case; end if; end Process I2C; end Behavioral;
The problem is...I can't read anything...The SDA line doesn't send or reads any addresses.. There are the waveforms that I get:
when I press the reset button, the SDA gets strange, why??
I don't have a logic analyzer avaiable but I used my digital osciloscope and I get similar results from the ones you can see above.
What I am doing wrong?
04-07-2014 10:23 AM
Two things:
a) Without seeing a test bench and a model of the I2C slave, we can't guess at why it doesn't work.
b) Stop using std_logic_vectors to count. Use a natural.
04-07-2014 11:14 AM
@bassman59 wrote:
Two things:
a) Without seeing a test bench and a model of the I2C slave, we can't guess at why it doesn't work.
b) Stop using std_logic_vectors to count. Use a natural.
a) Are you asking for these???
b) I'll look into it. Thank you for the tip.
04-07-2014 02:23 PM
No. ChipScope is no replacement for a proper simulation test bench.
You must simulate and verify your design before you even think about implementation in hardware.
04-07-2014 03:52 PM
@bassman59 wrote:
No. ChipScope is no replacement for a proper simulation test bench.
You must simulate and verify your design before you even think about implementation in hardware.
Humm...My knowlegde on simulation test bench is still very limited. Would you please tell me about a good pdf that teaches how to write the VHDL test bench?
In this case I don't know how to send a 0 through the sda line when the state is ACK and how to simulate like if the sensor were sending the data using the SDA line as well....
Currently, my file is like this:
-------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 23:30:02 03/09/2014 -- Design Name: -- Module Name: D:/fpga_aprender/i2c/test_step1.vhd -- Project Name: i2c -- Target Device: -- Tool versions: -- Description: -- -- VHDL Test Bench Created by ISE for module: i2c -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- -- Notes: -- This testbench has been automatically generated using types std_logic and -- std_logic_vector for the ports of the unit under test. Xilinx recommends -- that these types always be used for the top-level I/O of a design in order -- to guarantee that the testbench will bind correctly to the post-implementation -- simulation model. -------------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --USE ieee.numeric_std.ALL; ENTITY test_step1 IS END test_step1; ARCHITECTURE behavior OF test_step1 IS -- Component Declaration for the Unit Under Test (UUT) COMPONENT i2c PORT( CLK_27MHz : IN std_logic; reset : IN std_logic; i2c_sda : INOUT std_logic; i2c_scl : OUT std_logic ); END COMPONENT; --Inputs signal CLK_27MHz : std_logic := '0'; signal reset : std_logic := '0'; --Outputs signal i2c_sda : std_logic; signal i2c_scl : std_logic; -- Clock period definitions constant clk_period : time := 37 ns; BEGIN -- Instantiate the Unit Under Test (UUT) uut: i2c PORT MAP ( CLK_27MHz => CLK_27MHz, reset => reset, i2c_sda => i2c_sda, i2c_scl => i2c_scl ); -- Clock process definitions clk_process :process begin CLK_27MHz <= '0'; wait for clk_period/2; CLK_27MHz <= '1'; wait for clk_period/2; end process; -- Stimulus process stim_proc: process begin reset <= '1'; wait for clk_period; reset <= '0'; -- insert stimulus here wait; end process; END;
Thank you!
04-10-2014 11:49 AM
@nnunes wrote:
@bassman59 wrote:
No. ChipScope is no replacement for a proper simulation test bench.
You must simulate and verify your design before you even think about implementation in hardware.
Humm...My knowlegde on simulation test bench is still very limited. Would you please tell me about a good pdf that teaches how to write the VHDL test bench?
The only real reference that's of any use is Janick Bergeron's "Writing Testbenches" text. The latest edition is probably expensive and covers stuff that's beyond VHDL test benches, so an earlier edition is still useful.
But, put simply, you must have a VHDL model of your I2C bus slave device, and your master in your FPGA interacts with that slave in the simulation.
04-14-2014 01:03 PM
@bassman59 wrote:
But, put simply, you must have a VHDL model of your I2C bus slave device, and your master in your FPGA interacts with that slave in the simulation.
I'm having some trouble doing that. Probably it's some roockie mistake...
I have the i2c.vhd :
entity i2c is Port ( CLK_27MHz : in STD_LOGIC; reset : in STD_LOGIC; i2c_sda : inout STD_LOGIC; i2c_scl : out STD_LOGIC); end i2c; architecture Behavioral of i2c is etc etc
Then I have the tmp421.vhd as slave:
entity tmp421 is Port ( tmp_sda : inout STD_LOGIC; tmp_scl : in STD_LOGIC); end tmp421; architecture Behavioral of tmp421 is etc
To interconnect these models in the testbench I am doing the following:
IBRARY ieee; USE ieee.std_logic_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --USE ieee.numeric_std.ALL; ENTITY test_step1 IS END test_step1; ARCHITECTURE behavior OF test_step1 IS -- Component Declaration for the Unit Under Test (UUT) COMPONENT i2c PORT( CLK_27MHz : IN std_logic; reset : IN std_logic; i2c_sda : INOUT std_logic; i2c_scl : OUT std_logic ); END COMPONENT; COMPONENT TMP421 PORT( tmp_sda : INOUT std_logic; tmp_scl : OUT std_logic ); END COMPONENT; For all: i2c use entity work.i2c; For all: TMP421 use entity work.tmp421; --Inputs signal CLK_27MHz : std_logic := '0'; signal reset : std_logic := '0'; --Outputs signal i2c_sda : std_logic; signal i2c_scl : std_logic; signal tmp_sda : std_logic; signal tmp_scl : std_logic; -- Clock period definitions constant clk_period : time := 37 ns; BEGIN -- Instantiate the Unit Under Test (UUT) uut: i2c PORT MAP ( CLK_27MHz => CLK_27MHz, reset => reset, i2c_sda => tmp_sda, i2c_scl => tmp_scl ); -- Clock process definitions clk_process :process begin CLK_27MHz <= '0'; wait for clk_period/2; CLK_27MHz <= '1'; wait for clk_period/2; end process; -- Stimulus process stim_proc: process begin reset <= '1'; wait for clk_period; reset <= '0'; -- insert stimulus here wait; end process; END;
I don't get any errors but I can't simulate this because it doesn't generate the clock...Maybe it is something wrong in the Instatiation. Would you please give an hint on this?
Thank you!
04-14-2014 01:11 PM
Some comments:
a) Stop using the old-style component declaration and instantiation, and instead use direct entity instantiation. In other words, delete the component declarations, and for the lower-level entity instantiations you write something like:
u_foo : entity work.foo
port map (
... signals ...
);
Less typing, less duplication, and less prone to making mistakes.
b) " I can't simulate this because it doesn't generate the clock...Maybe it is something wrong in the Instatiation. Would you please give an hint on this?"
Your CLK_27MHZ generator looks correct.