Problem beim Hinzufügen von zwei Zählern in Reihe auf einem FPGA

Ich verwende Verilog in Lattice Diamond IDE mit einem Lattice MachXO2 7000HE Breakout Board.

Ich habe einen einfachen Zähler mit einem Grenzwerteingang gebaut, der einen Taktausgang mit variabler Periode erzeugt. Es funktioniert für sich genommen gut, aber wenn ich zwei Instanzen dieses Moduls hinzufüge und sie in Reihe schalte (um die Frequenz zweimal zu skalieren), erhalte ich ein seltsames Ergebnis auf dem FPGA. Die Simulation scheint jedoch das zu zeigen, was ich vom Code erwartet hatte.

Hier ist das oberste Modul:

 module clock_generator (fpga_clock, cnt1_clock, cnt2_clock, cnt2_counter);
    output  wire            fpga_clock;
    output  wire            cnt1_clock;
    output  wire            cnt2_clock;
    output  wire    [7:0]   cnt2_counter;

    reg     [7:0]   default_period_1    = 8'b00000011;
    reg     [7:0]   default_period_2    = 8'b00000011;

    defparam OSCH_inst.NOM_FREQ = "2.08";
    OSCH OSCH_inst(.STDBY(1'b0), .OSC(fpga_clock));

    counter Counter_1_inst(.clk_in(fpga_clock), .limit_in(default_period_1), .clk_out(cnt1_clock), .cnt_out());
    counter Counter_2_inst(.clk_in(cnt1_clock), .limit_in(default_period_1), .clk_out(cnt2_clock), .cnt_out(cnt2_counter)); 
endmodule

module counter (clk_in, limit_in, clk_out, cnt_out, rst);
    input   wire            clk_in;
    input   wire    [7:0]   limit_in;
    output  reg             clk_out     = 1'b1;
    output  reg     [7:0]   cnt_out     = 8'b00000000;
    input   wire            rst;

    always @(posedge clk_in or posedge rst) begin
        if (rst) begin
            clk_out <=0;
            cnt_out <=0;
        end else if (cnt_out == limit_in) begin
            clk_out <= !clk_out;
            cnt_out <= 0;
        end else begin
            cnt_out <= cnt_out + 1'b1;
        end
    end
endmodule

Und hier ist die Testbench für meine Simulation:

`timescale 1 ns / 1 ns

module testbench;
    wire            fpga_clock;
    wire            cnt1_clock;
    wire            cnt2_clock;
    wire    [7:0]   cnt2_counter;

    clock_generator dut(.fpga_clock(fpga_clock), .cnt1_clock(cnt1_clock), .cnt2_clock(cnt2_clock), .cnt2_counter(cnt2_counter));

    initial begin
        #1400000000
        $finish;
    end
endmodule

Hier ist die Simulationsausgabe:

Simulationsausgabe

Und die Scope-Ausgabe:

ch1 - fpga_clock

ch2 - cnt1_clock

ch3 - cnt2_clock

ch4 - cnt2_counter[1]

Scope-AusgabeUnd das Sonden-Setup:Einrichtung1

Kanal 3 ( cnt2_clock ) sollte die doppelte Periode von cnt2_counter[1] haben , wie es in der Simulationsausgabe steht. Stattdessen ist es, wie Sie sehen können, ein Burst von Flanken mit höherer Frequenz, wo die einzelne Flanke sein sollte. Ich bin jetzt schon eine Weile dabei. Was vermisse ich?

Lassen Sie mich auch das Schema hinzufügen:Geben Sie hier die Bildbeschreibung ein

Danke schön!

########## Mit zusätzlichen Bildern bearbeiten

Scope-Ausgabe mit cnt2_counter[0]

ch1 - fpga_clock

ch2 - cnt1_clock

ch3 - cnt2_counter[0]

ch4 - cnt2_counter[1]

[ cnt2_counter0[4]Und das Sonden-Setup:Setup2

Pin-ListePin-Liste

Führen Sie das Reset-Signal ein und führen Sie die Einstellung der Register beim Reset-Signal durch (anstatt Werte am Anfang des Moduls zuzuweisen - ich vermute, Sie sollten eine Liste mit Warnungen erhalten?). Gemäß Ihren Messwerten ändert sich das Register, wenn der Eingangstakt niedrig ist. Ein weiterer Eingang zum Durchführen einer Registrierungszustandsänderung ist sein Set/Reset-Eingang, und er wird hier nicht explizit geleitet.
@Anonymous, nein, die einzige Warnung lautet: .../top.v(12,2-12,49) (VERI-1927) port SEDSTDBY bleibt für diese Instanz unverbunden . Ich habe wie von Ihnen vorgeschlagen einen Reset hinzugefügt, der jedoch keine Auswirkungen auf die Oszilloskopausgabe hatte.
Sind Sie absolut sicher, dass Ch3 auf dem Oszilloskopdiagramm cnt2_clock ist? Ich frage, da es sich synchron zu Ch1 ändert, von dem Sie gesagt haben, dass es fpga_clock ist. Der von Ihnen gepostete Code besagt ausdrücklich, dass cnt2_clock bei jeder steigenden Flanke von cnt1_clock aktualisiert wird.
Zum Kommentar von @Vance ... überprüfen Sie Ihren PAR-Bericht auf IO-Zuweisungen.
@Vance, ja, da bin ich mir sicher. Ich habe cnt2_clock ein paar verschiedenen Pins zugewiesen und das Ergebnis ist immer dasselbe.
@CapnJJ, sorry, ich bin mir nicht sicher, was du mit "PAR-Bericht" meinst.
Nachdem Sie Place-and-Route (PAR) durchlaufen haben, sollte eine Berichtsdatei vorhanden sein, die Ihnen unter anderem mitteilt, wo die Pins zugewiesen wurden. Sie wird während der letzten Phase Ihrer Synthese generiert, wenn Sie die .bit erstellen (Programmier-) Datei
Ich denke, wir brauchen noch mehr Informationen zu Ihrem Testaufbau. Die Scope-Ergebnisse sind sehr seltsam. Ihr Code ist ziemlich einfach (obwohl ich mit VHDL besser vertraut bin als mit Verilog), und die Simulation bestätigt die Funktionalität, sodass ich nicht glaube, dass das Problem dort liegt. Sie haben auch eine RTL-Ansicht davon bereitgestellt, die okay aussieht. Daher gibt es etwas in der tatsächlichen Hardware, das diesen Effekt verursacht. Dies ist also zu einem allgemeineren Debug-Problem geworden. Könnten Sie Ihren Testaufbau beschreiben oder ein Bild posten? Können wir uns auch den Trace cnt2_counter[0] ansehen.
@Vance, Nun, es ist jetzt ein Durcheinander, aber ich habe Bilder des Setups hinzugefügt. Ich bin mir ziemlich sicher, dass es nicht das Problem ist. Ich habe auch cnt2_counter[0] hinzugefügt .
@CapnJJ Der einzige Bericht, den ich bezüglich der Pinbelegung gefunden habe, heißt "Signal / Pad" unter "Process Reports". Es zeigt die gleichen Pins, die ich zugewiesen habe.
Danke für das Update amfast. Wie sicher sind Sie, dass Sie cnt2_clk im ersten Scope-Bild messen ? Überprüfen Sie die Pinbelegung, die dem Gerät zugewiesen wurde (entweder automatisch oder durch Ihre ucf/sdc-Datei), und überprüfen Sie das Datenblatt auf die Pinbelegung des Devkits. Tatsache ist, dass cnt2_counter wie erwartet funktioniert, also sollte die Ausgabe funktionieren.

Antworten (2)

Sie verwenden eine generierte Uhr. Dies ist normalerweise auf einem FPGA nicht ratsam, da es sehr sorgfältig durchgeführt werden muss, um Störungen zu vermeiden und sicherzustellen, dass ein Timing-Schließen möglich ist. Es sieht so aus, als ob Sie einige Störungen auf cnt1_clock bekommen, die die zweite Instanz vermasseln. Versuchen Sie es mit Clock Enables und sehen Sie, was passiert.

Außerdem sollte fpga_clock ein Eingang und kein Ausgang in Ihrem Top-Modul sein.

Wenn Sie "generierte Uhr" sagen, meinen Sie cnt1_clock und cnt1_clock ? Wollen Sie damit sagen, dass ich die Taktfreigabe anstelle des hier beschriebenen Taktteilers verwenden sollte ? Die Tatsache, dass dies ein Problem ist, ist mir neu, aber wenn ich darüber lese, entsteht der Eindruck, dass mein Code von Anfang an schlecht geschrieben ist.
Es ist im Allgemeinen ratsam, @(posedge something_that_isn't_a_proper_clock) zu vermeiden, da dies bedeutet, dass Ihre Logik durch jede Art von Störungen "getaktet" werden könnte, die von der Logik erzeugt werden könnten, die Ihr Taktsignal generiert, und die Simulation wird dies nicht abfangen. Es macht auch die Timing-Analyse komplexer und es ist schwieriger, das Timing auf diese Weise zu schließen. Daher werden Taktfreigaben bevorzugt. Nun scheint es, als würde Ihre generierte Uhr direkt von einem Flip-Flop angesteuert, also sollte es theoretisch keine Störungen geben, also bin ich mir nicht sicher, warum Sie genau das Verhalten sehen, das Sie sind.

Wie soll das funktionieren?

always @(posedge clk_in) begin
    cnt_out <= cnt_out + 1'b1;
    if (cnt_out == limit_in) begin
        clk_out <= !clk_out;
        cnt_out <= 0;
    end
end 

Vielleicht meinst du:

always @(posedge clk_in) begin
    cnt_out <= (cnt_out == limit_in) ? 0 : cnt_out + 1;
    clk_out <= (cnt_out == limit_in) ? ~clk_out : clk_out;
end 
Es soll genauso funktionieren wie in der Simulation. Und auch auf dem FPGA so weit wie Counter_1_inst geht. Ich habe den obigen Code jetzt so geändert, dass er auch eine Reset-Funktion enthält.
Dieser Code sollte genau auf die gleiche Weise synthetisiert werden, während er schwieriger zu lesen ist.