cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
ronnywebers
Advisor
Advisor
10,679 Views
Registered: ‎10-10-2014

Edge detecting on a slow external clock

Jump to solution

What's the best practice to do a (rising or falling) edge detection on an external asynchronous clock (like SPI clock)?

 

note that I want to accomplish a fully synchronous design, so run everything on my internal (100MHz) clock wich is sufficiently larger than the external clock signal, and use 'ticks' to trigger events.

 

one idea :

 

  • put a 2-stage synchronizer first, to avoid metastability
  • after the synchronizer, a 2-stage register to detect a rising or falling edge

other idea :

 

  • use a 3-stage synchronizer, and look at the last 2 FF's to detect the edge

additional question :

 

  • if the external signal has slow rise/fall times, is a best practice to 'filter' this signal, i.e. by passing it through a shift register, sufficiently long (to cover the slow edge 'length'), and check if all bits in the shift register are '0' or '1'? 
  • or do I need an external schmitt trigger?
  • or can I enable schmitt triggers on FPGA pins (7 series / Zynq devices)

 

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Reply
1 Solution

Accepted Solutions
avrumw
Guide
Guide
16,445 Views
Registered: ‎01-23-2009

use a 3-stage synchronizer, and look at the last 2 FF's to detect the edge

 

By definition, this doesn't exist. In order to be a "synchronizer", the chain of flip-flops must be back to back with no fanout  - the output of one flip-flop must drive only the input of the next flip-flop. In the case you state above, the 3rd flip-flop is not a synchronizer flip-flop, since the output of the 2nd flip-flop also drives the gate that does the edge detect.

 

So your two circuits are the same.

 

Now, in RTL, you can write this system a variety of ways. You can have two processes - one which does the two synchronizer flip-flops and one that does the extra flip-flop and the gate, or you can have one process that implements a 3 stage shifter and use the 2nd to last and last outputs as your edge detect. These two descriptions end up being the same - a 2 stage synchronizer followed by an edge detector.

 

Note: To make this a true synchornizer, the first two flip-flops should have the ASYNC_REG property set on them (in Vivado). If you try and set the ASYNC_REG on the third flip-flop, then the report_cdc command should give you a warning (or error), due to the extra fanout between things that have been marked as synchronizer flip-flops.

 

Avrum

View solution in original post

9 Replies
balkris
Xilinx Employee
Xilinx Employee
10,675 Views
Registered: ‎08-01-2008
check this third party link about synchronization and edge detection
https://www.doulos.com/knowhow/fpga/synchronisation/
Thanks and Regards
Balkrishan
--------------------------------------------------------------------------------------------
Please mark the post as an answer "Accept as solution" in case it helped resolve your query.
Give kudos in case a post in case it guided to the solution.
kapsy_27
Adventurer
Adventurer
10,650 Views
Registered: ‎07-04-2013

Idea No. 1 would be the best practice in my opinion. Following Fig shows a synchronizer circuit with a Neg edge detector circuit.

 

 

edge_detect.JPG

avrumw
Guide
Guide
16,446 Views
Registered: ‎01-23-2009

use a 3-stage synchronizer, and look at the last 2 FF's to detect the edge

 

By definition, this doesn't exist. In order to be a "synchronizer", the chain of flip-flops must be back to back with no fanout  - the output of one flip-flop must drive only the input of the next flip-flop. In the case you state above, the 3rd flip-flop is not a synchronizer flip-flop, since the output of the 2nd flip-flop also drives the gate that does the edge detect.

 

So your two circuits are the same.

 

Now, in RTL, you can write this system a variety of ways. You can have two processes - one which does the two synchronizer flip-flops and one that does the extra flip-flop and the gate, or you can have one process that implements a 3 stage shifter and use the 2nd to last and last outputs as your edge detect. These two descriptions end up being the same - a 2 stage synchronizer followed by an edge detector.

 

Note: To make this a true synchornizer, the first two flip-flops should have the ASYNC_REG property set on them (in Vivado). If you try and set the ASYNC_REG on the third flip-flop, then the report_cdc command should give you a warning (or error), due to the extra fanout between things that have been marked as synchronizer flip-flops.

 

Avrum

View solution in original post

ronnywebers
Advisor
Advisor
10,611 Views
Registered: ‎10-10-2014

