Dual Edged Counter

Discussion in 'VHDL' started by Cory Shol, Apr 17, 2013.

  1. Cory Shol

    Cory Shol Guest

    Hi All,

    I am researching ways onto create a dual edged Counter.

    Problem details:

    Original Clock = 25 MHz Put the Original clock through a PLL and multiply it by 5 making a new: Clk_125MHz = 125 MHz clock.

    Using the 125 MHz clock, I want to use a 9 bit register [Called Duty_cycle] to state the Duty cycle of a PWM.
    For example if the Duty_cycle = "011111111" it will have a 50% duty cycle. Duty_cycle = "1111111110" it will have a ~0.2% duty cycle etc...

    The period of the PWM is 4096 ns (125 Mhz/ 2^9) = 125000000/512 = 244KHz =1/244KHz= 4096 ns.
    Code looks something like:

    process(clk_125Mhz, reset)

    begin
    if (reset = '1') then
    dc_count_i <= X"00" &'0'; -- you can use others statement as well.
    elsif(rising_edge(clk_125Mhz)) then
    if(dc_count_i < duty_cycle) then
    duty_out <='0';
    else
    duty_out <= '1';
    end if;
    dc_count_i <= dc_count_i + 1;
    end if;
    end process;

    Alright this is all fine and works decent.

    Now the extension I want to make my PWM have a period of 2048 ns. There are three ways I can think of to do this:
    1) PLL the clock to 250 MHz ( Do not want to run at Max frequency in the device)
    2) Change the 9 bit Duty Cycle register to 8 bits (Lower the resolution)
    3) Every time there is a rising or falling edge count up the counter

    This is coming back to topic title: to create a dual Edged Counter that can generate a duty cycle of a PWM.

    I tried something like:
    ------------------------------------------------------
    process(clk_125Mhz, reset)

    begin
    if (reset = '1') then
    rise_counter <= X"00" &'0';
    elsif(rising_edge(clk_125Mhz)) then

    rise_counter <= rise_counter + 2;
    end if;
    end process;

    process(clk_125Mhz, reset)

    begin
    if (reset = '1') then
    fall_counter <= X"00" &'1';
    elsif(falling_edge(clk_125Mhz)) then
    fall_counter <= fall_counter + 2;
    end if;
    end process;


    process(xor_counter, final_counter)
    begin
    final_counter <= final_counter + 1;
    end process;


    xor_counter <= rise_counter XOR fall_counter;

    dc_count <= final_counter;

    duty_out <= '0' when (final_counter < duty_cycle) else '1';

    But this creates a Combinatorial loop.

    I tried:
    ---------------------------------------------------

    process(clk_125Mhz, reset)

    begin
    if (reset = '1') then
    rise_counter <= X"00" &'0';
    elsif(rising_edge(clk_125Mhz)) then

    rise_counter <= rise_counter + 2;
    end if;
    end process;

    final_counter <= rise_counter when clk_125Mhz ='1' else (rise_counter or "000000001");

    duty_out <= '0' when (final_counter < duty_cycle) else '1';

    But this produced a glitch in simulation.

    Does anyone else have any other ideas, on how to implement a dual edged counter? I feel like this should be an easy solution, I just keep thinking too complex.
     
    Cory Shol, Apr 17, 2013
    #1
    1. Advertisements

  2. Cory Shol

    GaborSzakacs Guest

    Is the output of the PWM going to a pin that is supported by a DDR
    output flop? If so, then you could simply reduce the counter
    by one bit, but compare it with the upper bits of the duty cycle
    input. If the LSB of the duty cycle is zero, then the output DDR
    flop D inputs go from 11 to 00, but the it is 1, then the D inputs
    go from 11 to 10 to 00 as you pass the duty cycle threshold.
    No internal dual edges, no glitches.
     
    GaborSzakacs, Apr 17, 2013
    #2
    1. Advertisements

  3. Cory Shol

    Cory Shol Guest

    The research is for an Microsemi Actel Igloo AGL1000. I don't think it has a DDR output flop.
     
    Cory Shol, Apr 17, 2013
    #3
  4. Cory Shol

    GaborSzakacs Guest

    Realize that without an output DDR flop, there will be some influence
    of routing delays between even and odd values of duty cycle, but the
    same approach of using a shorter counter to make the PWM with half the
    resolution could work. Follow that with a single flop on the falling
    clock edge. Then you have two PWM signals offset by half a clock cycle.
    At the output, you would either select the first, or the OR of the two
    signals based on the LSB of duty cycle. Again no glitches, but the
    monotonicity could suffer slightly.
     
    GaborSzakacs, Apr 17, 2013
    #4
  5. Cory Shol

    Cory Shol Guest

    THE DDR flip flop got me thinking. So I went back and looked at Spartan 3A user guide to see the DDR flip flop.

    I then looked for a similar flip flop in the Actel AGL1000 and it indeed does have a DDR register input or output type.

    Even after working 2 years in Logic design I still feel like I know nothing.
     
    Cory Shol, Apr 17, 2013
    #5
  6. Cory Shol

    rickman Guest

    I know the feeling. There is just so much to learn.

    Are you looking for an *average* PWM on the pin or does it need to be
    exact on every cycle? If the average value is what is important you can
    use a fractional divider which should be easier and can get you even
    more precision.

    A fractional divider just counts the number of PWM cycles and
    periodically adds or subtracts one from the duty_cycle value. This can
    be done in a manner that is not actually periodic so that the side tones
    it introduces are spread out and at a low level if that is important.

    You might also consider using a DCO. I tried to do that for a few
    minutes and couldn't think of how that would work. But I'm pretty sure
    there is a way. I'm just drawing a blank at the moment. A DCO will
    give you a much more precise average value with one clock cycle of
    jitter on the edge, similar to the fractional divider, but easier to tune.
     
    rickman, Apr 17, 2013
    #6
  7. Cory Shol

    rickman Guest

    Ok, brain cramp over...

    Use a DCO to generate a ramp signal in as many bits as you want. The
    step size will set the rate at which it rolls over and so the PWM
    frequency. Since the DCO can be lots of bits, the duty_cycle can be
    more bits than with a simple counter. So the point in the cycle where
    the counter is above the duty_cycle will jitter around a clock edge, but
    the average can be very precise, as long as your step_size is not an
    integer ratio to the modulus. You need the steps to walk around the
    number space.
     
    rickman, Apr 17, 2013
    #7
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.