问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 3107 人浏览分享

开启左侧

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK高级篇连载-05读取SD卡图片方案(VDMA/HDMI)

[复制链接]
3107 0
AMD-FPGA课程
AMD课程: 12-ZYNQ7100实验 »
​软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
本文的FPGA硬件工程部分和前文一样,本文的demo实现从SD卡读取图片在液晶屏上的显示。
本文实验目的:
1:掌握基于VDMA IP的图像显示系统的搭建方法
2:掌握VDMA Parked模式的简单应用
4:掌握HDMI显示器、7寸液晶屏的使用
5:掌握从SD卡读取bmp格式图片,并通过显示器显示
2系统框图
如下图所示,该方案中 PS 部分的 CPU 读取 SD 卡中的图片到 DDR 中,VDMA 从 PS DDR 中读取图片数据,发送给 AXI4-Stream to Video Out IP(简称 VID OUT),VID OUT IP 把 Stream 流数据转为 RGB 时序给 HDMI 输出 IP,这样就能驱动 HDMI 显示器了。
这里还用到了 Video Timing Controller IP(简称 VTC),该 IP 产生 RGB 视频时序,和 VID OUT IP 配合实现 AXIStream 视频数据流转为 RGB 视频数据。
652f8f4d72374a95b420434faa38cb56.jpg ​

如果是米联客 7 寸液晶屏,可以支持 LVDS(必须修改 BANK 电压支持 LVDS 通信,如果有不清楚请咨询米联 客技术支持)接口或者 RGB 接口,比如 LVDS 接口的系统框图中也是把 RGB 时序转为 LVDS 驱动液晶屏。
c9d0f2466a81434f8f1f2299f12ff73b.jpg ​
如果是使用RGB接口可以直接用RGB时序驱动液晶屏.
bc7b3e6771494153ac42b82f0ae954df.jpg ​
3硬件电路分析
硬件接口和子卡模块请阅读“附录1”
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
4搭建SOC系统工程
请阅读“04视频图形显示方案(VDMA)”一文中“5.4搭建SOC系统工程”这一章节
5搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
5.1创建SDK Platform工程
274959bebe644dd8a1443361477acab3.jpg ​
勾选对于FAT格式文件系统的支持
f1c5ea16db2a41b3b0abbc2beb38d927.jpg ​
5.2创建sd_img_read测试工程
Sd_img_read APP使用到了parked模式,使用parked对缓存切换控制可以防止图片的撕裂
50a3682f81cf49b388c2000030659570.jpg ​
6程序分析
6.1sd_img_test.c主程序
#include   "xil_exception.h"

