概述: TF 卡读写数据,利用 VDMA 和 HDMI 显示视频图像,实现从 SD 卡读取图片并且在 HDMI 显示器上显示。
步骤一:PL端配置IP
- 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)控制器。主要功能是将一系列寄存器进行设置,以实现对视频传输的控制。
具体流程:
-
初始化视频存储区域,循环遍历
VIDEO_LENGTH
次,每次写入0到VIDEO_BASEADDR0
偏移i*4字节的地址上。这个操作的目的是清空视频存储区域。 -
刷新数据缓存,通过调用
Xil_DCacheFlush()
函数将修改过的数据写回存储器。 -
配置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)函数,定位到图像数据的位置,之后再读出图像的数据。文章来源:https://www.toymoban.com/news/detail-855671.html
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模板网!