Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Verilog

Verilog Clock Generator: Design & Implementierungsleitfaden

Takte sind fundamental für den Aufbau digitaler Schaltungen, da sie es verschiedenen Blöcken ermöglichen, miteinander synchron zu sein.

Eigenschaften eines Takts

Die wichtigsten Eigenschaften eines digitalen Takts sind seine Frequenz, die die Taktperiode bestimmt, sein Duty Cycle und die Taktphase in Relation zu anderen Takten.

Taktperiode

Die Frequenz gibt an, wie viele Zyklen in einem bestimmten Zeitraum zu finden sind. Und deshalb ist die Taktperiode die Zeit, die benötigt wird, um 1 Zyklus abzuschließen.

Duty Cycle

Die Zeit, in der der Takt high ist, im Vergleich zu seiner Periode definiert den Duty Cycle.

Taktphase

Wenn ein Zyklus eines Takts als ein vollständiger Kreis mit 360 Grad betrachtet werden kann, kann ein anderer Takt relativ an einer anderen Stelle im Kreis platziert werden, die eine andere Phase einnimmt. Zum Beispiel kann ein anderer Takt derselben Periode, der um 1/4 seiner Periode nach rechts verschoben ist, als 90 Grad Phasenunterschied bezeichnet werden.

Verilog Clock Generator

Simulationen müssen auf einem gegebenen Timescale operieren, der eine begrenzte Präzision hat, wie durch die Timescale-Direktive spezifiziert. Daher ist es wichtig, dass die Präzision des Timescale gut genug ist, um eine Taktperiode darzustellen. Zum Beispiel, wenn die Frequenz des Takts auf 640000 kHz gesetzt ist, dann wird seine Taktperiode 1.5625 ns betragen, wofür eine Timescale-Präzision von 1ps nicht ausreichen wird, weil ein zusätzlicher Punkt dargestellt werden muss. Daher wird die Simulation die letzte Ziffer runden, um in die 3-Stellen-Timescale-Präzision zu passen. Dies erhöht die Taktperiode auf 1.563, was tatsächlich 639795 kHz repräsentiert!

Das folgende Verilog-Clock-Generator-Modul hat drei Parameter, um die drei oben diskutierten Eigenschaften anzupassen. Das Modul hat einen Input Enable, der es erlaubt, den Takt nach Bedarf zu deaktivieren und zu aktivieren. Wenn mehrere Takte durch ein gemeinsames Enable-Signal gesteuert werden, können sie relativ einfach gephased werden.

