将100MHz时钟划分为16MHz时钟[Verilog]

将100MHz时钟划分为16MHz时钟[Verilog],verilog,clock,Verilog,Clock,正如锡上所说,我有一个100MHz的时钟(取自Nexys 3 Spartan 6板),我想把它分成16MHz的时钟。我制作了1Mhz和60Hz的时钟,没有问题,但我在获取清晰的16MHz信号时遇到了一些问题 以下是我目前正在测试的内容: module clk_gen( input clk_100MHz, output reg clk_16MHz, output reg clk_1MHz, output reg clk_1s ); integer count_

正如锡上所说,我有一个100MHz的时钟(取自Nexys 3 Spartan 6板),我想把它分成16MHz的时钟。我制作了1Mhz和60Hz的时钟,没有问题,但我在获取清晰的16MHz信号时遇到了一些问题

以下是我目前正在测试的内容:

module clk_gen(
    input clk_100MHz,
      output reg clk_16MHz,
    output reg clk_1MHz,
    output reg clk_1s );

integer count_16MHz;
integer count_1MHz;
integer count_1s;
integer skip_cnt;

initial begin
    count_16MHz = 1;
    count_1MHz = 1;
    count_1s = 1;
    skip_cnt = 1;
    clk_1s = 1'b0;
    clk_1MHz = 1'b0;
    clk_16MHz = 1'b0;
end

//16MHz
always@(posedge clk_100MHz) begin
     //8*(100Mhz/6.25) == 7*(100MHz/6)+((100MHz/8))
     if((skip_cnt == 8) & (count_16MHz == 4)) begin
        clk_16MHz = ~clk_16MHz;
        skip_cnt = 1;
        count_16MHz = 1;
     end
     else if((skip_cnt < 8) & (count_16MHz == 3)) begin
        clk_16MHz = ~clk_16MHz;
        skip_cnt = skip_cnt + 1;
        count_16MHz = 1;
   end
     count_16MHz = count_16MHz + 1;
end
//1MHz
always@(posedge clk_100MHz) begin
     if(count_1MHz == 50) begin
        clk_1MHz = ~clk_1MHz;
        count_1MHz = 1;
     end
     count_1MHz = count_1MHz + 1;
end
模块时钟发电机(
输入时钟100MHz,
输出调节时钟16MHz,
输出调节时钟1MHz,
输出寄存器clk_1s);
整数计数_16MHz;
整数计数_1MHz;
整数计数_1s;
整数跳跃;
初始开始
计数_16MHz=1;
计数_1MHz=1;
计数1s=1;
跳过cnt=1;
时钟1s=1'b0;
时钟频率1MHz=1'b0;
时钟频率16MHz=1'b0;
结束
//16MHz
始终@(posedge时钟100MHz)开始
//8*(100Mhz/6.25)==7*(100Mhz/6)+(100Mhz/8))
如果((跳过cnt==8)和(计数16MHz==4))开始
clk_16MHz=~clk_16MHz;
跳过cnt=1;
计数_16MHz=1;
结束
否则如果((跳过cnt<8)和(计数16MHz==3))开始
clk_16MHz=~clk_16MHz;
skip_cnt=skip_cnt+1;
计数_16MHz=1;
结束
计数_16MHz=计数_16MHz+1;
结束
//1MHz
始终@(posedge时钟100MHz)开始
如果(计数频率=50)开始
clk_1MHz=~clk_1MHz;
计数_1MHz=1;
结束
计数频率=计数频率+1;
结束
我有1Mhz和60Hz(1秒)的分频,但16MHz是一种痛苦。有没有更好的方法(在Verilog中)


不幸的是,我确实想要一个非常严格的16MHz,因为在1MHz时钟周期之间会发生16次移位操作。我唯一的另一种攻击方法可能是将1MHz降低到较慢的速度,更容易除以16。

使用FPGA上可用的时钟资源

由于您使用的是Spartan-6,因此可以访问DCM_CLKGEN和DCM_SP原语。设置这些的最简单方法是使用Xilinx时钟向导,但是如果您真的想使用Verilog,可以直接实例化DCM_CLKGEN

从100MHz到16MHz的最简单方法是乘以4,然后除以25。DCM还可以通过将输出除以16,同时生成1 MHz时钟

DCM_CLKGEN #(
    .CLKIN_PERIOD("100 MHZ"),
    .CLKFX_MULTIPLY(4),
    .CLKFX_DIVIDE(25),
    .CLKFXDV_DIVIDE(16)
) clkgen_100to16and1 (
    .RST     (1'b0),
    .CLKIN   (clk_100MHz),
    .CLKFX   (clk_16MHz),
    .CLKFXDV (clk_1MHz)
);
请注意,16 MHz和1 MHz输出之间没有保证的相位关系


有关Spartan-6中可用的DCM和其他时钟资源的详细信息,请参阅Xilinx文档。

听起来您想用数字电路实现分数时钟分频器。由于时钟的划分是一个分数,因此输出时钟将在两个时钟周期之间抖动(在您的情况下,在100 MHz时钟的6到7个周期之间),但平均值将为100/16=6.25个周期长。如果分数小于或等于原始频率的一半,则如下示例:

always@(posedge clk_100MHz) begin
  if(count_16MHz >= 100) begin
    clk_16MHz <= 1;
    count_16MHz <= count_16MHz - 100 + 16;
  end
  else begin
    count_16MHz <= count_16Mhz + 16;
    if(count_16MHz >= 50) begin
      clk_16MHz <= 0
    end
  end
end
始终@(posedge时钟100MHz)开始
如果(计数16MHz>=100)开始

clk_16MHz您可以共享此文档吗?这也适用于任何非整数除法吗?@KaranShah是的,这是通用的,可以用来产生被任何分数除法的时钟。我已经将其与Cypress PSoC微控制器一起使用,然后将产生的时钟输入PLL,以平滑和缩放产生的时钟。这是一种从相互锁定的USB时钟创建音频时钟的经济高效的方法。您应该能够轻松地搜索有关此技术的参考。此方法有任何限制吗?如果我想从100MHz制作75MHz。@KaranShah是的,有一个限制。我更新了我的答案,补充说这只适用于分数。你知道>1/2*freq(从100MHz到75MHz)的逻辑吗?
always@(posedge clk_100MHz) begin
  if(count_75MHz >= 100) begin
    pos <= ~neg;
    count_75MHz <= count_75MHz - 100 + 75;
  end
  else begin
    count_75MHz <= count_75Mhz + 75;
  end
end

always@(negedge clk_100MHz) begin
  neg <= pos;
end

assign clk_75MHz <= pos ^ neg;