【FPGA开发】关于如何使用FPGA配置AD9528

这次工作中接触到了AD9528这个亚诺半导体的时钟发生芯片,可以产生多路同步的时钟。这个时钟使用spi接口进行相应的配置。后面记录自己如何针对这个过程进行相应FPGA代码编写。

AD9528 基本介绍:

 

具体的配置参数及方法:

具体我们在项目中使用了,五路时钟,我们的配置要求如下所示:

官网中有相应的可以下载的上位机软件,可以进行相应的配置,配置之后就可以知道相应的需要配置的寄存器参数是什么。

这个是咨询厂家之后的基本配置方法,具体的配置原理,要详细的阅读datasheet,具体的就是OUT1 OUT2两个时钟需要使用从PLL2 divider中产生的时钟

具体需要配置的寄存器如下:

代码编写及AD9528的spi时序图:

AD9528 原理图:

AD9528时序图:

针对这个时序图,我们就开始展开代码编写了:

Verilog代码实现SPI配置寄存器:

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : xibo wu (Gatsby)
// File   : spi.v
// Create : 2023-10-25 16:16:08
// Revise : 2023-10-27 13:46:23
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------



module spi_module
(
    input               i_clk       , // 全局时钟100MHz
    input               i_rst_n     , // 复位信号,低电平有效

    // 四线标准SPI信号定义
    input               i_spi_miso  , // SPI串行输入,用来接收从机的数据
    output              o_spi_sck   , // SPI时钟
    output              o_spi_cs    , // SPI片选信号
    output              o_spi_mosi    // SPI输出,用来给从机发送数据          
);



//-------parameter--------//
parameter TX_IDLE      = 4'b0001;
parameter TX_HEADER    = 4'b0010;
parameter TX_PAYLOAD   = 4'b0100;
parameter TX_END       = 4'b1000;


//-----parameter_reg-------//
//---form “addr_data”------//
parameter REG_1         = 24'h0104_01; 
parameter REG_2         = 24'h0100_01; 
parameter REG_3         = 24'h0102_01;
parameter REG_4         = 24'h0204_01;  
parameter REG_5         = 24'h0201_14;
parameter REG_6         = 24'h010A_02;
parameter REG_7         = 24'h0208_13;
parameter REG_8         = 24'h0501_E0;
parameter REG_9         = 24'h0502_3F;
parameter REG_10        = 24'h0302_11;
parameter REG_11        = 24'h030E_23;
parameter REG_12        = 24'h0303_00;
parameter REG_13        = 24'h0305_05;
parameter REG_14        = 24'h0308_05;          

//---------regs-----------//
reg [4:0]  tx_bit_sel; 
reg        wr_en;
reg [3:0]  clk_cnt;
reg        cs_n_t; 
reg        sck_t = 1'b0;
reg [4:0]  reg_cnt = 5'd14; //此处还不明确后续需要更改
reg        mosi_t;  
reg [23:0] reg_cfg;         //可变的寄存器写入配置数值

//--------debug-----------//
reg [23:0] reg_debug;





reg [3:0]  cur_state;
reg [3:0]  nxt_state;
reg        skip_en;



//-------assign----------//
assign o_spi_sck  = sck_t;
assign o_spi_cs   = cs_n_t;
assign o_spi_mosi = mosi_t;



//---------debug-----------//


always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        reg_debug <= 24'b0;
    end else if(cs_n_t == 1'b0 && clk_cnt == 'd1) begin
        reg_debug <= {reg_debug[22:0],mosi_t};
    end else begin
        reg_debug <= reg_debug;
    end
end


//---------main------------//

