Crossing clock domains - Signal

From: http://www.fpga4fun.com/CrossClockDomain.html

A signal to another clock domain

Let's say a signal from clkA domain is needed in clkB domain. It needs to be "synchronized" to clkB domain, so we want to build a "synchronizer" design, which takes a signal from clkA domain, and creates a new signal into clkB domain.

cross clock domain


In this first design, we assume that the signal-in changes "slowly" compared to both clkA and clkB clock speeds. Typically all you need to do is to use two flip-flops to move the signal from clkA to clkB (to learn why, get back to the links).


 1cross clock domainmodule Signal_CrossDomain(
 2cross clock domain
 3cross clock domain    clkA, SignalIn,
 4cross clock domain
 5cross clock domain    clkB, SignalOut);
 6cross clock domain
 7cross clock domain 
 8cross clock domain
 9cross clock domain// clkA domain signals
10cross clock domain
11cross clock domaininput clkA;
12cross clock domain
13cross clock domaininput SignalIn;
14cross clock domain
15cross clock domain 
16cross clock domain
17cross clock domain// clkB domain signals
18cross clock domain
19cross clock domaininput clkB;
20cross clock domain
21cross clock domainoutput SignalOut;
22cross clock domain
23cross clock domain 
24cross clock domain
25cross clock domain// Now let's transfer SignalIn into the clkB clock domain
26cross clock domain
27cross clock domain// We use a two-stages shift-register to synchronize the signal
28cross clock domain
29cross clock domainreg [1:0] SyncA_clkB;
30cross clock domain
31cross clock domainalways @(posedge clkB) SyncA_clkB[0<= SignalIn;      // notice that we use clkB
32cross clock domain
33cross clock domainalways @(posedge clkB) SyncA_clkB[1<= SyncA_clkB[0]; // notice that we use clkB
34cross clock domain
35cross clock domain 
36cross clock domain
37cross clock domainassign SignalOut = SyncA_clkB[1]; // new signal synchronized to (=ready to be used in) clkB domain
38cross clock domain
39cross clock domainendmodule

 

The two flip-flops have the side-effect of delaying the signal. For example, here are waveforms where you can see the slow moving signal being synchronized (and delayed) to clkB domain by the two flip-flops:

cross clock domain


Crossing clock domains - Flag

A flag to another clock domain

If the signal that needs to cross the clock domains is just a pulse (i.e. it lasts just one clock cycle), we call it a "flag". The previous design usually doesn't work (the flag might be missed, or be seen for too long, depending on the ratio of the clocks used).

We still want to use a synchronizer, but one that works for flags.

cross clock domain


The trick is to transform the flags into level changes, and then use the two flip-flops technique.

module Flag_CrossDomain(

    clkA, FlagIn_clkA,

    clkB, FlagOut_clkB);

 

// clkA domain signals

input clkA, FlagIn_clkA;

 

// clkB domain signals

input clkB;

output FlagOut_clkB;

 

reg FlagToggle_clkA;

reg [2:0] SyncA_clkB;

 

// this changes level when a flag is seen

always @(posedge clkA) if(FlagIn_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;

 

// which can then be sync-ed to clkB

always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};

 

// and recreate the flag from the level change

assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);

endmodule

Now if you want the clkA domain to receive an acknowledgment (that clkB received the flag), add a busy signal.

cross clock domain



 1cross clock domainmodule FlagAck_CrossDomain(
 2cross clock domain
 3cross clock domain    clkA, FlagIn_clkA, Busy_clkA,
 4cross clock domain
 5cross clock domain    clkB, FlagOut_clkB);
 6cross clock domain
 7cross clock domain 
 8cross clock domain
 9cross clock domain// clkA domain signals
10cross clock domain
11cross clock domaininput clkA, FlagIn_clkA;
12cross clock domain
13cross clock domainoutput Busy_clkA;
14cross clock domain
15cross clock domain 
16cross clock domain
17cross clock domain// clkB domain signals
18cross clock domain
19cross clock domaininput clkB;
20cross clock domain
21cross clock domainoutput FlagOut_clkB;
22cross clock domain
23cross clock domain 
24cross clock domain
25cross clock domainreg FlagToggle_clkA;
26cross clock domain
27cross clock domainreg [2:0] SyncA_clkB;
28cross clock domain
29cross clock domainreg [1:0] SyncB_clkA;
30cross clock domain
31cross clock domain 
32cross clock domain
33cross clock domainalways @(posedge clkA) if(FlagIn_clkA & ~Busy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;
34cross clock domain
35endmodule

 

Crossing clock domains - Task

Getting a task done in another clock domain

If the clkA domain has a task that needs to be completed in the clkB domain, you can use the following design.

cross clock domain


Here's one way to do it


 1cross clock domainmodule TaskAck_CrossDomain(
 2cross clock domain
 3cross clock domain    clkA, TaskStart_clkA, TaskBusy_clkA, TaskDone_clkA,
 4cross clock domain
 5cross clock domain    clkB, TaskStart_clkB, TaskBusy_clkB, TaskDone_clkB);
 6cross clock domain
 7cross clock domain 
 8cross clock domain
 9cross clock domain// clkA domain signals
10cross clock domain
11cross clock domaininput clkA;
12cross clock domain
13cross clock domaininput TaskStart_clkA;
14cross clock domain
15cross clock domainoutput TaskBusy_clkA, TaskDone_clkA;
16cross clock domain
17cross clock domain 
18cross clock domain
19cross clock domain// clkB domain signals
20cross clock domain
21cross clock domaininput clkB;
22cross clock domain
23cross clock domainoutput TaskBusy_clkB, TaskStart_clkB;
24cross clock domain
25cross clock domaininput TaskDone_clkB;
26cross clock domain
27cross clock domain 
28cross clock domain
29cross clock domainreg FlagToggle_clkA, FlagToggle_clkB, Busyhold_clkB;
30cross clock domain
31cross clock domainreg [2:0] SyncA_clkB, SyncB_clkA;
32cross clock domain
33cross clock domain 
34cross clock domain
35cross clock domainalways @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;
36cross clock domain
37cross clock domain 
38cross clock domain
39endmodule

and here's a matching simulation waveform

cross clock domain


Crossing clock domains - Data bus

Data bus to another clock domain

To move a data bus (2 bits wide or more) from one clock domain to another, we have several techniques to our disposal.
Here are a few ideas.

  1. Gray code: If the data bus is a monotonic counter (i.e. only incrementing or decrementing), we can convert it to a gray code, which has the ability to cross clock domains (under certain timing conditions).
  2. Data freeze: If the data bus is non-monotonic, use a flag to signal the other domain to capture the value (while it is frozen in the source clock domain).
  3. Data burst: If the data bus has many consecutive values that need to cross the clock domain, use an asynchronous FIFO, where you push values from the source clock domain, and read back values at the other domain.

 

相关文章: