赞
踩
目录
在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 ; //存储最大值
用作数据缓存
- // 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
读地址操作与写地址类似。
在原本官方状态机上删除读状态与读写错误判断状态。
- 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
与写状态机类似,照着来就行
- 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总线我也是一头雾水,但认真看完总线介绍还是比较简单的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。