Generando un reloj en FPGA en primitivas

Al leer las hojas de datos sobre los FPGA, puede encontrar signos sobre sus frecuencias operativas ... Pero



no, la historia comienza en 2015, cuando me familiaricé con los FPGA. En mis primeros trabajos simples, formé el reloj que necesitaba del contador y alimente toda la lógica (naturalmente, siempre que necesitara el reloj más lento de lo que se alimentó al FPGA, por ejemplo, UART y SPI). Naturalmente, me persiguieron por esto, pero tenía una simple excusa "¡pero funciona!", Y todo realmente funcionó. Desde entonces, la idea se me ha metido en la cabeza: "¿De dónde puedo obtener la señal de sincronización?"



No hay muchas opciones para que las fuentes tomen una pizca. Puede tomarlo de un cierto ClockWizard basado en PLL o MMCM, o formarlo desde un contador, o inmediatamente desde el tramo, por así decirlo, de un solo extremo. ¿Qué pasa si tomamos la señal de reloj generada por la primitiva FPGA?



Como parte de este artículo, decidí considerar tres opciones: un multiplexor (MUXF7), una tabla de verdad (LUT1) y cortocircuitar las piernas FPGA para ellos mismos.



En el caso de un multiplexor, la salida se alimenta a la señal de control y las señales de entrada se llevan a 0 y 1.



imagen


En el caso de LUT, cortocircuitamos la salida a la entrada y configuramos la tabla de verdad inversora. Al suministrar "1", salida cero, y al suministrar "0", salida uno.



imagen


En el caso de GPIO, todo es simple allí, a la señal de salida se le asigna el inverso de la señal de entrada:

asignar s2 = ~ s1;


El propósito del experimento: generar una frecuencia de tres maneras y medirla.

Mediremos la frecuencia a expensas de los contadores. Habrá 4 contadores: tres para cada opción y un contador básico, en relación con el cual se contará todo. Y veremos estos contadores a través de ChipScope.



Y aquí está el código completo del módulo:
module gen_clk(
    input clk_base,
    input s1, //gpio
    output s2 //gpio
    );

