脱离ADI官方SDK!纯FPGA硬件SPI驱动AD9361(完整工程+源码解析)

因最近公司需要,借此机会和大家一起学习AD9361

制作不易,记得三连哦,给我动力,持续更新!

工程文件下载:纯硬件SPI配置AD9361   提取码:g9jy 

----------------------------------------------------------------------------------------

ADI 官方目前主要提供基于软件 SDK 与硬件平台 Vivado 的 AD936x 配置方案,但在实际工程应用中,该类方法存在一定局限性。为此,本文将为大家带来一套纯硬件配置 AD936x 的详尽操作指南。考虑到这是手把手教学,若内容偏细致还请行业资深人士海涵。后续我们也会持续更新工程场景下的项目设计内容,话不多说,让我们一同开启 AD936x 的探索之旅!
本次教学以 ZedBoard 搭配 AD9361 为硬件平台,使用同款硬件的小伙伴可完全参照以下步骤操作,搭载 Zynq7020 FPGA 芯片的设备也可适用。其他硬件配置的用户可根据实际芯片规格做相应调整。
通过前两章的内容讲解,相信大家已完成 AD936x 配置脚本的前期准备工作。本章将重点介绍如何通过 SPI 接口,将上一环节生成的脚本文件写入 AD9361 芯片完成参数配置。

一、新建一个vivado工程

新建vivado硬件工程,然后分别把图中这几个文件代码导入工程中,

二、AD9361配置脚本文件

此文件就是上一节,通过AD936X Evaluation Software软件配置好的,脚本文件转化成Verilog的脚本文件,里面包含了所有的ad9361的寄存器配置信息。

 三、顶层设计

顶层主要连接各个模块例化

部分代码:

module system_top(
//系统输入时钟
    input               i_clk,
//AD936X SPI配置
    output              o_spi_clk,
    output              o_spi_csn,
    input               i_spi_miso,
    output              o_spi_mosi,
//AD936X 状态控制引脚
    output              en_agc,
    output reg          enable,
    output reg          txnrx,
    output              chip_rst_n,
    output              sync_in,
    output      [3:0]   ctrl_in,
//AD936X 接收通道数据引脚
    input               rx_clk_in_p,
    input               rx_clk_in_n,
    input       [5:0]   rx_data_in_n,
    input       [5:0]   rx_data_in_p,
    input               rx_frame_in_n,
    input               rx_frame_in_p,
//AD936X 发射通道数据引脚
字
数
太
多
省
略
一
部
分
//接收数据信号
    .rx0_i_data                 (rx0_i_data ),
    .rx0_q_data                 (rx0_q_data ),
    .rx1_i_data                 (rx1_i_data ),
    .rx1_q_data                 (rx1_q_data ),
      /*   
    .tx0_i_data                 (tx0_i_data1),
    .tx0_q_data                 (tx0_q_data1),
    .tx1_i_data                 (tx1_i_data1),
    .tx1_q_data                 (tx1_q_data1)*/
     
    .tx0_i_data                 (tx0_i_data),
    .tx0_q_data                 (tx0_q_data),
    .tx1_i_data                 (tx1_i_data),
    .tx1_q_data                 (tx1_q_data),
    .clk_200M                   (clk_200M  )
    );

endmodule

四、数据处理模块

ad9361数据处理模块,此模块设计了采用LVDS传输模式的接口,接口设计清晰,可以嫁接到任何ad9361和其他FPGA开发板的接口连接,并且接口均为ad9361的接口,并没有其余无用的端口,移植起来非常方便。其中包含了9361数据发射和数据接收。

部分代码:

module data_process(
//接收数据通道
    input                   rx_clk_in_p,
    input                   rx_clk_in_n,
    input                   rx_frame_in_p,   
    input                   rx_frame_in_n,
    input         [5:0]     rx_data_in_p,
    input         [5:0]     rx_data_in_n,
//发送数据通道  
    output                  tx_clk_out_p,
    output                  tx_clk_out_n,
    output                  tx_frame_out_p,
    output                  tx_frame_out_n,
    output        [5:0]     tx_data_out_p,
    output        [5:0]     tx_data_out_n,
//复位信号  
    input                   reset,
    output                  sample_clk,
//接收数据信号  
    output   reg [11:0]     rx0_i_data,
    output   reg [11:0]     rx0_q_data,
    output   reg [11:0]     rx1_i_data,
    output   reg [11:0]     rx1_q_data,
//发送数据信号  
    input        [11:0]     tx0_i_data,
    input        [11:0]     tx0_q_data,
    input        [11:0]     tx1_i_data,
    input        [11:0]     tx1_q_data,
    input wire clk_200M
    );
/****************************SELECTIO IO***********************************/
//selectIO输入和输出的数据
wire [13:0] selectio_rx_data_delay,selectio_rx_data;
reg  [13:0] selectio_tx_data;   
//selectIO输出的单端时钟
// wire data_clk;
//物理接口
wire [6:0] selectio_rx_data_in_p;
wire [6:0] selectio_rx_data_in_n;
wire [6:0] selectio_tx_data_out_p;
wire [6:0] selectio_tx_data_out_n;

assign selectio_rx_data_in_p = {rx_frame_in_p,rx_data_in_p};
assign selectio_rx_data_in_n = {rx_frame_in_n,rx_data_in_n};

wire [4:0]DELAY;//步长78ps,最大步数31约为2.418ns
vio_0 vio_0_inst (
  .clk(clk_200M),                // input wire clk
  .probe_out0(DELAY)  // output wire [4 : 0] probe_out0
);

 五、ad9361初始化模块

