I have a problem with writing Verilog HDL code. I want to design a simple PID controller in FPGA I am using Cyclone II family. I want to feedback my output value as an input in a previous stage of calculations. Equation looks like this u(n) = u(n-1) + x (x is calculated correctly) so I created a register to save the output value and connected it to a previous stage in my design.
Unfortunately this solution doesn't work when I simulate this I get 'unknown' value in the register that I am saving the output value to and the output value itself is also 'unknown' (by unknown I mean 'x').
Is it possible to create a feedback loop between certain components in HDL design? How can it be done? Should I try to resolve this issue by doing the calculations step by step in an FSM?
EDIT: This is my code as requested
PID Module
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
2 Answers 2
I don't see any code that resets K0
, K1
, and K2
, until the load state is used.
This means that on start-up, these registers have X
value.
Therefore the outputs of u_mult1
, u_mult2
, and u_mult3
have X
value.
Therefore the outpus of u_adder1
, u_adder2
, and u_adder3
get X
value.
Therefore on the next clock edge, sum_out_old
gets X
value. Probably at the same time, the K variables get loaded with their values from the module inputs. But it's too late. Since sum_out
is calculated from sum_out_old
, it then becomes X
, and sum_out_old
is trapped in the X
state.
The easy way to solve this is to have K0
, K1
, and K2
reset to 0 when rst_n
is asserted (low), but you should consider if this is correct for your situation.
For simulation, you need to reset your values to a known state at the beginning. You can use the reset line for this, but this ends up synthesised as The Photon mentions (not usually a problem)
Another way to do it is to set the value when you code the register, such as:
reg [N-1:0]K0 = 8'b00000000;
reg [N-1:0]K1 = 8'b00000000;
reg [N-1:0]K2 = 8'b00000000;
Depending on your tools, this may or may not work (I use Xilinx tools), and actually may end up being synthesised (i.e. the registers are set during the bitstream being loaded into the FPGA) but give it a go and let us know.
-
\$\begingroup\$ My memory is that some version of Xilinx tools that I used once wouldn't respect this in synthesis. Because of that, I habitually don't code it this way. But I think it's good in recent tools. \$\endgroup\$The Photon– The Photon2013年01月20日 21:39:04 +00:00Commented Jan 20, 2013 at 21:39
-
\$\begingroup\$ Yes, I think you have the choice for it to synthesise now - In any case I just use it for simulation when I don't have a reset line (and I don't mind whether the synthesis tools respect it or not, as in most cases you don't mind what the register starts out at) \$\endgroup\$Oli Glaser– Oli Glaser2013年01月20日 22:07:54 +00:00Commented Jan 20, 2013 at 22:07
reset
? That sounds like you did everything right --- if you can, share your code and we can look for typo's or other kinds of problems. \$\endgroup\$reg reg1 (.CLK(c), .RST(r), .I(x), .O(y))
), there's no way I can be sure of this part of your code. \$\endgroup\$