Zynq-7000电子相册的实现

作者:OpenSLee

1 背景知识

电子相册的实现就是通过按键来改变显示器的图片轮换。本节将通过ps端的按键来控制ARM选择不同的图片通过HDMI输出到显示屏。

1.1 AXI_VDMA的介绍

Xilinx的AXI VDMA(Video Direct Memory Access)核是个软核。它提供了高带宽的直接内存存取在内存和支持AXI4-Stream video的目标互联。如下图所示既是一个axi_vdma IP。

如下图所示,它是AXI VDMA结构框图。

当Registers通过AXI4-Lite接口被编程,Control/Status模块产生适当的合适命令去DataMover模块,DataMover模块初始化读和写命令在AXI4 Master接口上。

一个可配置的异步行缓冲区用于在之前临时保存像素数据把它写在AXI4 Memory Map接口或AXI4-Stream接口上。

在写路径中,AXI VDMA接受AXI4-stream slave接口的帧使用AXI4 Master接口将其写到系统内存中。

在读路径中,AXI VDMA使用AXI4 Master接口从系统内存读帧和输出在AXI4-Stream Master接口上。

Read (MM2S) Path Timing

Write(S2MM) Path Timing

1.2 V-tc模块的介绍

V_tc(Video Timing Controller) IP 主要用来产生显示器输出所需的时序信号。IP模块如下图所示。

1.3 AXI4-Stream to Video Out IP 的介绍

该模块主要是将AXI4-stream 转换为视频输出模块。模块图如下。

2 电子相册的实现

整个模块图如上图所示。对于工程的创建在此不再赘述。可参考《Zynq-7000 ARM端helloworld实验》。

1) ZYNQ7 Processing System 的设置

为了使用PS端的按键我们勾选GPIO MIO如下图所示。

为了与DDR3通信我们勾选HP0接口。

时钟配置如下

2) VDMA的配置

VDMA的配置如下图所示,因为没有用到视频的输入所以在这里不需要选择写通道。

其他模块的配置和使用在此不再赘述,需要源工程的可以联系FPGA开源工作室。

3) launch SDK

(1)首先选中system右键选中Generate Output Products...

(2)选中system右键选中Create HDL Wrapper...

(3)建立约束文件XDC

(4)生成bitstream。

(5)导出硬件 选择菜单File->Export->Export Hardware...。这里包括bitstream

(6)Launch SDK 选择菜单File->Launch SDK,启动SDK环境。

4)SDK编程

新建APP也在此不再赘述。

图片的制作:

从网上下载800*600的图片,使用img2lcd工具设置如下。

主程序如下所示:

/* ------------------------------------------------------------ */

/*Include File Definitions*/

/* ------------------------------------------------------------ */

#include "display_demo.h"

#include "display_ctrl/display_ctrl.h"

#include

#include "math.h"

#include

#include

#include "xil_types.h"

#include "xil_cache.h"

#include "xparameters.h"

#include "pic_800_600.h"

#include "pic1_800_600.h"

#include "pic2_800_600.h"

#include "pic3_800_600.h"

#include "pic4_800_600.h"

#include "xgpiops.h"

#include "sleep.h"

#include "xil_printf.h"

#include "stdio.h"

/*

* XPAR redefines

*/

#define DYNCLK_BASEADDR XPAR_AXI_DYNCLK_0_BASEADDR

#define VGA_VDMA_ID XPAR_AXIVDMA_0_DEVICE_ID

#define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID

#define VID_VTC_IRPT_ID XPS_FPGA3_INT_ID

#define VID_GPIO_IRPT_ID XPS_FPGA4_INT_ID

#define SCU_TIMER_ID XPAR_SCUTIMER_DEVICE_ID

#define UART_BASEADDR XPAR_PS7_UART_1_BASEADDR

/* ------------------------------------------------------------ */

/*Global Variables*/

/* ------------------------------------------------------------ */

/*

* Display Driver structs

*/

DisplayCtrl dispCtrl;

XAxiVdma vdma;

/*

* Framebuffers for video data

*/

u8 frameBuf[DISPLAY_NUM_FRAMES][DEMO_MAX_FRAME] __attribute__ ((aligned(64)));

