【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

仿真结果如下:

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

### 回答1: FPGA(可编程逻辑门阵列)是一种基于可重构逻辑门和触发器阵列的芯片,具有灵活编程能力和高性能处理能力。AD7616是ADI(Analog Devices Inc.)公司生产的一款高精度、高速16通道的模数转换器。 要配置FPGA来接口AD7616,首先需要了解AD7616的规格和特性。AD7616采用SPI(串行外设接口)进行通信,因此需要使用FPGA的SPI模块进行通信。同时,AD7616还具有配置引脚(如CONVST、CS),这些引脚需要与FPGA的GPIO(通用输入输出)引脚相连。 配置步骤如下: 1. 将FPGA的SPI模块与AD7616的SPI接口相连。SPI包括四个信号线:时钟线(SCK)、主输入(MISO)、主输出(MOSI)和片选线(CS)。这些信号线需要正确连接到FPGA和AD7616的对应引脚。 2. 根据AD7616的配置寄存器设置,编写FPGA的控制逻辑代码。这些代码通过SPI发送相应的配置命令和数据给AD7616。可以使用FPGA的编程语言(如VHDL或Verilog)来编写控制逻辑。 3. 配置AD7616的CONVST引脚和FPGA的GPIO引脚相连。CONVST引脚用于触发AD7616的转换操作,可以使用FPGA的GPIO来控制。通过设置GPIO引脚的电平,可以在需要时启动或停止转换。 4. 编译、综合和下载FPGA程序。在完成代码编写后,使用FPGA开发工具进行编译、综合和生成比特流文件。然后将比特流文件下载到FPGA芯片中。 5. 运行和测试。一旦FPGA配置完成,可以启动FPGA并测试AD7616的功能。通过读取SPI接口返回的数据,可以验证AD7616是否正确配置并且转换结果是否准确。 需要注意的是,配置AD7616的具体细节可能会由于FPGA和AD7616的型号和具体应用而有所不同。因此,在实际应用中,请参考AD7616和FPGA的相关数据手册和应用笔记,以确保正确配置和接口操作。 ### 回答2: AD7616是一款高性能的12位模数转换器(MDAC),FPGA(现场可编程门阵列)是一种可实现现场编程的集成电路,可以灵活地配置为不同的逻辑电路。将FPGA配置为AD7616的接口可以实现将模拟信号转换为数字信号的功能。 配置AD7616需要以下步骤: 1. 引脚映射:将AD7616的引脚与FPGA的引脚相连接。通过Pin Planner工具,将AD7616的模拟输入引脚与FPGA的输入引脚相连,将AD7616的数字输出引脚与FPGA的输出引脚相连。确保引脚映射正确,以确保正常通信。 2. 配置时序:根据AD7616的时序要求,设置FPGA的时序。根据AD7616的数据手册,设置FPGA的时钟频率、数据传输速率和时钟相位,以确保AD7616能够正常工作。 3. 驱动程序:编写FPGA的驱动程序,以控制AD7616的工作。通过编程FPGA的逻辑电路,实现与AD7616的通信协议,如SPI。驱动程序需要发送配置命令给AD7616,控制转换速率、参考电压等参数。 4. 测试与调试:在配置完成后,进行测试与调试。通过向AD7616输入模拟信号,观察从FPGA输出的数字信号是否与预期相符。如果存在问题,可以通过调整时序、更改驱动程序等方式进行调试。 总结:通过将AD7616的引脚与FPGA的引脚相连,并根据AD7616的时序要求配置FPGA的时序,编写驱动程序,最后进行测试与调试,就可以实现FPGA配置AD7616的功能。配置过程中需要注意引脚映射、时序设置和驱动程序的编写,以确保AD7616能够正常地工作。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值