Why Learn Edge Detectors? Many signals in a design are levels that stay high for many cycles, such as a button that is held down, a status flag or a request line, while the logic that reacts to them needs a single event: start the FSM once, count the press once, raise one interrupt. An edge detector converts a level change into a pulse exactly one clock cycle wide. It takes one flip-flop and one gate, and it appears in almost every design.

A positive edge detector produces a pulse on its output when the signal it monitors changes from 0 to 1. In Verilog, it is built by delaying the signal by one clock cycle with a flip-flop and combining the delayed copy with the current value: pe = sig & ~sig_dly is high only when the signal is 1 now and was 0 one cycle earlier.

10 min read | Beginner Level

What You'll Learn

  • How a one-cycle delay and an AND gate detect a rising edge
  • Write positive, negative and any-edge detectors in Verilog
  • What the design synthesizes into, down to FPGA primitives
  • Why asynchronous inputs need a synchronizer and a registered output

Design

The detector keeps a copy of the input that is one clock cycle old, called sig_dly. At any moment, comparing the two tells you what happened at the last clock edge:

sig_dly (previous)sig (current)pe = sig & ~sig_dlyMeaning
000Stayed low
011Rising edge
100Falling edge
110Stayed high

Inverting the delayed copy and ANDing it with the current input gives 1 in exactly one row: the rising edge.

positive edge detector block diagram Positive edge detector built from a D flip-flop that delays sig, an inverter on the delayed output and an AND gate

module pos_edge_det ( input sig,            // Input signal for which positive edge has to be detected
                      input clk,            // Input signal for clock
                      output pe);           // Output signal that gives a pulse when a positive edge occurs

    reg   sig_dly;                          // Internal signal to store the delayed version of signal

    // This always block ensures that sig_dly is exactly 1 clock behind sig
	always @ (posedge clk) begin
		sig_dly <= sig;
	end

    // Combinational logic where sig is AND with delayed, inverted version of sig
    // Assign statement assigns the evaluated expression in the RHS to the internal net pe
	assign pe = sig & ~sig_dly;
endmodule
positive-edge-detector Timing of sig, sig_dly and pe, with pe high from the rising edge of sig until the next clock edge

When sig rises, pe goes high immediately. At the next rising clock edge, sig_dly captures the 1, ~sig_dly becomes 0, and pe goes low again. If sig changes right at a clock edge, as it does when it comes from other logic on the same clock, pe is exactly one clock cycle wide.

Negative and Any-Edge Detection

The same flip-flop supports the other edge types by changing only the gate:


assign pe = sig & ~sig_dly;   // Rising edge:  now 1, was 0
assign ne = ~sig & sig_dly;   // Falling edge: now 0, was 1
assign ae = sig ^ sig_dly;    // Any edge:     now differs from before

Quick Check

Q: sig stays high for 10 clock cycles. How many clock cycles is pe high?

Show Answer

One, at most. pe is high only until the first clock edge after the rise, when sig_dly becomes 1. For the rest of the time sig is high, both inputs of the comparison are 1 and pe stays 0. This is what makes an edge detector useful: a long level becomes a single event.

Where are Edge Detectors Used?

A push button on a development board or appliance stays pressed for many milliseconds, which is millions of clock cycles. After debouncing, an edge detector turns each press into one pulse, so a counter or menu advances once per press instead of continuously while the button is held. See Verilog Debounce Circuit.

Testbench

The testbench uses a clock period of 10 time units, which is 100 MHz if the time unit is 1 ns. It raises sig twice: once in step with a clock edge, and once between edges.

Testbench driving clk and sig into pos_edge_det and observing pe

module tb;
	reg sig;         // Declare internal TB signal called sig to drive the sig pin of the design
	reg clk;         // Declare internal TB signal called clk to drive clock to the design
	wire pe;         // Declare a wire to observe the pe output of the design

	// Instantiate the design in TB and connect with signals in TB
	pos_edge_det ped0 (  .sig(sig),
    					 .clk(clk),
 			      		 .pe(pe));

	// Generate a clock with a period of 10 time units (100 MHz with a 1 ns time unit)
	always #5 clk = ~clk;      // Rising edges at 5, 15, 25, ...

	// Drive stimulus to the design
	initial begin
		clk <= 0;
		sig <= 0;
		#15 sig <= 1;          // t=15: rises together with a clock edge
		#20 sig <= 0;          // t=35
		#15 sig <= 1;          // t=50: rises between clock edges
		#10 sig <= 0;          // t=60
		#20 $finish;
	end
endmodule
Waveform of clk, sig and pe, showing a full-cycle pulse on pe at the first rise of sig and a shorter pulse at the second