u8 *pFrames[DISPLAY_NUM_FRAMES]; //array of pointers to the frame buffers

/* ------------------------------------------------------------ */

/*Procedure Definitions*/

/* ------------------------------------------------------------ */

int main(void)

{

int Status;

XAxiVdma_Config *vdmaConfig;

int i;

static XGpioPs psGpioInstancePtr;

XGpioPs_Config* GpioConfigPtr;

int xStatus;

int MIO_Led0 = 0; //MIO0_LED

int MIO_Led1 = 13; //MIO13_LED

int MIO_Key0 = 50; //MIO0_LED

int MIO_Key1 = 51; //MIO13_LED

u32 Pin_out = 0x1;//1表示输出,0表示输入

u32 Pin_in = 0x0;//1表示输出,0表示输入

int key0,key1;

int counter = 0;

//--MIO的初始化

GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);

if(GpioConfigPtr == NULL)

return XST_FAILURE;

xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr, GpioConfigPtr->BaseAddr);

if(XST_SUCCESS != xStatus)

print(" PS GPIO INIT FAILED \n\r");

//--MIO的输入输出操作

XGpioPs_SetDirectionPin(&psGpioInstancePtr, MIO_Led0,Pin_out);//配置MIO输出方向

XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, MIO_Led0,1);//配置MIO的第0位输出

XGpioPs_SetDirectionPin(&psGpioInstancePtr, MIO_Led1,Pin_out);//配置MIO输出方向

XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, MIO_Led1,1);//配置MIO的第0位输出

XGpioPs_SetDirectionPin(&psGpioInstancePtr, MIO_Key0,Pin_in);//配置MIO输出方向

XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, MIO_Key0,1);//配置MIO的第0位输出

XGpioPs_SetDirectionPin(&psGpioInstancePtr, MIO_Key1,Pin_in);//配置MIO输出方向

XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, MIO_Key1,1);//配置MIO的第0位输出

/*

* Initialize an array of pointers to the 3 frame buffers

*/

for (i = 0; i < DISPLAY_NUM_FRAMES; i++)

{

pFrames[i] = frameBuf[i];

}

/*

* Initialize VDMA driver

*/

vdmaConfig = XAxiVdma_LookupConfig(VGA_VDMA_ID);

if (!vdmaConfig)

{

xil_printf("No video DMA found for ID %d\r\n", VGA_VDMA_ID);

}

Status = XAxiVdma_CfgInitialize(&vdma, vdmaConfig, vdmaConfig->BaseAddress);

if (Status != XST_SUCCESS)

{

xil_printf("VDMA Configuration Initialization failed %d\r\n", Status);

}

/*

* Initialize the Display controller and start it

*/

Status = DisplayInitialize(&dispCtrl, &vdma, DISP_VTC_ID, DYNCLK_BASEADDR, pFrames, DEMO_STRIDE);

if (Status != XST_SUCCESS)

{

xil_printf("Display Ctrl initialization failed during demo initialization%d\r\n", Status);

}

Status = DisplayStart(&dispCtrl);

if (Status != XST_SUCCESS)

{

xil_printf("Couldn't start display during demo initialization%d\r\n", Status);

}

while(1){

sleep(1);//延时

key0 = XGpioPs_ReadPin(&psGpioInstancePtr, MIO_Key0);

if(key0 == 0){

usleep(20000);

xil_printf("key0 down\n");

if(key0 == 0){

XGpioPs_WritePin(&psGpioInstancePtr, MIO_Led0, 0);

counter = counter+1;

if(counter == 5)

counter = 0;

sleep(2);

XGpioPs_WritePin(&psGpioInstancePtr, MIO_Led0, 1);

}

}

DemoPrintTest(dispCtrl.framePtr[dispCtrl.curFrame], dispCtrl.vMode.width, dispCtrl.vMode.height, dispCtrl.stride, counter);

}

return 0;

}

void DemoPrintTest(u8 *frame, u32 width, u32 height, u32 stride, int pattern)

