C
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.
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.