1
votes

As it says on the tin, I have a 100MHz clock (drawn from Nexys 3 Spartan 6 board) that I want divided a into 16MHz clock. I made 1Mhz and 60Hz clocks without issue, but I'm having some issues getting clean 16MHz signal.

Here's what I'm currently testing out:

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

I have my 1Mhz and 60Hz (1sec) divides, but the 16MHz is being a pain. Is there a better way (while staying in Verilog)?

Unfortunately I do want a very strict 16MHz due to a shifting operation occurring 16 times between the 1MHz clock's cycle. My only other method of attack is perhaps lowering the 1MHz to something slower and more easily divided by 16.

2

2 Answers

1
votes

Use the clocking resources available on the FPGA.

Since you're using a Spartan-6, you have access to the DCM_CLKGEN and DCM_SP primitives. The easiest way to set these up is using the Xilinx clocking wizard, but if you really want to do it with Verilog, you can instantiate a DCM_CLKGEN directly.

The easiest way to get from 100 MHz to 16 MHz is to multiply by 4, then divide by 25. The DCM can also generate a 1 MHz clock at the same time by dividing the output by 16.

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)
);

Note that there is no guaranteed phase relationship between the 16 MHz and 1 MHz outputs.

For details on the DCM and other clocking resources available in the Spartan-6, consult Xilinx document UG382: Spartan-6 FPGA Clocking Resources.

0
votes

It sounds like you want to implement a fractional clock divider with a digital circuit. Since the division of the clocks is a fraction, the output clock will jitter between two clock periods (in your case between 6 and 7 periods of the 100 MHz clock), but the average will be 100/16=6.25 periods long. Here is an implementation if the fraction is less than or equal half of the original frequency like this example:

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

The key thing to the divider is that it doesn't get reset to 0, it just gets decremented by 100 when a clock period happens.

This circuit doesn't work if the fraction is greater than one half. Since this circuit is only clocked on the posedge of the original clock, in that case there aren't enough posedge clocks in order to generate both the rising and falling edge of the generated clock.

Here is an implementation that holds the clock high always for a half clock cycle of the faster clock and therefore can work for ratios that are greater than 1/2.

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;

In this case the posedge causes the clock to go high by making the two signals different and the negedge always makes the clock go low.