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

来源:互联网 发布:三网合一网站源码 编辑:程序博客网 时间:2024/05/02 07:47

其实通过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 slaveparameter  C_M_TARGET_SLAVE_BASE_ADDR= 32'h40000000,// Burst Length. Supports 1, 2, 4, 8, 16, 32, 64, 128, 256 burst lengthsparameter 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,大号:不告诉你



原创粉丝点击