Search code examples
vhdlfpgahdl

Pulse generator in VHDL with any frequency


I am doing this project that will output a desired frequency. For most frequencies i can make valid code, but when it comes to frequency like 300 Hz I'm having trouble.

So here is my code for most of them:

library ieee;
use ieee.std_logic_1164.all;    

entity test is
port(
    clk:in std_logic:='0';
    clk_o:buffer std_logic:='0'
);
end test;

architecture Behavioral of test is
begin
process(clk)
variable temp:integer range 0 to 1000000:=0;
begin
if(clk'event)then
    temp:=temp+1;
    if(temp>=1000000)then
        clk_o<=not clk_o;
        temp:=0;
    end if;
end if;
end process;
end Behavioral;

This will generate frequency of 50 Hz because the clock speed of my FPGA is 50 MHz. So first I tried to divide it, but problem is that you can't generate 300 Hz because 50*10^6/300 is 166666.667 and so on.

Then I saw that you can make time type of variable and make period last 1/300 but then i realized it is not synthesis eligible so it's no good. Also goes with REAL type of variable that could make it more accurate then integer variable but it's also not synthesis eligible.

So I'm out of ideas, if anyone can give me some hint I would much appreciate it.


Solution

  • If you just use 166666 you will only be too fast by 0.0004% or 4ppm. This is such a small error that it typically won't matter in a real implementation - your 50MHz oscillator probably has more error than that.
    [EDIT: as noted in the comments, crystal oscillators are likely to have 10-20ppm error, but there are other types of oscillators that have much higher or lower error (although the 50MHz FPGA clock is probably a crystal)]

    If you really need to get rid of that 0.0004% error, you can use a DCM/MMCM/PLL (depending on the capabilities of your FPGA) to multiply your 50MHz clock to 150MHz first which will divide evenly to 300 Hz.

    As Brian Drummond mentioned, you could also use a 0-2 counter to count to 166667 2 out of every 3 cycles and to 166666 on the other, which will avoid cumulative phase error if you were trying to remain in-phase with a perfectly ideal 300MHz source.

    The fact that no real oscillators are perfectly matched to the advertized frequency is why RS232 re-syncs to the clock (to avoid cumulative phase error) frequently and why higher speed transfers use source synchronous clocking or Clock-and-data-recovery PLLs.