目录
前言
一、添加端口
二、添加局部变量
三、例化读写FIFO
四、内部变量修改,设置一次读写进行多少次突发操作
五、写地址
六、读地址
七、状态机
1.写状态机
2.读状态机
总结
前言
在Altera FPGA进行图像处理时,我们采用的存储芯片为SDRAM,当时参照正点原子的例程是封装SDRAM控制器,然后像操作FIFO一样去控制SDRAM。现在换了ZYNQ的板子后,由于DDR3是挂载在PS端的,Xilinx官方提供了视频接口的IP,但是IP这东西像个小黑盒子一样,在开发过程中遇到了问题,极其不易排查,所以我就在官方的AXI4—FULL接口代码上稍做修改,实现像以前一样像操作FIFO一样去操作PS端的DDR3。
一、添加端口
// Users to add ports here
//图像数据写端口
input wire wr_clk, //输入像素时钟
input wire wr_en, //数据有效信号
input wire [15:0] wr_data, //像素数据
//图像数据读端口
input wire rd_clk, //输入hdmi驱动时钟
input wire rd_en, //读请求
output wire [15:0] rd_data, //像素数据
二、添加局部变量
触发一次读写DDR3的FIFO中的数据量设置为256,当写FIFO中的数据量大于THRESHOLD进行一次写操作的触发,当读FIFO中的数据量小于THRESHOLD时进行一次读操作的触发。一帧图像的最大存储地址为FIRST_FRAME
// I/O Connections assignments
localparam THRESHOLD = 256 ; //触发写FIFO读数据个数
localparam FIRST_FRAME = (640*480)*4 ; //存储最大值
三、例化读写FIFO
用作数据缓存
// Add user logic here
//写数据补位
assign din_wr_fifo = {16'd0,wr_data};
assign wr_en_wr_fifo = wr_en;
assign rd_en_wr = wnext;
//写FIFO
wr_fifo inst_fifo (
.wr_clk(wr_clk), // input wire wr_clk
.rd_clk(M_AXI_ACLK), // input wire rd_clk
.din(din_wr_fifo), // input wire [31 : 0] din
.wr_en(wr_en_wr_fifo), // input wire wr_en
.rd_en(rd_en_wr), // input wire rd_en
.dout(dout_wr_fifo), // output wire [31 : 0] dout
.full(full_wr_fifo), // output wire full
.empty(empty_wr_fifo), // output wire empty
.rd_data_count(rd_data_count_wr_fifo) // output wire [11 : 0] rd_data_count
);
assign rd_data = dout_rd_fifo[15:0];
assign wr_en_rd_fifo = rnext;
//读FIFO
rd_fifo inst_rd_fifo (
.wr_clk(M_AXI_ACLK), // input wire wr_clk
.rd_clk(rd_clk), // input wire rd_clk
.din(M_AXI_RDATA), // input wire [63 : 0] din
.wr_en(wr_en_rd_fifo), // input wire wr_en
.rd_en(rd_en), // input wire rd_en
.dout(dout_rd_fifo), // output wire [31 : 0] dout
.full(full_rd_fifo), // output wire full
.empty(empty_rd_fifo), // output wire empty
.rd_data_count(rd_data_count_rd_fifo), // output wire [11 : 0] rd_data_count
.wr_data_count(wr_data_count_rd_fifo) // output wire [10 : 0] wr_data_count
);
四、内部变量修改,设置一次读写进行多少次突发操作
将原本代码里面C_MASTER_LENGTH 的数值12更改为10,原本的12表示一次读写操作进行64次突发操作,由于一次突发的数据量为16个32位的数据,所以64*16=1024个数据,与AXI4读写DDR3的实验现象一致,更改位10的原因为让其一次读写的数据量保持跟设置的THRESHOLD 一致都为256,避免数据冲突。
五、写地址
由于DDR3可以自由设置数据存储的地址,所以我们在代码内部自己划分读写bank,从而可以实现乒乓操作。
always @(posedge M_AXI_ACLK)begin
if(M_AXI_ARESETN == 0)begin
bank_1 <= 2'b00;
end
else if((axi_awaddr[21:0] == FIRST_FRAME) && writes_done && bank_1 == 2'b00)begin
bank_1 <= 2'b01;
end
else if((axi_awaddr[21:0] == FIRST_FRAME) && writes_done && bank_1 == 2'b01)begin
bank_1 <= 2'b00;
end
else
bank_1 <= bank_1;
end
always @(posedge M_AXI_ACLK)
begin
if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)
begin
axi_awaddr <= 'b0;
sw_bank_en <= 1'b0;
rw_bank_flag <= 1'b0;
end
else if (M_AXI_AWREADY && axi_awvalid)
begin
//bank0的剩余地址满足一次突发长度
if(axi_awaddr[21:0] < FIRST_FRAME - burst_size_bytes)begin
axi_awaddr <= axi_awaddr + burst_size_bytes;
end
//不满足切换BANK
else begin
axi_awaddr <= {8'b0000_0000,bank_1,22'd0};
end
end
else
axi_awaddr <= axi_awaddr;
end
六、读地址
读地址操作与写地址类似。
七、状态机
1.写状态机
在原本官方状态机上删除读状态与读写错误判断状态。
always @ ( posedge M_AXI_ACLK)
begin
if (M_AXI_ARESETN == 1'b0 )
begin
// reset condition
// All the signals are assigned default values under reset condition
mst_exec_state <= IDLE;
start_single_burst_write <= 1'b0;
compare_done <= 1'b0;
ERROR <= 1'b0;
end
else
begin
// state transition
case (mst_exec_state)
IDLE:
// This state is responsible to wait for user defined C_M_START_COUNT
// number of clock cycles.
if ( init_txn_pulse == 1'b1 || rd_data_count_wr_fifo >= THRESHOLD)
begin
mst_exec_state <= INIT_WRITE;
start_single_burst_write <= 1'b0;
ERROR <= 1'b0;
compare_done <= 1'b0;
end
else
begin
mst_exec_state <= IDLE;
end
INIT_WRITE:
// This state is responsible to issue start_single_write pulse to
// initiate a write transaction. Write transactions will be
// issued until burst_write_active signal is asserted.
// write controller
if (writes_done)
begin
mst_exec_state <= IDLE;//
start_single_burst_write <= 1'b0;
end
else
begin
mst_exec_state <= INIT_WRITE;
if (~axi_awvalid && ~start_single_burst_write && ~burst_write_active)
begin
start_single_burst_write <= 1'b1;
end
else
begin
start_single_burst_write <= 1'b0; //Negate to generate a pulse
end
end
default :
begin
mst_exec_state <= IDLE;
end
endcase
end
end
2.读状态机
与写状态机类似,照着来就行文章来源:https://www.toymoban.com/news/detail-787489.html
always @(posedge M_AXI_ACLK)begin
if(M_AXI_ARESETN == 1'b0)begin
curr_state <= IDLE;
start_single_burst_read <= 1'b0;
end
else begin
case(curr_state)
IDLE:
if(wr_data_count_rd_fifo < 2048-THRESHOLD)begin
curr_state <= INIT_READ;
start_single_burst_read <= 1'b0;
end
else begin
curr_state <= IDLE;
end
INIT_READ:
if(reads_done)begin
curr_state <= IDLE;
start_single_burst_read <= 1'b0;
end
else begin
curr_state <= INIT_READ;
if(~axi_arvalid && ~burst_read_active && ~start_single_burst_read)begin
start_single_burst_read <= 1'b1;
end
else begin
start_single_burst_read <= 1'b0;
end
end
default :
begin
curr_state <= IDLE;
end
endcase
end
end
总结
一开始拿到AXI4总线我也是一头雾水,但认真看完总线介绍还是比较简单的文章来源地址https://www.toymoban.com/news/detail-787489.html
到了这里,关于ZYNQ AXI4总线访问DDR3实现图像数据乒乓存储与显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!