Post Go back to editing

AD9910,FPGA

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

Thread Notes