FPGARelated.com
Forums

duty cycle of clock divider

Started by promach September 21, 2017
http://www.fpga4fun.com/MusicBox1.html

The frequency is 440Hz, as expected, but the output duty cycle is not 50% anymore. The low level goes from counter=0 to counter=32767 (when bit 15 of counter is low) and then high level from 32768 to 56817. That gives us "speaker" being high only 42% of the time. The easiest way to get a 50% duty cycle is to add a stage that divides the output by 2. So first we divide by 28409 (instead of 56818) and then by 2.  ???? 

I do not understand why we need to divide by 2.
Could anyone explain the above reasoning in more laymen way ?
On 21/09/2017 13:32, promach wrote:
> http://www.fpga4fun.com/MusicBox1.html > > The frequency is 440Hz, as expected, but the output duty cycle is not 50% anymore. The low level goes from counter=0 to counter=32767 (when bit 15 of counter is low) and then high level from 32768 to 56817. That gives us "speaker" being high only 42% of the time. The easiest way to get a 50% duty cycle is to add a stage that divides the output by 2. So first we divide by 28409 (instead of 56818) and then by 2. ???? > > I do not understand why we need to divide by 2. > Could anyone explain the above reasoning in more laymen way ? >
He means divide the frequency by 2, implemented by a single stage counter flip flop. This will then always give a 50% duty cycle.
I do not get how just dividing by 2 could get 50% duty cycle instead of 42% ?
On 21/09/2017 15:29, promach wrote:
> I do not get how just dividing by 2 could get 50% duty cycle instead of 42% ? >
Assuming the input frequency to the divider is constant, then:- that frequency is defined by the reciprocal of the time period that elapses between successive rising or falling or some fixed point in the repetitive waveform ... True or false ... If true then if you clock a flip flop at the fixed point in the repetive waveform then the outout will toggle high for one complete period of the input waveform, and toggle low for one complete period of the input waveform. If the frequency is constant, then the period of successive cycle of the input waveform will be the same. Therefore the output of the flip flop divider will have a 50% duty cycle. If false then it is not a constant input frequency and all the above does not apply. Andy
Strange, I have the clock divider coding at http://www.edaplayground.com/x/gXC

but it does not divide accordingly as mentioned in the article.

Any idea about what I missed out ?



// Adapted from http://www.fpga4fun.com/MusicBox1.html

module clk_div (i_clk, ck_stb);
  
  input i_clk;
  output reg ck_stb = 0;
  
  localparam THRESHOLD = 3;  // divides i_clk by (2*THRESHOLD = 6) to obtain ck_stb which is the divided clock signal
  
  reg [($clog2(THRESHOLD)-1):0] counter = 0;
  reg counter_reset = 0;
  
  always @(posedge i_clk)
    counter_reset <= (counter == THRESHOLD-1'b1);
  
  always @(posedge i_clk)
  begin
    if(counter_reset)
      counter <= 1;    
    else
      counter <= counter + 1;
    
    //$display("$clog2(THRESHOLD) = ", $clog2(THRESHOLD));
  end
  
  always @(posedge i_clk)
    ck_stb <= ~ck_stb;
  
endmodule
I have tried clock divider at http://www.edaplayground.com/x/gXC , but it does not divide accordingly as mentioned in the article.

Any idea about what I missed out ?

// Adapted from http://www.fpga4fun.com/MusicBox1.html

module clk_div (i_clk, ck_stb);
  
  input i_clk;
  output reg ck_stb = 0;
  
  localparam THRESHOLD = 3;  // divides i_clk by (2*THRESHOLD = 6) to obtain ck_stb which is the divided clock signal
  
  reg [($clog2(THRESHOLD)-1):0] counter = 0;
  reg counter_reset = 0;
  
  always @(posedge i_clk)
    counter_reset <= (counter == THRESHOLD-1'b1);
  
  always @(posedge i_clk)
  begin
    if(counter_reset)
      counter <= 1;    
    else
      counter <= counter + 1;
    
    //$display("$clog2(THRESHOLD) = ", $clog2(THRESHOLD));
  end
  
  always @(posedge i_clk)
    ck_stb <= ~ck_stb;
  
endmodule

I have found out the bug.

The last always block should look like the following:


  always @(posedge i_clk)
    if(counter_reset)
      ck_stb <= ~ck_stb;
@Andy

For ambulance siren at http://www.fpga4fun.com/MusicBox2.html and http://www.edaplayground.com/x/5aSK , could you comment on the simulation waveform   https://i.imgur.com/gN0cqAJ.png   ?

Note: I will do the actual hardware (speaker) audio testing tomorrow.



// http://www.fpga4fun.com/MusicBox2.html  - Ambulance siren

module clk_div (i_clk, ck_stb);
  
  input i_clk;
  output reg ck_stb = 0;
  
  localparam THRESHOLD = 6;  // divides i_clk by 6 to obtain ck_stb which is the divided clock signal
  localparam TOGGLE_FREQUENCY_RATIO = 4;  // MSB bit of "tone" toggles with a frequency of about [i_clk / 2^4]
  
  reg [($clog2(THRESHOLD) - 1):0] counter = 0;
  reg counter_reset = 0;
  
  reg [(TOGGLE_FREQUENCY_RATIO - 1):0] tone = 0;
  
  always @(posedge i_clk) 
    tone <= tone+1;
  
  always @(posedge i_clk)
    if(tone[TOGGLE_FREQUENCY_RATIO-1])
      counter_reset <= (counter == THRESHOLD - 1'b1);
    else
      counter_reset <= (counter == (THRESHOLD >> 1) - 1'b1);
  
  always @(posedge i_clk)
  begin
    if(counter_reset)
      counter <= 1;    
    else
      counter <= counter + 1;
    
    //$display("$clog2(THRESHOLD) = ", $clog2(THRESHOLD));
  end
  
  always @(posedge i_clk)
    if(counter_reset)
      ck_stb <= ~ck_stb;
  
endmodule
On 21/09/2017 17:52, promach wrote:
> I have tried clock divider at http://www.edaplayground.com/x/gXC , but it does not divide accordingly as mentioned in the article. > > Any idea about what I missed out ? > > // Adapted from http://www.fpga4fun.com/MusicBox1.html > > module clk_div (i_clk, ck_stb); > > input i_clk; > output reg ck_stb = 0; > > localparam THRESHOLD = 3; // divides i_clk by (2*THRESHOLD = 6) to obtain ck_stb which is the divided clock signal > > reg [($clog2(THRESHOLD)-1):0] counter = 0; > reg counter_reset = 0; > > always @(posedge i_clk) > counter_reset <= (counter == THRESHOLD-1'b1); > > always @(posedge i_clk) > begin > if(counter_reset) > counter <= 1; > else > counter <= counter + 1; > > //$display("$clog2(THRESHOLD) = ", $clog2(THRESHOLD)); > end > > always @(posedge i_clk) > ck_stb <= ~ck_stb; > > endmodule >
I'm guessing you have declared output register, which just defines the output state. You should have just declared a register (reg?) which has both an input and output state.