thanks @avrumw, I followed your suggestions, googled a bit around and came up with this :

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity sync_with_edge_detect is
    port
    ( 
        clock               : in std_logic;
        async_in            : in std_logic;
        
        sync_out            : out std_logic;
        rising_edge_tick    : out std_logic;
        falling_edge_tick   : out std_logic
    );
end sync_with_edge_detect;

architecture Behavioral of sync_with_edge_detect is
    
    -- *** SYNCHRONIZER FLIPFLOPS ***
    signal sync_ffs : std_logic_vector(1 downto 0) := (others => '0');
    
    attribute ASYNC_REG : string;
    attribute ASYNC_REG of sync_ffs : signal is "true";
    
    -- *** EDGE DETECT FLIPFLOP ***
    signal edge_detect_ff : std_logic := '0';
    
begin

    process (clock)
    begin
        if rising_edge(clock) then
            sync_ffs(0) <= async_in;
            sync_ffs(1) <= sync_ffs(0);
        end if;
    end process;

    sync_out <= sync_ffs(1);
    
    process (clock)
    begin
        if rising_edge(clock) then
            edge_detect_ff <= sync_ffs(1);
        end if;
    end process;
    
    -- edge detect
    rising_edge_tick <= (not edge_detect_ff) and sync_ffs(1);
falling_edge_tick <= edge_detect_ff and (not sync_ffs(1)); end Behavioral;

after googling around, I'm a bit puzzled with something basic VHDL I guess : should I assign an initial value during signal declaration or not? (I mean the := '0' and := (others => '0'). 

 

Do these have an impact on synthesis? Or is it only necessary for simulation?

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Reply
avrumw
Guide
Guide
10,606 Views
Registered: ‎01-23-2009

I'm a bit puzzled if I should assign an initial value during signal declaration (the := '0' and := (others => '0'). 

 

Yes, they affect synthesis.

 

When the FPGA is configured (the bitstream is downloaded), all flip-flops in the design are initialized to a known value. The synthesis tool decides what the value is. The mechanism is (pretty much) as follows

  a) if there is an initialization value for the underlying signal/reg, then that is used

  b) if there is no initialization for the signal/reg, but the RTL describes a reset value for the flip-flop then that is used

  c) if neither of the above are true, then the flip-flop is initialized to 0

 

So, in this case, since you have no explicit reset, without the initial value, the FFs would end up with case c, and get initialized to 0. With the initialization, you end up in case a). So on the face of it, it looks like it would make no difference. However, as you mentioned, it does affect simulation. With case c) the signal/reg would start with an unknown value, whereas with case a), it is set to 0. Since synthesis will end up with this FF being initialized to 0 in either case, one would argue that a) is better, because simulation will now match what ends up happening in synthesis.

 

And, of course, I just want to point out that if you use a) with a value of 1 (rather than 0) then you will end with the INIT value of the flip-flop being 1. Again, simulation and synthesis will match...

 

Avrum

ronnywebers
Advisor
Advisor
10,602 Views
Registered: ‎10-10-2014

thanks @avrumw, that's the most concise and clear explanation I've read so far on signal initialisation ... :-)

 

so I should pay more attention to initialisation, especially when there is no reset ...

 

that probably explains why my post-synthesis simulation shows a lot of undefined signals (orange), while in behavioural simulation all signals are defined (green) 

 

note : I just edited my code above, I had rising and falling edge ticks switched.

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Reply
avrumw
Guide
Guide
10,592 Views
Registered: ‎01-23-2009

that probably explains why my post-synthesis simulation shows a lot of undefined signals (orange), while in behavioural simulation all signals are defined (green) 

 

It really should be the other way around...

 

When simulating a synthesized netlist, the model for the FDCE/FDPE/FDSE/FDRE simulates the INIT functionality - so at time 0 all flip-flops will initialize to the INIT value assigned to them by the synthesis engine.

 

However, in RTL code, if you have a signal that doesn't have an initial value at declaration, it will implicitly have an undefined value until some process gives it a value.

 

Avrum

ronnywebers
Advisor
Advisor
10,585 Views
Registered: ‎10-10-2014

thanks @avrumw

 

mmm .. my simulation issue is solved ... think it was some caching problem, or the sim was using an outdated synthesised netlist - I've seen this more than once ... let's forget about that, sorry.

 

to complete this thread, I'm interested to understand better the init mechanism (It probably deserves it's own thread ...if you want me to start a new topic let me know, I'll be happy to do that)

 

Is this correct reasoning (?) :

 

