目标
AD9226为12位,65MHz采样率ADC。基于ZYNQ7010平台,PL端采集AD数据,通过内部AXI总线,将数据搬运到PS的DDR。
可以将如上目标分解为3个小目标
实现PL采集AD9226模块,采集后的数据为AXIS接口。
实现PL侧DMA可搬运AXIS数据到PS的DDR,可配置地址,帧长度,帧数量等。
实现PS侧DMA驱动
本章节实现第一个小目标:
硬件:
主控板
采集模块
模块引脚功能:
D0-D11:并口数据
CLK:时钟
OTR:输入超量程
AD时序
可以发现,此ADC的时序非常简单,只需给AD输入时钟,在时钟上升沿读取12位AD值
FPGA代码实现
AD9226 fpga驱动
`timescale 1ns / 1ps
`default_nettype none
module ad9226_dri #(
parameter TDATA_WIDTH = 32
) (
input wire clk,
input wire rstn,
input wire[11:0] i_ad_data,
input wire i_en, //ad使能
input wire[15:0] i_number, //一个axis报文包含多少次采样数据
output reg[TDATA_WIDTH-1:0] m_axis_fifo_tdata,
output wire[(TDATA_WIDTH/8)-1:0] m_axis_fifo_tkeep,
output reg m_axis_fifo_tlast,
input wire m_axis_fifo_tready,
output reg m_axis_fifo_tvalid
);
localparam BYTE_NUM = (TDATA_WIDTH / 8);
reg[15:0] ad_cnt_reg;
reg[15:0] seq_cnt_reg;
wire[11:0] ad_data_conv;
reg[11:0] ad_data_reg;
assign ad_data_conv[0] = i_ad_data[11];
assign ad_data_conv[1] = i_ad_data[10];
assign ad_data_conv[2] = i_ad_data[9];
assign ad_data_conv[3] = i_ad_data[8];
assign ad_data_conv[4] = i_ad_data[7];
assign ad_data_conv[5] = i_ad_data[6];
assign ad_data_conv[6] = i_ad_data[5];
assign ad_data_conv[7] = i_ad_data[4];
assign ad_data_conv[8] = i_ad_data[3];
assign ad_data_conv[9] = i_ad_data[2];
assign ad_data_conv[10] = i_ad_data[1];
assign ad_data_conv[11] = i_ad_data[0];
// ila_0 ila_0_inst2(
// .clk (clk ),
// .probe0 ({
// m_axis_fifo_tdata,
// m_axis_fifo_tkeep,
// m_axis_fifo_tlast,
// m_axis_fifo_tready,
// m_axis_fifo_tvalid,
// i_en,
// i_number,
// ad_data_conv,
// ad_cnt_reg
// })
// );
always @(posedge clk or negedge rstn) begin
if(rstn == 1'b0) begin
m_axis_fifo_tdata <= 0;
m_axis_fifo_tlast <= 1'b0;
m_axis_fifo_tvalid <= 0;
ad_cnt_reg <= 0;
seq_cnt_reg <= 0;
ad_data_reg <= 0;
end
else begin
if (m_axis_fifo_tready && i_en) begin
/* 偶数0\2\4 */
if (ad_cnt_reg[0] == 0) begin
if (ad_cnt_reg == 0) begin
m_axis_fifo_tdata <= seq_cnt_reg;
m_axis_fifo_tvalid <= 1;
m_axis_fifo_tlast <= 0;
ad_cnt_reg <= ad_cnt_reg + 1;
end
else if (ad_cnt_reg == i_number) begin
m_axis_fifo_tdata <= ad_data_conv;
m_axis_fifo_tvalid <= 1;
m_axis_fifo_tlast <= 1;
ad_cnt_reg <= 0;
seq_cnt_reg <= seq_cnt_reg + 1;
end
else begin
m_axis_fifo_tvalid <= 0;
m_axis_fifo_tlast <= 0;
ad_cnt_reg <= ad_cnt_reg + 1;
end
ad_data_reg <= ad_data_conv;
end
/* 奇数1\3\5 */
else begin
m_axis_fifo_tvalid <= 1;
m_axis_fifo_tdata <= {4'b0, ad_data_conv, 4'b0, ad_data_reg};
if (ad_cnt_reg == i_number) begin
m_axis_fifo_tlast <= 1;
ad_cnt_reg <= 0;
seq_cnt_reg <= seq_cnt_reg + 1;
end
else begin
m_axis_fifo_tlast <= 0;
ad_cnt_reg <= ad_cnt_reg + 1;
end
end
end
else
m_axis_fifo_tvalid <= 0;
end
end
assign m_axis_fifo_tkeep = {BYTE_NUM{1'b1}};
endmodule
`default_nettype wire
仿真代码
`timescale 1ns / 1ns
module ad9226_tb (
);
`include "../../sources_1/new/inc/base.h"
reg clk, reset;
reg[11:0] ad_data;
always #(10) clk = ~clk; //50MHz
initial begin
clk = 0;
ad_data = 0;
end
initial
begin
reset = 1'b1;
#7;
reset = 1'b0; // 解复位
for (; ;) begin
/* 读fifo */
ad_data = ad_data + 1;
#20;
end
$stop;
end
ad9226_dri #(
.TDATA_WIDTH (32 )
) ad9226_dri_inst0 (
.clk (clk ),
.rstn (!reset ),
.i_ad_data (ad_data ),
.i_en (1 ), //ad使能
.i_number (16'hf ), //一个axis报文包含多少次采样数据
.m_axis_fifo_tdata ( ),
.m_axis_fifo_tkeep ( ),
.m_axis_fifo_tlast ( ),
.m_axis_fifo_tready (1 ),
.m_axis_fifo_tvalid ( )
);
endmodule
仿真结果如下:
- AD数据值是递增的
- AXIS是32位的,每个时钟周期传输2次AD采样的数据
- 每个AXIS包,包含16帧AD采样数据
- AXIS帧首先传输的是帧计数