Clockgenerator in VHDL

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Dieses Modul dient zur Erzeugung einer beliebigen Frequenz ohne spezielle FPGA-Resourcen zu verwenden. Die Ausgangsfrequenz ist natürlich nur dann jitterfrei, wenn sich die Eingangsfrequenz ganzzahlig durch die Ausgangsfrequenz teilen lässt.

Aber z.B. für RS232 ist keine jitterfreie Frequenz notwendig, dafür könnte man dieses Modul verwenden (vor allem für sehr hohe Baudraten).

Es wird für jede halbe Taktperiode eine Division mit Rest durchgeführt. Der Rest der vorherigen Division wird bei der nächsten halben Taktperiode wieder mit eingerechnet. So erhält man im mittel die gewünschte Ausgangsfrequenz.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;



entity ClockDivide is
  generic (
    InputFreq  : integer := 50000000;
    OutputFreq : integer := 9600
  );
  port (
    RST           : in std_logic;
    CLK           : in std_logic;
    CLKOUT        : out std_logic;
  );
end ClockDivide;



architecture rtl1 of ClockDivide is

  -- log2 is used to get the MSB+1 of val
  function log2 (val: INTEGER) return natural is
    variable res : natural;
  begin
        for i in 0 to 31 loop
            if (val <= (2**i)) then
                res := i;
                exit;
            end if;
        end loop;
        return res;
  end function log2;
  
  function max(L, R: integer) return integer is
  begin
      if L > R then
          return L;
      else
          return R;
      end if;
  end;
  
  -- Greatest common divisor
  function GCD(v1 : integer; v2 : integer) return integer is
    variable a : integer;
    variable b : integer;
    variable h : integer;
  begin
    a := v1; b := v2;
    while (b /= 0) loop
      h := a mod b;
      a := b;
      b := h;
    end loop;
    return a;
  end;
  
  CONSTANT tmpGCD        : integer := GCD(2 * OutputFreq , InputFreq);
  CONSTANT Multiplikator : integer := 2 * OutputFreq / tmpGCD; -- Multiply by 2 because we generate clock edges
  CONSTANT Teiler        : integer := InputFreq / tmpGCD;
  CONSTANT N : integer := max(log2(Multiplikator), log2(Teiler));
  
  -- Clock mutliplier
  CONSTANT m : unsigned(N-1 downto 0) := to_unsigned(Multiplikator, N);
  -- Clock divisor
  CONSTANT d : unsigned(N-1 downto 0) := to_unsigned(Teiler, N);

  -- Counter register
  SIGNAL a : unsigned(N-1 downto 0) := to_unsigned(0, N);
  -- Output latch
  SIGNAL q : STD_LOGIC := '0';
  
begin
  
  -- Connect q with output
  CLKOUT <= q;
  
  -- Clock division with remainder
  pDiv: process(RST, CLK)
  begin
    if RST = '1' then
      a <= to_unsigned(0,N);
      q <= '0';
    elsif rising_edge(CLK) then
      if a > d then
        -- Subtract d to prevent overflow
        -- a will now hold the remainder of the division
        a <= a + m - d;
        -- Toggle the output
        q <= NOT q;
      else
        -- increase a by multiplier
        a <=  a + m;
      end if;
    end if;
  end process pDiv;

end rtl1;
-- EOF