viernes, 17 de marzo de 2023

120 - Divisor de Frecuencia

 Circuito Divisor de Frecuencia

Fig1. Salida del Divisor
 

Saludos cordiales, en esta entrada, veremos como describir un circuito divisor de frecuencia con dispositivos biestables. Este trabajo complementa el avance académico para la materia de Sistemas Digitales II, siendo requisito que el lector ya tenga conocimientos básicos sobre el diseño de circuitos digitales, lenguaje verilog y dispositivos lógicos programables.

Para elaborar el código  del modulo y llevar a cabo pruebas de funcionamiento, utilizaremos uno de los siguientes programas:

Operación del circuito divisor

Es un circuito que permite incrementar en múltiplos de dos el periodo de una señal del reloj, donde la relación para este incremento en la señal de salida dependerá del numero de biestables conectados en serie.

Por ejemplo si conectamos dos Flip Flop JK en serie, tal como se observa en la imagen, la relación de salida con respecto a la entrada en el divisor sera 1:4.

Fig2. Circuito Divisor 1:4
La salida del circuito divisor sera siempre la salida q del ultimo biestable, como ambas entradas J y K están en nivel logico alto, el primer biestable conmuta su salida con cada flanco del reloj en la entrada clk, mientras que el segundo biestable conmuta únicamente cuando la salida del primero esta en nivel logico alto. Una representación mas clara de esta operación se observa en el siguiente diagrama de tiempos.

Fig3. Diagrama de tiempo, Divisor 1:4
 

Descripción del Circuito Divisor

Si modificamos el circuito anterior adicionando un biestable, como se muestran en la figura 4, la salida de este ahora tendrá una relación 1:8 con respecto a la señal del reloj.

Fig4. Circuito Divisor 1:8  
 
Fig5. Diagrama de tiempos Divisor 1:8

La nivel mas básico para describir en verilog el circuito divisor 1:8 de la figura 4,  es la descripción estructural, donde primero se debe elaborar un modulo descriptivo para el biestable JK, y luego el modulo divisor donde se describen conexiones entre los biestables utilizando instancias. Observe el siguiente ejemplo:

//Modulo descriptivo del Divisor 1:8
module div8(clk, rstn, s);
input clk, rstn;
output s;
wire q0, q1, q2, jk1, jk2;
assign s = q2; //Salida del ultimo FF
assign jk1 = q0;
assign jk2 = q0 & q1;
FFJKC ff0(clk, 1, 1, rstn, q0);
FFJKC ff1(clk, jk1, jk1, rstn, q1);
FFJKC ff2(clk, jk2, jk2, rstn, q2);
endmodule
 
//Modulo descriptivo del Flip Flop JK
module FFJKC(clk, j, k, clrn, q);
input clk, j, k, clrn;
output reg q;
always @(posedge clk or negedge clrn)
 if(clrn == 0) q <= 0;
 else
   case({j,k})
   2'b00 : q <= q;
   2'b01 : q <= 0;
   2'b10 : q <= 1;
   2'b11 : q <= ~q;
   endcase
endmodule

   
 l
Fig6. Salida del Divisor 1:8
 
Otra manera de elaborar en verilog este circuito es mediante una descripción procedural, donde no es necesario conocer la estructura del circuito en si, porque nos bastara saber su comportamiento a nivel funcional. Para este fin lo importante es considerar que un divisor es en esencia un registro contador limitado por cantidad de bits que lo conforman, y donde el bit de mayor peso estará asignado a su salida, el registro se desborda cada vez que llegue al valor limite. 
 
Fig5. Comportamiento del divisor 1:8
El siguiente código corresponde al modulo descriptivo de la funcionalidad que tiene el circuito divisor 1:8
 
module div8(clk, rstn, s);
input clk, rstn;
output s;
reg [2:0] q; //Registro de 3 bit
assign s = q[2]; //Asigna el bit MSB
always @(posedge clk or negedge rstn)
  if(rstn == 0) q <= 0;
  else q <= q + 1; //Incrementa el registro
endmodule

Tomando como referencia el código anterior del circuito divisor, y haciendo algunas modificaciones, podemos implementar fácilmente un circuito contador con secuencia truncada para conseguir cualquier frecuencia final de salida.  El siguiente modulo llamado drv_clock permite definir como parámetro la frecuencia del reloj y la frecuencia deseada en la salida.

module drv_clock(clk, rstn, clko);
input clk, rstn; //Entrada de reloj principal
output reg clko; //Salida de reloj
parameter SYSFREQ = 50000000; //Frecuencia principal en Hz
parameter OUTFREQ =  1000000; //Frecuencia de salida en Hz
localparam halfOUTFREQ = (SYSFREQ/OUTFREQ)/2;
localparam WIDTH = $clog2(halfOUTFREQ); //Medio ciclo
reg [WIDTH-1:0] cnt; //Contador para medio ciclo OUTFREQ
always @(posedge clk or negedge rstn) 
if(!rstn)
  begin
  clko <= 0;
  cnt <= 0;
  end
else
  begin
    if(cnt < (halfOUTFREQ-1)) //medio ciclo
    cnt <= cnt + 1'd1;
    else
      begin
      clko = ~clko; //Conmutación de salida
      cnt <= 0;  
      end
  end
endmodule

El modulo previo describe un circuito divisor 1:50, con esto es posible obtener una frecuencia de 1 MHz(OUTFREQ) si la entrada es de 50 MHz(SYSFREQ), los parámetros definidos permiten determinar la capacidad del registro contador durante la sintetización del circuito. para este caso la función verilog $log2 nos devolverá un valor entero de 5, con la que se dimensionara el registro contador


Ensayando el Divisor 
Para mostrar la correcta operacion de nuestro divisor, crearemos un modulo de estimulo que permita obtener pulsos de 1MHz a partir de un reloj de 24 MHz que es el oscilador utilizado por la placa TangNANO.
El modulo de estimulo descrito a continuacion crea una instancia de drv_clock, con la definicion a requerimiento de los parametros SYSFREQ y OUTFREQ.

`timescale 10ns/10ns //tienmpo base 10ns y precisión 1
module dvr_clock_tb;
reg clk, rstn;
wire out;
drv_clock #(.SYSFREQ(24000000), .OUTFREQ(1000000))
          inst0(clk, rstn, out);
initial begin
clk = 0; rstn = 0;
 forever #1 clk = ~clk; //Conmuta cada 10ns
end
initial begin
  #1 rstn = 1; //Desactiva luego de 10ns
end
endmodule

Fig8. Salida Divisor 1:24

Para finalizar solo quiero agradecer tu visita a mi blog, espero que el contenido de esta entrada hubiera sido de ayuda en tu formación educativa, favor cualquier consulta al respecto pueden escribirme a:

pablinzte@gmail.com / pablinza@me.com

Pablo Cesar Zárate.

No hay comentarios:

Publicar un comentario