Category: Hardware
Product Number: AD9910
我现在用FPGA驱动AD9910没办法锁定PLL到1GHz。(PLL_LOCK引脚一直是低电平,REFCLK_OUT有时钟信号)
我用了50MHz外部有源时钟,然后降压到700mVpp。
计算环路滤波电路,根据计算公式,我采用分频系数N=20,鉴相器增益KD=387uA,VCO增益KV=850MHz/v,开环带宽fOL=200kHz,相位裕量0.785(45°),得出R1 ≈ 92.25 Ω,C1 ≈ 20.81 nF,C2 ≈ 4.32 nF。
设置CFR3寄存器也使能了PLL标志位。我的串行通讯设置没有问题,可以正常初始化设置,但因为没法锁定时钟,导致我输出5MHz正弦信号实际只有3.5MHz。
请问问题出在了哪里,实在是找不出来了。下面有我的配置代码和电路信息。
module AD9910#
(
parameter CFR2_PARALLEL=32'h0140083E,//并行使能,FM:1110(左移14bit)
parameter cfr1=32'h00400000,
parameter cfr2=32'h01400820,
// parameter cfr3=32'h1D3F4114,
parameter cfr3=32'h15384114,
parameter profil0=64'h1FFF00001DB1A6D6,
parameter pwr=1'b0,
parameter pf3=3'b000,
parameter osk1=1'b0,
parameter addr0_start=5'b00000,
parameter addr0_end=5'b00010,
parameter addr1_start=5'b01110,
parameter addr1_end=5'b01110,
parameter F_Freq = 2'b10 ,
parameter F_Amp = 2'b00
)
(
input clk,
input rst_n, // 异步复位信号,低电平有效
//SPI
output reg sclk,
output reg csn,
output reg dout,
//DRG
output reg drctrl=1'b0,
output reg drhold=1'b0,
//IO
output reg io_updata,
output reg io_reset,
output reg master_reset,
output pwrdwnctl,
output [2:0] pf,
//pll_lock
input pll_lock,
//osk
output osk,
//f
output reg [1:0] f,
input [27:0] i_2aom_freq , // 输入的28位目标频率(单位Hz)50m-150m
input [13:0] i_asf , // 调制完的并行输入的14位幅值控制字
input i_asf_done ,
input [1:0] i_para_set , // 参数设置使能,1幅值设置,2:频率设置
output reg [15:0] o_d , //16位并行数据端口
output reg o_tx_parall //使能
);
assign pwrdwnctl=pwr;
assign pf=pf3;
assign osk=osk1;
//------------------------- FTW计算函数(频率转调谐字)16bit ----------------------
localparam RECIPROCAL = 19'd281474; // 1/1G在Q3.16格式下的定点数 (2^32<<16)/1G ≈ 281474
wire [46:0] product; // 乘法器输出结果
reg [15:0] ftw0;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
ftw0 <= 16'd0;
end
else begin
// 计算:ftw = (i_2aom_freq * RECIPROCAL) >> 30
// 取乘积结果的高16位作为FTW
ftw0 <= product[45:30];
end
end
///////////////////////////*sclk-dout-csn-config_start-config_end*/////////////////
localparam addr_cfr1=5'b00000,addr_cfr2=5'b00001,addr_cfr3=5'b00010;
localparam addr_dac=5'b00011,addr_ioup=5'b00100,addr_ftw=5'b00111,addr_pow=5'b01000,addr_asf=5'b01001,addr_syns=5'b01010;
localparam addr_drlimit=5'b01011,addr_drstep=5'b01100,addr_drspeed=5'b01101;
localparam addr_profil0=5'b01110,addr_profil1=5'b01111,addr_profil2=5'b10000,addr_profil3=5'b10001;
localparam addr_profil4=5'b10010,addr_profil5=5'b10011,addr_profil6=5'b10100,addr_profil7=5'b10101;
localparam addr_ram=5'b10110;
localparam start=5'b00101,reset=5'b00110,please=5'b10111,wrinstructions=5'b11000,stop=5'b11001,parrellset=5'b11010;
localparam instructions_trans=1'b0,data_trans=1'b1;
reg edge_config_start;
reg [15:0] reset_delay;
reg [4:0] addr_reg;
reg [5:0] addr_bit;
reg [63:0] trans_data;
reg trans_type;
reg delay;
reg [4:0] status;
reg parallel_en;
reg config_end;
reg config_start;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
sclk <= 1'b0;
csn <= 1'b1;
dout <= 1'b0;
master_reset <= 1'b0;
f <= 2'd0;
o_d <= 16'd0;
o_tx_parall <= 1'b0;
edge_config_start <= 1'b0;
reset_delay <= 16'h0000;
addr_reg <= addr_cfr1;
addr_bit <= 6'b000000;
trans_data <= {{59{1'b0}},addr_cfr1};
trans_type <= data_trans;
status <= start;
config_end <= 1'b0;
parallel_en <= 1'b0;
config_start <= 1'b1;
end
else
case(status)
start:
if(~edge_config_start && config_start)
begin edge_config_start<=config_start;
reset_delay<=16'h0000;
master_reset<=1'b1;
status<=reset;
end
else edge_config_start<=config_start;
reset:
if(reset_delay<16'h03E8)
reset_delay<=reset_delay+1'b1;
else begin master_reset<=1'b0;
csn<=1'b0;
status<=please;
end
please:
if(delay)
begin trans_type<=instructions_trans;
dout<=1'b0;
//The first reg address starts.
trans_data<={{59{1'b0}},addr0_start};
addr_bit<=6'b000111;
//The first reg address starts.
addr_reg<=addr0_start;
config_end<=1'b0;
status<=wrinstructions;
end
else ;
wrinstructions:
if(~sclk && ~delay && ~io_updata && ~io_reset)
sclk<=1'b1;
else if(sclk && (trans_type==instructions_trans))
if(addr_bit==6'b000001)
begin sclk<=1'b0;
dout<=trans_data[addr_bit-1'b1];
addr_bit<=addr_bit-1'b1;
status<=trans_data[4:0];
end
else begin sclk<=1'b0;
dout<=trans_data[addr_bit-1'b1];
addr_bit<=addr_bit-1'b1;
end
else if(sclk && (trans_type==data_trans))
//The second reg address ends.
if((addr_reg==addr_cfr2) && (addr_bit==6'b000001) && (parallel_en==1'b1))
begin sclk<=1'b0;
dout<=trans_data[addr_bit-1'b1];
addr_bit<=addr_bit-1'b1;
status<=stop;
end
else
if((addr_reg==addr1_end) && (addr_bit==6'b000000))
begin sclk<=1'b0;
dout<=1'b0;
trans_data<={{59{1'b0}},addr_cfr2};
addr_bit<=6'b000111;
//The second reg address starts.
addr_reg<=addr_cfr2;
trans_type<=instructions_trans;
parallel_en<=1'b1;
end
//The first reg address ends.
else if((addr_reg==addr0_end) && (addr_bit==6'b000000))
begin sclk<=1'b0;
dout<=1'b0;
//The second reg address starts.
trans_data<={{59{1'b0}},addr1_start};
addr_bit<=6'b000111;
//The second reg address starts.
addr_reg<=addr1_start;
trans_type<=instructions_trans;
end
else if(addr_bit==6'b000000)
begin sclk<=1'b0;
dout<=1'b0;
trans_data<=addr_reg+1'b1;
addr_bit<=6'b000111;
addr_reg<=addr_reg+1'b1;
trans_type<=instructions_trans;
end
else begin sclk<=1'b0;
dout<=trans_data[addr_bit-1'b1];
addr_bit<=addr_bit-1'b1;
end
else ;
addr_cfr1:
if(~sclk)
sclk<=1'b1;
else begin sclk<=1'b0;
dout<=cfr1[31];
trans_data<={32'h00000000,cfr1};
addr_bit<=6'b011111;
trans_type<=data_trans;
status<=wrinstructions;
end
addr_cfr2:
if(~sclk)
sclk<=1'b1;
else if (~parallel_en)begin
sclk<=1'b0;
dout<=cfr2[31];
trans_data<={32'h00000000,cfr2};
addr_bit<=6'b011111;
trans_type<=data_trans;
status<=wrinstructions;
end
else begin
sclk<=1'b0;
dout<=CFR2_PARALLEL[31];
trans_data<={32'h00000000,CFR2_PARALLEL};
addr_bit<=6'b011111;
trans_type<=data_trans;
status<=wrinstructions;
end
addr_cfr3:
if(~sclk)
sclk<=1'b1;
else begin sclk<=1'b0;
dout<=cfr3[31];
trans_data<={32'h00000000,cfr3};
addr_bit<=6'b011111;
trans_type<=data_trans;
status<=wrinstructions;
end
addr_profil0:
if(~sclk)
sclk<=1'b1;
else begin sclk<=1'b0;
dout<=profil0[63];
trans_data<=profil0;
addr_bit<=6'b111111;
trans_type<=data_trans;
status<=wrinstructions;
end
stop:
if(~sclk && ~delay && ~io_updata && ~io_reset)
sclk<=1'b1;
else if(sclk)
sclk<=1'b0;
else if(~config_end & parallel_en)
begin csn<=1'b1;
config_end<=1'b1;
parallel_en<=1'b0;
o_tx_parall <= 1'b1;// 使能TXENABLE,进入并行模式
status<=parrellset;
// status<=start;
end
else ;
parrellset:
if(o_tx_parall) begin // TXENABLE使能后才更新并行数据
status<=parrellset;
case (i_para_set)
2'b01: begin // 幅值模式
if(i_asf_done) begin
f <= F_Amp;
o_d <= {i_asf, 2'b00}; // 14位ASF左移2位到D[15:2]
end
end
2'b10: begin // 频率模式
f <= F_Freq;
o_d <= ftw0; // 16位频率增量
end
default: ;
endcase
end
default:;
endcase
////////////////////////////////////////*delay*/////////////////////////////////////////////
always@(posedge clk or negedge rst_n)
if(!rst_n)
delay<=1'b0;
else if(~csn && (addr_bit==6'b000000) && ~sclk)
delay<=1'b1;
else if(io_updata)
delay<=1'b0;
else ;
////////////////////////////////////////*io_updata*////////////////////////////////////
always@(posedge clk or negedge rst_n)
if(!rst_n)
io_updata<=1'b0;
else if(delay)
io_updata<=1'b1;
else if(io_updata)
io_updata<=1'b0;
else ;
////////////////////////////////////////*io_reset*////////////////////////////////////
always@(posedge clk or negedge rst_n)
if(!rst_n)
io_reset<=1'b0;
else if(io_updata && (trans_type==instructions_trans))
io_reset<=1'b1;
else if(io_reset)
io_reset<=1'b0;
else ;
mult_gen_9910 AD9910 (
.CLK(clk), // input wire CLK - 统一使用50MHz时钟
.A(i_2aom_freq), // input wire [27 : 0] A
.B(RECIPROCAL), // input wire [18 : 0] B
.CE(1'b1), // input wire CE
.P(product) // output wire [46 : 0] P
);
endmodule
