Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
15 years ago

Varible clock rate

Hello together

I have a verilog-module that is working with an external 25 MHz clock. Now in my application I would like to work with a variable clock rate. Some other logic modules in the FPGA shoule still work with 25 MHz

The idea:

A DDS (e.g. AD9834) would create a clock rate between 0 Hz to 25 Mhz with 1 Hz steps. The Clock rate can change during program execution. For example a sweep from 1Mhz to 10 Mhz in 5 seconds.

An example application could be a bit pattern generator.

Will this approach work in general?

Is there an easier solution without a DDS?

Best regards and thank you for your help

Geri

10 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The DDS chip is well known solution for clk generation. But it is only justified if you want a clean clk every time. Alternatively you can design a dds-like module in your rtl. This can generate any rate which can be applied as clk enable for a fixed 25MHz.

    The idea is very simple: just a free running 2^n accummulator with variable increment. use its overflow pulse signal as enable. for example if your accum. is 32 bits wide then run it on 25MHz. if the increment value is say 2345 then the enable rate = 2345/2^32 of clk rate.

    i.e. freq = 25000000 * incr/2^32 in Hz.

    This is the very idea used by commercial DDS...

    make sure that the pulse is one clk short. the easiest way for this is to use 33 bits for 32 bit accum. to let it overflow without loss of count.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    There are two possible variants of using DDS techniques for digital clock generation:

    - The basic variant is to use only the fractional frequency divider of the DDS designs. You get an effectively unlimited frequency resolution, but the output clock has a jitter.

    - The extended variant uses the low pass filtered sine output of the DDS and a comparator to generate an interpolated digital clock. To be able to reduce output jitter in the low pass filter, the maximum generated frequency must be considerably lower than the DDS clock.

    In practise, a DDS design is the only simple way to generate a stepwise variable frequency. Alternatively a PLL with a reference frequency of 1 Hz can do, but it would be rather slow. Or a PLL with e.g. 32 or 64 Hz reference frequency and a post divider.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks to all of you for the fast response and the approaches!

    @Kaz: Thats sounds very fine and simple and no DDS is necessary.

    Attached my understanding. Does this piece of code reflect your approach?

    
    // Verilog module for clock variable clock generation of logic
    module DDS(clk, ClkEnable);
    input clk;
    output ClkEnable;
    // Binary counter, 16-bits wide
    parameter ClockGeneratorAccWidth = 33;  // plus overflow bit
    parameter ClockGeneratorAccIncWidth = 32;
    reg  ClockGeneratorAcc;
    reg  ClockGeneratorAccInc = 2345; // any value for frequency setting e.g. 2345
    always @(posedge clk) 
    begin
        ClockGeneratorAcc <= ClockGeneratorAcc + ClockGeneratorAccInc;
        if (ClockGeneratorAcc == 1) ClockGeneratorAcc <= 0;
    end
    // Use the highest bit of the counter (MSB) to enable clock
    assign ClkEnable = ClockGeneratorAcc;
    endmodule
    

    @FvM

    The AD9834 has an integrated comparator that can be conected to the sin wave output to create a rectangular signal. So if I understand you right, the approach with the external DDS could work but what percentage do

    you estimate has it lower than the DDS frequency?

    Friendly regards and thank you again

    Geri
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I am currently not good at reading verilog but let me suggest my algorithm in vhdl:

    
    signal accum : unsigned(32 downto 0) := (others => '0');
    -- on a clked process
    accum <= accum(31 downto 0) + increment;
    end process;
     
    enable <= accum(32);
    

    The main idea is adding 31:0 to 32:0 freely as this wraps up the result back and so the overflow should be one pulse. Please let me know if it works. Remember all your clked staements and clked components must have clk enable added to them.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello kaz

    Thank you very much for your help. Your code looks similar for me, mine is a little bit more cosmectic.

    --- Quote Start ---

    Remember all your clked staements and clked components must have clk enable added to them.

    --- Quote End ---

    Yes, I will implement it as code block

    always @(posedge clk or ClkEnable rst)
    begin
      // do something
    end
    
    I am currently struggeling a little bit if e.g. a 20 Mhz clock can be realized using a clock rate of 25 MHz because the enable signal itself is derived from the 25 MHz clock

    I will let you know if it works!

    Best regards and thank you again

    Geri
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Geri,

    for whatever rate value you choose, the final rate will tend to be correct over time despite the irregular nature of enable. This is a matter of accum. resolution and design toloerances but 32 bits is pretty high for most.

    You can if you wish use a dedicated accum for a given ratio e.g. for 20MHz on 25MHz you have two choices:

    generic high resolution accum: modulo 2 above then:

    20 = 25 * incr/2^32 then incr = 2^32 * 20/25 = 2^32 * 0.80000...

    option 2:

    dedicated accum: i.e. incr = 20, accum 0~24

    or incr = 4, accum = 0~4 (in effect a divider)
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello

    Now I did some tests with the following code and measuring output frequency with an oscillosope.

    fOsc = 24 MHz

    
    // Verilog module for variable clock generation of logic
    //  fOut = fclk * ClockGeneratorAccInc/2^32
    module DDS(clk, ClkEnable);
    input clk;
    output ClkEnable;
    parameter ClockGeneratorAccWidth = 32;  // plus overflow bit
    reg  ClockGeneratorAcc;
    always @(posedge clk) 
    begin
        ClockGeneratorAcc <= ClockGeneratorAcc + 178956971;
     //    if (ClockGeneratorAcc == 1) ClockGeneratorAcc <= 0;
    end
    // Use the highest bit of the counter (MSB) to enable clock
    assign ClkEnable = ClockGeneratorAcc;
    endmodule
    // test logic
    module TestDDS(clk, fOut);
    input clk;
    output fOut;
    wire cEn;
    reg ClkOut;
    DDS ClockGenerator(.clk(clk),.ClkEnable(cEn));
    always @(posedge clk)
    begin
        if (cEn) ClkOut = ~ClkOut;
    end
    assign PWM = ClkOut;
    endmodul
    
    Results:

    Using this design without reset on overflow:

    There is a periodical signal on the output but the output signal

    has area of 12 Mhz clock output and an area with output level 0.

    The freuquency of the total signal follows the formula

    fOut = 24 Mhz * Increment / 2^32

    Using this design with reset on overflow:

    There is a periodical signal, the high-low changes are evenly distributed.

    I think it works a standard frequency divider.

    On higer frequencies e.g. a set value of 18 Mhz I think the output is always 12 MHz

    So the logic is not working as expected.

    Does anybody have an idea?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    First you shouldn't reset the accumulator and second you shouldn't add accum to itself. see my previous post:

    add bits 31:0 of accum to increment and assign result to accum 32:0

    The binary counter should be allowed free running without reset once it starts. The increment value can be changed on the fly.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello kaz

    Wow, now it works fine.

    For others, that are interested in the working code, it looks like:

    
    // Verilog module for variable clock generation triggering logic
    // fOut = fclk * ClockGeneratorAccInc/2^32  
    // Accumulator increment value = fout/fOsc * 2^32; 
    // e.g.  value = 19123456/24000000 * 2^32 = 3422275754
    module DDS(clk, ClkEnable); 
    input clk; 
    output ClkEnable;  
     
    parameter ClockGeneratorAccWidth = 32;  // plus overflow bit reg
    ClockGeneratorAccWidth:0] ClockGeneratorAcc;  always @(posedge clk) 
     
    begin     
        ClockGeneratorAcc <= ClockGeneratorAcc + 3422275754; // 19123456 MHz
    end
     
    // Use the highest bit of the counter (MSB) to enable clock
    assign ClkEnable = ClockGeneratorAcc;
    endmodule
     
    // Example of use
    // because ClkOut is toggeling we have the half frequency on output pin:)
    module TestDDS(clk, fOut);
    input clk;
    output fOut;
    wire cEn;
    reg ClkOut;
    DDS ClockGenerator(.clk(clk),.ClkEnable(cEn));
    always @(posedge clk)
    begin
     if (cEn) ClkOut = ~ClkOut;
    end
    assign PWM = ClkOut;
    endmodule
    
    Thank you very much for your help again

    Geri
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Geri,

    I'm glad that I found your code. But when I cut & pasted and attempted to simulate it with Fclk = 24 MHz, the clockout didn't come out as expected. First, the ModelSim gave a warning that the number 3422275754 will be a signed integer and will cause overflow. Second, without any hard reset at the beginning to set the accumulator to a default value (all 0's in this case), the subsequent accumulations resulted in all red in ModelSim. 3rd, the clock enable pulse is not a single pulse when FOut (~19 MHz) is so close to the sampling clock, Fclk, at 24 MHz. I've noticed when the sampling clock, Fclk, is at least 10 times the generated clock, FOut, then it would work! Can you/anyone provide some inputs into how to generate a variable clock with fine resolution. Thank you.