Xilinx 平台 drp 动态调节 mmcm
分享个人觉得有意思的知识:
-
什么样的时钟 会输入到 锁相环里
-
锁相环框图 VCO 控制电压控制频率 DS182 可以查看 VCO 范围
a. 先生成高频 的 VCO
b. 再通过 倍频和分频 产生具体各路时钟
c. -
怎么控制 输出频率?XAPP888
a. high time 是VCO 高电平 持续周期
b. low time 是 VCO 低电平持续周期
c. no count 是 VCO时钟周期的计数
d. edge 将high time 再扩展半个vco 周期 ,可以用来奇数分频 变成 50%占空比
e. high time 和 low time的 和 是 分频值 -
控制相位
b. 八个可变调节 以 45°为步长
c. 如果需要 20°就需要使用delay time
d. vco 频率越高,分频系数越高,相位越精细,如果是 10分频那么VCO输出一周期就是便宜360/10 = 36° -
小数分频
-
时序图:
- 代码:
此代码 配置 其中的一个时钟输出,首先读出对于寄存器,然后设置,再读出对比寄存器值,观察是否设置成功,可以使用 LED 观察现象。
代码分享
`timescale 1ns / 1ps
module drp(
input i_clk ,
input i_rst ,
output [6 :0] o_daddr ,
output o_dclk ,
output o_den ,
output [15:0] o_din ,
output o_dwe ,
input [15:0] i_dout ,
input i_drdy ,
output o_mmcm_rst
);
localparam P_CLKOUT0_REG1_ADDR = 16'h08 ;
localparam [5 :0] P_HIGN_TIME = 6'd10 ;
localparam [5 :0] P_LOW_TIME = 6'd10 ;
localparam P_ST_IDLE = 0 ,
P_ST_RST = 1 ,
P_ST_RREG = 2 ,
P_ST_WRDY = 3 ,
P_ST_SET = 4 ,
P_ST_WAIT_RDY = 5 ,
P_ST_2RREG = 6 ,
P_ST_2WRDY = 7 ,
P_ST_END = 8 ;
reg [7 :0] r_st_current ;
reg [7 :0] r_st_next ;
reg [15:0] r_st_cnt ;
reg [6 :0] ro_daddr ;
reg ro_dclk ;
reg ro_den ;
reg [15:0] ro_din ;
reg ro_dwe ;
reg ro_mmcm_rst ;
(* MARK_DEBUG = "TRUE" *)reg [15:0] r_clkout0_reg1 ;
(* MARK_DEBUG = "TRUE" *)reg [15:0] r_clkout0_2reg1 ;
reg [1 :0] r_rdy ;
assign o_daddr = ro_daddr ;
assign o_dclk = ro_dclk ;
assign o_den = ro_den ;
assign o_din = ro_din ;
assign o_dwe = ro_dwe ;
assign o_mmcm_rst = ro_mmcm_rst ;
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_current <= P_ST_IDLE;
else
r_st_current <= r_st_next;
end
always@(*)
begin
case(r_st_current)
P_ST_IDLE : r_st_next = r_st_cnt == 20000 ? P_ST_RST : P_ST_IDLE ;
P_ST_RST : r_st_next = r_st_cnt == 20 ? P_ST_RREG : P_ST_RST ;
P_ST_RREG : r_st_next = P_ST_WRDY;
P_ST_WRDY : r_st_next = r_rdy[1] ? P_ST_SET : P_ST_WRDY ;
P_ST_SET : r_st_next = P_ST_WAIT_RDY;
P_ST_WAIT_RDY : r_st_next = r_rdy[1] ? P_ST_2RREG : P_ST_WAIT_RDY;
P_ST_2RREG : r_st_next = P_ST_2WRDY;
P_ST_2WRDY : r_st_next = r_rdy[1] ? P_ST_END : P_ST_2WRDY;
P_ST_END : r_st_next = P_ST_END;
default : r_st_next = P_ST_IDLE;
endcase
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_cnt <= 'd0;
else if(r_st_current != r_st_next)
r_st_cnt <= 'd0;
else
r_st_cnt <= r_st_cnt + 1;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_mmcm_rst <= 'd0;
else if(r_st_current == P_ST_END)
ro_mmcm_rst <= 'd0;
else if(r_st_current == P_ST_RST)
ro_mmcm_rst <= 'd1;
else
ro_mmcm_rst <= ro_mmcm_rst;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst) begin
ro_daddr <= 'd0;
ro_den <= 'd0;
ro_din <= 'd0;
ro_dwe <= 'd0;
end else if(r_st_current == P_ST_RREG || r_st_current == P_ST_2RREG) begin
ro_daddr <= P_CLKOUT0_REG1_ADDR;
ro_den <= 'd1;
ro_din <= 'd0;
ro_dwe <= 'd0;
end else if(r_st_current == P_ST_SET) begin
ro_daddr <= P_CLKOUT0_REG1_ADDR;
ro_den <= 'd1;
ro_din <= (r_clkout0_reg1 | 16'b0000_1111_1111_1111) & {4'b1111,P_HIGN_TIME,P_LOW_TIME};
ro_dwe <= 'd1;
end else begin
ro_daddr <= 'd0;
ro_den <= 'd0;
ro_din <= 'd0;
ro_dwe <= 'd0;
end
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_rdy <= 'd0;
else
r_rdy <= {r_rdy[0],i_drdy};
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_clkout0_reg1 <= 'd0;
else if(r_st_current == P_ST_WRDY && i_drdy)
r_clkout0_reg1 <= i_dout;
else
r_clkout0_reg1 <= r_clkout0_reg1;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_clkout0_2reg1 <= 'd0;
else if(r_st_current == P_ST_2WRDY && i_drdy)
r_clkout0_2reg1 <= i_dout;
else
r_clkout0_2reg1 <= r_clkout0_2reg1;
end
endmodule