/* 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 |