zynq pl读写ddr 实现vga高清显示

其实通过vga显示官方有一个ip核可以用,但是我不是主要为了实现vga显示,而是为了实现如何从ps端向pl端进行大量的数据传送,经过了间断性的不断代码测试,编写,我最终实现了。下面简单说下我是怎样实现的。

目的:

1.实现pl读取ddr内的数据将数据转换成vga的数据流显示到屏幕上,显示大小640*480

2.ps端向ddr内写入像素值,pl端能够同步转换并显示出来。

3.利用axi总线实现。

本次是使用的板子,zybo,板子上的芯片是zynq7010,pl端通信通过axi总线与ps端进行数据的交互,如果要进行简单的交互,可以通过利用axi从模式来进行交互,但是从模式有一个缺点,就是只能等待主端来读这个数据,没有办法来实现pl端主动去写。所以在这里我们就要用要axi的Master模式,从下面这个图片可以看到有7个axi总线可以去读写ddr,2个低速,和4个高速总线,我们这次使用高速总线。



1.配置zynq的外设:这个就不用讲了,网上一搜索一堆。

2.生成一个带axi master的例程ip核。




3. 对于生成的实例代码,其实是向0x xxxx_xxxx地址连续写入4KB的数据,然后在读出来,当然这个实例不满足我们的要求,我们显示的大小是640*480,60Hz,而且在编写代码时我偷了懒,每32bit才传一个像素值(颜色是16bit的),那么我一秒钟要写入的数据量就是 640*480*4*60KB=70.3125兆字节的数据,其实我可以优化到只占一半的带宽,但是我有点懒。

下面对实例进行改造,首先看如下几点:


一次事务传输的大小和长度,这些参数都可以在gui界面中配置,暂时不用管,要知道一次传输的长度最大只有256个字节。

		// Base address of targeted slave
		parameter  C_M_TARGET_SLAVE_BASE_ADDR	= 32'h40000000,
		// Burst Length. Supports 1, 2, 4, 8, 16, 32, 64, 128, 256 burst lengths
		parameter integer C_M_AXI_BURST_LEN	= 16,

要传输的事务次数,第二个参数被我们改过,原来是

C_MASTER_LENGTH-clogb2((C_M_AXI_BURST_LEN*C_M_AXI_DATA_WIDTH/8)-1);
传输的次数就是  [2-1:0] 所占的大小的2次方,也就是4次。从clogb2这个函数就是取以2为底的对数。

// C_TRANSACTIONS_NUM is the width of the index counter for 
	// number of write or read transaction.
	 localparam integer C_TRANSACTIONS_NUM = clogb2(C_M_AXI_BURST_LEN-1);

	// Burst length for transactions, in C_M_AXI_DATA_WIDTHs.
	// Non-2^n lengths will eventually cause bursts across 4K address boundaries.
	// localparam integer C_MASTER_LENGTH	= 12;
	// total number of burst transfers is master length divided by burst length and burst size
	 localparam integer C_NO_BURSTS_REQ = 2;//C_MASTER_LENGTH-clogb2((C_M_AXI_BURST_LEN*C_M_AXI_DATA_WIDTH/8)-1);

这个例子的读写其实是一个3态的状态机实现的,从下面两个地方可以看出来,后面我把写的部分给干掉了,因为我只需要读数据:


代码有点长,粘过来了:

  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;                                                                   
	        start_single_burst_read  <= 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)                                                      
	              begin                                                                                         
	                mst_exec_state  <= INIT_READ;                                                              
	                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 <= INIT_READ;//                                                              
