时钟分频与时钟使能

Scroll Down

为什么要使用时钟使能电路

时钟使能电路是同步设计的基本电路,在很多设计中,虽然内部不同模块的处理速度不同,但由于这些时钟是同源的,可以将它们转化为单一时钟处理;在ASIC中可以通过STA(Staic Time Anlyis,静态时序分析)约束让分频始终和源时钟同相,但FPGA由于器件本身和工具的限制,分频时钟和源时钟的Skew(偏移)不容易控制(使用锁相环分频是个例外),难以保证分频时钟和源时钟同相,因此推荐的方法是使用时钟使能,通过使用时钟使能可以避免时钟“满天飞”的情况,进而避免了不必要的亚稳态发生,在降低设计复杂度的同时也提高了设计的可靠性。

应该禁止使用计数器分频后的信号做其它模块的时钟

禁止用计数器分频后的信号做其它模块的时钟,而要用改成时钟使能的方式,否则这种时钟满天飞的方式对设计的可靠性极为不利,也大大增加了静态时序分析的复杂性。

如何实现时钟使能电路

使用带使能端的D触发器,比一般D触发器多了使能端,只有在使能信号EN有效时,数据才能从D端被打入D触发器,否则Q端输出不改变,我们可以用带使能端的D触发器来实现时钟使能的功能。
使能D触发器.jpg

verilog模型举例

在某系统中,前级数据输入位宽为8位,而后级的数据输出位宽为32,我们需要将8bit数据转换为32bit,由于后级的处理位宽为前级的4倍,因此后级处理的时钟频率也将下降为前级的1/4,若不使用时钟使能,则要将前级的时钟进行4分频来作后级处理的时钟;这种设计方法会引入新的时钟域,处理上需要采取多时钟域处理的方式,因而在设计复杂度提高的同时系统的可靠性也将降低。为了避免以上问题,我们应该采用时钟使能的设计以减少设计复杂度。

  • 采用时钟使能的设计
module clk_en(
  clk, rst_n, data_in, data_out
    );
  input clk;
    input rst_n;
    input [7:0] data_in;
    output [31:0] data_out;
    
    reg [31:0] data_out;
    reg [31:0] data_shift;
    reg [1:0] cnt;
    reg clken;//使能信号
    
    always @(posedge clk or negedge rst_n)
    begin
       if (!rst_n)
          cnt <= 0;
       else
          cnt <= cnt + 1;
    end
    
    always @(posedge clk or negedge rst_n)
    begin
       if (!rst_n)
          clken <= 0;
       else if (cnt == 2'b01)
          clken <= 1;//使能信号只在一个周期拉高
       else
          clken <= 0;
    end
    
    always @(posedge clk or negedge rst_n )
    begin
       if (!rst_n)
          data_shift <= 0;
       else 
          data_shift <= {data_shift[23:0],data_in};//移位
    end
    
    always @(posedge clk or negedge rst_n)
    begin
       if (!rst_n)
          data_out <= 0;
       else if (clken == 1'b1)
          data_out <= data_shift;//只在一个周期输出
    end
endmodule
  • 采用时钟分频的设计
module clk_en1(clk, rst_n, data_in, data_out);
input clk;
input rst_n;
input [7:0] data_in;
output [31:0] data_out;

reg [31:0] data_out;
reg [31:0] data_shift;
reg [1:0] cnt;
wire clken;

always @(posedge clk or negedge rst_n)
begin
   if (!rst_n)
      cnt <= 0;
   else
      cnt <= cnt + 1;
end

assign clken = cnt[1];

always @(posedge clk or negedge rst_n)
begin
   if (!rst_n)
      data_shift <= 0;
   else 
      data_shift <= {data_shift[23:0],data_in};
end

always @(posedge clken or negedge rst_n)
begin
   if (!rst_n)
      data_out <= 0;
   else 
      data_out <= data_shift;
end

endmodule