提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
使用GUI来配置rpll还是很明了的,这个不需要太多说明就能直接使用了,我主要是要搞清楚原语的使用以及rPLL的内部结构
端口介绍如下:
module my_pll (
clkout,
lock,
clkoutp,
reset,
clkin,
idsel,
fbdsel,
odsel,
psda,
dutyda,
fdly
);
output clkout;
output lock;
output clkoutp;
input reset;
input clkin;
input [5:0] idsel;
input [5:0] fbdsel;
input [5:0] odsel;
input [3:0] psda;
input [3:0] dutyda;
input [3:0] fdly;
wire clkoutd_o;
wire clkoutd3_o;
wire gw_vcc;
wire gw_gnd;
assign gw_vcc = 1'b1;
assign gw_gnd = 1'b0;
rPLL rpll_inst (
.CLKOUT(clkout),
.LOCK(lock),
.CLKOUTP(clkoutp),
.CLKOUTD(clkoutd_o),
.CLKOUTD3(clkoutd3_o),
.RESET(reset),
.RESET_P(gw_gnd),
.CLKIN(clkin),
.CLKFB(gw_gnd),
.FBDSEL(fbdsel),
.IDSEL(idsel),
.ODSEL(odsel),
.PSDA(psda),//4'b0011
.DUTYDA(dutyda), //4'b1000
.FDLY(fdly) //4'b1111
);
defparam rpll_inst.FCLKIN = "25";
defparam rpll_inst.DYN_IDIV_SEL = "true";
defparam rpll_inst.IDIV_SEL = 0;
defparam rpll_inst.DYN_FBDIV_SEL = "true";
defparam rpll_inst.FBDIV_SEL = 0;
defparam rpll_inst.DYN_ODIV_SEL = "true";
defparam rpll_inst.ODIV_SEL = 48;
defparam rpll_inst.PSDA_SEL = "0100";
defparam rpll_inst.DYN_DA_EN = "true";
defparam rpll_inst.DUTYDA_SEL = "1000";
defparam rpll_inst.CLKOUT_FT_DIR = 1'b1;
defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1;
defparam rpll_inst.CLKOUT_DLY_STEP = 0;
defparam rpll_inst.CLKOUTP_DLY_STEP = 0;
defparam rpll_inst.CLKFB_SEL = "internal";
defparam rpll_inst.CLKOUT_BYPASS = "false";
defparam rpll_inst.CLKOUTP_BYPASS = "false";
defparam rpll_inst.CLKOUTD_BYPASS = "false";
defparam rpll_inst.DYN_SDIV_SEL = 2;
defparam rpll_inst.CLKOUTD_SRC = "CLKOUT";
defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT";
defparam rpll_inst.DEVICE = "GW2A-18";
endmodule
这几个地方设置为true,则表示参数可以通过外部来进行配置
defparam rpll_inst.DYN_IDIV_SEL = "true";
defparam rpll_inst.DYN_FBDIV_SEL = "true";
defparam rpll_inst.DYN_ODIV_SEL = "true";
defparam rpll_inst.DYN_DA_EN = "true";
CLKOUT的计算公式如下:
使用的GW2A-18器件VCO的范围:
同时,我们要根据下面的表选择合适的参数
根据下面这些表
那么假设输入时钟为25MHz,输出时钟为100MHz,那么IDIV:FBDIV = 1:4
将VCO配置为800MHz,那么ODIV = 8,IDIV=1,FBDIV = 4 则是一组合法的配置值
那么假设输入时钟为25MHz,输出时钟为150MHz,那么IDIV:FBDIV = 1:6
将VCO配置为1200MHz,那么ODIV = 8,IDIV=1,FBDIV = 6 则是一组合法的配置值
等等。
注意,实际值和参数值的转换关系,输入端口的数据还要做一下处理:
assign para_idsel = 7'd64 - idsel;
assign para_fbdsel = 7'd64 - fbdsel;
always @*
begin
case(odsel)
2:para_odsel = 6'b111111;
4:para_odsel = 6'b111110;
8:para_odsel = 6'b111100;
16:para_odsel = 6'b111000;
32:para_odsel = 6'b110000;
48:para_odsel = 6'b101000;
64:para_odsel = 6'b100000;
80:para_odsel = 6'b011000;
96:para_odsel = 6'b010000;
112:para_odsel = 6'b001000;
128:para_odsel = 6'b000000;
default:para_odsel = 6'b101000;
endcase
end
对应着这三个参数:
input [3:0] psda;
input [3:0] dutyda;
input [3:0] fdly;
对于这些参数的设置范围是:
占空比我只固定设置为50%,但调整相移的时候,不仅仅是只调整 psda这个参数,还要调整dutyda这个参数,否则,占空比会变成不是50%,这点要注意。
手册上也讲到了
动态占空比调整需要参考相移设置。例如,当相移设置为"0”(0000)时,50%占空比设置为"8”(1000)。如果相移的设置是"180o”,50%占空比的设置为"0”(0000)。
动态占空比计算:若DUTYDA [3:0]> PSDA [3:0]时,DutyCycle=1/16 x (DUTYDA [3:0]-PSDA [3:0])。
若DUTYDA [3:0]< PSDA [3:0]时,DutyCycle=1/16 x (16+ DUTYDA[3:0]- PSDA [3:0])。
可以用下面代码来实现上面的公式:
assign para_psda = psda;
assign para_dutyda = {~para_psda[3],para_psda[2:0]};
最后,如果还要更精细的调整,可以通过端口FDLY [3:0]动态控制输出时钟CLKOUTP 的延迟。每一步增加0.125ns。需要结合相移设置实现滞后(时钟信号CLKOUTP 滞后于输入时钟)和超前(时钟信号CLKOUTP 超前输入时钟)。
可以实现1,2,4,8步的调整