MYIR-ZYNQ7000系列-zturn教程(25):讀取SD卡里的圖片使用hdmi顯示

開發板環境:vivado 2017.4 ,開發板型號xc7z010clg400-1,這個工程主要讀取SD卡里的圖片使用hdmi來進行顯示

鏈接:https://pan.baidu.com/s/1QkbI0J-A_DJdUKwZKBMDDg       提取碼:wp8a 

這個工程是以前面一篇博客裏的hdmi顯示通路上面進行更改的,所以vivado工程不變只是更改了SDK代碼。

上一篇的hdmi的SDK工程和主程序

SDK工程

主程序

/*
 * Copyright (c) 2009-2012 Xilinx, Inc.  All rights reserved.
 *
 * Xilinx, Inc.
 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
 * COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
 * ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
 * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
 * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
 * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
 * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
 * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
 * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
 * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 */
 
/*
 * 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 "xparameters.h"
#include "xil_io.h"
#include "sleep.h"
 
 
 
#define DDR_BASEADDR        0x00000000
 
#define VDMA_BASEADDR       XPAR_AXI_VDMA_0_BASEADDR
#define H_STRIDE            1920
#define H_ACTIVE            1920
#define V_ACTIVE            1080
 
 
#define VIDEO_LENGTH  (H_STRIDE*V_ACTIVE)
#define VIDEO_BASEADDR0 DDR_BASEADDR + 0x2000000
#define VIDEO_BASEADDR1 DDR_BASEADDR + 0x3000000
#define VIDEO_BASEADDR2 DDR_BASEADDR + 0x4000000
 
//函數聲明
void Xil_DCacheFlush(void);
 
 
extern const unsigned char gImage_beijing[8294400];
 
void show_img(u32 x, u32 y, u32 disp_base_addr, const unsigned char * addr, u32 size_x, u32 size_y)
{
	//計算圖片 左上角座標
	u32 i=0;
	u32 j=0;
	u32 r,g,b;
	u32 start_addr=disp_base_addr;
	start_addr = disp_base_addr + 4*x + y*4*H_STRIDE;
	for(j=0;j<size_y;j++)
	{
		for(i=0;i<size_x;i++)
		{
			b = *(addr+(i+j*size_x)*4+1);
			g = *(addr+(i+j*size_x)*4+2);
			r = *(addr+(i+j*size_x)*4+3);
			Xil_Out32((start_addr+(i+j*H_STRIDE)*4),((r<<24)|(g<<16)|(b<<8)|0x0));
		}
	}
	Xil_DCacheFlush();
}
 
int main()
{
 
    sii9022_init();
 
	//各種顯示 相關的參數
	Xil_Out32((VDMA_BASEADDR + 0x000), 0x00000003); 		// 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*4)); 		// h offset (1920 * 4) bytes
	Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4)); 		// h size (1920 * 4) bytes
	Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE); 			// v size (1080)
 
 
	while(1)
	{
		show_img(0,0,VIDEO_BASEADDR0,&gImage_beijing[0],1920,1080);
	}
 
 
}

這個讀取SD卡圖片工程的SDK工程和主程序

SDK工程

主程序

/*
 * Copyright (c) 2009-2012 Xilinx, Inc.  All rights reserved.
 *
 * Xilinx, Inc.
 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
 * COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
 * ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
 * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
 * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
 * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
 * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
 * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
 * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
 * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 */

/*
 * 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 "xparameters.h"
#include "xil_io.h"
#include "ff.h"
#include "sleep.h"



#define DDR_BASEADDR        0x00000000

#define VDMA_BASEADDR       XPAR_AXI_VDMA_0_BASEADDR
#define H_STRIDE            1920
#define H_ACTIVE            1920
#define V_ACTIVE            1080


#define VIDEO_LENGTH  (H_STRIDE*V_ACTIVE)
#define VIDEO_BASEADDR0 DDR_BASEADDR + 0x2000000
#define VIDEO_BASEADDR1 DDR_BASEADDR + 0x3000000
#define VIDEO_BASEADDR2 DDR_BASEADDR + 0x4000000

#define BYTES_PIXEL 3
#define DEMO_STRIDE (1920 * BYTES_PIXEL)

unsigned char read_line_buf[1920 * 3];


u8 frameBuf[1920*1080*3];

static FIL fil;		/* File object */
static FATFS fatfs;


