Synchronous vs Asynchronous Resets in FPGA system

2019-03-04 16:49发布

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;

3条回答
Evening l夕情丶
2楼-- · 2019-03-04 17:04

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).

查看更多
SAY GOODBYE
3楼-- · 2019-03-04 17:04

@Stuart Vivian

(this should be posted as comment but I don't have enough reputation points to do so, sorry about that)

Consider using a counter instead of a shift register for delaying resets because if a LUT content is not cleared after loading the bitstream (some FPGA families have this behaviour), the reset signal may bounce, leading to unpredictable results.

查看更多
来,给爷笑一个
4楼-- · 2019-03-04 17:15

A robust way of handling the resets in a system like this is as follows:

Use a DCM/PLL/MMCM in the Xilinx FPGA to process the input system clock and generate all the output clock frequencies you need, bearing in mind for really low frequencies you should use a clock within the specifications of the clock manager and generate a clock enable signal to use in conjunction with it. This can be reset from the host system at start-up or if at any point the input clock is removed and then re-applied.

Invert the LOCKED signal from the clock manager to generate an active high reset when it is in reset or in the process of locking to the input. This should be passed through an SRL16 or SRL32 to delay it. This SRL should be clocked with the output of the PLL after it's been put onto the global clock routing with a BUFG. Use an extra flip-flop after the SRL for improved timing. This signal can then be used as an active high synchronous reset to rest of the logic in the device where it is needed.

If you get timing errors on the clock enable signal because it is high-fanout net the this could also be put through a BUFG to access the fast global clock network to improve timing.

查看更多
登录 后发表回答