Erstmal danke für die Hilfe gestern. Diesmal werde ich meinen Code korrekt dokumentieren.
Wir wurden also beauftragt, eine Parkuhr zu erstellen, die 4 Eingaben benötigt, eine addiert 50 Sekunden, eine addiert 150 Sekunden, eine addiert 250 Sekunden und eine addiert 500 Sekunden. Wenn mehr als 10 Sekunden verbleiben, sollte eine grüne LED mit einer Dauer von 2 Sekunden blinken. Wenn weniger als 10 Sekunden verbleiben, sollte eine rote LED mit einer Periode von 2 Sekunden blinken, und wenn keine Sekunden mehr übrig sind, sollte eine rote LED mit einer Periode von 1 Sekunde blinken. Jeder Taktzyklus ohne Eingabe soll eins vom Zähler subtrahieren.
Wir wurden beauftragt, einen Entpreller sowie eine Einzelimpuls-Zustandsmaschine für die Eingänge und eine 7-Segment-Anzeige für die Ausgänge zu verwenden. Also habe ich eine Zustandsmaschine für meine Addition und LED-Blinken verwendet, dann den Zähler an einen Binär-zu-BCD-Konverter und dann an eine BCD-zu-7-Segment-Anzeige gesendet. Ich frage mich, ob ich die Uhr durcheinander gebracht habe und die Simulation irgendwie meine Fehler ignoriert, wodurch das FPGA irgendwie nicht in der Lage ist, meinen Code richtig zu verwenden?
ohne weitere Umschweife, hier sind meine Codeschnipsel:
Top-Modul
module parkingmeter(clk,rst,b0,b1,b2,b3,out0,out1,out2,out3,GRNLED,REDLED);
input b0,b1,b2,b3,clk,rst;
output [6:0] out0,out1,out2,out3;
output GRNLED,REDLED;
wire outt0,outt1,outt2,outt3;
wire [15:0] counter;
wire [3:0] bcd0,bcd1,bcd2,bcd3;
wire clkout;
clockdivider onesec(clk,clkout);
add_sub yep(b0,clkout,rst,outt0);
add_sub yesh(b1,clkout,rst,outt1);
add_sub yeah(b2,clkout,rst,outt2);
add_sub ok(b3,clk,rst,outt3);
controlparker Second(outt0,outt1,outt2,outt3,clkout,rst,counter,REDLED,GRNLED);
EC Third(counter,bcd0,bcd1,bcd2,bcd3,out0,out1,out2,out3);
endmodule
mein Entprellmodul
module cleandebounce(clk,rst,I0,out);
input clk,rst,I0;
output out;
reg f0,f1;
always @ (posedge clk, posedge rst) begin
if (rst==1) begin
f0 <= I0;
f1 <= f0;
end else begin
f0 <= 0;
f1 <= 0;
end
end
assign out = f1;
endmodule
Meine Einzelpuls-Zustandsmaschine
module add_sub(in,clk,rst,out);
input in,clk,rst;
output reg out = 1'b0;
reg state = 1'b0;
wire outt;
cleandebounce one(clk,rst,in,outt);
always @ (posedge clk,posedge rst) begin
case(state)
1'b0: begin
if (rst==1) begin
out <= 0;
if (outt == 1) begin
out <= 1'b1;
state <= 1'b1;
end else state <= 1'b0;
end else begin
out <= 1'b0;
state <= 1'b0;
end
end
1'b1: begin
out <= 1'b0;
if (outt == 1) begin
out <= 1'b0;
state <= 1'b1;
end else state <= 1'b0;
end
endcase
end
endmodule
Und mein Modul zum Hinzufügen der Eingänge sowie zum Ein- und Ausschalten von LEDs
module controlparker(B0,B1,B2,B3,clk,rst,counter,REDLED,GRNLED);
input B0,B1,B2,B3,clk,rst;
output reg [15:0] counter = 16'b0000000000000000;
reg state = 1'b0;
reg [2:0] area = 3'b000;
output reg REDLED = 0;
output reg GRNLED = 0;
always @ (posedge clk, posedge rst) begin
case(state)
0: begin
if (rst==1) begin
if (counter > 0)
counter <= counter - 1;
if (counter > 9999)begin
counter <= 9999;
end
state <= 1;
end else begin
counter <= 0;
state <= 0;
end
end
1: begin
if (B0 == 1) begin
counter <= counter + 16'b00000000000110010;
state <= 0;
end else if (B1 == 1) begin
counter <= counter + 16'b00000000010010110;
state <= 0;
end else if (B2 == 1) begin
counter <= counter + 16'b00000000011111010;
state <= 0;
end else if (B3 == 1) begin
counter <= counter + 16'b00000000111110010;
state <= 0;
end else state <= 0;
end
endcase
end
always @ (posedge clk, posedge rst) begin
case(area)
3'b000: begin
if (rst==1)begin
if (counter >= 10)begin
GRNLED <= 1;
REDLED <= 0;
area <= 3'b001;
end
else if (counter < 10 && counter > 0) begin
REDLED <= 1;
GRNLED <= 0;
area <= 3'b010;
end
else REDLED <= ~REDLED;
end
else begin
REDLED <= 0;
GRNLED <= 0;
end
end
3'b001: begin
GRNLED <= 0;
area <= 3'b000;
end
3'b010: begin
REDLED <= 0;
area <= 3'b000;
end
endcase
end
endmodule
Mein Modul konvertiert BinarytoBCD sowie die Ausgabe der 7-Segment-Anzeige:
module EC(in,bcd0,bcd1,bcd2,bcd3,out0,out1,out2,out3);
input [15:0] in;
output reg [3:0] bcd0 = 4'b0000;
output reg [3:0] bcd1 = 4'b0000;
output reg [3:0] bcd2 = 4'b0000;
output reg [3:0] bcd3 = 4'b0000;
output reg [6:0] out0 = 7'b0000000;
output reg [6:0] out1 = 7'b0000000;
output reg [6:0] out2 = 7'b0000000;
output reg [6:0] out3 = 7'b0000000;
reg [15:0] temp;
integer i;
always @ (in) begin
bcd0 = 4'b0000;
bcd1 = 4'b0000;
bcd2 = 4'b0000;
bcd3 = 4'b0000;
temp = in;
for(i=15; i>=0; i=i-1) begin
if (bcd3 >= 4'b0101)
bcd3 = bcd3 + 4'b0011;
if (bcd2 >= 4'b0101)
bcd2 = bcd2 + 4'b0011;
if (bcd1 >= 4'b0101)
bcd1 = bcd1 + 4'b0011;
if (bcd0 >= 4'b0101)
bcd0 = bcd0 + 4'b0011;
bcd3 = bcd3 << 1;
bcd3[0] = bcd2[3];
bcd2 = bcd2 << 1;
bcd2[0] = bcd1[3];
bcd1 = bcd1 << 1;
bcd1[0] = bcd0[3];
bcd0 = bcd0 << 1;
bcd0[0] = temp[i];
end
end
always @ (bcd0) begin
if (bcd0==4'b0000) out0 = 7'b0000001;
else if (bcd0==4'b0001) out0 = 7'b1001111;
else if (bcd0==4'b0010) out0 = 7'b0010010;
else if (bcd0==4'b0011) out0 = 7'b0000110;
else if (bcd0==4'b0100) out0 = 7'b1001100;
else if (bcd0==4'b0101) out0 = 7'b0100100;
else if (bcd0==4'b0110) out0 = 7'b0100000;
else if (bcd0==4'b0111) out0 = 7'b0001111;
else if (bcd0==4'b1000) out0 = 7'b0000000;
else if (bcd0==4'b1001) out0 = 7'b0000100;
else out0=7'b0000001;
end
always @ (bcd1) begin
if (bcd1==4'b0000) out1 = 7'b0000001;
else if (bcd1==4'b0001) out1 = 7'b1001111;
else if (bcd1==4'b0010) out1 = 7'b0010010;
else if (bcd1==4'b0011) out1 = 7'b0000110;
else if (bcd1==4'b0100) out1 = 7'b1001100;
else if (bcd1==4'b0101) out1 = 7'b0100100;
else if (bcd1==4'b0110) out1 = 7'b0100000;
else if (bcd1==4'b0111) out1 = 7'b0001111;
else if (bcd1==4'b1000) out1 = 7'b0000000;
else if (bcd1==4'b1001) out1 = 7'b0000100;
else out1=7'b0000001;
end
always @ (bcd2) begin
if (bcd2==4'b0000) out2 = 7'b0000001;
else if (bcd2==4'b0001) out2 = 7'b1001111;
else if (bcd2==4'b0010) out2 = 7'b0010010;
else if (bcd2==4'b0011) out2 = 7'b0000110;
else if (bcd2==4'b0100) out2 = 7'b1001100;
else if (bcd2==4'b0101) out2 = 7'b0100100;
else if (bcd2==4'b0110) out2 = 7'b0100000;
else if (bcd2==4'b0111) out2 = 7'b0001111;
else if (bcd2==4'b1000) out2 = 7'b0000000;
else if (bcd2==4'b1001) out2 = 7'b0000100;
else out2=7'b0000001;
end
always @ (bcd3) begin
if (bcd3==4'b0000) out3 = 7'b0000001;
else if (bcd3==4'b0001) out3 = 7'b1001111;
else if (bcd3==4'b0010) out3 = 7'b0010010;
else if (bcd3==4'b0011) out3 = 7'b0000110;
else if (bcd3==4'b0100) out3 = 7'b1001100;
else if (bcd3==4'b0101) out3 = 7'b0100100;
else if (bcd3==4'b0110) out3 = 7'b0100000;
else if (bcd3==4'b0111) out3 = 7'b0001111;
else if (bcd3==4'b1000) out3 = 7'b0000000;
else if (bcd3==4'b1001) out3 = 7'b0000100;
else out3=7'b0000001;
end
endmodule
Und schließlich mein Taktteiler, den ich jedem Modul zuführe, das eine Uhr benötigt, um auf dem FPGA korrekt zu laufen:
module clockdivider(clk,clkout);
input clk;
output clkout;
reg [24:0] q = 0;
always @ (posedge clk) begin
q <= q + 1;
end
assign clkout = q[0];
endmodule
Da ist also alles. Wenn ich mein FPGA aktiviere, zeigt es Zufallszahlen an, obwohl ich keine Tasten gedrückt habe. Wie ist das möglich? Ich bin relativ neu bei Verilog. Wenn es also eine Möglichkeit gibt, meinen Code zu vereinfachen, wäre ich sehr dankbar. Wieder simuliert alles perfekt. Danke an alle
Es könnte viele Probleme geben, da Sie mit echten FPGAs nicht vertraut zu sein scheinen, also werde ich sie im Folgenden auflisten:
Sind alle externen Eingänge mit der Taktdomäne Ihres FPGA synchronisiert? Eingehende Signale können in der Mitte der FPGA-Taktflanken übergehen, was zu Metastabilität führt. Der Weg, damit umzugehen, besteht darin, den externen Eingang durch eine Kette von Flip-Flops zu leiten, bevor Sie ihn verwenden (dh den Eingang durch eine Kette von Signalen / Registern bei jedem Takt kopieren). Jedes Mal, wenn es passiert wird, werden die Chancen, dass ein metastabiles Signal zu Ihrem funktionellen Kern durchdringt, weniger wahrscheinlich, bis es verschwindend gering ist. Das Minimum sind zwei, hochzuverlässige Geräte können drei verwenden. Das sollte offensichtlich sein, aber ich sage es trotzdem: Dies muss der ERSTE Schritt jedes Signals sein, das in das FPGA eintritt. Wenn Sie das Signal entprellen oder filtern möchten (wie in Nr. 2), müssen Sie dies NACH diesem Schritt tun, da die Metastabilität nicht zulässt, dass etwas anderes ordnungsgemäß funktioniert.
Sind Ihre externen Tasten entprellt? Wenn elektromechanische Kontakte aufeinander treffen, passen sie nicht sauber zusammen und werden wiederholt verbunden und getrennt, bis sich die Dinge beruhigt haben. Die Elektronik ist schnell genug, um dies zu erfassen. Sie können Eingänge in einem FPGA auf verschiedene Weise filtern. Einige Ansätze sind: (a) Sobald ein Übergang erkannt wird, ignorieren Sie alle nachfolgenden Übergänge für einen bestimmten Zeitraum (als Blanking bezeichnet). (b) Geben Sie den Eingangszustand nur weiter, damit er von anderen Werten verwendet werden kann, wenn er sich für eine gewisse Anzahl von Abtastwerten stabilisiert hat .
Ihr FPGA muss wissen, welche Signale welchen Pins zugeordnet sind. Es muss dem FPGA auch mitteilen, welche Art von Pins das sein muss. Wie dies geschieht, hängt von Ihrer Synthesesoftware ab. Das muss stimmen.
Ihr FPGA muss auch wissen, wie hoch die Taktrate sein wird, damit es weiß, wie lange es einem Signal erlauben kann, sich auszubreiten, da alle Signale (insbesondere Taktsignale) rechtzeitig an ihrem Ziel ankommen müssen, damit die Schaltung ordnungsgemäß funktioniert.
Taktsignale müssen überall in einem FPGA hingehen und müssen überall ungefähr zur gleichen Zeit ankommen. Sie leiten Takte nicht durch das normale FPGA-Fabric, da es zu variabel und zu langsam ist, um Takte durch die gesamte konfigurierbare FPGA-Logik laufen zu lassen. Der Zeitversatz wird zu hoch sein. FPGAs verfügen über dedizierte Taktnetzwerke, um den Takt mit minimaler Ausbreitungsverzögerung über den gesamten Chip zu verteilen. Diese müssen Sie verwenden, wenn Sie eine Uhr verteilen möchten.
Schlüsselwörter wie „Posedge“ und „Negedge“ sind sehr speziell und teilen der Software mit, dass es sich um ein Taktsignal handelt, sodass es durch das dedizierte Taktverteilungsnetz geleitet wird. Dies geschieht automatisch bei jedem Signal, das diesen Schlüsselwörtern zugeordnet ist, aber es gibt nur sehr wenige davon auf einem FPGA. Verwenden Sie dieses Schlüsselwort also nicht für Dinge, die keine tatsächlichen Taktsignale sind. Wenn Sie eine steigende Flanke auf einem Nicht-Taktsignal betrachten möchten, schreiben Sie ein separates Modul, das den vorherigen logischen Zustand mit dem aktuellen vergleicht, um zu sehen, ob er anders ist.
Ein Taktaktivierungssignal ist ein Signal, das nur für einen einzigen Taktimpuls hoch geht, bevor es wieder niedrig wird. Es wird ausgelöst, wenn ein Modul etwas tun wird, aber das Modul nicht davon getaktet wird. Das Modul wird immer noch vom FPGA-Haupttakt getaktet (über das Taktverteilungsnetzwerk). Sie können ein Modul erstellen, das vom FPGA-Takt getaktet wird, aber alle N Zyklen eine Taktfreigabe ausgibt, und dies zur Taktfreigabe verwenden, um Ereignisse in anderen Modulen auszulösen. Alle Module werden immer noch vom FPGA-Takt getaktet und die Tatsache, dass die Taktfreigabe nach einem Taktzyklus erlischt, stellt sicher, dass die Module nicht ständig jeden Taktzyklus auslösen, wenn sie es nicht sollten.
Chris Stratton
DKNguyen
Hilfe benötigt
DKNguyen
Ale..chenski
Hilfe benötigt
Solar-Mike
Ale..chenski
alex.forencich
Hilfe benötigt
Neil_DE