//函數聲明
void Xil_DCacheFlush(void);


void bmp_read(char * bmp,u8 *frame,u32 stride)
{
	u32 i;
	u32 r,g,b;

	short y,x;
	short Ximage;
	short Yimage;
	u32 iPixelAddr = 0;
	FRESULT res;
	unsigned char TMPBUF[64];
	unsigned int br;         // File R/W count

	res = f_open(&fil, bmp, FA_OPEN_EXISTING | FA_READ);
	if(res != FR_OK)
	{
		return ;
	}
	res = f_read(&fil, TMPBUF, 54, &br);
	if(res != FR_OK)
	{
		return ;
	}
	Ximage=(unsigned short int)TMPBUF[19]*256+TMPBUF[18];
	Yimage=(unsigned short int)TMPBUF[23]*256+TMPBUF[22];
	iPixelAddr = (Yimage-1)*stride ;

	for(y = 0; y < Yimage ; y++)
	{
		f_read(&fil, read_line_buf, Ximage * 3, &br);
		for(x = 0; x < Ximage; x++)
		{
			b = frame[x * BYTES_PIXEL + iPixelAddr + 0] = read_line_buf[x * 3 + 0];

			g = frame[x * BYTES_PIXEL + iPixelAddr + 1] = read_line_buf[x * 3 + 1];

			r = frame[x * BYTES_PIXEL + iPixelAddr + 2] = read_line_buf[x * 3 + 2];

			Xil_Out32((VIDEO_BASEADDR0 + (((1920-1-x)+(1080-1-y)*H_STRIDE)*4)) ,((r<<24)|(g<<16)|(b<<8)|0x0));

		}
		iPixelAddr -= stride;
	}

	f_close(&fil);
}

int main()
{
   u32 i;
	FRESULT rc;

    sii9022_init();

	//各種顯示 相關的參數
	Xil_Out32((VDMA_BASEADDR + 0x000), 0x00000003); 		// 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*4)); 		// h offset (1920 * 4) bytes
	Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4)); 		// h size (1920 * 4) bytes
	Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE); 			// v size (1080)


	rc = f_mount(&fatfs, "0:/", 0);
	if (rc != FR_OK)
	{
		return 0 ;
	}

	while(1)
	{
		bmp_read("1.bmp",frameBuf, DEMO_STRIDE);

	}
}

從兩個程序比較可以看到這裏添加了一個SD卡的讀寫程序和一些SD卡的文件系統之類的,主要是下面這段讀寫SD卡的程序

void bmp_read(char * bmp,u8 *frame,u32 stride)
{
	u32 i;
	u32 r,g,b;

	short y,x;
	short Ximage;
	short Yimage;
	u32 iPixelAddr = 0;
	FRESULT res;
	unsigned char TMPBUF[64];
	unsigned int br;         // File R/W count

	res = f_open(&fil, bmp, FA_OPEN_EXISTING | FA_READ);
	if(res != FR_OK)
	{
		return ;
	}
	res = f_read(&fil, TMPBUF, 54, &br);
	if(res != FR_OK)
	{
		return ;
	}
	Ximage=(unsigned short int)TMPBUF[19]*256+TMPBUF[18];
	Yimage=(unsigned short int)TMPBUF[23]*256+TMPBUF[22];
	iPixelAddr = (Yimage-1)*stride ;

	for(y = 0; y < Yimage ; y++)
	{
		f_read(&fil, read_line_buf, Ximage * 3, &br);
		for(x = 0; x < Ximage; x++)
		{
			b = frame[x * BYTES_PIXEL + iPixelAddr + 0] = read_line_buf[x * 3 + 0];

			g = frame[x * BYTES_PIXEL + iPixelAddr + 1] = read_line_buf[x * 3 + 1];

			r = frame[x * BYTES_PIXEL + iPixelAddr + 2] = read_line_buf[x * 3 + 2];

			Xil_Out32((VIDEO_BASEADDR0 + (((1920-1-x)+(1080-1-y)*H_STRIDE)*4)) ,((r<<24)|(g<<16)|(b<<8)|0x0));

		}
		iPixelAddr -= stride;
	}

	f_close(&fil);
}

