FPGA实现SD卡读写照片显示在HDMI显示屏(IP调用)

        概述: TF 卡读写数据,利用 VDMA 和 HDMI 显示视频图像,实现从 SD 卡读取图片并且在 HDMI 显示器上显示。

步骤一:PL端配置IP

  1. SD卡配置

确保 SDIO 接口,设置正确,SD_0 是 TF 卡

在ZYNQ的IP核中配置好SD卡,SD0是TF卡,SD1是EMMC

   2.VDMA配置

查找官方IP:

·VTC IP:这个 IP 就是一个时序发生器,产生显示器输出所需要的时序信号

Enable Generation:支持产生时序。

Enable Detection:支持时序扑捉,这个不是必须的,根据需要而定,这个选项,就可以先扑捉输入的时序,然后再设置输出的时序,实现输入和输出一致的效果。

·PLL 时钟 IP:PLL 的设置原则取决于分辨率的大小。根据 VTC 中的相关分辨率的配置参数来计算所需要的像素时钟的大小,计算方法为:(行的 Frame size) x (列的 Frame size) x(刷新频率)。

·VIDEO OUT 输出 IP:

Pixels Per Clock:设置每个时钟输出的像素个数,可以是 1、2、4

Input Component Width 输入像素的宽度,这个参数影响 TDATA 的位宽

Output Component Width 输出像素的宽度

 Clock Mode 时钟的模式,可以选择独立时钟,或者共享时钟

Video Format 视频格式

FIFO Depth FIFO 深度

Hysteresis Level 滞后输出

·VDMA IP 配置:

VDMA是Xilinx的一款IP,用于将 AXI Stream 格式的数据流转换为 Memory Map 格式或将 Memory Map 格式的数据转换为 AXI Stream 数据流,从而实现与 DDR3 进行通信。其中的MM2S和S2MM分别为该IP的读通道和写通道。

·HDMI IP:

直接添加进即可

最后完整框图:

步骤二:PS端写软件代码

void VDMA_init()
{
	int i;
	for(i=0;i<VIDEO_LENGTH;i++)
	{
		Xil_Out32(VIDEO_BASEADDR0+i*4,0);
	}
	Xil_DCacheFlush();
	Xil_Out32((VDMA_BASEADDR + 0x000), 0x3);
	Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0);
	Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR0);
	Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR0);
	Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4));
	Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4));
	Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE);

}

初始化VDMA(Video Direct Memory Access)控制器。主要功能是将一系列寄存器进行设置,以实现对视频传输的控制。

具体流程:

  1. 初始化视频存储区域,循环遍历VIDEO_LENGTH次,每次写入0到VIDEO_BASEADDR0偏移i*4字节的地址上。这个操作的目的是清空视频存储区域。

  2. 刷新数据缓存,通过调用Xil_DCacheFlush()函数将修改过的数据写回存储器。

  3. 配置VDMA控制寄存器:

    • 0x000寄存器,设置为0x3,表示启用VDMA控制器及启用直接传输模式。
    • 0x05c寄存器,设置为VIDEO_BASEADDR0,表示传输目的地址为视频存储区域的起始地址。
    • 0x060寄存器,同样设置为VIDEO_BASEADDR0,表示传输源地址为视频存储区域的起始地址。
    • 0x064寄存器,同样设置为VIDEO_BASEADDR0,表示传输行为后的回写地址为视频存储区域的起始地址。
    • 0x058寄存器,设置为H_STRIDE*4,表示设置水平行的步长,乘以4是因为每个像素占4个字节。
    • 0x054寄存器,设置为H_ACTIVE*4,表示设置水平行的活动像素数。
    • 0x050寄存器,设置为V_ACTIVE,表示设置垂直行的活动行数。

通过以上配置,完成了VDMA控制器的初始化,可以开始进行视频传输操作。

