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

这篇具有很好参考价值的文章主要介绍了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 就是一个时序发生器,产生显示器输出所需要的时序信号

fpga hdmi ip,fpga开发

Enable Generation:支持产生时序。

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

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

fpga hdmi ip,fpga开发

·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 滞后输出

fpga hdmi ip,fpga开发

·VDMA IP 配置:

fpga hdmi ip,fpga开发

fpga hdmi ip,fpga开发

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

·HDMI IP:

fpga hdmi ip,fpga开发

直接添加进即可

最后完整框图:

fpga hdmi ip,fpga开发

步骤二: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读取到的文件信息是小端模式。高位是低字节,低位是高字节文章来源地址https://www.toymoban.com/news/detail-855671.html

到了这里,关于FPGA实现SD卡读写照片显示在HDMI显示屏(IP调用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32单片机LED显示屏驱动原理与实现

    STM32单片机驱动LED显示屏的原理与实现方法与Arduino类似,但涉及到的具体硬件资源和库函数可能会有所不同。下面是一个详细的介绍:   原理: STM32单片机驱动LED显示屏的原理是通过控制GPIO引脚的电平状态来控制LED的亮灭。通过设置引脚的输出电平为高电平(VCC)或低电平

    2024年02月10日
    浏览(34)
  • arduino-esp32:基于TFT-eSPI库实现触摸显示屏

    在arduino的IDE上已经搭建好了ESP32环境的话,写写小应用的话还是很简单的,毕竟有这么多优秀的库。 之前用自己买的TFT屏试了一下TFT-eSPI库的驱动效果,显示效果挺好的,但是触摸一直没用上。最近有空了弄了一下。 我的屏幕是2.2寸/2.4/2.8/3.2/3.5/4.0寸TFT触摸彩色SPI串口液晶屏

    2023年04月09日
    浏览(27)
  • LCD拼接屏、LED显示屏和OLED显示屏的主要区别

    我们在生活或工作中经常看到大大小小的显示屏,但很多人却分不清楚这些屏到底属于哪一类,今天sostron与大家一起来分享下关于:LCD拼接屏、LED显示屏、OLED透明屏三者的区别。 LCD拼接屏、LED显示屏和OLED显示屏是不同类型的显示技术,它们在构成、工作原理和特点上存在明

    2024年02月17日
    浏览(28)
  • iMX6ULL驱动开发 | OLED显示屏SPI驱动实现(SH1106,ssd1306)

    周日业余时间太无聊,又不喜欢玩游戏,大家的兴趣爱好都是啥?我觉得敲代码也是一种兴趣爱好。正巧手边有一块儿0.96寸的OLED显示屏,一直在吃灰,何不把玩一把?于是说干就干,最后在我的imax6ul的linux开发板上使用spi用户态驱动成功点亮。这里总结下过程,分享给有需

    2024年02月14日
    浏览(24)
  • 矩阵键盘控制LCD1602显示屏显示数字

     主函数部分,其中的LCD1602.h的头文件是在哔哩哔哩江科大自化协的博主的视频资料 总结:     首先是我学习时遇到的问题: 在我一开始运行的时候出现的问题就是,一开始在给主函数的keynumber赋值的时候,等号的左值是叫做Matrixkey的函数,当我按下1按键时显示屏显示01,

    2024年02月11日
    浏览(28)
  • 看着显示屏,学习新知识

    m a p k e y ( 键 ) , v a l u e ( 值 ) n a m e ( 名 ) mapkey(键), value(值) name(名) ma p k ey ( 键 ) , v a l u e ( 值 ) nam e ( 名 ) u n o r d e r e d _ m a p 如法炮制 unordered_map如法炮制 u n or d ere d _ ma p 如法炮制 m a p u n o r d e r e d _ m a p 的区别 : map unordered_map 的区别: ma p u n or d ere d _ ma p 的区别 : 1.

    2024年02月11日
    浏览(27)
  • 显示屏分辨率计算

    今天研究了下我的笔记本显示屏的分辨率问题,我的笔记本是 联想 拯救者 Y9000K 2019SE 显示器的尺寸如下所示 17.3英寸的显示屏,那么长和宽分别是(英寸和毫米之间的换算是25.4) 长为 17.3 × 16 9 2 + 1 6 2 = 15.0783 inch = 382.9877 mm 17.3 times frac{16}{sqrt{9^2+16^2}} =15.0783text{inch}=382.9

    2024年02月09日
    浏览(23)
  • LCD1602液晶显示屏

    主函数 LCD1602.c LCD1602.h 接线图:   1、1602屏幕=16x2=32个字符,总共有32个字符  2、每个字符由35个像素组成 每个像素由一小块液晶控制 --------------------------------------------------------------------------------------------------------------------------------- 液晶的控制原理: 不施加电压——液晶完

    2024年02月07日
    浏览(35)
  • 3分钟,掌握“曲面屏显示屏”

    在3分钟内掌握“曲面屏显示屏”的概念和特点,可以按照以下步骤进行: 一、了解曲面屏显示屏的基本概念 曲面屏显示屏是一种采用柔性塑料的显示屏,主要通过OLED面板来实现。相比直面屏幕,曲面屏幕弹性更好,不易破碎。此外,正面屏幕绕其对称轴旋转而生成的曲面即

    2024年02月04日
    浏览(23)
  • STM32-OLED显示屏

    *本文采用的OLED显示屏为4针脚IIC显示屏,4针脚分别为GND,VCC,SCL,SDA OLED.C OLED_Font.h main.c

    2024年02月05日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包