ZYNQ AXI4总线访问DDR3实现图像数据乒乓存储与显示

目录

前言

一、添加端口

二、添加局部变量

三、例化读写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.读状态机

与写状态机类似,照着来就行

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总线我也是一头雾水,但认真看完总线介绍还是比较简单的

  • 14
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FPGA(现场可编程门阵列)是一种灵活可编程的硬件平台,可以用于实现各种不同的电路功能。而AXI(Advanced eXtensible Interface)是一种高性能、低功耗的总线接口协议,用于连接FPGA与外部设备,如DDR3(双倍数据速率3代)内存。 要通过AXI读取DDR3内存数据,首先需要在FPGA上实例化AXI接口和DDR3控制器模块。AXI接口模块负责与外部设备通信,而DDR3控制器模块则负责管理DDR3内存存取操作。 在设计中,需要按照AXI协议规范进行接口的连接和配置。AXI协议定义了读写操作的时序和数据传输约束。通过连接AXI接口与DDR3控制器,FPGA可以通过AXI总线发送读取指令到DDR3内存,然后读取数据返回。 具体而言,通过AXI读取DDR3的操作步骤如下: 1. 配置AXI接口和DDR3控制器模块,并确保其正确连接。 2. 在FPGA中编写相应的代码,按照AXI协议要求构建读取指令。 3. 将读取指令通过AXI接口发送到DDR3控制器模块。 4. DDR3控制器模块接收到读取指令后,根据指令的地址信息,从DDR3内存中读取相应数据。 5. 读取的数据通过AXI接口返回给FPGA,供后续处理使用。 需要注意的是,AXIDDR3之间的通信速度和性能受到FPGA资源、时钟频率、数据宽度等因素的影响。因此,在设计中需要根据实际情况进行综合考虑,以保证数据的准确读取和传输。同时,还需要确保AXI接口和DDR3控制器模块的接口匹配和正确配置,以确保数据的正确传输和存取。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值