El divisor de frecuencia funciona solo para algunos divisores (Verilog en Lattice iCEstick FPGA)

3

Estoy tratando de construir un divisor de frecuencia en un iCEstick de Lattice usando Verilog (con yosys, arachne-pnr, y icepack / iceprog):

 module demo(input clk, output LED1, LED2, LED3, LED4, LED5);

   assign LED1 = state;

   // Generate impulse at lower frequency:                                                                                                                          
   wire out_clk;
   reg [31:0] cnt;
   initial cnt <= 0;
   always @(posedge clk) cnt <= cnt >= 6000000 ? 0 : cnt + 1;
   assign out_clk = cnt == 0;

   // On impulse, toggle state:                                                                                                                                     
   reg state;
   initial state <= 0;
   always @(posedge out_clk) state <= ~state;

endmodule

Esto funciona como se esperaba, es decir, el LED en la placa parpadea una vez por segundo (el reloj es de 12MHz).

Sin embargo, cuando 6000000 ('h5B8D80) se reemplaza por 5000000 (' h4C4B40), el LED simplemente permanece encendido permanentemente. ¿Por qué es eso?

Simulando con Icarus muestra los cambios de estado esperados, sin importar cuál sea el divisor.

Aquí hay una tabla de experimentos con más valores:

'h5B8D80 blinking
'h5B8D7f permanently on
'h5B8D7e blinking
'h5B8D7d blinking
'h5B8D7c blinking
'h5B8D78 blinking
'h5B8D70 blinking
'h5B8D60 blinking
'h5B8D40 blinking
'h5B8D00 blinking
'h5B8C80 blinking
'h4C4B40 permanently on
'h400000 blinking

También, para 'h4C4B40 agregando la línea "asignar LED2 = 1;" hace que LED1 (!) parpadee como se esperaba. Este no es el caso para 'h5B8D7f.

En conjunto, el comportamiento parece muy aleatorio.

EDITAR Para el registro, al sintetizar el mismo diseño con iCEcube2 de Lattice, el problema no se produce.

    
pregunta Maxim

2 respuestas

1

Si usa contadores largos (32 bits) con relojes bastante rápidos (12 MHz), puede haber un problema al usar contadores sin una lógica de acarreo anticipado. El acarreo de rizado necesita tanto tiempo de LSB a MSB que el siguiente impulso de reloj estará en la entrada antes de que la señal de acarreo de rizo haya alcanzado los bits más altos del contador. Si el acarreo de ondulación tiene que recorrer un largo camino desde la entrada del reloj hasta la MSB, no queda tiempo cuando todos los bits de contador se mantienen estables en el mismo momento. La comparación del estado del contador con el valor máximo ya no es posible. Un mejor enfoque es usar un contador de abajo cargado el factor de división cada vez que se realiza una cuenta regresiva a cero. Es mucho más fácil detectar el estado cero cuando todos los bits de contador son 0, invierte todos los bits y los alimenta a una entrada y compuerta de 32 entradas. En lugar de usar un contador muy largo, es mejor usar un prescaler dividiendo por 16 y un contador con solo 28 en lugar de 32 bits. Por cierto, para un valor de contador máximo de 6E6, solo necesita 23 bits, no 32. Puede usar un preescalador que se divide entre 8 y un contador de 20 bits solamente.

    
respondido por el Uwe
1

Supongo que su sintetizador está tratando a assign out_clk = cnt == 0; como lógica combinacional pura. Dado que la lógica y el enrutamiento son diferentes para cada valor máximo de reloj, esto podría sesgar el retraso parasitario. Por lo tanto, el pulso out_clk podría ser demasiado corto o inestable para activar un cambio state .

Una línea de clan general es mantener los relojes derivados limpios y sin problemas.

Una opción es hacer que out_clk sea un flop.

initial begin
  cnt <= 0;
  state <= 0;
  out_clk <= 0;
end
always @(posedge clk) begin
  cnt <= cnt >= 6000000 ? 0 : cnt + 1;
  out_clk <= cnt == 0;
end
always @(posedge out_clk) begin
  state <= ~state;
end

O ya que realmente no necesitas un reloj derivado; solo usa un bloque siempre:

initial begin
  cnt <= 0;
  state <= 0;
end
always @(posedge clk) begin
  cnt <= cnt >= 6000000 ? 0 : cnt + 1;
  if (cnt == 0) begin 
    state <= ~state;
  end
end

Como nota final, compruebe las advertencias en el archivo de registro de síntesis. A veces, los problemas de tiempo se informan como advertencias y no errores. Siempre intente resolver las advertencias y, si no puede, comprenda cuáles son.

    
respondido por el Greg

Lea otras preguntas en las etiquetas