Search code examples
asynchronousvhdlresetclockxilinx

Synchronous vs Asynchronous Resets in FPGA system


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

enter image description here

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;

Solution

  • Don't generate internal clocks with user logic, but use a device specific PLL/DCM if multiple clocks are really needed. All the user logic running on the derived clocks should then be held in reset until the clocks are stable, and reset for user logic can then be released as required by design. Either synchronous reset or asynchronous reset can be used.

    But i this case, probably generate a clock enable signal instead, and assert this enable signal for a single cycle each time update of the signals are required in order to generate whatever protocol is needed, e.g. the I2C protocol with appropriate timing.

    Using fewer clocks, combined with synchronous clock enable signals, makes setup for Static Timing Analysis (STA) easier, and also avoid issues with reset synchronization and Clock Domain Crossing (CDC).