Generar un reloj de 100 Hz desde un reloj de 50 MHz en Verilog

6

Tengo una placa DE0 con un reloj de 50 Mhz que estoy intentando reducir a 100 Hz en Verilog. ¿Podría alguien ayudarme con el código para hacer esto?

    
pregunta ELL

1 respuesta

13

Construye un contador de 18 bits. Cada vez que llega a 250,000, alterna un flip-flop. 50 MHz / 250,000 = 200 Hz. Alternar un pin a 200 Hz le da 100 Hz con un ciclo de trabajo del 50 por ciento. Si solo necesita un pulso con una frecuencia de repetición de 100 Hz, genere un contador de 19 bits y genere un pulso cuando llegue a 500,000.

Afortunadamente, 250,000 y 500,000 son enteros pares. Generar un ciclo de trabajo perfecto del 50 por ciento con un divisor impar significa que debe activar la salida en un flanco ascendente y en un flanco descendente. En un Xilinx FPGA, esto se puede hacer con un ODDR / ODDR2 y un contador con un pequeño rasguño en la cabeza para configurar correctamente las entradas D0 / D1. Sin embargo, esto solo funciona para enviar la señal desde el chip a través de un pin de E / S, ya que la salida de un ODDR / ODDR2 no se puede usar dentro de un diseño. Sin embargo, un pulso es realmente todo lo que necesitas dentro de un diseño.

Generar cualquier cosa con una proporción no entera es más complicado. Si es una fracción racional, puede usar un PLL o DDS para ayudar, ya sea solo o en combinación con un contador. Si no es una fracción racional, entonces estás más o menos desafortunado a menos que puedas aproximarlo con una fracción racional. Si un PLL no está disponible, no irá lo suficientemente bajo, o si no puede obtener la proporción correcta de una combinación de PLL y contador, entonces puede usar un DDS fraccional. La idea con un DDS fraccional es agregar una constante a un acumulador en cada ciclo de reloj y alternar la salida cuando el acumulador gira. Esto producirá una salida con un poco de jitter, pero puede producir una frecuencia precisa en promedio. Para producir una onda cuadrada de 100 Hz con 50 por ciento de trabajo con un acumulador de 32 bits, todo lo que debe hacer es agregar 100 * 2 ^ 32 / 50e6 = 8589.93459 ~ = 8590 en cada ciclo de reloj. El MSB del acumulador cambiará a 50e6 / (2 ^ 32 * 8590) = 100.00076145 Hz. Cuanto más grande sea el acumulador, más preciso será este. La resolución de frecuencia de un acumulador de 32 bits es bastante buena: si sube o baja 1 LSB, obtiene 98.989119 o 100.012403 Hz. Sin embargo, obtendrá +/- 1 período de reloj de lo que se denomina fluctuación de fase determinista. En otras palabras, los bordes se cuantifican por período de reloj y, por lo tanto, pueden ser hasta 1/2 período de reloj temprano o tarde. A diferencia de la fluctuación de fase normal, si ve la fluctuación de fase determinista en un osciloscopio, verá una distribución muy bimodal de los tiempos de ciclo con dos o más promedios discretos, en oposición a una distribución uniforme. Además, como el .00076145 es un desplazamiento y no un promedio, la fase cambiará lentamente con respecto al reloj del sistema. Esto puede o no puede ser tolerable en su aplicación.

Ejemplo de verilog para generar 100 Hz desde 50 MHz con un ciclo de trabajo del 50%:

// generate 100 Hz from 50 MHz
reg [17:0] count_reg = 0;
reg out_100hz = 0;

always @(posedge clk_50mhz or posedge rst_50mhz) begin
    if (rst_50mhz) begin
        count_reg <= 0;
        out_100hz <= 0;
    end else begin
        if (count_reg < 249999) begin
            count_reg <= count_reg + 1;
        end else begin
            count_reg <= 0;
            out_100hz <= ~out_100hz;
        end
    end
end

Ejemplo de verilog para generar un pulso de 10 Hz de repetición de 100 Hz desde un reloj de 50 MHz:

// generate 100 Hz pulse chain from 50 MHz
reg [18:0] count_reg = 0;
reg out_100hz = 0;

always @(posedge clk_50mhz or posedge rst_50mhz) begin
    if (rst_50mhz) begin
        count_reg <= 0;
        out_100hz <= 0;
    end else begin
        out_100hz <= 0;
        if (count_reg < 499999) begin
            count_reg <= count_reg + 1;
        end else begin
            count_reg <= 0;
            out_100hz = 1;
        end
    end
end

Ejemplo de verilog para generar una salida de 10 MHz con un ciclo de trabajo del 50% desde un reloj de 250 MHz con un ODDR2 en un Spartan 6:

// generate 10 MHz from 250 MHz
// 25 cycle counter, falling edge interpolated
reg [4:0] count_reg = 0;
reg q0 = 0;
reg q1 = 0;

always @(posedge clk_250mhz or posedge rst_250mhz) begin
    if (rst_250mhz) begin
        count_reg <= 0;
        q0 <= 0;
        q1 <= 0;
    end else begin
        if (count_reg < 24) begin
            count_reg <= count_reg + 1;
        end else begin
            count_reg <= 0;
        end
        q0 <= count_reg < 12;
        q1 <= count_reg < 13;
    end
end

ODDR2
clk_10mhz_out_oddr2_inst
(
    .Q(clk_10mhz_out),
    .C0(clk_250mhz),
    .C1(~clk_250mhz),
    .CE(1),
    .D0(q0),
    .D1(q1),
    .R(0),
    .S(0)
);

Ejemplo de código verilog para generar 100 Hz desde 50 MHz con un ciclo de trabajo del 50% utilizando un acumulador:

// generate 100 Hz from 50 MHz
reg [31:0] count_reg = 0;
wire out_100hz = count_reg[31];

always @(posedge clk_50mhz or posedge rst_50mhz) begin
    if (rst_50mhz) begin
        count_reg <= 0;
    end else begin
        count_reg <= count_reg + 8590; //(((100 * 1 << 32) + 50000000/2) / 50000000)
    end
end
    
respondido por el alex.forencich

Lea otras preguntas en las etiquetas