根据上一节的ad9361_lut.v脚本文件,可以将读取脚本用状态机实现,分为三个状态为写状态、读状态和延时状态,并通过循环来反复执行这些状态,直到所有寄存器都被配置完毕。最后,可以将状态机设置为一个固定状态,并发出配置结束的标志信号。

为了确保正常操作,我建议将时钟频率设置为25MHz,并与SPI读写时钟保持一致。这样可以确保数据传输的稳定性和可靠性。

通过这种方式,您可以有效地配置AD9361芯片的寄存器,并在配置完成后获得一个明确的结束标志,以确保配置的正确性和完整性。

 通过ad9361_config_writedata传输到SPI读写模块进行读写操作,实现对9361配置脚本的读写,从而配置9361

 部分代码:

module AD936X_Init#
(
    parameter           SPI_CLK_FREQ = 25
)
    (
	input 				i_clk       ,
	input 				i_rst       ,
    output              o_spi_clk   , 
    output              o_spi_cs    , 
    output              o_spi_mosi  ,
    input               i_spi_miso  ,
	output	reg			chip_rst_n  ,
	output 	reg			init_done
);


    /************************reg****************************/
    reg	       [11:0]	            index       ;       //初始化参数索引
    reg         [18:0]	            command     ;       //配置参数命令
    reg         [7:0]                readdata   ;       //读出的8位数据
    /************************wire***************************/
    wire                            w_active;            //SPI总线激活信号
    reg         [23:0]              i_user_data ;        //SPI写数据信号
    reg                             i_user_valid;        //SPI写有效信号
    wire                            o_user_ready;        //SPI驱动准备好信号
    wire        [23:0]              o_user_read_data;    //读出数据
    wire                            o_user_read_valid;   //读出数据有效信号
    /*********************component*************************/

/*****配置命令索引控制*****/
always @(posedge i_clk or posedge i_rst) begin
    if(i_rst)
        index <= 'd0;
    else if(st_current == P_ST_ADD)
        index <= index + 1;
    else 
        index <= index;
end

/*****初始化完成信号*****/
always @(posedge i_clk or posedge i_rst) begin
    if(i_rst)
        init_done <= 'd0;
    else if(st_current == P_ST_END)
        init_done <= 'd1;
    else 
        init_done <= init_done;
end

六、SPI驱动模块

依据上一节从脚本文件中读取到的地址与数据信息,我们能够设计一款具备广泛适用性的 SPI 控制器,用于对各类配置寄存器执行读写操作。利用 always 语句,可实现数据的实时输入,从而完成寄存器的配置工作。
这款通用 SPI 控制器具备显著特性:
  • 高灵活适配:能够依据不同的寄存器配置要求,精准识别脚本文件内的地址与数据信息,针对性地对对应寄存器进行读写操作,满足多样化配置场景。
  • 强工程复用:凭借其通用性优势,该控制器可跨工程重复利用,无论何种寄存器配置需求,都能快速适配投入使用。
  • 状态机精准管控:借助 “开始传输”“传输状态”“传输完成” 三个状态机阶段,在不同操作进程中,控制器可执行相应动作,保障数据传输准确无误,确保操作流程顺利完成。
通过应用这款通用 SPI 控制器,用户可便捷地完成各类寄存器的配置工作。当传输操作结束后,还能获取对应的状态信号反馈,以此确认配置操作成功执行,保障配置的完整性与有效性。

部分代码:

module spi_drive#(
    parameter                   P_DATA_WIDTH    = 8 ,
    parameter                   P_CPOL          = 0 ,
    parameter                   P_CPHA          = 0 
)(
    input                       i_clk               ,
    input                       i_rst               ,

    output                      o_spi_clk           ,
    output                      o_spi_cs            ,
    output                      o_spi_mosi          ,
    input                       i_spi_miso          ,

    input   [P_DATA_WIDTH-1:0]  i_user_data         ,
    input                       i_user_valid        ,
    output                      o_user_ready        ,

    output  [P_DATA_WIDTH-1:0]  o_user_read_data    ,
    output                      o_user_read_valid   
);

字
数
限
制
省
略
always @(posedge i_clk or posedge i_rst) begin
    if(i_rst)
        ro_user_read_data <= 'd0;
    else if(!r_spi_cnt && P_CPHA==0 && r_run)
        ro_user_read_data <= {ro_user_read_data[P_DATA_WIDTH - 2:0],i_spi_miso}; 
    else if(r_spi_cnt && P_CPHA==1  && r_run)
       ro_user_read_data <= {ro_user_read_data[P_DATA_WIDTH - 2:0],i_spi_miso}; 
    else
       ro_user_read_data <= ro_user_read_data;         
end

always @(posedge i_clk or posedge i_rst) begin
    if(i_rst)
        ro_user_read_valid <= 'd0;
    else if(r_spi_cnt && r_cnt == P_DATA_WIDTH - 1)
        ro_user_read_valid <= 'd1;       
    else
        ro_user_read_valid <= 'd0;
end

endmodule

七、下板测试

将上述所有文件添加至工程后,完成管脚分配操作,接着进行编译与实现处理,最终生成 bit 流文件。
AD9361 需工作在 FDD 模式下,启用 tx1 与 rx1、tx2 与 rx2 双通道进行收发。其中,接收频率和发射频率均设定为 2.4GHz。为便于测试,本次设计生成稳定的正弦波信号,通过频谱仪和 ILA 工具分别进行测试,所得实验结果如下:

 

并且通过ila查看了每个读寄存器的值,均符合要求。  

本次纯逻辑配置ad9361设计完成,更多设计后续继续更新使用纯verilog实现AD9361的各种调制解调

posted @ 2025-06-03 15:40  FPGAmaster  阅读(1380)  评论(0)    收藏  举报