{

u32 xcoi, ycoi;

u32 iPixelAddr = 0;

u8 wRed, wBlue, wGreen;

u32 xInt;

u32 pic_number=0;

switch (pattern)

{

case DEMO_PATTERN_0:

for(ycoi = 0; ycoi < height; ycoi++)

{

for(xcoi = 0; xcoi < (width * 4); xcoi+=4)

{

frame[xcoi + iPixelAddr + 0] = gImage_pic_800_600[pic_number++];

frame[xcoi + iPixelAddr + 1] = gImage_pic_800_600[pic_number++];

frame[xcoi + iPixelAddr + 2] = gImage_pic_800_600[pic_number++];

}

iPixelAddr += stride;

}

/*

* Flush the framebuffer memory range to ensure changes are written to the

* actual memory, and therefore accessible by the VDMA.

*/

Xil_DCacheFlushRange((unsigned int) frame, DEMO_MAX_FRAME);

break;

case DEMO_PATTERN_1:

for(ycoi = 0; ycoi < height; ycoi++)

{

for(xcoi = 0; xcoi < (width * 4); xcoi+=4)

{

frame[xcoi + iPixelAddr + 0] = gImage_pic1_800_600[pic_number++];

frame[xcoi + iPixelAddr + 1] = gImage_pic1_800_600[pic_number++];

frame[xcoi + iPixelAddr + 2] = gImage_pic1_800_600[pic_number++];

}

iPixelAddr += stride;

}

/*

* Flush the framebuffer memory range to ensure changes are written to the

* actual memory, and therefore accessible by the VDMA.

*/

Xil_DCacheFlushRange((unsigned int) frame, DEMO_MAX_FRAME);

break;

case DEMO_PATTERN_2:

for(ycoi = 0; ycoi < height; ycoi++)

{

for(xcoi = 0; xcoi < (width * 4); xcoi+=4)

{

frame[xcoi + iPixelAddr + 0] = gImage_pic2_800_600[pic_number++];

frame[xcoi + iPixelAddr + 1] = gImage_pic2_800_600[pic_number++];

frame[xcoi + iPixelAddr + 2] = gImage_pic2_800_600[pic_number++];

}

iPixelAddr += stride;

}

/*

* Flush the framebuffer memory range to ensure changes are written to the

* actual memory, and therefore accessible by the VDMA.

*/

Xil_DCacheFlushRange((unsigned int) frame, DEMO_MAX_FRAME);

break;

case DEMO_PATTERN_3:

for(ycoi = 0; ycoi < height; ycoi++)

{

for(xcoi = 0; xcoi < (width * 4); xcoi+=4)

{

frame[xcoi + iPixelAddr + 0] = gImage_pic3_800_600[pic_number++];

frame[xcoi + iPixelAddr + 1] = gImage_pic3_800_600[pic_number++];

frame[xcoi + iPixelAddr + 2] = gImage_pic3_800_600[pic_number++];

}

iPixelAddr += stride;

}

/*

* Flush the framebuffer memory range to ensure changes are written to the

* actual memory, and therefore accessible by the VDMA.

*/

Xil_DCacheFlushRange((unsigned int) frame, DEMO_MAX_FRAME);

break;

case DEMO_PATTERN_4:

for(ycoi = 0; ycoi < height; ycoi++)

{

for(xcoi = 0; xcoi < (width * 4); xcoi+=4)

{

frame[xcoi + iPixelAddr + 0] = gImage_pic4_800_600[pic_number++];

frame[xcoi + iPixelAddr + 1] = gImage_pic4_800_600[pic_number++];

frame[xcoi + iPixelAddr + 2] = gImage_pic4_800_600[pic_number++];

}

iPixelAddr += stride;

}

/*

* Flush the framebuffer memory range to ensure changes are written to the

* actual memory, and therefore accessible by the VDMA.

*/

Xil_DCacheFlushRange((unsigned int) frame, DEMO_MAX_FRAME);

break;

default :xil_printf("Error: invalid pattern passed to DemoPrintTest\n");

}

}

5)下载实现

连接好硬件后,右键选择EMIO_test工程,再选择Run as->Run Configurations...。双击xilinx C/C++ application (System Debugger) >>勾选Reset entire system和Program FPGA>>Apply>>Run如下图所示。

6)结果展示:


视频欣赏:

总结:

本节涉及到的内容比较多,使用到了很多与视频图像相关的IP,也为后期的图像采集系统打下了基础。

本文转载自: FPGA开源工作室

最新文章

最新文章