#include "xil_printf.h"
#include "xil_cache.h"
#include "vdma_pl.h"
#include "sleep.h"
#include "xsdps.h"
#include "ff.h"
extern XAxiVdma VDMA;
extern XAxiVdma_DmaSetup WriteCfg;
extern XAxiVdma_DmaSetup ReadCfg;
#define BUF_SIZE 1280*720*3 //图像大小
u32 GFrame[3][BUFFERSIZE] __attribute__ ((__aligned__(256)));
static FATFS SD_Dev; // File System instance
char *SD_Path = "0:/"; // string pointer to the logical drive number
u8 RD_Buf[3][BUF_SIZE] __attribute__ ((aligned(32))); //分配3个缓存保存图像
//把图像数据读出后,改成4字节对齐后再写入到内存中
void show_img( unsigned char * addr,u32 * vdma_pbuf,u32 size_x, u32 size_y)
{
u32 x=0;
u32 y=0;
u32 r,g,b;
for(y=size_y;y>0;y--)
{
for(x=0;x<size_x;x++)
{
b = *(addr++);
g = *(addr++);
r = *(addr++);
Xil_Out32((vdma_pbuf+(((y-1)*size_x)+x)),((r<<16)|(g<<8)|(b<<0)));//write image data to ddr
}

}
// flush all dcache data to ddr
Xil_DCacheFlushRange((u32)(vdma_pbuf), 1280*720*4);
}
//Initialize SD
int SD_init()
{
FRESULT result;
//-----------------------mount dev-----------------------------------------------
result = f_mount(&SD_Dev,SD_Path, 0);
if (result != 0) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
int main()
{
u8 mode_s =0;
u32 vcnt,hcnt;
u32* img_ptr;
SD_init();
//sleep(1);
//read image from sd card to ddr buffer
BMP_Picture((u8 *)"0001.bmp" , &RD_Buf[0],BUF_SIZE); //读取第1张图片
BMP_Picture((u8 *)"0002.bmp" , &RD_Buf[1],BUF_SIZE); //读取第2张图片
BMP_Picture((u8 *)"0003.bmp" , &RD_Buf[2],BUF_SIZE); //读取第三张图片
//set mm2s read channel address
ReadCfg.FrameStoreStartAddr[0] = (UINTPTR)(&GFrame[0]); //VDMA第1个缓存地址
ReadCfg.FrameStoreStartAddr[1] = (UINTPTR)(&GFrame[1]); //VDMA第2个缓存地址
ReadCfg.FrameStoreStartAddr[2] = (UINTPTR)(&GFrame[2]); //VDMA第3个缓存地址
//setup mm2s read channel
MM2S_ReadSetup(XPAR_AXIVDMA_0_DEVICE_ID, &VDMA, ReadCfg); //设置VDMA的读通道
xil_printf("VDMA Generic Video start! \r\n");
//read image from sd to ddr buffer
show_img(&RD_Buf[0],&GFrame[0],1280,720); //第1张图片刷入到DDR
show_img(&RD_Buf[1],&GFrame[1],1280,720); //第2张图片刷入到DDR
show_img(&RD_Buf[2],&GFrame[2],1280,720); //第3张图片刷入到DDR

while(1)

{

//parking ddr buffer to screen

XAxiVdma_StartParking(&VDMA, mode_s,XAXIVDMA_READ); //通过Park模式,每间隔1S更新一张图片

sleep(1);

if(mode_s >=2 ) mode_s = 0;

else mode_s ++;

}

return XST_SUCCESS;
}

以上函数中主要2个知识点:1、读取SD卡中的bmp格式图片到DDR内存中;2、把DDR内存中的图片通过VDMA的Park模式输出到显示器上。
读bmp格式图片
0719ea92857f4948b53a690945ae4c86.jpg ​
由于bmp格式图片读出来是rgb888(24bit)对齐,所以还用使用以下函数把rgb888改为rgbx888(32bits)
49a163c85eab4ec3a10f9a0db4e3e277.jpg ​
这样三副图片会保存到GFrame[0]、GFrame[1]、GFrame[2]内存地址中。
6.2bmp.c程序
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);
}
/****************************************************************************
* Function Name : BMP_Picture
* Description : 显示BMP格式的图片
* Input : dir:要显示的图片路径和名字
* Output : None
* Return : None
****************************************************************************/
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)函数,定位到图像数据的位置,之后再读出图像的数据。
#indef_bmp_H

#define _bmp_H
#include <stdio.h>
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;
typedef struct
{
BMP_FileHeaderTypeDef fileHeader;
BMP_InfoHeaderTypeDef infoHeader;
}BMP_HeaderTypeDef;
void BMP_ReadHeader(uint8_t *header, BMP_HeaderTypeDef *bmp);
void BMP_Picture(uint8_t *dir , uint8_t * buf ,uint32_t len);
#endif

7HDMI方案演示
对于 MLK-H3-CZ08-7100FC 不支持从 SD 卡启动, 因此必须通过 JTAG 调试模式完成本实验
7.1硬件准备
复制路径soc_prj/uisrc/06_doc/testimage路径下的测试图片到SD卡,并且插入到开发中。
817ce5560680430daad59af46e620c23.jpg ​
本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON (注意新版本的 MLK-H3-CZ08-7100FC(米联客 7X 系列),支持 JTAG 模式,对于老版本的核心板,JTAG 调试 的时候一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)
c446768667084d04a3c031a8dfd04ff3.jpg ​
7.2实验结果
4ba5768ef0a0498aa8d94c819b956639.jpg ​
8液晶屏LVDS方案演示
对于 MLK-H3-CZ08-7100FC 不支持从 SD 卡启动, 因此必须通过 JTAG 调试模式完成本实验
8.1硬件准备
复制路径soc_prj/uisrc/06_doc/testimage路径下的测试图片到SD卡,并且插入到开发中。
83fd629e224a4612baacdf20dab0e822.jpg ​
液晶屏,模式开关1脚切到OFF
bd1de29eb01d40678c592930eac2d37b.jpg ​
本实验需要用到 TF 卡方测试图片
4f187a319758473ba5da6321ca07d603.jpg ​
8.2实验结果
7f5f7bdf9a1345a08ada8f608f3ab6f7.jpg ​


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

0

粉丝

303

主题
精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版