a) -> the init values assigned at signal declaration are put into the bitstream in such a way that they asynchronously preset the FF with the '0' or '1', at the moment the bitstream finished downloading? I asume this mechanism also works for vectors like := X"1234"


b) -> what if both init value and RTL reset are there, or they are conflicting? i.e. signal is declared with := '1', but the RTL process describes a reset signal that sets the value to := '0'?

Would there be a difference if the RTL reset is synchronous vs asynchronous?


c) -> I've read that the 'leftmost' value in the enumeration list of possible values is used, so for std_logic this is '0' (?)

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Reply
avrumw
Guide
Guide
10,571 Views
Registered: ‎01-23-2009

a) -> the init values assigned at signal declaration are put into the bitstream in such a way that they asynchronously preset the FF with the '0' or '1', at the moment the bitstream finished downloading? I asume this mechanism also works for vectors like := X"1234"

 

While correct, I would like to expand on some points for clarity.

 

First, in Xilinx parlance, certain words are used for certain types of resets

  - preset - asynchronously load a 1 (FDPE)

  - clear   - asynchronously load with 0 (FDCE)

  - set      - synchronously load with a 1 (FDSE)

  - reset   - synchronously load with a 0 (FDRE)

 

(Although sometimes all of the above are referred to as "resetting" the flip-flop). The rest of the acronym is (probably) Flip-flop D-type preset/clear/set/reset with Enable.

 

So, I would not use the word "preset the FF" in the above statement, but "load"...

 

Next, the INIT value is a property of the flip-flop that is loaded via the bitstream. The loading of the INIT value into the flip-flop storage element is controlled by the GSR (Global Set Reset) net from the configuration logic. The GSR remains active during the first stages of the configuration, but is deasserted at a particular point in the sequence (you have some control over this by setting configuration bitstream options).

 

The GSR functionality can be used to minimize the need for user resets, but the GSR is (by definition) asynchronous to any user clock, and is relatively slow - it is not guaranteed to affect all flip-flops at the same time. (So there is some complexity to using this).

 

The GSR can also be reasserted by user logic, by instantiating the STARTUPE2 block and connecting a fabric signal to the GSR pin. However, this is not recommended and is very hard to use (since the act of asserting the GSR affects all flip-flops, probably including the ones that were responsible for asserting GSR...)

 

I assume this mechanism also works for vectors like := X"1234"

 

At synthesis time, a "bus" of flip-flops is implemented as independent flip-flops. So, in this case, you would end up with 16 flip-flops, with some of them implemented as FDRE and some as FDSE (assuming they were synchronously set/reset).

 

b) -> what if both init value and RTL reset are there, or they are conflicting? i.e. signal is declared with := '1', but the RTL process describes a reset signal that sets the value to := '0'?

 

In most FPGA families they are not conflicting. The nomenclature is a bit different in ISE and Vivado - I will talk about the Vivado way.

 

The INIT property is orthogonal to any reset value. The reset value determines whether the flip-flop is implemented using an FDCE, FDPE, FDRE, or FDSE. All these flip-flops have an INIT property which determines the value during GSR. So, it is perfectly acceptable to have an FDCE or FDRE with an INIT of 1 (or vice versa).

 

Be aware that the tools can do some changes to map the synchronous Reset or Set functionality (FDRE/FDSE) to use combinatorial logic in front of the D input, and then use any type of flip-flop with the user reset functionality disabled (so, for example, an FDPE with the P tied to ground). This can be done as part of "control set optimization".

 

The ISE terminology is a bit different; in ISE (at least after place and route, not after synthesis), there is only one type of flip-flop primitive and it has a number of properties

INIT - the GSR initialization value

SRVAL - the reset value

SRTYPE - asynchronous or synchronous

(you can see how these map to the same thing as the Vivado FDPE/FDCE/FDSE/FDRE representation).

 

The only exception are the Spartan families (Spartan-6 for sure, and I am pretty certain earlier Spartan families as well), which have one combined SRINITVAL (instead of a separate one for SRVAL and INIT). For these families, if both a reset value and an signal initialization value exist in your RTL, the SRINITVAL gets set to the reset value.

 

Would there be a difference if the RTL reset is synchronous vs asynchronous?

 

No.

 

c) -> I've read that the 'leftmost' value in the enumeration list of possible values is used, so for std_logic this is '0' (?)

 

I don't know - this is a VHDL detail (and I am mostly a Verilog guy...)

 

Avrum