int SD_init()
{
	FRESULT result;
	//-----------------------mount dev-----------------------------------------------
	result = f_mount(&SD_Dev,SD_Path, 0);
	if (result != 0) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

SD卡初始化。程序载入到读SD卡的文件中。
int main()
{

	VDMA_init();
	SD_init();
	BMP_Picture((u8 *)"1.bmp" , RD_Buf1 ,BUF_SIZE);
	BMP_Picture((u8 *)"2.bmp" , RD_Buf2 ,BUF_SIZE);
	//BMP_Picture((u8 *)"3.bmp" , RD_Buf3 ,BUF_SIZE);
	//BMP_Picture((u8 *)"4.bmp" , RD_Buf4 ,BUF_SIZE);

	while(1)
	{
		show_img(RD_Buf1,1280,720);
		sleep(2);
		show_img(RD_Buf2,1280,720);
		sleep(2);
		//show_img(RD_Buf3,1280,720);
		//sleep(5);
		//show_img(RD_Buf4,1280,720);
		//sleep(5);
	}

    return 0;
}

main函数在这个函数中,读取 SD 卡中的图片。1.bmp是图片的名字,以24bit去保存。在显示器上显示,测试的图片的大小是 1280*720P ,图片格式为 BMP格式。

Bmp函数:

#include "bmp.h"
#include "ff.h"



void BMP_ReadHeader(uint8_t *header, BMP_HeaderTypeDef *bmp)
{

	bmp->fileHeader.bfType = ((*header) << 8) | (*(header + 1));
	header += 2;
	
	bmp->fileHeader.bfSize = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                         ((*(header + 1)) << 8) | (*header);
	header += 8;

	bmp->fileHeader.bfOffBits = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                            ((*(header + 1)) << 8) | (*header);
	header += 4;

	bmp->infoHeader.bitSize = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                          ((*(header + 1)) << 8) | (*header);
	header += 4;

	bmp->infoHeader.biWidth = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                          ((*(header + 1)) << 8) | (*header);
	header += 4;

	bmp->infoHeader.biHeight = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                           ((*(header + 1)) << 8) | (*header);
	header += 6;

	bmp->infoHeader.biBitCount = ((*(header + 1)) << 8) | (*header);
	                         
	header += 2;

	bmp->infoHeader.biCompression = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                                ((*(header + 1)) << 8) | (*header);
	header += 4;

	bmp->infoHeader.biSizeImage = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                              ((*(header + 1)) << 8) | (*header);
	header += 4;

	bmp->infoHeader.biXPelsPerMeter = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                                  ((*(header + 1)) << 8) | (*header);
	header += 4;

	bmp->infoHeader.biYPelsPerMeter = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
	                                  ((*(header + 1)) << 8) | (*header);
}

void BMP_Picture(uint8_t *dir , uint8_t  * buf ,uint32_t len)
{
		FRESULT res;
		FIL fsrc;
		UINT  br;
		UINT  a;

		uint8_t buffer[1024];

		BMP_HeaderTypeDef bmpHeader;
		
		/* 打开要读取的文件 */
		res = f_open(&fsrc, (const TCHAR*)dir, FA_READ);

		if(res == FR_OK)   //打开成功
	    {
			/* 读取BMP文件的文件信息 */
	        res = f_read(&fsrc, buffer, sizeof(buffer), &br);

			/* 将数组里面的数据放入到结构数组中,并排序好 */
			BMP_ReadHeader(buffer, &bmpHeader);

			a = bmpHeader.fileHeader.bfOffBits;    //去掉文件信息才开始是像素数据

			res=f_lseek(&fsrc, a);
			if(res)
			{
				return 0;
			}
			res = f_read(&fsrc, buf, len, &br);
	    }
    f_close(&fsrc);
}

Bmp.c函数中重要是需要对BMP图片格式的头部进行解析,并且获取图像数据的开始位置,然后用f_lseek(&fsrc, a)函数,定位到图像数据的位置,之后再读出图像的数据。

typedef struct
{
uint16_t bfType; //文件类型,BMP格式为字符串BM
uint32_t bfSize; //图片大小,单位为KB
uint16_t bfReserved1; //保留位
uint16_t bfReserved2; //保留位
uint32_t bfOffBits; //从文件头到实际图像数据之间的字节偏移量
} BMP_FileHeaderTypeDef;
typedef struct
{
uint32_t bitSize; //BMP_InfoHeaderTypeDef结构体所需要的字节数
uint32_t biWidth; //图片宽度,像素位单位
int32_t biHeight; //图片高度,像素为单位。正为倒立,负为正向。
uint16_t biPlanes; //颜色平面数,总为1
uint16_t biBitCount; //比特数/像素。其值为:1、4、8、16、24或32
uint32_t biCompression; //数据压缩类型
uint32_t biSizeImage; //图像大小
uint32_t biXPelsPerMeter;//水平分辨率
uint32_t biYPelsPerMeter;//垂直分辨率
uint32_t biClrUsed; //颜色索引数
uint32_t biClrImportant; //重要颜色索引数
}BMP_InfoHeaderTypeDef

结构体函数将读取到的数组函数转换位BPM文件信息结构体类型。由于在内存上面数组的存储方式与结构体不同,所以要转换,而且SD读取到的文件信息是小端模式。高位是低字节,低位是高字节

FPGA读写SD卡读取BMP图片通过LCD显示例程实验 Verilog逻辑源码Quartus工程文件+文档说明,FPGA型号Cyclone4E系列中的EP4CE6F17C8,Quartus版本17.1。 1 实验简介 在前面的实验中我们练习了 SD 卡读写,VGA 视频显示等例程,本实验将 SD 卡里的 BMP 图 片读出,写入到外部存储器,再通过 VGA、LCD 等显示。 本实验如果通过液晶屏显示,需要有液晶屏模块。 2 实验原理 在前面的实验中我们在 VGA、LCD 上显示的是彩条,是 FPGA 内部产生的数据,本实验将彩 条替换为 SD 内的 BMP 图片数据,但是 SD 卡读取速度远远不能满足显示速度的要求,只能先写 入外部高速 RAM,再读出后给视频时序模块显示 module top( input clk, input rst_n, input key1, output [5:0] seg_sel, output [7:0] seg_data, output vga_out_hs, //vga horizontal synchronization output vga_out_vs, //vga vertical synchronization output[4:0] vga_out_r, //vga red output[5:0] vga_out_g, //vga green output[4:0] vga_out_b, //vga blue output sd_ncs, //SD card chip select (SPI mode) output sd_dclk, //SD card clock output sd_mosi, //SD card controller data output input sd_miso, //SD card controller data input output sdram_clk, //sdram clock output sdram_cke, //sdram clock enable output sdram_cs_n, //sdram chip select output sdram_we_n, //sdram write enable output sdram_cas_n, //sdram column address strobe output sdram_ras_n, //sdram row address strobe output[1:0] sdram_dqm, //sdram data enable output[1:0] sdram_ba, //sdram bank address output[12:0] sdram_addr, //sdram address inout[15:0] sdram_dq //sdram data ); parameter MEM_DATA_BITS = 16 ; //external memory user interface data width parameter ADDR_BITS = 24
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

is llong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值