//	              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                                                                                           
	                                                                                                            
	          INIT_READ:                                                                                        
	            // This state is responsible to issue start_single_read pulse to                                
	            // initiate a read transaction. Read transactions will be                                       
	            // issued until burst_read_active signal is asserted.                                           
	            // read controller                                                                              
	            if (reads_done)                                                                                 
	              begin                                                                                         
	                mst_exec_state <= IDLE;                                                             
	              end                                                                                           
	            else                                                                                            
	              begin                                                                                         
	                mst_exec_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; //Negate to generate a pulse                            
	                 end                                                                                        
	              end                                                                                           
	                                                                                                            
	          INIT_COMPARE:                                                                                     
	            // This state is responsible to issue the state of comparison                                   
	            // of written data with the read data. If no error flags are set,                               
	            // compare_done signal will be asseted to indicate success.                                     
	            //if (~error_reg)                                                                               
	            begin                                                                                           
	              ERROR <= error_reg;
	              mst_exec_state <= IDLE;                                                               
	              compare_done <= 1'b1;                                                                         
	            end                                                                                             
	          default :                                                                                         
	            begin                                                                                           
	              mst_exec_state  <= IDLE;                                                              
	            end                                                                                             
	        endcase                                                                                             
	      end                                                                                                   
	  end //MASTER_EXECUTION_PROC                                                                               
	                                 

读地址的地方我也进行了修改,实例中的地址是读到4096个字节就自动复位了,而我们需要读到0x12C000才能复位,这里的复位信号用的是vga显示的场同步来复位的,刚我满足要求。

  

  // Next address after ARREADY indicates previous address acceptance 
      //指向要读的地址,可以通过改变这里来改变要读的地址 
      always @(posedge M_AXI_ACLK)                                       
      begin                                                              
       // if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                          
        if (M_AXI_ARESETN == 0 || vga_vs==1'b0)                                          
          begin                                                          
            axi_araddr <= 'b0;                                           
          end                                                            
        else if (M_AXI_ARREADY && axi_arvalid)                           
          begin                                                          
            axi_araddr <= axi_araddr + burst_size_bytes;                 
          end                                                            
        else                                                             
          axi_araddr <= axi_araddr;                                      
      end       
      


vga实例化的代码如下,增加了许多的数据传输的信号。

 vga utt1_vga(
        clk_25,//25Mhz时钟
        M_AXI_ARESETN,//复位
        out_color,//输出的颜色
        vga_hs,//行同步
        vga_vs,//场同步
        M_AXI_RDATA,//读的数据
        M_AXI_ACLK,//读数据的时钟
        rnext,//读取下一个数据
		init_txn_pulse,//读取脉冲
		repeat_one//重复或开始读取
      );


vga的代码就不粘了,给大家个思路就好。

仿真得到如下波形,不要问我读缓存中的数据为啥是红色,因为我没有去写过数据,所以是全是X,这不重要,我开的缓存有点大,其实用不了这个大,懒的优化了:





可以看到,地址读取是连续的,取数据也没有冲突,仿真已经满足要求了。

在xilinx sdk中进行图片显示测试,代码如下:

/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/

/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xgpio.h"
#include "img.h"


int *axi_addr=(int*)0x10000000;
void set_point(int x,int y,long color){
	if((x>=640||x<0)||(y>=480||y<0)){
		return;
	}
	axi_addr[x+y*(640)]=color;
}

XGpio Gpio; /* The Instance of the GPIO Driver */

void delay(int n){
	int i,j;
	for(i=0;i<n;i++){
		for(j=0;j<2048;j++){

		}
	}
}
int main()
{

	int Status;
    init_platform();
    cleanup_platform();
	/* Initialize the GPIO driver */
	Status = XGpio_Initialize(&Gpio, XPAR_GPIO_0_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/* Set the direction for all signals as inputs except the LED output */
	XGpio_SetDataDirection(&Gpio, 1, 0);

	XGpio_DiscreteWrite(&Gpio,1,0x1);//开始传送数据
	delay(10);
	XGpio_DiscreteWrite(&Gpio,1,0x0);



    int i,j;

	for(i=0;i<640*480;i++)
	axi_addr[i]=0xffff;

	int x_y=0;
//	while(1){
		for(i=0;i<480;i++){
			for(j=0;j<640;j++){
				unsigned short temp=((unsigned short*)gImage_img)[j+i*640];
				temp=(temp>>11)|((temp&0x1f)<<11)|(temp&0x7e0);
				set_point((x_y%640)+j,i,temp);
			}
		}

//		x_y++;
//	}

    return 0;
}









点亮屏幕得到显示完美(其实我已经失败了很多次才完美的):




本来是张美女照片的,我们寝室的拿刀逼我让我换成风景照,没办法他们人多。


有问题,联系小号:549654313,大号:不告诉你



评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值