Rückkopplungsschleife in Verilog

Ich habe ein Problem mit dem Schreiben von Verilog-HDL-Code. Ich möchte einen einfachen PID-Controller in FPGA entwerfen. Ich verwende die Cyclone II-Familie. Ich möchte meinen Ausgabewert als Eingabe in einer vorherigen Berechnungsphase zurückgeben. Die Gleichung sieht folgendermaßen aus: u(n) = u(n-1) + x (x wird korrekt berechnet), also habe ich ein Register erstellt, um den Ausgabewert zu speichern, und es mit einer vorherigen Stufe in meinem Design verbunden.

Leider funktioniert diese Lösung nicht, wenn ich dies simuliere. Ich bekomme einen 'unbekannten' Wert in dem Register, in dem ich den Ausgabewert speichere, und der Ausgabewert selbst ist auch 'unbekannt' (mit unbekannt meine ich 'x').

Ist es möglich, eine Rückkopplungsschleife zwischen bestimmten Komponenten im HDL-Design zu erstellen? Wie kann es gemacht werden? Sollte ich versuchen, dieses Problem zu lösen, indem ich die Berechnungen Schritt für Schritt in einem FSM durchführe?

BEARBEITEN: Dies ist mein angeforderter Code

PID-Modul

module pid(clk,rst_n,Kp_in, Kd_in, Ki_in,temp_data_in,setpoint,pwm_out);


parameter N = 8;
parameter M = 16;

input   clk;
input   rst_n;
input   [N-1:0]temp_data_in;
input   [N-1:0]setpoint;    
input [N-1:0]Kp_in;
input [N-1:0]Kd_in;
input [N-1:0]Ki_in;

output [N-1:0]pwm_out;

wire    clk;
wire    rst_n;

reg [N-1:0]temp_data_reg;
reg [N-1:0]setpoint_reg;
reg [N-1:0]pwm_out_reg;

localparam [1:0] idle = 2'b00, load = 2'b01, run= 2'b10;
localparam k = 2;

reg [1:0] state_reg, state_next;

always@(posedge clk, negedge rst_n) begin
    if(!rst_n) begin
        state_reg <= idle;
    end else
        state_reg <= state_next;
    end

reg sum_out_old_reg_en;

reg     [N-1:0]K0;
reg [N-1:0]K1;
reg [N-1:0]K2;

wire [N-1:0] ex0;
wire [N-1:0] ex1;
wire [N-1:0] ex2;

wire [2*N-1:0] out0;
wire [2*N-1:0] out1;
wire [2*N-1:0] out2;

wire [2*N-1:0] sum1;
wire [2*N-1:0] sum2;
wire [2*N-1:0] sum_out_old;
wire [2*N-1:0] sum_out;

register e0(clk,rst_n,(temp_data_in-setpoint),ex0);
register e1(clk,rst_n,ex0,ex1);
register e2(clk,rst_n,ex1,ex2);
mult u_mult1(ex0,K0,out0);
mult u_mult2(ex1,K1,out1);
mult u_mult3(ex2,K2,out2);
adder u_adder1(out0,out1,sum1);
adder u_adder2(out2,sum_out_old,sum2);
adder u_adder3(sum1,sum2,sum_out);  

register16b u_old(clk,rst_n,sum_out,sum_out_old);

always@(posedge clk) begin
    state_next = state_reg; 
    case(state_reg)
        idle: begin
                    state_next = load;
                end
        load: begin
                    K0 = Kp_in + Kd_in + Ki_in;
                    K1 = -Kp_in + (-2)*Kd_in;
                    K2 = Kd_in;         
                    state_next = run;
                end
        run: begin

                state_next = run;
              end
    endcase
end

endmodule
Kannst du deinen Code teilen? Haben Sie einen Anfangswert für das Halteregister angegeben oder ein Reset-Signal verwendet, um es zu Beginn Ihrer Simulation in einen bekannten Zustand zu versetzen?
Ja, der Ausgangswert des Registers ist 0, wenn der Reset niedrig ist.
Und Ihre Simulations-Testbench-Sets setzen sich lange genug zurück, um alle Register in einen bekannten Zustand zu bringen, aber dann sehen Sie immer noch, dass 'X'-Werte wieder erscheinen, sobald Sie loslassen reset? Das hört sich so an, als hätten Sie alles richtig gemacht – wenn Sie können, teilen Sie uns Ihren Code mit und wir können nach Tippfehlern oder anderen Problemen suchen.
Sind Sie absolut sicher, dass Sie die Reihenfolge Ihrer Ein- und Ausgänge für instanziierte Blöcke richtig gewählt haben? Ohne explizite Verbindungen (wie reg reg1 (.CLK(c), .RST(r), .I(x), .O(y))) kann ich mir bei diesem Teil Ihres Codes nicht sicher sein.

Antworten (2)

Ich sehe keinen Code K0, der K1, und zurücksetzt K2, bis der Ladezustand verwendet wird.

Dies bedeutet, dass diese Register beim Start Xeinen Wert haben.

Daher haben die Ausgaben von u_mult1, u_mult2, und einen Wert.u_mult3X

Daher erhalten die Ausgaben von u_adder1, u_adder2, und Wert.u_adder3X

sum_out_oldErhält daher bei der nächsten Taktflanke Xeinen Wert. Wahrscheinlich werden gleichzeitig die K-Variablen mit ihren Werten aus den Moduleingängen geladen. Aber es ist zu spät. Da sum_outaus berechnet wird sum_out_old, wird es dann zu Xund sum_out_oldist im XZustand gefangen.

Der einfache Weg, dies zu lösen, besteht darin K0, K1, , und K2auf 0 zurückzusetzen, wenn rst_nbehauptet wird (niedrig), aber Sie sollten überlegen, ob dies für Ihre Situation richtig ist.

Für die Simulation müssen Sie Ihre Werte zu Beginn auf einen bekannten Zustand zurücksetzen. Sie können dafür die Reset-Leitung verwenden, aber dies wird synthetisiert, wie The Photon erwähnt (normalerweise kein Problem).

Eine andere Möglichkeit besteht darin, den Wert beim Codieren des Registers festzulegen, z. B.:

reg [N-1:0]K0 = 8'b00000000;
reg [N-1:0]K1 = 8'b00000000;
reg [N-1:0]K2 = 8'b00000000;

Abhängig von Ihren Tools kann dies funktionieren oder nicht (ich verwende Xilinx-Tools) und tatsächlich synthetisiert werden (dh die Register werden gesetzt, während der Bitstrom in das FPGA geladen wird), aber versuchen Sie es und lassen Sie es uns wissen.

Meine Erinnerung ist, dass einige Versionen von Xilinx-Tools, die ich einmal verwendet habe, dies in der Synthese nicht respektieren würden. Aus diesem Grund codiere ich es normalerweise nicht auf diese Weise. Aber ich denke, es ist gut in neueren Tools.
Ja, ich denke, Sie haben jetzt die Wahl, es zu synthetisieren - Auf jeden Fall verwende ich es nur zur Simulation, wenn ich keine Reset-Leitung habe (und es ist mir egal, ob die Synthese-Tools dies respektieren oder nicht, wie in In den meisten Fällen ist es Ihnen egal, wo das Register beginnt)