Cómo dividir 50MHz hasta 2Hz en VHDL en Xilinx FPGA

12

Tengo una placa FPGA Xilinx, con un cristal de 50MHz. Necesito dividir eso a 2Hz en VHDL. ¿Cómo hago esto?

    
pregunta ABAYOMI STEPHEN

5 respuestas

18

Básicamente, hay dos formas de hacer esto. El primero es utilizar el núcleo del sintetizador de reloj nativo de Xilinx. Una de las ventajas de esto es que las herramientas Xlinx reconocerán el reloj como tal y lo guiarán a través de las vías requeridas. Las herramientas también manejarán cualquier restricción de tiempo (no es realmente aplicable en este caso, ya que es un reloj de 2Hz)

La segunda forma es usar un contador para contar el número de pulsos de reloj más rápidos hasta que haya pasado la mitad de su período de reloj más lento. Por ejemplo, para su caso, la cantidad de pulsos de reloj rápido que conforman un período de reloj de un ciclo de reloj lento es 50000000/2 = 25000000. Como queremos medio período de reloj, eso es 25000000/2 = 12500000 para cada semiciclo . (la duración de cada alta o baja).

Esto es lo que parece en VHDL:

library IEEE;
use IEEE.STD_LOGIC_1164.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.all;

entity scale_clock is
  port (
    clk_50Mhz : in  std_logic;
    rst       : in  std_logic;
    clk_2Hz   : out std_logic);
end scale_clock;

architecture Behavioral of scale_clock is

  signal prescaler : unsigned(23 downto 0);
  signal clk_2Hz_i : std_logic;
begin

  gen_clk : process (clk_50Mhz, rst)
  begin  -- process gen_clk
    if rst = '1' then
      clk_2Hz_i   <= '0';
      prescaler   <= (others => '0');
    elsif rising_edge(clk_50Mhz) then   -- rising clock edge
      if prescaler = X"BEBC20" then     -- 12 500 000 in hex
        prescaler   <= (others => '0');
        clk_2Hz_i   <= not clk_2Hz_i;
      else
        prescaler <= prescaler + "1";
      end if;
    end if;
  end process gen_clk;

clk_2Hz <= clk_2Hz_i;

end Behavioral;

Cosas a tener en cuenta:

  • El reloj generado es cero durante el reinicio. Esto está bien para algunas aplicaciones, y no para otras, solo depende de para qué necesita el reloj.
  • El reloj generado se enrutará como una señal normal mediante las herramientas de síntesis de Xilinx.
  • 2Hz es muy lento. Simular por un segundo va a tomar un tiempo. Es una pequeña cantidad de código, por lo que debería ser relativamente rápido para simular incluso durante 1 segundo, pero si comienza a agregar código, el tiempo necesario para simular un ciclo de reloj de 2 Hz podría ser significativamente largo.

EDIT: clk_2Hz_i se utiliza para amortiguar la señal de salida. A VHDL no le gusta usar una señal a la derecha de una asignación cuando también es una salida.

    
respondido por el stanri
9

Use un prescaler de reloj.

Su valor de prescaler será su (clock_speed / desired_clock_speed) / 2 así que (50Mhz (50,000,000) / 2hz (2)) / 2 = 12,500,000 que en binario sería 101111101011110000100000.

Más simplemente: (50,000,000) / 2) / 2 = 12,500,000 convertir a binario - > 101111101011110000100000

Aquí hay un código de qué hacer: Use newClock para lo que necesite 2Hz para ...

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ClockPrescaler is
    port(
        clock   : in STD_LOGIC; -- 50 Mhz
        Led     : out STD_LOGIC
    );
end ClockPrescaler;

architecture Behavioral of ClockPrescaler is
    -- prescaler should be (clock_speed/desired_clock_speed)/2 because you want a rising edge every period
    signal prescaler: STD_LOGIC_VECTOR(23 downto 0) := "101111101011110000100000"; -- 12,500,000 in binary
    signal prescaler_counter: STD_LOGIC_VECTOR(23 downto 0) := (others => '0');
    signal newClock : std_logic := '0';
begin

    Led <= newClock;

    countClock: process(clock, newClock)
    begin
        if rising_edge(clock) then
            prescaler_counter <= prescaler_counter + 1;
            if(prescaler_counter > prescaler) then
                -- Iterate
                newClock <= not newClock;

                prescaler_counter <= (others => '0');
            end if;
        end if;
    end process;


end Behavioral;
    
respondido por el MLM
7

Por lo general, en realidad no quieres ver nada tan lento, solo crea una habilitación a la velocidad correcta y úsala en la lógica:

 if rising_edge(50MHz_clk) and enable = '1' then

puedes crear la habilitación de esta manera:

process 
   variable count : natural;
begin
   if rising_edge(50MHz_clk) then
       enable <= '0';
       count := count + 1;
       if count = clock_freq/desired_freq then
          enable <= '1';
          count := 0;
       end if;
    end if;
end process;

cree un par de constantes con su frecuencia de reloj y la frecuencia de habilitación deseada y listo, con un código de auto-documentación para arrancar.

    
respondido por el Martin Thompson
3

Prefiero sugerir el uso de IP de IPilinx primitice digital clock manager .

Tiene una interfaz de configuración gráfica donde puede especificar qué frecuencia desea. Generará un componente con la salida deseada como frecuencia.

Se puede encontrar en el Asistente de IP;

Yluegopodrásespecificarquéfrecuenciaquieres:

    
respondido por el Arturs Vancans
0

Factor = entrada-señal-frecuencia / salida-prescaler-frecuencia.

CE = Reloj habilitado. Debe ser un pulso ancho de un reloj (clk) o alto si no se usa.

Q = Señal de salida de un pulso de ancho de reloj con la frecuencia deseada.

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity prescaler is

  generic (
    FACTOR : integer);

  port (
    clk : in  std_logic;
    rst : in  std_logic;
    CE  : in  std_logic;
    Q   : out std_logic);

end prescaler;

architecture for_prescaler of prescaler is
  signal counter_reg, counter_next : integer range 0 to FACTOR-1;
  signal Q_next: std_logic;
begin  -- for_prescaler

  process (clk, rst)
  begin  -- process
    if rst = '1' then                   -- asynchronous reset (active low)
      counter_reg <= 0;
    elsif clk'event and clk = '1' then  -- rising clock edge
      counter_reg <= counter_next;
    end if;
  end process;

  process (counter_reg, CE)
  begin  -- process
    Q_next <= '0';
     counter_next <= counter_reg;
     if CE = '1' then
        if counter_reg = FACTOR-1  then
          counter_next <= 0;
           Q_next <= '1';
         else
           counter_next <= counter_reg + 1;
        end if;
      end if;
  end process;

  process (clk, rst)
  begin  -- process
    if rst = '1' then                   -- asynchronous reset (active low)
      Q <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      Q <= Q_next;
    end if;
  end process; 

end for_prescaler;
    
respondido por el Roger Garzon Nieto

Lea otras preguntas en las etiquetas