always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        clk_cnt <= 4'b0;
    end else if(clk_cnt == 'd3) begin
        clk_cnt <= 'd0;
    end else begin 
        clk_cnt <= clk_cnt + 4'd1;
    end 
end

//要在sck上升沿之前把数据准备好
always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        wr_en <= 1'b0;
    end else if(clk_cnt == 'd2) begin
        wr_en <= 1'b1;
    end else begin
        wr_en <= 1'b0;
    end
end

always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        sck_t <= 1'b0;
    end else if(clk_cnt == 'd1 && cs_n_t == 1'b0) begin
        sck_t <= 1'b1;
    end else if(clk_cnt == 'd3 && cs_n_t == 1'b0) begin
        sck_t <= 1'b0;
    end else begin
        sck_t <= sck_t;
    end
end


// 寄存器数据配置单元 j

always @(posedge i_clk or posedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        reg_cfg <= REG_1;
    end else begin
        case(reg_cnt)
            5'd14 : reg_cfg <= REG_1 ;
            //中间后续填充相应的寄存器数值
            5'd13 : reg_cfg <= REG_2 ;
            5'd12 : reg_cfg <= REG_3 ;
            5'd11 : reg_cfg <= REG_4 ;
            5'd10 : reg_cfg <= REG_5 ;
            5'd9  : reg_cfg <= REG_6 ;
            5'd8  : reg_cfg <= REG_7 ;
            5'd7  : reg_cfg <= REG_8 ;
            5'd6  : reg_cfg <= REG_9 ;
            5'd5  : reg_cfg <= REG_10;
            5'd4  : reg_cfg <= REG_11;
            5'd3  : reg_cfg <= REG_12;
            5'd2  : reg_cfg <= REG_13;
            5'd1  : reg_cfg <= REG_14;
            default:;
        endcase
    end
end


always @(posedge i_clk  or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        cur_state  <=  TX_IDLE;
    end else begin
        cur_state  <=  nxt_state;
    end
end

always @(*) begin
    nxt_state  =  TX_IDLE;
    case (cur_state)
        TX_IDLE : begin
            if (skip_en) begin
                nxt_state  =  TX_HEADER;
            end else begin
                nxt_state  =  TX_IDLE;
            end
        end
        TX_HEADER : begin
            if (skip_en) begin
                nxt_state  =  TX_PAYLOAD;
            end else begin
                nxt_state  =  TX_HEADER;
            end
        end
 
        TX_PAYLOAD : begin
            if (skip_en) begin
                nxt_state  =  TX_END;
            end else begin
                nxt_state  =  TX_PAYLOAD;
            end
        end
  
        TX_END : begin
            if (skip_en) begin
                nxt_state  =  TX_IDLE;
            end else begin
                nxt_state  =  TX_END;
            end
        end

        default : nxt_state  =  TX_IDLE;
    endcase
end

always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        skip_en    <= 1'b0;
        cs_n_t     <= 1'b1;
        tx_bit_sel <= 5'd0;
    end else begin
        skip_en  <=  1'b0;
        case (nxt_state)
            TX_IDLE : begin
                if(reg_cnt != 'd0) begin
                    skip_en <=  1'b1;
                end else begin
                	cs_n_t  <= 1'b1;
                end
            end
            TX_HEADER : begin
                cs_n_t <= 1'b0;
                if (wr_en == 1'b1) begin
                    tx_bit_sel <= tx_bit_sel + 'd1;
                    cs_n_t     <=  1'b0;
                    case(tx_bit_sel)
                        5'd0  : mosi_t <= reg_cfg[23]; //读写位
                        5'd1  : mosi_t <= reg_cfg[22]; //空
                        5'd2  : mosi_t <= reg_cfg[21]; //空
                        5'd3  : mosi_t <= reg_cfg[20]; //addr[12]
                        5'd4  : mosi_t <= reg_cfg[19]; //addr[11]
                        5'd5  : mosi_t <= reg_cfg[18]; //addr[10] 
                        5'd6  : mosi_t <= reg_cfg[17]; //addr[9] 
                        5'd7  : mosi_t <= reg_cfg[16]; //addr[8] 
                        5'd8  : mosi_t <= reg_cfg[15]; //addr[7] 
                        5'd9  : mosi_t <= reg_cfg[14]; //addr[6] 
                        5'd10 : mosi_t <= reg_cfg[13]; //addr[5] 
                        5'd11 : mosi_t <= reg_cfg[12]; //addr[4] 
                        5'd12 : mosi_t <= reg_cfg[11]; //addr[3] 
                        5'd13 : mosi_t <= reg_cfg[10]; //addr[2] 
                        5'd14 : mosi_t <= reg_cfg[9];  //addr[1]
                        5'd15 : begin
                                mosi_t <= reg_cfg[8];  //addr[0]
                                tx_bit_sel <= 'd0;
                                skip_en <= 1'b1;
                                end
                    endcase
                end
            end

            TX_PAYLOAD : begin
                cs_n_t <= 1'b0;
                if (wr_en == 1'b1) begin
                    tx_bit_sel <= tx_bit_sel + 'd1; 
                    case(tx_bit_sel)
                        5'd0 : mosi_t <= reg_cfg[7];  //data[7]
                        5'd1 : mosi_t <= reg_cfg[6];  //data[6]
                        5'd2 : mosi_t <= reg_cfg[5];  //data[5]
                        5'd3 : mosi_t <= reg_cfg[4];  //data[4]
                        5'd4 : mosi_t <= reg_cfg[3];  //data[3]
                        5'd5 : mosi_t <= reg_cfg[2];  //data[2]
                        5'd6 : mosi_t <= reg_cfg[1];  //data[1]
                        5'd7 : begin
                               mosi_t <= reg_cfg[0]; //data[0]
                               tx_bit_sel <= 'd0;
                               skip_en <= 1'b1;
                               end
                    endcase
                end
            end

            TX_END : begin
                if(reg_cnt != 'd0) begin
                    reg_cnt <= reg_cnt - 1'd1;
                    skip_en <=  1'b1;
                end
            end
            default :;
        endcase
    end
end


endmodule

仿真结果如下:

该文章仅用来交流,有错误欢迎各位指正。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值