赞
踩
因最近公司需要,借此机会和大家一起学习AD9361
制作不易,记得三连哦,给我动力,持续更新!
工程文件下载:纯硬件SPI配置AD9361 提取码:g9jy
----------------------------------------------------------------------------------------
因为ADI官方,只提供了利用软件(SDK)和硬件平台(vivado)去配置AD936x,但是在一些工程中,这种方法很难去应用到实际的项目中,所以给大家介绍一个纯硬件配置AD936x的一个详细教程。因为是手把手教程,所以有些大佬不要嫌麻烦。同时后期会更新工程上的项目设计。废话不多说了,直接进入主题!和我一起学习神秘而又神奇AD936x吧!少年!
我用的是zedboard+ad9361,和我的硬件一样的伙伴,可以完全按照我的步骤进行,FPGA芯片为zynq7020的应该也可以。其余的根据自身芯片要求略微修改即可
根据前两章的讲解,相信大家已经完成了AD936x的脚本准备工作,这节将给大家讲解如果通过SPI把上一节生成的脚本文件,配置到AD9361上。
新建vivado硬件工程,然后分别把图中这几个文件代码导入工程中,
此文件就是上一节,通过AD936X Evaluation Software软件配置好的,脚本文件转化成Verilog的脚本文件,里面包含了所有的ad9361的寄存器配置信息。
ad9361接口文件,此模块设计了采用LVDS传输模式的接口,接口设计清晰,可以嫁接到任何ad9361和其他FPGA开发板的接口连接,并且接口均为ad9361的接口,并没有其余无用的端口,移植起来非常方便。
通过设置adc_r1_mode
和dac_r1_mode
来选择单通道或双通道读写功能。这些配置选项允许您在单通道模式下只使用一个通道进行数据读写,或者在双通道模式下同时使用两个通道进行数据读写。
通过设置adc_r1_mode
和dac_r1_mode
,您可以根据系统需求选择合适的模式。在单通道模式下,您只需使用一个通道进行数据读取或写入,这可能在某些应用中更为简单和高效。而在双通道模式下,您可以同时使用两个通道进行数据读取和写入,这可能在一些需要同时处理多个信号的应用中更为有用。
代码:
- module axi_ad9361_dev_if (
- // 物理接口(接收)
- input rx_clk_in_p,
- input rx_clk_in_n,
- input rx_frame_in_p, //每个数据包起始位置(n:下降 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,
- // 数据时钟
- output data_clk,
- // 接收数据路径接口
- output reg adc_valid,
- output reg [11:0] adc_data_i1,
- output reg [11:0] adc_data_q1,
- output reg [11:0] adc_data_i2,
- output reg [11:0] adc_data_q2,
- output reg adc_status,
- input adc_r1_mode,
- // 发送数据路径接口
- input dac_valid,
- input [11:0] dac_data_i1,
- input [11:0] dac_data_q1,
- input [11:0] dac_data_i2,
- input [11:0] dac_data_q2,
- input dac_r1_mode
- );
-
-
- 字
- 数
- 太
- 多
- 省
- 略
- 一
- 部
- 分
-
- // 发送帧接口, oddr -> obuf
- ODDR #(
- .DDR_CLK_EDGE ("SAME_EDGE" ))
- i_tx_frame_oddr (
- .CE (1'b1 ),
- .R (1'b0 ),
- .S (1'b0 ),
- .C (data_clk ),
- .D1 (tx_frame ),
- .D2 (tx_frame ),
- .Q (tx_frame_oddr_s ));
- OBUFDS i_tx_frame_obuf (
- .I(tx_frame_oddr_s),
- .O(tx_frame_out_p),
- .OB(tx_frame_out_n)
- );
- // 发送时钟接口, oddr -> obuf (需要和data_clk,相同频率和占空比)
- ODDR #(
- .DDR_CLK_EDGE ("SAME_EDGE" ))
- i_tx_clk_oddr (
- .CE (1'b1 ),
- .R (1'b0 ),
- .S (1'b0 ),
- .C (data_clk ),
- .D1 (1'b0 ),
- .D2 (1'b1 ),
- .Q (tx_clk_oddr_s ));
- OBUFDS i_tx_clk_obuf (
- .I(tx_clk_oddr_s),
- .O(tx_clk_out_p),
- .OB(tx_clk_out_n)
- );
-
- endmodule
根据上一节的ad9361_lut.v脚本
文件,可以将读取脚本用状态机实现,分为三个状态为写状态、读状态和延时状态,并通过循环来反复执行这些状态,直到所有寄存器都被配置完毕。最后,可以将状态机设置为一个固定状态,并发出配置结束的标志信号。
为了确保正常操作,我建议将时钟频率设置为20MHz,并与SPI读写时钟保持一致。这样可以确保数据传输的稳定性和可靠性。
通过这种方式,您可以有效地配置AD9361芯片的寄存器,并在配置完成后获得一个明确的结束标志,以确保配置的正确性和完整性。
通过ad9361_config_writedata传输到SPI读写模块进行读写操作,
代码:
- module ad9361_init(
- input clk,
- input rst_n,
- output reg read,
- output reg write,
- output reg [9:0] address,
- output reg [7:0] writedata,
- input [7:0] readdata,
- input waitrequest,
- output reg chip_rst_n,
- output [12:0] init_index,
- output reg init_done
- );
-
- //`define MODELSIM
- `define SPI_CLK_FREQ 20 //MHz
- `include "ad9361_lut.v"
- reg [12:0] index;
- reg [2:0] state;
- reg [31:0] delay_cnt;
- reg [18:0] command;
-
- assign init_index = index;
- always @ (posedge clk) command <= ad9361_lut(index);
-
-
- 字
- 数
- 太
- 多
- 省
- 略
- 一
- 部
- 分
-
-
- 3'd4 : begin
- index <= index + 1;
- state <= state + 1;
- end
- 3'd5 : begin
- state <= state + 1;
- end
- 3'd6 : begin
- state <= 1;
- end
- 3'd7 : begin
- init_done <= 1;
- end
- default : state <= 0;
- endcase
- end
-
- endmodule
基于上一节读取脚本文件读出的地址和数据,我们可以设计一个通用的SPI控制器,用于读写各种配置寄存器。该控制器采用三个状态机来实现不同的功能:开始传输、传输状态和传输完成。同时,我们可以使用一个always
语句来实时输入数据,实现对寄存器的配置。
这个通用SPI控制器具有以下特点:
通过使用这个通用SPI控制器,您可以方便地配置各种寄存器,并在传输完成后获得相应的状态信号,以确保配置的成功和完整性。
代码:
- module ad9361_spi(
- input clk,
- input rst_n,
- //ad9361 interface
- input read,
- input write,
- input [9:0] address,
- input [7:0] writedata,
- output reg [7:0] readdata,
- output reg waitrequest,
- //SPI interface
- output spi_clk,
- output reg spi_csn,
- output reg spi_sdo,
- input spi_sdi
- );
- reg [4:0] bit_cnt;
- reg [23:0] command;
- reg [1:0] state;
- //SPI state
- localparam START = 0,
- TR = 1,
- DONE = 2;
-
- wire wr_rdn; //只写不读
- assign wr_rdn = write && !read;
-
- 字
- 数
- 限
- 制
- 省
- 略
-
- reg [7:0] readdata_shift = 0;
- always @ (posedge clk)
- begin
- readdata_shift <= {readdata_shift[6:0], spi_sdi};
- end
-
- always @ (posedge clk)
- begin
- if (bit_cnt == 24 && read)begin
- readdata <= {readdata_shift[6:0], spi_sdi};
- end
- end
-
- endmodule
需要注意完成配置后,dac_valid才拉高,然后把dac_data传给tx_data,保证传输数据的正确。防止数据进行错位。
代码:
- module system_top(
- //USER GPIO (PL GCLK 100MHz)
- input pl_gclk,
- output led7,
- output reg led0,
- input SW0,
- //ad9361 spi
- output spi_clk,
- output spi_csn,
- input spi_sdi,
- output spi_sdo,
- //ad9361 control
- output en_agc,
- output reg enable,
- output reg txnrx,
- output resetb,
- output sync_in,
- output [3:0] ctrl_in,
- input [7:0] ctrl_out,
- //ad9361 rx channel
- 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,
- 字
- 数
- 限
- 制
- 省
- 略
- ad9361_spi ad9361_spi_0(
- .clk ( gclk_div ),
- .rst_n ( rstr ),
- .read ( ad9361_config_read ),
- .write ( ad9361_config_write ),
- .address ( ad9361_config_address ),
- .writedata ( ad9361_config_writedata ),
- .readdata ( ad9361_config_readdata ),
- .waitrequest ( ad9361_config_waitrequest ),
- .spi_clk ( spi_clk ),
- .spi_csn ( spi_csn ),
- .spi_sdo ( spi_sdo ),
- .spi_sdi ( spi_sdi )
- );
- endmodule
把上述文件全部加入工程之后,然后分配管脚,进行编译和实现,产生bit流文件
AD9361应处在FDD工作状态,tx1和rx1单通道收发,收的频率2.4GHz,发的频率2.4GHz,为了测试方便本次设计产生一个稳定的正弦波信号,用频谱仪和ila分别测试,得出实验结果如下所示:
并且通过ila查看了每个读寄存器的值,均符合要求。
本次纯逻辑配置ad9361设计完成,更多设计后续继续更新,,,
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。