//  - 
assign s2 = ~s1;
wire clk_gpio = s1;
reg [31:0] cnt_gpio = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_gpio_buf = 0;
always@(posedge clk_gpio)
begin 
    if(cnt_gpio[2:0]==3'd0) cnt_gpio_buf<=cnt_gpio; 
    cnt_gpio <= cnt_gpio + 1'b1;
end

//  
wire clk_mux;
MUXF7 MUXF7_inst
(
    .O(clk_mux),
    .I0(1'b1),
    .I1(1'b0),
    .S(clk_mux)
);
reg [31:0] cnt_mux = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_mux_buf = 0;
always@(posedge clk_mux)
begin 
    if(cnt_mux[2:0]==3'd0) cnt_mux_buf<=cnt_mux; 
    cnt_mux <= cnt_mux + 1'b1;
end
//   
wire clk_lut;
LUT1#(
    .INIT(2'b01)
)
LUT1_inst(
    .O(clk_lut),
    .I0(clk_lut)
);
reg [31:0] cnt_lut = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_lut_buf = 0;
always@(posedge clk_lut)
begin 
    if(cnt_lut[2:0]==3'd0) cnt_lut_buf<=cnt_lut; 
    cnt_lut <= cnt_lut + 1'b1;
end
//         
 (* MARK_DEBUG="true" *) reg [31:0] cnt_base = 'd0;        
always@(posedge clk_base)
begin
    cnt_base <= cnt_base + 1'b1;
end    
   
endmodule




Aquí hay un esquema del proyecto. Las primitivas están encerradas en un círculo y las flechas indican la señal que se ingresará en el ChipScope para el análisis de frecuencia:



imagen




Parte práctica Tengo



tres tableros a mi disposición:



  1. Kit de evaluación KC705



    imagen


  2. Kit de evaluación ML507



    imagen


  3. Tablero chino Spartan-6 XC6SLX16



    imagen


    Mirando hacia el futuro
    , , .





Y ahora los resultados reales



Kintex-7:



desde que el proyecto comenzó a hacerse para él, el proyecto no se escribió por completo de una vez, sino por etapas. Primero, conecté un LUT, agregué señales a la depuración y comencé a mirar.



El contador base está sincronizado a 200 MHz, por lo que no es difícil calcular la frecuencia de los relojes generados en el botín, cuántas veces el contador delta del contador de botín es el delta del contador básico al mismo tiempo, tantas veces su frecuencia. En este caso: la frecuencia generada por el botín es de 381.55 MHz.



imagen


Ahora agregaremos un multiplexor al proyecto, y por analogía con un botín, calcularemos la frecuencia para él y para el botín (después de todo, algo debe cambiar).



imagen


Lo primero que llama la atención es cuánto tiembla el contador. Esto afecta la enorme frecuencia del multiplexor, pero en general está claro que el contador está aumentando, lo que significa que también se puede tomar y contar. Finalmente:



  • Frecuencia multiplexor: 5953.89 MHz
  • Frecuencia de botín (modificada): 379,98 MHz


Bueno, al final, agreguemos un ciclo cerrado de un par GPIO al proyecto. La placa KC705 tiene conectores SMA J13 y J14. Aquí los cerré con un conductor de unos 10 cm de largo. Como resultado:



  • Frecuencia GPIO: 90.59 MHz
  • Frecuencia multiplexor: 12994.13 MHz
  • Frecuencia de botín: 380.18 MHz


Reemplacemos, por el bien del experimento, el conductor con uno más largo, tengo un cable el doble de largo. Como resultado, la frecuencia cayó a 85.29 MHz.



En esta etapa del experimento, se puede observar que la frecuencia de operación de las primitivas en FPGA no es la misma. En el caso de que solo hubiera un botín, el sintetizador eligió el botín más rápido y construyó un circuito alrededor de él, luego, cuando se agregó el multiplexor, el sintetizador intentó encontrar esa súper posición donde tanto el botín como el multiplexor funcionan lo más rápido posible, y estos son otros elementos y frecuencias que ya son más lentos. Cuando se agregaron pines externos, todo el proyecto en un cristal se reubicó básicamente en estas patas y el proyecto comenzó a sintetizarse en elementos cercanos, por alguna razón, en ese lugar, las frecuencias del botín y el multiplexor aumentaron notablemente, pero no olvide que en el contexto de todo esto, al proyecto se conecta un ChipScope con una profundidad de 1024 y un bus de datos de 64 a 128 (cambia de proyecto a proyecto). Ahora pasemos al siguiente tablero.



Virtex-5:



No hice todo lo que hice con el tablero anterior, inmediatamente agregué las 3 opciones para generar una capa y busqué en ChipScope lo que sucedió.



imagen


La figura muestra dos etiquetas X y O. Además de sus valores en las columnas, el formato de los números es decimal sin signo. Vale la pena señalar que el contador base ahora cuenta a 100 MHz. Y entonces el resultado:



  • Frecuencia GPIO: 96.34 MHz
  • Frecuencia multiplexor: 614.41 MHz
  • Frecuencia de botín: 5761.1 MHz


Se puede ver que en este tablero el botín resultó ser más rápido que el multiplexor, y la frecuencia de los pines resultó ser más alta que en el primer tablero, tal vez esto se deba a que conecté los dos pines no con un conductor de 10 cm, sino con un puente, como resultado, la línea de comunicación se hizo más corta y la frecuencia fue más alta.



Y ahora la última opción con un tablero chino.



Spartan-6:



Hay dos contadores básicos en ChipScope, de hecho, es el mismo contador simplemente no quería reconfigurar ChipScope. En este proyecto, el contador básico está sincronizado a 50 MHz.



imagen


En el caso de esta placa, todo resultó ser mucho más complicado. En primer lugar, el proyecto no quería ser sintetizado de ninguna manera en la forma en que se sintetizó en las versiones anteriores. En segundo lugar, al final, tuve que tirar el LUT, traté de reemplazarlo por uno de cinco vías, pero tampoco funcionó. En general, aquí están los resultados:



  • Frecuencia GPIO: 51.77 MHz
  • Frecuencia del multiplexor: 3 490 504 MHz
  • Frecuencia de botín: no se pudo recopilar


Los resultados en el rendimiento de esta placa resultaron no ser del todo felices, y no solo porque el botín no podía usarse como un fragmento, sino también debido a la increíblemente enorme frecuencia del multiplexor. En cuanto a la trituración generada en las patas, se usó un conductor de aproximadamente 25-30 cm, al final cerrado con un cable, probablemente se formaron capacitancias parásitas e inductancias allí, lo que tuvo su efecto en la generación de la trituración.



Conclusión



En general, logramos generar señales de reloj en varias primitivas, y también logramos ver (usando el Kintex-7 como ejemplo) que las primitivas tienen una latencia diferente dependiendo de su ubicación. En mi propio nombre, quiero agregar que no considero que el experimento llevado a cabo sea completamente correcto, por ejemplo, no se calculó el ancho de bits de los contadores, no se tuvo en cuenta la transferencia de señal de diferentes dominios de marcado (aunque hice que la señal en el búfer permanezca durante varios ciclos de reloj), el ChipScope en sí mismo debería eliminarse idealmente y debería encontrarse otra forma Analizar la frecuencia generada.



Problemas encontrados:
Vivado ISE , . :



  • set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets -of_objects [get_cells gen_clk_inst/LUT1_inst]]
  • NET «s1» CLOCK_DEDICATED_ROUTE = FALSE;





All Articles