Verilog Práctico

Capítulo 3. Prescaler y contadores.

2 de enero de 2021

En este capítulo veremos dos elementos muy útiles, el contador y el prescaler. El primer elemento intuimos para qué sirve, el segundo se utiliza para dividir la frecuencia del reloj del sistema en frecuencias menores.


1. Prescaler


1.1 Prescaler de 8 bits.


Tenemos una entrada clk que es el reloj del sistema y un registro de salida de 8 bits que llamamos cont y que declaramos así: output reg [7:0] cont. Podemos hacer el símil de que un registro es un bus de datos.


Cuando declaramos una salida como un registro quiere decir que ese registro almacena bits, sin embargo cuando declaramos con wire lo que hacemos es conectar entradas y salidas; wire no almacena el valor de ningún bit.


El código para el prescaler de 8 bits es el siguiente:



//-- prescaler 8 bits

//-- clk - reloj del sistema

//-- reg [7:0] cont - registro de salida de 8 bits

module prescaler(input clk, output reg [7:0] cont);


wire clk;


//-- con cada flanco de subida del reloj, se incrementa el contador

always @(posedge clk) begin

  cont <= cont + 1;

end

endmodule



Asignamos del pin 21 a la señal clk, porque en el pinout de la Alhambra vemos que el reloj del sistema es el pin 21. A cada uno de los 8 bits del registro cont le asignamos un led en la Alhambra. El número entre corchetes cont[X] es cada uno de los bits del registro.


El archivo pcf queda así:


set_io clk 21

set_io cont[7] 95

set_io cont[6] 96

set_io cont[5] 97

set_io cont[4] 98

set_io cont[3] 99

set_io cont[2] 101

set_io cont[1] 102

set_io cont[0] 104 


Lo compilamos y subimos a la Alhambra y lo que vemos son los 8 ledes encendidos.

¿Qué ha pasado? Lo que sucede es que como el reloj del sistema es de 12 MHz el contador se incrementa tan deprisa que los ledes aparecen siempre encendidos. 

1.2 Prescaler de 24 bits


Para ver la diferencia vamos a hacer un prescaler de 24 bits y sacaremos por los ledes, los 8 bits más significativos.


Declaramos como salidas los 8 ledes de la Alhambra dentro de module prescaler()


output led0, led1, led2, led3, led4, led5, led6, led7


Declaramos un contador de 24 bits 


reg [23:0] cont; 


Asignamos a cada uno de los ledes, un bit del registro cont


assign ledX = cont [XX];


Lo ponemos todo junto y el código queda así:


//-- prescaler 24 bits

//-- clk - reloj del sistema


module prescaler(input clk, output led0, led1, led2, led3, led4, led5, led6, led7);


wire clk;

wire led0, led1, led2, led3, led4, led5, led6, led7;

reg [23:0] cont;


assign led0 = cont [23];

assign led1 = cont [22];

assign led2 = cont [21];

assign led3 = cont [20];

assign led4 = cont [19];

assign led5 = cont [18];

assign led6 = cont [17];

assign led7 = cont [16];


//-- con cada flanco de subida del reloj, se incrementa el contador

always @(posedge clk) begin

  cont <= cont + 1;

end

endmodule


Archivo pcf con asignación de E/S:


set_io clk 21

set_io led0 95

set_io led1 96

set_io led2 97

set_io led3 98

set_io led4 99

set_io led5 101

set_io led6 102

set_io led7 104 


Lo subimos a la Alhambra y vemos parpadear los 6 bits más significativos. ¡Hemos dividido las frecuencias hasta hacerlas visibles al ojo humano!


Sigue leyendo para ver un ejemplo de aplicación.

2. Contadores


Como su nombre indica los contadores sirven para contar eventos. 


En los siguientes ejemplos veremos dos contadores, el primero de 4 bits que se incrementa de manera manual cada vez que pulsamos el SW1 de la Alhambra. El segundo contador -de 8 bits- se incrementa de manera automática, con una tasa que seleccionamos mediante un prescaler como los que hemos visto más arriba.


2.1 Contador de 4 bits.


// contador manual de 4 bits por flanco de SW1

module counter(input SW1, output reg [3:0] counter);

always @(posedge SW1)

begin

  counter <= counter + 1;

end

endmodule


El archivo pcf asociado es:


set_io SW1  10

set_io counter[3] 95

set_io counter[2] 96

set_io counter[1] 97

set_io counter[0] 98 


Lo subimos a la Alhambra y con cada pulsación de SW1 vemos como se incrementa el contador. El resultado se muestra en los ledes 0 a 3.

2.2. Contador automático de 8 bits.


Cómo hacer un contador automático de 8 bits. La frecuencia de refresco la seleccionaremos mediante el uso de un prescaler.


Declaramos la entrada de reloj y el contador de 8 bits como salida, para ver su valor en los 8 ledes de la Alhambra.


module counter(input clk, output reg [7:0] counter); 


Declaramos los relojes clk y clk_cont y un registro de 24 bits para el prescaler.


wire clk;             // reloj del sistema

wire clk_cont;              // reloj auxiliar para el contador

reg [23:0] prescaler = 0;   // registro prescaler inicializado a 0 


Asignamos la frecuencia de refresco al bit 17 del prescaler.


assign clk_cont = prescaler[17]; 


El registro prescaler se incrementa con cada flanco del reloj del sistema.


always @(posedge clk)

begin

  prescaler <= prescaler + 1;

end


Sin embargo el contador se incrementa con cada flanco de clk_cont.


always @(posedge clk_cont)

begin

  counter <= counter + 1;

end

endmodule


Lo ponemos todo junto y el código queda así:


// contador automatico de 8 bits con prescaler

module counter(input clk, output reg [7:0] counter);


wire clk;

wire clk_cont;              // reloj auxiliar para el contador

reg [24:0] prescaler = 0;   // registro prescaler


// asignamos la frecuencia de refresco al bit 17 del prescaler

assign clk_cont = prescaler[17];


// el registro prescaler se incrementa con cada flanco del reloj del sistema

always @(posedge clk)

begin

  prescaler <= prescaler + 1;

end


/*

    el contador se incrementa con cada flanco de clk_cont

    que equivale al bit 17 del prescaler

*/

always @(posedge clk_cont)

begin

  counter <= counter + 1;

end

endmodule


El archivo pfc queda así:


set_io clk 21

set_io counter[7] 95

set_io counter[6] 96

set_io counter[5] 97

set_io counter[4] 98

set_io counter[3] 99

set_io counter[2] 101

set_io counter[1] 102

set_io counter[0] 104 



Lo compilamos y subimos a la Alhambra. Vemos como el contador se incrementa de manera automática. Podemos seleccionar la velocidad tan solo modificando el bit que asignamos al reloj auxiliar en assign clk_cont = prescaler[17];


Eso es todo, espero que os haya gustado.


¡Hasta la próxima!

Links


Open FPGA Verilog tutorial. Capítulo 5: Prescaler de N bits

Open FPGA Verilog tutorial. Capítulo 4: Contador de 26 bits