blob: 7416ef70506b35da4fe39cfcbc9c95b98d102637 [file] [log] [blame]
/* PID controller
sigma=Ki*e(n)+sigma
u(n)=(Kp+Kd)*e(n)+sigma+Kd*(-e(n-1))
Data width of Wishbone slave port can be can be toggled between 64-bit, 32-bit and 16-bit.
Address width of Wishbone slave port can be can be modified by changing parameter adr_wb_nb.
Wishbone compliant
Work as Wishbone slave, support Classic standard SINGLE/BLOCK READ/WRITE Cycle
registers or wires
[15:0]kp,ki,kd,sp,pv; can be both read and written
[15:0]kpd; read only
[15:0]err[0:1]; read only
[15:0]mr,md; not accessable
[31:0]p,b; not accessable
[31:0]un,sigma; read only
RS write 0 to RS will reset err[0], OF, un and sigma
[4:0]of; overflow register, read only through Wishbone interface, address: 0x40
of[0]==1 : kpd overflow
of[1]==1 : err[0] overflow
of[2]==1 : err[1] overflow
of[3]==1 : un overflow
of[4]==1 : sigma overflow
[0:15]rl; read lock, when asserted corelated reagister can not be read through Wishbone interface
[0:7]wl; write lock, when asserted corelated reagister can not be written through Wishbone interface
*/
//// SPDX-License-Identifier: LGPL-2.1-or-later ////
`define wb_32bit
module PID #(
`ifdef wb_16bit
parameter wb_nb=16,
`endif
`ifdef wb_32bit
parameter wb_nb=32,
`endif
`ifdef wb_64bit
parameter wb_nb=64,
`endif
adr_wb_nb=16,
kp_adr = 0,
ki_adr = 1,
kd_adr = 2,
sp_adr = 3,
pv_adr = 4,
kpd_adr = 5,
err_0_adr = 6,
err_1_adr = 7,
un_adr = 8,
sigma_adr = 9,
of_adr = 10,
RS_adr = 11
)(
input i_clk,
input i_rst, //reset when high
//Wishbone Slave port
input i_wb_cyc,
input i_wb_stb,
input i_wb_we,
input [adr_wb_nb-1:0]i_wb_adr,
input [wb_nb-1:0]i_wb_data,
output o_wb_ack,
output [wb_nb-1:0]o_wb_data,
//u(n) output
output [31:0]o_un,
output o_valid
);
reg [15:0]kp,ki,kd,sp,pv;
reg wla,wlb; // write locks
wire wlRS;
assign wlRS=wla|wlb;
wire [0:7]wl={{3{wla}},{2{wlb}},3'h0};
reg wack; //write acknowledged
wire [2:0]adr; // address for write
`ifdef wb_16bit
assign adr=i_wb_adr[3:1];
`endif
`ifdef wb_32bit
assign adr=i_wb_adr[4:2];
`endif
`ifdef wb_64bit
assign adr=i_wb_adr[5:3];
`endif
wire [3:0]adr_1; // address for read
`ifdef wb_32bit
assign adr_1=i_wb_adr[5:2];
`endif
`ifdef wb_16bit
assign adr_1=i_wb_adr[4:1];
`endif
`ifdef wb_64bit
assign adr_1=i_wb_adr[6:3];
`endif
wire we; // write enable
assign we=i_wb_cyc&i_wb_we&i_wb_stb;
wire re; //read enable
assign re=i_wb_cyc&(~i_wb_we)&i_wb_stb;
reg state_0; //state machine No.1's state register
wire adr_check_1; // A '1' means address is within the range of adr_1
`ifdef wb_32bit
assign adr_check_1=i_wb_adr[adr_wb_nb-1:6]==0;
`endif
`ifdef wb_16bit
assign adr_check_1=i_wb_adr[adr_wb_nb-1:5]==0;
`endif
`ifdef wb_64bit
assign adr_check_1=i_wb_adr[adr_wb_nb-1:7]==0;
`endif
wire adr_check; // A '1' means address is within the range of adr
`ifdef wb_16bit
assign adr_check=i_wb_adr[4]==0&&adr_check_1;
`endif
`ifdef wb_32bit
assign adr_check=i_wb_adr[5]==0&&adr_check_1;
`endif
`ifdef wb_64bit
assign adr_check=i_wb_adr[6]==0&&adr_check_1;
`endif
//state machine No.1
reg RS;
always@(posedge i_clk or posedge i_rst)
if(i_rst)begin
state_0<=0;
wack<=0;
kp<=0;
ki<=0;
kd<=0;
sp<=0;
pv<=0;
RS<=0;
end
else begin
if(wack&&(!i_wb_stb)) wack<=0;
if(RS)RS<=0;
case(state_0)
0: begin
if(we&&(!wack)) state_0<=1;
end
1: begin
if(adr_check)begin
if(!wl[adr])begin
wack<=1;
state_0<=0;
case(adr)
0: begin
kp<=i_wb_data[15:0];
end
1: begin
ki<=i_wb_data[15:0];
end
2: begin
kd<=i_wb_data[15:0];
end
3: begin
sp<=i_wb_data[15:0];
end
4: begin
pv<=i_wb_data[15:0];
end
endcase
end
end
else if((adr_1==RS_adr)&&(!wlRS)&&(i_wb_data==0))begin
wack<=1;
state_0<=0;
RS<=1;
end
else begin
wack<=1;
state_0<=0;
end
end
endcase
end
//state machine No.2
reg [9:0]state_1;
wire update_kpd;
assign update_kpd=wack&&(~adr[2])&&(~adr[0])&&adr_check; //adr==0||adr==2
wire update_esu; //update e(n), sigma and u(n)
assign update_esu=wack&&(adr==4)&&adr_check;
reg rla; // read locks
reg rlb;
reg [4:0]of;
reg [15:0]kpd;
reg [15:0]err[0:1];
wire [15:0]mr,md;
reg [31:0]p;
reg [31:0]a,sigma,un;
reg cout;
wire cin;
wire [31:0]sum;
wire [31:0]product;
reg start; //start signal for multiplier
reg [1:0]mr_index;
reg [1:0]md_index;
assign mr= mr_index==1?kpd:
mr_index==2?kd:ki;
assign md= md_index==2?err[1]:
md_index==1?err[0]:sum[15:0];
wire of_addition[0:1];
assign of_addition[0]=(p[15]&&a[15]&&(!sum[15]))||((!p[15])&&(!a[15])&&sum[15]);
assign of_addition[1]=(p[31]&&a[31]&&(!sum[31]))||((!p[31])&&(!a[31])&&sum[31]);
always@(posedge i_clk or posedge i_rst)
if(i_rst)begin
state_1<=12'b000000000001;
wla<=0;
wlb<=0;
rla<=0;
rlb<=0;
of<=0;
kpd<=0;
err[0]<=0;
err[1]<=0;
p<=0;
a<=0;
sigma<=0;
un<=0;
start<=0;
mr_index<=0;
md_index<=0;
cout<=0;
end
else begin
case(state_1)
10'b0000000001: begin
if(update_kpd)begin
state_1<=10'b0000000010;
wla<=1;
rla<=1;
end
else if(update_esu)begin
state_1<=10'b0000001000;
wla<=1;
wlb<=1;
rlb<=1;
end
else if(RS)begin //start a new sequance of U(n)
un<=0;
sigma<=0;
of<=0;
err[0]<=0;
end
end
10'b0000000010: begin
p<={{16{kp[15]}},kp};
a<={{16{kd[15]}},kd};
state_1<=10'b0000000100;
end
10'b0000000100: begin
kpd<=sum[15:0];
wla<=0;
rla<=0;
of[0]<=of_addition[0];
state_1<=10'b0000000001;
end
10'b0000001000: begin
p<={{16{sp[15]}},sp};
a<={{16{~pv[15]}},~pv};
cout<=1;
start<=1; // start calculate err0 * ki
state_1<=10'b0000010000;
end
10'b0000010000: begin
err[0]<=sum[15:0];
of[1]<=of_addition[0];
of[2]<=of[1];
p<={{16{~err[0][15]}},~err[0]};
a<={31'b0,1'b1};
cout<=0;
mr_index<=1; // start calculate err0 * kpd
md_index<=1;
state_1<=10'b0000100000;
end
10'b0000100000: begin
err[1]<=sum[15:0];
mr_index<=2; // start calculate err1 * kd
md_index<=2;
state_1<=10'b0001000000;
end
10'b0001000000: begin
mr_index<=0;
md_index<=0;
start<=0;
p<=product; // start calculate err0*ki + sigma_last
a<=sigma;
state_1<=10'b0010000000;
end
10'b0010000000: begin
a<=sum; // start calculate err0*kpd + sigma_recent
sigma<=sum;
of[3]<=of[4]|of_addition[1];
of[4]<=of[4]|of_addition[1];
p<=product;
state_1<=10'b0100000000;
end
10'b0100000000: begin
a<=sum; // start calculate err0*kpd + sigma_recent+err1*kd
of[3]<=of[3]|of_addition[1];
p<=product;
state_1<=10'b1000000000;
end
10'b1000000000: begin
un<=sum;
of[3]<=of[3]|of_addition[1];
state_1<=10'b0000000001;
wla<=0;
wlb<=0;
rlb<=0;
end
endcase
end
wire ready;
multiplier_16x16bit_pipelined multiplier_16x16bit_pipelined(
i_clk,
~i_rst,
start,
md,
mr,
product,
ready
);
adder_32bit adder_32bit_0(
a,
p,
cout,
sum,
cin
);
wire [wb_nb-1:0]rdata[0:15]; //wishbone read data array
`ifdef wb_16bit
assign rdata[0]=kp;
assign rdata[1]=ki;
assign rdata[2]=kd;
assign rdata[3]=sp;
assign rdata[4]=pv;
assign rdata[5]=kpd;
assign rdata[6]=err[0];
assign rdata[7]=err[1];
assign rdata[8]=un[15:0];
assign rdata[9]=sigma[15:0];
assign rdata[10]={11'b0,of};
`endif
`ifdef wb_32bit
assign rdata[0]={{16{kp[15]}},kp};
assign rdata[1]={{16{ki[15]}},ki};
assign rdata[2]={{16{kd[15]}},kd};
assign rdata[3]={{16{sp[15]}},sp};
assign rdata[4]={{16{pv[15]}},pv};
assign rdata[5]={{16{kpd[15]}},kpd};
assign rdata[6]={{16{err[0][15]}},err[0]};
assign rdata[7]={{16{err[1][15]}},err[1]};
assign rdata[8]=un;
assign rdata[9]=sigma;
assign rdata[10]={27'b0,of};
`endif
`ifdef wb_64bit
assign rdata[0]={{48{kp[15]}},kp};
assign rdata[1]={{48{ki[15]}},ki};
assign rdata[2]={{48{kd[15]}},kd};
assign rdata[3]={{48{sp[15]}},sp};
assign rdata[4]={{48{pv[15]}},pv};
assign rdata[5]={{48{kpd[15]}},kpd};
assign rdata[6]={{48{err[0][15]}},err[0]};
assign rdata[7]={{48{err[1][15]}},err[1]};
assign rdata[8]={{32{un[31]}},un};
assign rdata[9]={{32{sigma[31]}},sigma};
assign rdata[10]={59'b0,of};
`endif
assign rdata[11]=0;
assign rdata[12]=0;
assign rdata[13]=0;
assign rdata[14]=0;
assign rdata[15]=0;
wire [0:15]rl;
assign rl={5'b0,rla,{4{rlb}},rla|rlb,5'b0};
wire rack; // wishbone read acknowledged
assign rack=(re&adr_check_1&(~rl[adr_1]))|(re&(~adr_check_1));
assign o_wb_ack=(wack|rack)&i_wb_stb;
assign o_wb_data=adr_check_1?rdata[adr_1]:0;
assign o_un=un;
assign o_valid=~rlb;
endmodule