讀寫SD卡程序中這兩個主對讀取bmp圖片的行場大小,也就是圖片大小

    Ximage=(unsigned short int)TMPBUF[19]*256+TMPBUF[18];
    Yimage=(unsigned short int)TMPBUF[23]*256+TMPBUF[22];

上圖中可以看到TMPBUF[18] = 0x80 、TMPBUF[19] = 0x07 、TMPBUF[22] = 0x38 、TMPBUF[23] = 0x04

    Ximage=(unsigned short int)TMPBUF[19]*256+TMPBUF[18];

                 =(0x07)*256 + 0x80  (這裏是十六進制)

                 = 7*256 + 128  (十進制)

                 =  1920

Yimage=(unsigned short int)TMPBUF[23]*256+TMPBUF[22];

                 =(0x04)*256 + 0x38  (這裏是十六進制)

                 = 4*256 + 56  (十進制)

                 =  1080

直接打開一個bmp圖片屬性可以看到基本是24位的

 但我的這個hdmi顯示工程vdma讀取ddr是每次讀取32位的,所以要將SD卡程序讀取的24位圖片數據拼

接爲32位,我這就是對低8位添0

下面這三句主要是每次讀取3個8位也就是讀取一個24位

            b = frame[x * BYTES_PIXEL + iPixelAddr + 0] = read_line_buf[x * 3 + 0];

            g = frame[x * BYTES_PIXEL + iPixelAddr + 1] = read_line_buf[x * 3 + 1];

            r = frame[x * BYTES_PIXEL + iPixelAddr + 2] = read_line_buf[x * 3 + 2];

下面這句就是將低8位直接補0湊成一個32位數據

            ((r<<24)|(g<<16)|(b<<8)|0x0));

下面就是往VDMA所讀取的DDR地址空間寫入讀取的SD卡圖片數據

Xil_Out32((VIDEO_BASEADDR0 + ((x+y*H_STRIDE)*4)) ,((r<<24)|(g<<16)|(b<<8)|0x0));

下面是顯示效果

可以看到圖片是倒着顯示的,說明這個SD卡圖片應該是倒着寫入進去的,只要將圖片再倒着寫入DDR就可以顯示正常圖片了

Xil_Out32((VIDEO_BASEADDR0 + (((1920-1-x)+(1080-1-y)*H_STRIDE)*4)) ,((r<<24)|(g<<16)|(b<<8)|0x0));

也就是像上面這樣用直接用1920和1080去減掉不斷增加的行場座標就相當於倒着寫入到DDR,就可以正常顯示圖片了

顯示效果

工程主要是將放到SD卡里的圖片讀取到DDR並且通過hdmi顯示,所以先將工程生成的BOOT.bin拷貝到SD卡

再到SD卡里放一個1920*1080的1.bmp圖片,這裏要注意的是圖片不能直接將網上下載的jpg圖片直接更改擴展名爲bmp,

這樣更改的圖片數據格式是無法更改過來的,要麼直接下載一個bmp的1080p圖片,要麼下載一個1080p的jpg圖片用

圖片轉換器轉換爲bmp格式的,直接更改擴展名爲bmp的圖片是無法讀取的這裏一定要注意。

最後比較SD卡里的圖片和顯示的圖片是左右顛倒的雖然圖片上下顛倒已經倒過來了,大家可以想一下如何將左右顛倒

給倒過來我這裏暫時不進行說明,大家可以在紙上畫一個上下顛倒的圖片最後如何變爲正常圖片再對寫入的DDR程序進

更改就行了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章