EBAZ4205 第二十六个工程 用VDMA模块来缓存图像并在HDMI上显示(三)显示TF卡上的BMP格式图片

本节作为前两节的补充,将TF卡上的图片通过VDMA的方式显示在HDMI设备上,作为VDMA的实战演练

因为本文内容和前两节有大量的重复雷同工作,所以本节只介绍关键的几个地方,需要看详细工程创建的请看 VDMA的第一和第二节内容

以下工程均在vivado2018.3下实现,其他版本请自行尝试

VIVADO工程的修改

vivado 在blockdesign里 使能SD功能,(之前两个工程其实已经做了这一步)

SDK部分的修改

接下来SDK部分我们作如下修改, 因为我们要加载TF卡,而TF卡的格式是FAT32的,所以这里我们需要加载FatFs库,xilinx已经帮我们集成了这部分库的功能,我们只需要使能功能就好,操作如下

添加 XILFFS 库

接下来需要使能 文件名称的功能 默认是关闭的

代码的编写

复制以下代码到main.c中

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xil_types.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xaxivdma.h"
#include "xaxivdma_i.h"
#include "ff.h"
#include "sleep.h"



void load_sd_bmp(u8 *frame,unsigned char mode);

void load_sd_bmp(u8 *frame,unsigned char mode)
{
	static 	FATFS fatfs;
	FIL 	fil;
	u8		bmp_head[54];
	UINT 	*bmp_width,*bmp_height;
	UINT 	br;
	int 	i;

	//挂载文件系统
	f_mount(&fatfs,"",1);
	//打开文件
	if(mode==0)f_open(&fil,"C.bmp",FA_READ);
	else f_open(&fil,"D.bmp",FA_READ);
	//移动文件读写指针到文件开头
	f_lseek(&fil,0);
	//读取BMP文件头
	f_read(&fil,bmp_head,54,&br);

	//打印BMP图片分辨率和大小
	bmp_width  = (UINT *)(bmp_head + 0x12);
	bmp_height = (UINT *)(bmp_head + 0x16);
	//读出图片,写入DDR
	for(i=*bmp_height-1;i>=0;i--){
		f_read(&fil,frame+i*(*bmp_width)*3,(*bmp_width)*3,&br);
	}

	//关闭文件
	f_close(&fil);
	
	Xil_DCacheFlush();     //刷新Cache,数据更新至DDR3中
}


#define H_STRIDE	1280
#define H_ACTIVE	1280
#define V_ACTIVE	720

#define VDMA_BASEADDR	XPAR_AXI_VDMA_0_BASEADDR

#define VIDEO_BASEADDR0 0x01000000//帧存0地址
#define VIDEO_BASEADDR1 0x02000000//帧存1地址

void VDMA_init(){
	Xil_Out32((VDMA_BASEADDR + 0x000), 0x3); 		// enable circular mode
	Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); 	// start address
	Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR0); 	// start address
	Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR0); 	// start address
	Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*3)); 		// h offset (H_STRIDE * 3) bytes
	Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*3)); 		// h size (H_ACTIVE * 3) bytes
	Xil_Out32((VDMA_BASEADDR + 0x050),  V_ACTIVE); 			// v size (V_ACTIVE)
}

int main(void)
{
		load_sd_bmp((u8*)VIDEO_BASEADDR0,0);
		load_sd_bmp((u8*)VIDEO_BASEADDR1,1);
		VDMA_init();

	while(1){

		Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); 	// start address
		Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR0); 	// start address
		Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR0); 	// start address
		Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*3)); 		// h offset (H_STRIDE * 3) bytes
		Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*3)); 		// h size (H_ACTIVE * 3) bytes
		Xil_Out32((VDMA_BASEADDR + 0x050),  V_ACTIVE); 			// v size (V_ACTIVE)

		sleep(1);

		Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR1); 	// start address
		Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1); 	// start address
		Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR1); 	// start address
		Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*3)); 		// h offset (H_STRIDE * 3) bytes
		Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*3)); 		// h size (H_ACTIVE * 3) bytes
		Xil_Out32((VDMA_BASEADDR + 0x050),  V_ACTIVE); 			// v size (V_ACTIVE)
		sleep(1);
	}
    return 0;
}

代码非常好理解,load_sd_bmp 实现的功能是挂载TF卡,并且根据mode的值来读取TF卡中对应名称的图片,并将图片的内容存入对应的DDR地址内。(mode 是我自己加入的,通过mode的值的大小分别载入两张不同的图片,最终在主函数里实现两张图片显示的动态切换)

VIDEO_BASEADDR0,和VIDEO_BASEADDR1分别对应两帧的缓存地址(只要两个帧之间的地址相差的位置可以调整,只要不要彼此相互有交集产生内存相互影响就可以了)

#define VIDEO_BASEADDR0 0x01000000//帧存0地址
#define VIDEO_BASEADDR1 0x02000000//帧存1地址

VDMA 的初始化,因为之前我们在VIVADO 的blockdesign 里设计的VDMA缓存有3个,所以这里需要同时定义3个缓存区对应的DDR上的地址映射(为了方便演示,我们这里将3个缓存区映射到同一个DDR区)

备注 多缓存区存在的目的是为了防止画面的撕裂,但是VDMA会在多个缓存区中循环的显示内容,比方说如果我们这里设置成3个缓存区地址不同的话,实际我们修改了其中一帧的内容会造成,3帧中的一帧不一致,导致画面另外两帧还是原先的内容,然后画面快速三帧循环,效果就是不停的切换闪烁, 所以这里为了方便演示将VDMA三个缓存区映射到相同的地址进行演示(等效于VDMA 只有一帧的效果)

主程序里 加载两张照片分别到VIDEO_BASEADDR0内存区域,和VIDEO_BASEADDR1内存区域,并完成VDMA初始化

		load_sd_bmp((u8*)VIDEO_BASEADDR0,0);
		load_sd_bmp((u8*)VIDEO_BASEADDR1,1);
		VDMA_init();

主循环也很简单,通过调整VDMA 帧缓存的映射地址(这些地址在之前已存入TF图片信息),来实现HDMI不同画面的切换

上机调试

之后在电脑上插入FAT32格式的TF卡,并将下列文件下载并解压并存入TF卡的根目录(切记 TF卡必须为fat32格式)

其中A,B是1080P的BMP,C,D是720P的BMP图片文件

之后回到SDK,对程序进行正常编译,并debug,没问题的话,应该可以看到两张720p的图片在循环播放的

备注 切换vdma缓存的方法 暂时没有找到更简单的,所以就向上面这样,通过寄存器完整的修改了,后续如果找到更简单的方法我再修改

以下是720P图片显示的完整工程 仅供参考(需要事先先把TF卡中放入对应分辨率和名称的bmp图片文件,上文中有提供下载)

1080P 的修改类似, 要注意的是1080P要 加载的是 A.bmp 和B.bmp (720P的工程是C.bmp和D.bmp), 1080P的工程这里就不演示了,大家自行尝试,备注4205加转接板的形式我自己只能实现1080P 50hz下的稳定输出(可能是因为EBAZ4205主板上对应的走线没有走差分的原因)

PS和前两节的VDMA初始化不同,前两节用的是库函数,而这里直接对寄存器写入来实现VDMA初始化,两种方式都是可以的

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注