`timescale 1ns/1ps
module clock_gen (
  input enable,
  output reg clk
);
  parameter FREQ = 100000; // in kHz
  parameter PHASE = 0;     // in Grad
  parameter DUTY = 50;     // in Prozent
  
  real clk_pd = 1.0/(FREQ * 1e3) * 1e9; // in ns umrechnen
  real clk_on = DUTY/100.0 * clk_pd;
  real clk_off = (100.0 - DUTY)/100.0 * clk_pd;
  real quarter = clk_pd/4;
  real start_dly = quarter * PHASE/90;
  reg start_clk;
  
  initial begin
    $display("FREQ = %0d kHz", FREQ);
    $display("PHASE = %0d deg", PHASE);
    $display("DUTY = %0d %%", DUTY);
    $display("PERIOD = %0.3f ns", clk_pd);
    $display("CLK_ON = %0.3f ns", clk_on);
    $display("CLK_OFF = %0.3f ns", clk_off);
    $display("QUARTER = %0.3f ns", quarter);
    $display("START_DLY = %0.3f ns", start_dly);
  end
  
  // Variablen auf Null initialisieren
  initial begin
    clk <= 0;
    start_clk <= 0;
  end
  
  // Wenn Takt aktiviert ist, das Treiben des Takts auf 1 verzögern, um
  // den Phase-Effekt zu erreichen. start_dly ist auf die korrekte
  // Verzögerung für die konfigurierte Phase konfiguriert. Wenn enable 0 ist,
  // genug Zeit lassen, um die aktuelle Taktperiode abzuschließen
  always @ (posedge enable or negedge enable) begin
    if (enable) begin
      #(start_dly) start_clk = 1;
    end else begin
      #(start_dly) start_clk = 0;
    end
  end
  
  // Duty Cycle durch verzerrte Takt-ein/aus-Zeit erreichen und dies
  // so lange laufen lassen, wie die Takte eingeschaltet sind.
  always @(posedge start_clk) begin
    if (start_clk) begin
      clk = 1;
      while (start_clk) begin
        #(clk_on) clk = 0;
        #(clk_off) clk = 1;
      end
      clk = 0;
    end
  end
endmodule

Testbench mit verschiedenen Taktfrequenzen

module tb;
  wire clk1, clk2, clk3, clk4;
  reg enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.FREQ(200000)) u1(enable, clk2);
  clock_gen #(.FREQ(400000)) u2(enable, clk3);
  clock_gen #(.FREQ(800000)) u3(enable, clk4);
  
  initial begin
    enable <= 0;
    for (int i = 0; i < 10; i= i+1) begin
      dly = $random;
      #(dly) enable <= ~enable;
      $display("i=%0d dly=%0d", i, dly);
      #50;
    end
    #50 $finish;
  end
endmodule

Simulationslog:

xcelium> run
FREQ = 100000 kHz
PHASE = 0 deg
DUTY = 50 %
PERIOD = 10.000 ns
CLK_ON = 5.000 ns
CLK_OFF = 5.000 ns
QUARTER = 2.500 ns
START_DLY = 0.000 ns
FREQ = 200000 kHz
PHASE = 0 deg
DUTY = 50 %
PERIOD = 5.000 ns
CLK_ON = 2.500 ns
CLK_OFF = 2.500 ns
QUARTER = 1.250 ns
START_DLY = 0.000 ns
FREQ = 400000 kHz
PHASE = 0 deg
DUTY = 50 %
PERIOD = 2.500 ns
CLK_ON = 1.250 ns
CLK_OFF = 1.250 ns
QUARTER = 0.625 ns
START_DLY = 0.000 ns
FREQ = 800000 kHz
PHASE = 0 deg
DUTY = 50 %
PERIOD = 1.250 ns
CLK_ON = 0.625 ns
CLK_OFF = 0.625 ns
QUARTER = 0.312 ns
START_DLY = 0.000 ns
i=0 dly=36
i=1 dly=129
i=2 dly=9
i=3 dly=99
i=4 dly=13
i=5 dly=141
i=6 dly=101
i=7 dly=18
i=8 dly=1
i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

Testbench mit verschiedenen Taktphasen

module tb;
  wire clk1, clk2;
  reg enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.FREQ(50000), .PHASE(90)) u1(enable, clk2);
  
  initial begin
    enable <= 0;
    for (int i = 0; i < 10; i=i+1) begin
      dly = $random;
      #(dly) enable <= ~enable;
      $display("i=%0d dly=%0d", i, dly);
    end
    #50 $finish;
  end
endmodule

Simulationslog:

xcelium> run
FREQ = 100000 kHz
PHASE = 0 deg
DUTY = 50 %
PERIOD = 10.000 ns
CLK_ON = 5.000 ns
CLK_OFF = 5.000 ns
QUARTER = 2.500 ns
START_DLY = 0.000 ns
FREQ = 100000 kHz
PHASE = 90 deg
DUTY = 50 %
PERIOD = 10.000 ns
CLK_ON = 5.000 ns
CLK_OFF = 5.000 ns
QUARTER = 2.500 ns
START_DLY = 2.500 ns
FREQ = 100000 kHz
PHASE = 180 deg
DUTY = 50 %
PERIOD = 10.000 ns
CLK_ON = 5.000 ns
CLK_OFF = 5.000 ns
QUARTER = 2.500 ns
START_DLY = 5.000 ns
FREQ = 100000 kHz
PHASE = 270 deg
DUTY = 50 %
PERIOD = 10.000 ns
CLK_ON = 5.000 ns
CLK_OFF = 5.000 ns
QUARTER = 2.500 ns
START_DLY = 7.500 ns
i=0 dly=36
i=1 dly=129
i=2 dly=9
i=3 dly=99
i=4 dly=13
i=5 dly=141
i=6 dly=101
i=7 dly=18
i=8 dly=1
i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

Testbench mit verschiedenen Duty Cycles

module tb;
  wire clk1, clk2, clk3, clk4;
  reg enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.DUTY(25)) u1(enable, clk2);
  clock_gen #(.DUTY(75)) u2(enable, clk3);
  clock_gen #(.DUTY(90)) u3(enable, clk4);
  
  initial begin
    enable <= 0;
    for (int i = 0; i < 10; i= i+1) begin
      dly = $random;
      #(dly) enable <= ~enable;
      $display("i=%0d dly=%0d", i, dly);
      #50;
    end
    #50 $finish;
  end
endmodule

Simulationslog:

xcelium> run
FREQ = 100000 kHz
PHASE = 0 deg
DUTY = 50 %
PERIOD = 10.000 ns
CLK_ON = 5.000 ns
CLK_OFF = 5.000 ns
QUARTER = 2.500 ns
START_DLY = 0.000 ns
FREQ = 100000 kHz
PHASE = 0 deg
DUTY = 25 %
PERIOD = 10.000 ns
CLK_ON = 2.500 ns
CLK_OFF = 7.500 ns
QUARTER = 2.500 ns
START_DLY = 0.000 ns
FREQ = 100000 kHz
PHASE = 0 deg
DUTY = 75 %
PERIOD = 10.000 ns
CLK_ON = 7.500 ns
CLK_OFF = 2.500 ns
QUARTER = 2.500 ns
START_DLY = 0.000 ns
FREQ = 100000 kHz
PHASE = 0 deg
DUTY = 90 %
PERIOD = 10.000 ns
CLK_ON = 9.000 ns
CLK_OFF = 1.000 ns
QUARTER = 2.500 ns
START_DLY = 0.000 ns
i=0 dly=36
i=1 dly=129
i=2 dly=9
i=3 dly=99
i=4 dly=13
i=5 dly=141
i=6 dly=101
i=7 dly=18
i=8 dly=1
i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

Enable toggeln, um Takte zu starten/stoppen

Verilog

  1. Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
  2. Verilog Concatenation meistern: Praktischer Leitfaden
  3. Verilog Assignments verstehen: Typen, Syntax und Best Practices
  4. Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
  5. Verilog Functions meistern für effizientes RTL-Design
  6. Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
  7. Verilog Math Functions meistern für effizientes Hardware-Design
  8. Verilog $timeformat meistern: Präzision und Anzeigesteuerung
  9. Verilog Timescales an jedem Scope verstehen und ausgeben
  10. Datei-E/A in Verilog meistern: Öffnen, Lesen, Schreiben und Schließen