I'm new to creating a FPGA system to drive an I2C Bus (although I imagine that this problem applies to any FPGA system) using a variety of different modules, and which all use a synchronous reset.
The modules are clocked using a clock divider module that takes the system clock and outputs a lower frequency to the rest of the system.
The problem I'm having is, when the reset signal goes low, the clock divider resets, and therefore the clock that other modules depend on stop - thus the other modules do not register the reset
An obvious solution would be to have an asynchronous reset, however, in Xilinx ISE it doesn't appear to like them and throws a warning saying that this is incompatible with the Spartan-6 FPGA (especially when the code after the asynchronous code IS synchronous, which it is because an I2C bus uses the bus clock to put bits onto the bus).
Another solution would be for the clock divider to simply not be reset-able, thus the clock would never stop and all modules would reset correctly. However this then means that the clock divider registers cannot be initialised/reinitialised to a known state - which I've been told would be a big problem, although I know you can use the := '0'/'1';
operator in simulation, but this does not work once programmed on the actual FPGA(?).
What is the convention for synchronous resets? Are clock generators generally just not reset? Or do they only reset on the instantaneous edge of the reset signal? Or are none of my suggestions a real solution!
I've put in a timing diagram as well as my code to illustrate both what I mean, and to show the code I've been using.
Thanks very much!
David
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
ENTITY CLK_DIVIDER IS
GENERIC(INPUT_FREQ : INTEGER;
OUT1_FREQ : INTEGER;
OUT2_FREQ : INTEGER
);
PORT(SYSCLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
OUT1 : OUT STD_LOGIC;
OUT2 : OUT STD_LOGIC);
END CLK_DIVIDER;
architecture Behavioral of Clk_Divider is
constant divider1 : integer := INPUT_FREQ / OUT1_FREQ / 2;
constant divider2 : integer := INPUT_FREQ / OUT2_FREQ / 2;
signal counter1 : integer := 0;
signal counter2 : integer := 0;
signal output1 : std_logic := '0';
signal output2 : std_logic := '0';
begin
output1_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if RESET_N = '0' then
counter1 <= 0;
output1 <= '1';
else
if counter1 >= divider1 - 1 then
output1 <= not output1;
counter1 <= 0;
else
counter1 <= counter1 + 1;
end if;
end if;
end if;
end process;
output2_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if RESET_N = '0' then
counter2 <= 0;
output2 <= '1';
else
if counter2 >= divider2 - 1 then
output2 <= not output2;
counter2 <= 0;
else
counter2 <= counter2 + 1;
end if;
end if;
end if;
end process;
OUT1 <= output1;
OUT2 <= output2;
end Behavioral;