In the waveform:

  • First rise, t=15: sig changes on the clock edge, so the flip-flop still captures the old 0 at that edge. pe is high from 15 to 25, one full clock cycle.
  • Second rise, t=50: sig changes halfway between the edges at 45 and 55. pe goes high at 50 and low at 55, when sig_dly catches up, so the pulse is only half a clock cycle wide.
  • Before the first clock edge: sig_dly has no value yet (x), but sig is 0, so pe = 0 & ~x is already 0. pe would only be x if sig were 1.

The short second pulse shows a property of this design: because pe comes directly from sig through a gate, its width depends on when sig changes. That is fine when sig is produced by logic on the same clock, but not when it is an external or asynchronous signal, as explained below.

Quick Check

Q: Suppose the second rise of sig happened at t=54 instead of t=50. How wide would the pulse on pe be, and why is that a problem for logic clocked by clk?

Show Answer

1 time unit, from 54 to 55, because sig_dly catches up at the clock edge at 55. A flip-flop that samples pe at 55 needs it to be stable for its setup time before the edge. A pulse that starts just before the edge may violate that requirement, so the event can be missed or the flip-flop can go metastable. The registered design shown below avoids this.

Hardware Schematic

The design was synthesized with an FPGA synthesis tool. The one-cycle delay becomes a D flip-flop, and its output passes through an inverter into an AND gate together with sig. In the schematic, the generic gates have been mapped to cells of the target technology.

Synthesized schematic of pos_edge_det: a flip-flop delaying sig and a LUT combining sig with the inverted flip-flop output

Synthesized Netlist

The netlist below targets an Artix-7 FPGA and lists the primitives the design uses:

  • IBUF and OBUF - Input and output buffers for the pins
  • BUFG - Global clock buffer that distributes clk
  • FDRE - D flip-flop with clock enable and synchronous reset, used as sig_dly; its enable is tied high and its reset low
  • LUT2 - A 2-input lookup table implementing sig & ~sig_dly
  • GND and VCC - Constant 0 and 1 sources for the tied-off pins

module pos_edge_det
   (sig,
    clk,
    pe);
  input sig;
  input clk;
  output pe;

  wire \<const0> ;
  wire \<const1> ;
  wire clk;
  wire clk_IBUF;
  wire clk_IBUF_BUFG;
  wire pe;
  wire pe_OBUF;
  wire sig;
  wire sig_IBUF;
  wire sig_dly;

  GND GND
       (.G(\<const0> ));
  VCC VCC
       (.P(\<const1> ));
  BUFG clk_IBUF_BUFG_inst
       (.I(clk_IBUF),
        .O(clk_IBUF_BUFG));
  IBUF clk_IBUF_inst
       (.I(clk),
        .O(clk_IBUF));
  OBUF pe_OBUF_inst
       (.I(pe_OBUF),
        .O(pe));
  LUT2 #(
    .INIT(4'h2))
    pe_OBUF_inst_i_1
       (.I0(sig_IBUF),
        .I1(sig_dly),
        .O(pe_OBUF));
  IBUF sig_IBUF_inst
       (.I(sig),
        .O(sig_IBUF));
  FDRE #(
    .INIT(1'b0))
    sig_dly_reg
       (.C(clk_IBUF_BUFG),
        .CE(\<const1> ),
        .D(sig_IBUF),
        .Q(sig_dly),
        .R(\<const0> ));
endmodule

The INIT value of a LUT is its truth table. For a LUT2, bit n of INIT is the output when {I1, I0} equals n. 4'h2 is 4'b0010, so the output is 1 only for {I1, I0} = 2'b01, which is sig_dly = 0 and sig = 1: exactly the rising-edge row of the table above. The FDRE's INIT(1'b0) means that on an FPGA, sig_dly starts at 0 after configuration, unlike the x seen in simulation.

Edge-Triggered Interrupts

Interrupt controllers in microcontrollers let each interrupt line be configured as level-triggered or edge-triggered. In edge mode, an edge detector on the synchronized input sets a pending bit for one event per rising or falling edge, even if the external signal then stays high or low for a long time.

Registered Output and Asynchronous Inputs

When sig comes from outside the clock domain, such as a pin, a button or a block on a different clock, two changes make the detector reliable:

  • Synchronize the input through two flip-flops before using it. An asynchronous signal can change just as a flip-flop samples it, which can leave the flip-flop metastable for a short time. The second flip-flop gives that state time to settle.
  • Register the output by computing it from two flip-flop outputs instead of the raw input. The pulse is then exactly one clock cycle wide, and it starts and ends on clock edges.

module pos_edge_det_sync (
  input      clk,
  input      rstn,          // Active-low synchronous reset
  input      sig,           // Asynchronous input
  output     pe             // One-cycle pulse, aligned to clk
);

  reg sig_s1, sig_s2, sig_dly;

  always @(posedge clk) begin
    if (!rstn) begin
      sig_s1  <= 1'b0;
      sig_s2  <= 1'b0;
      sig_dly <= 1'b0;
    end else begin
      sig_s1  <= sig;        // Synchronizer stage 1 (may go metastable)
      sig_s2  <= sig_s1;     // Synchronizer stage 2 (settled value)
      sig_dly <= sig_s2;     // One cycle older copy for edge detection
    end
  end

  // Both inputs come from flip-flops, so pe changes only on clock edges
  assign pe = sig_s2 & ~sig_dly;

endmodule

The pulse now appears two to three clock cycles after the input changes, but it always lasts exactly one cycle and can never be shortened by the input's timing. The reset also removes the x at the start of simulation.

Start Pulses for State Machines

A control register bit written by software often stays set until software clears it, while the hardware block it controls needs a single "start" pulse. An edge detector on that bit produces the pulse, so the block starts once per write and does not restart on every cycle that the bit remains set.

Common Beginner Mistakes

Mistake #1: Using the signal as a clock

Wrong: always @(posedge sig) pe_count <= pe_count + 1;
Right: Detect the edge with sig & ~sig_dly and use it as an enable in logic clocked by clk

Why? posedge sig makes sig a clock, creating a new clock domain that timing analysis must handle separately. A noisy or glitching signal also produces extra clock edges. An edge detector keeps all logic on the system clock.

Mistake #2: Inverting the wrong signal

Wrong: assign pe = ~sig & sig_dly; for a rising edge
Right: assign pe = sig & ~sig_dly;

Why? ~sig & sig_dly means "now 0, was 1", which is a falling edge. Check the expression against the truth table: the rising edge is the row where the current value is 1 and the delayed value is 0.

Mistake #3: Feeding an asynchronous input straight into the detector

Wrong: Connecting a button or another clock domain's signal directly to sig
Right: Pass it through a two-flip-flop synchronizer first, as in pos_edge_det_sync

Why? The pulse width depends on when the input changes, as the second pulse in the testbench shows, and can be too short to be sampled. The first flip-flop can also go metastable. Both problems cause missed or extra events that appear only occasionally in hardware.

Mistake #4: Leaving the delay flip-flop without a reset

Wrong: Relying on sig_dly to start at 0 in simulation
Right: Reset sig_dly to a known value, usually the input's idle level

Why? Until the first clock edge, sig_dly is x, so pe is x too, which can propagate into the logic that uses it. On an ASIC, the flip-flop powers up in an unknown state and can create a false edge. If the input idles high, resetting sig_dly to 1 prevents a false rising edge right after reset.

Practice Exercise

Challenge: Three-Way Edge Detector

Write a module edge_det with inputs clk, rstn and an asynchronous input sig, and three outputs: pe (rising edge), ne (falling edge) and ae (any edge). All three must be one clock cycle wide and come directly from flip-flops, so that they are glitch-free.

Hint

Start from pos_edge_det_sync. To make the outputs come from flip-flops, compute the edge conditions combinationally and register them on the next clock edge.

Solution

module edge_det (
  input      clk,
  input      rstn,
  input      sig,         // Asynchronous input
  output reg pe,          // Rising edge pulse
  output reg ne,          // Falling edge pulse
  output reg ae           // Any edge pulse
);

  reg s1, s2, s_dly;

  always @(posedge clk) begin
    if (!rstn) begin
      {s1, s2, s_dly} <= 3'b000;
      {pe, ne, ae}    <= 3'b000;
    end else begin
      s1    <= sig;              // Two-flop synchronizer
      s2    <= s1;
      s_dly <= s2;               // Previous synchronized value
      pe    <=  s2 & ~s_dly;     // Registered edge outputs
      ne    <= ~s2 &  s_dly;
      ae    <=  s2 ^  s_dly;
    end
  end

endmodule

Synthesis builds 6 flip-flops and three small gates, or three LUTs on an FPGA. The outputs appear one cycle later than in pos_edge_det_sync, but since they come straight from flip-flops they cannot glitch, which matters when they drive logic in another block or leave the chip.

Summary

In this tutorial, you learned:

  • A positive edge detector compares a signal with a copy delayed by one clock cycle
  • sig & ~sig_dly detects a rising edge, ~sig & sig_dly a falling edge and sig ^ sig_dly any edge
  • The design synthesizes into one flip-flop and one gate, a single LUT2 on an FPGA
  • With an unregistered output, the pulse width depends on when the input changes
  • Asynchronous inputs need a two-flip-flop synchronizer before edge detection
  • Edge detectors turn long level signals into one-cycle events for counters, FSMs and interrupts
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5