fpga4fun.com - where FPGAs are fun.
Home
Welcome
Information


FPGA projects
Music box
Pong game
R/C servos
Text LCD module
Quadrature decoder
PWM and one-bit DAC
Debouncer
LED displays
Crossing clock domains
External contributions

FPGA interface projects
RS-232
JTAG
I2C
EPP
SPI
CNC steppers

FPGA advanced projects
Graphic LCD panel
Digital oscilloscope
10BASE-T interface
PCI interface
Spoc CPU core

Hands-on
A simple oscilloscope


FPGA introduction
What are FPGAs?
How FPGAs work
FPGA pins
Clocks and global lines
Download cables
Configuration
Learn more

FPGA software
Design software
Pin assignment
Design-entry/HDL
Simulation/HDL
Synthesis and P&R

FPGA electronic
SMD technology
Crystals and oscillators

HDL info
HDL tutorials
Verilog tips
VHDL tips

Quick-start guides
ISE
Quartus

Site
News
FPGA links
HDL tutorials
Forum


Crossing clock domains

An FPGA design can use multiple clocks. Each clock forms a "clock domain" inside the FPGA, and care needs to be taken if a signal generated in a clock domain is needed in another clock domain.

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.

In this first design, we assume that the signal 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, see the links section at the end of this page).

module Signal_CrossDomain(
    clkA, SignalIn, 
    clkB, SignalOut);

// clkA domain signals
input clkA;
input SignalIn;

// clkB domain signals
input clkB;
output SignalOut;

// Now let's transfer SignalIn into the clkB clock domain
// We use a two-stages shift-register to synchronize the signal
reg [1:0] SyncA_clkB;
always @(posedge clkB) SyncA_clkB[0] <= SignalIn;      // notice that we use clkB
always @(posedge clkB) SyncA_clkB[1] <= SyncA_clkB[0]; // notice that we use clkB

assign SignalOut = SyncA_clkB[1];
endmodule

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:

A flag to another clock domain

Now if the signal that needs to cross the clock domains is a one-clock-period-long pulse (called a "flag" here), 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.

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;

always @(posedge clkA) if(FlagIn_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;  // this changes level when a flag is seen
always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};   // which can then be synched to clkB

assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);  // recreate the flag from the level change
endmodule

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

module FlagAck_CrossDomain(
    clkA, FlagIn_clkA, Busy_clkA, 
    clkB, FlagOut_clkB);

// clkA domain signals
input clkA, FlagIn_clkA;
output Busy_clkA;

// clkB domain signals
input clkB;
output FlagOut_clkB;

reg FlagToggle_clkA;
reg [2:0] SyncA_clkB;
reg [1:0] SyncB_clkA;

always @(posedge clkA) if(FlagIn_clkA & ~Busy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;
always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[1]};

assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];
endmodule
Getting a task done in another clock domain

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

Here's one way to do it.

module TaskAck_CrossDomain(
    clkA, TaskStart_clkA, TaskBusy_clkA, TaskDone_clkA, 
    clkB, TaskStart_clkB, TaskBusy_clkB, TaskDone_clkB);

// clkA domain signals
input clkA;
input TaskStart_clkA;
output TaskBusy_clkA, TaskDone_clkA;

// clkB domain signals
input clkB;
output TaskBusy_clkB, TaskStart_clkB;
input TaskDone_clkB;

reg FlagToggle_clkA, Busyhold_clkB;
reg [2:0] SyncA_clkB, SyncB_clkA;

always @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;

always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
assign TaskStart_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
assign TaskBusy_clkB = TaskStart_clkB | Busyhold_clkB;
always @(posedge clkB) Busyhold_clkB <= ~TaskDone_clkB & TaskBusy_clkB;

always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};
assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];
assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];
endmodule
Links
To learn what is metastablity and why two flip-flops are used to cross clock domains, follow these links.

That's all folks!
Have fun crossing clock domains.






This page was last updated on December 27 2007.