Theoretically, signals in the fast clock domain will always sample signals transmitted from the slow clock domain. If the clocks are asynchronous, sampling errors may occur, so synchronization is required. This type of synchronization is relatively simple and generally uses the delay tapping method or the delayed sampling method.

Delay Tapping Method

The most common synchronization method is the two-stage flip-flop buffering method, commonly known as the delay tapping method. Before an asynchronous signal enters another clock domain, the signal is buffered twice consecutively by two stages of flip-flops, which effectively reduces metastability problems caused by timing violations. The circuit diagram is shown below.

In general designs, using two stages of flip-flops for buffering is sufficient to meet design timing requirements. A large number of experiments show that three-stage flip-flop buffering can solve more than 99% of such asynchronous timing problems.

The Verilog description of two-stage flip-flop delay tapping and rising-edge detection is as follows:

Example

module delay_clap(
    input       clk1,  // Asynchronous slow clock
    input       sig1,  // Asynchronous signal

    input       rstn,  // Reset signal
    input       clk2,  // Destination fast clock domain clock
    output      sig2); // Signal synchronized in the fast clock domain

   reg [2:0]    sig2_r ;   // 3-stage buffer; first two stages for synchronization, last two stages for edge detection
   always @(posedge clk2 or negedge rstn) begin
     if (!rstn) sig2_r  <= 3'b0 ;
     else       sig2_r  <= {sig2_r[1:0], sig1} ;  // Buffer
   end
   assign sig2 = sig2_r[1] && !sig2_r[2] ; // Rising edge detection

Delayed Sampling Method

This method is mainly aimed at multi-bit data transmission.

For example, when the frequency ratio of two asynchronous clocks is 5, you can first use the delay tapping method to buffer the data enable signal through two stages of registers, and then sample the data signal from the slow clock domain in the fast clock domain.

The basic idea of this method is to ensure that the signal is safely sampled at the right moment, without needing to synchronize multi-bit data signals, thus saving some hardware resources.

The Verilog description of delayed sampling using the tapping method is as follows.

Example

// Synchronization module working clock is 100MHz
// Asynchronous data comes from a module with a 20MHz working clock
module delay_sample(
    input               rstn,
    input               clk1,
    input [31:0]        din,
    input               din_en,

    input               clk2,
    output [31:0]       dout,
    output              dout_en);

   //sync din_en
   reg [2:0]    din_en_r ;
   always @(posedge clk2 or negedge rstn) begin
     if (!rstn) din_en_r  <= 3'b0 ;
     else       din_en_r  <= {din_en_r[1:0], din_en} ;
   end
   wire din_en_pos = din_en_r[1] && !din_en_r[2] ;

   //sync data
   reg [31:0]           dout_r ;
   reg                  dout_en_r ;
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)
        dout_r         <= 'b0 ;
      else if (din_en_pos)
        dout_r         <= din ;
   end
   //dout_en delay
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)        dout_en_r      <= 1'b0 ;
      else              dout_en_r      <= din_en_pos ;
   end
   assign       dout    = dout_r ;
   assign       dout_en = dout_en_r ;

endmodule

The timing result diagram of this method is shown below.

Obviously, in the clk2 clock domain, sampling and buffering data at time t2 is much safer than at time t1.

However, if the slow clock domain has no data enable signal din_en, or the data enable signal is always active, the method of detecting the rising edge of the data enable signal in the fast clock domain will fail. Because the data enable signal is always active, except for the first data, the fast clock domain will not be able to detect the transmission times of subsequent data.

The solution is to detect the edge of the slow clock signal in the fast clock domain.

If the frequency difference between the two clocks is small, it may be necessary to delay-buffer the data to ensure that the sampled data corresponds to the current clock beat; if the frequency difference is large, the data sampling time can be obtained by counting, without buffering the data.

The Verilog description of detecting the slow clock edge by using the counting delayed sampling method is as follows.

Example

// Synchronization module working clock is 100MHz
// Asynchronous data comes from a module with a 999KHz working clock
module delay_cnt_sample(
    input               rstn,
    input               clk1,
    input [31:0]        din,
    input               din_en,

    input               clk2,
    output [31:0]       dout,
    output              dout_en);

   // 4-stage buffer: 3 stages for tapping synchronization, 1 stage for edge detection
   reg [3:0]    edge_r ;
   always @(posedge clk2 or negedge rstn) begin
     if (!rstn) edge_r  <= 3'b0 ;
     else       edge_r  <= {edge_r[3:0], clk1} ;
   end
   wire edge_pos = edge_r[2] && !edge_r[3] ;

   // Delay counter: starts counting when the slow clock rising edge is detected
   reg [5:0] cnt ;
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)                cnt <= 6'h3f ;
      else if (edge_pos && din_en)
                                cnt <= 6'h0 ;
      else if (cnt != 6'h3f)    cnt <= cnt + 1'b1 ;
   end

   // Data synchronization
   reg [31:0]           dout_r ;
   reg                  dout_en_r ;
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)
        dout_r         <= 'b0 ;
      else if (din_en && cnt == 47) // Sample approximately at the middle of the slow clock period
        dout_r         <= din ;
   end
   // The data enable signal is output one cycle delayed from the data sampling time
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)        dout_en_r      <= 1'b0 ;
      else if (din_en && cnt==48)
                        dout_en_r      <= 1'b1 ;
      else              dout_en_r      <= 1'b0 ;
   end
   assign       dout    = dout_r ;
   assign       dout_en = dout_en_r ;

endmodule

The data synchronization sampling result diagram for a large frequency difference is shown below.

As can be seen from the figure, the fast clock sampling time is around the center of the slow clock period, which is very safe.

Source Code Download for This Chapter

Download