我的新博客

跨时钟域的设计

参考自fpga4fun.com

part 1.跨时钟域的信号

如果时钟域B需要使用来自时钟域A的信号,那么需要对这个信号进行同步。

image

如果输入信号比起时钟B来讲变化较慢,可以使用两个触发器来完成

 

   1:  module Signal_CrossDomain(
   2:      input clkA,   // we actually don't need clkA in that example, but it is here for completeness as we'll need it in further examples
   3:      input SignalIn_clkA,
   4:      input clkB,
   5:      output SignalOut_clkB
   6:  );
   7:   
   8:  // We use a two-stages shift-register to synchronize SignalIn_clkA to the clkB clock domain
   9:  reg [1:0] SyncA_clkB;
  10:  always @(posedge clkB) SyncA_clkB[0] <= SignalIn_clkA;   // notice that we use clkB
  11:  always @(posedge clkB) SyncA_clkB[1] <= SyncA_clkB[0];   // notice that we use clkB
  12:   
  13:  assign SignalOut_clkB = SyncA_clkB[1];  // new signal synchronized to (=ready to be used in) clkB domain
  14:  endmodule

image

part 2 跨时钟的Flag

当信号是一个短脉冲时

image

   1:  module Flag_CrossDomain(
   2:      input clkA,
   3:      input FlagIn_clkA, 
   4:      input clkB,
   5:      output FlagOut_clkB
   6:  );
   7:   
   8:  // this changes level when the FlagIn_clkA is seen in clkA
   9:  reg FlagToggle_clkA;
  10:  always @(posedge clkA) FlagToggle_clkA <= FlagToggle_clkA ^ FlagIn_clkA;
  11:   
  12:  // which can then be sync-ed to clkB
  13:  reg [2:0] SyncA_clkB;
  14:  always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
  15:   
  16:  // and recreate the flag in clkB
  17:  assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
  18:  endmodule

   1:  module FlagAck_CrossDomain(
   2:      input clkA,
   3:      input FlagIn_clkA,
   4:      output Busy_clkA,
   5:      input clkB,
   6:      output FlagOut_clkB
   7:  );
   8:   
   9:  reg FlagToggle_clkA;
  10:  always @(posedge clkA) FlagToggle_clkA <= FlagToggle_clkA ^ (FlagIn_clkA & ~Busy_clkA);
  11:   
  12:  reg [2:0] SyncA_clkB;
  13:  always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
  14:   
  15:  reg [1:0] SyncB_clkA;
  16:  always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[2]};
  17:   
  18:  assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
  19:  assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];
  20:  endmodule

part3 task

   1:  module TaskAck_CrossDomain(
   2:      input clkA,
   3:      input TaskStart_clkA,
   4:      output TaskBusy_clkA, TaskDone_clkA,
   5:   
   6:      input clkB,
   7:      output TaskStart_clkB, TaskBusy_clkB,
   8:      input TaskDone_clkB
   9:  );
  10:   
  11:  reg FlagToggle_clkA, FlagToggle_clkB, Busyhold_clkB;
  12:  reg [2:0] SyncA_clkB, SyncB_clkA;
  13:   
  14:  always @(posedge clkA) FlagToggle_clkA <= FlagToggle_clkA ^ (TaskStart_clkA & ~TaskBusy_clkA);
  15:   
  16:  always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
  17:  assign TaskStart_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
  18:  assign TaskBusy_clkB = TaskStart_clkB | Busyhold_clkB;
  19:  always @(posedge clkB) Busyhold_clkB <= ~TaskDone_clkB & TaskBusy_clkB;
  20:  always @(posedge clkB) if(TaskBusy_clkB & TaskDone_clkB) FlagToggle_clkB <= FlagToggle_clkA;
  21:   
  22:  always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], FlagToggle_clkB};
  23:  assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];
  24:  assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];
  25:  endmodule

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 FIFO, where you push values from the source clock domain, and read back values from the other domain.

That's all folks!

posted @ 2014-06-30 17:55  Leon#0534  阅读(833)  评论(0编辑  收藏  举报

我的新博客

专注天线学习,欢迎交流 yangli0534@gmail.com - 创建于 2010年

我永远是茫茫EE领域的一名小学生。