15 - VDMA之SD卡读BMP图片显示实验
文章目录
- 1 实验任务
- 2 系统框图
- 3 硬件设计
- 4 软件设计
- 4.1 工程架构
- 4.2 工程源码
- 4.2.1 sd_api.h文件
- 4.2.2 sd_api.c文件
- 4.2.3 main.c文件
1 实验任务
本实验任务是PS端从SD卡读取bmp格式图片到DDR3内存中,然后通过PL端的VDMA IP核将bmp图片读出,通过HDMI接口按照1080p@60Hz的时序输出显示。
2 系统框图
参见14.1。
3 硬件设计
注意事项:基于14.1做如下改动
- 在PS配置中勾选SD卡即可。
4 软件设计
注意事项:
- 在Board Support Package Settings➡Overview中,勾选xilffs选项。
4.1 工程架构
工程架构如下图所示:
4.2 工程源码
4.2.1 sd_api.h文件
代码如下所示:
/*****************************************************************************/#ifndef SRC_SD_SD_API_H_
#define SRC_SD_SD_API_H_/*****************************************************************************/#include "ff.h"/*****************************************************************************/// BMP文件头结构体
#pragma pack(push, 1) // 确保结构体按1字节对齐
typedef struct {u16 bfType; // 文件类型,必须是"BM"u32 bfSize; // 文件大小u16 bfReserved1; // 保留,必须为0u16 bfReserved2; // 保留,必须为0u32 bfOffBits; // 从文件头到像素数据的偏移
} BMPFileHeader;typedef struct {u32 biSize; // 信息头大小u32 biWidth; // 图像宽度(像素)u32 biHeight; // 图像高度(像素)u16 biPlanes; // 颜色平面数,必须为1u16 biBitCount; // 每像素位数u32 biCompression; // 压缩类型u32 biSizeImage; // 图像大小(字节)u32 biXPelsPerMeter; // 水平分辨率(像素/米)u32 biYPelsPerMeter; // 垂直分辨率(像素/米)u32 biClrUsed; // 使用的颜色数u32 biClrImportant; // 重要颜色数
} BMPInfoHeader;
#pragma pack(pop) // 恢复默认对齐方式/*****************************************************************************/int SdCardInit(FATFS* FatFsInstPtr);
int ReadSdCardBmpToDDR(const char* FileName, u8* DdrAddr);/*****************************************************************************/#endif /* SRC_SD_SD_API_H_ *//*****************************************************************************/
4.2.2 sd_api.c文件
代码如下所示:
/*****************************************************************************/#include "stdio.h"
#include "xstatus.h"
#include "xil_cache.h"
#include "sd_api.h"/*****************************************************************************/// 初始化文件系统
int SdCardInit(FATFS* FatFsInstPtr)
{//FRESULT Status;TCHAR *Path = "0:/";BYTE work[FF_MAX_SS];// 挂载SD卡(到一个具体的文件系统对象上)Status = f_mount(FatFsInstPtr, Path, 1);if (Status != FR_OK) {printf("Error : logical drive needs to be formatted.\n");//格式化SD卡Status = f_mkfs(Path, FM_FAT32, 0, work, sizeof(work));if (Status != FR_OK) {printf("Error : logical drive formatting failed.\n");return XST_FAILURE;}//格式化之后,重新挂载SD卡Status = f_mount(FatFsInstPtr, Path, 1);if (Status != FR_OK) {printf("Error : logical drive mounting failed.\n");return XST_FAILURE;}}//return XST_SUCCESS;
}/*****************************************************************************/int ReadSdCardBmpToDDR(const char* FileName, u8* DdrAddr)
{//FIL FileObj; // 文件对象FRESULT FatFsRes; // FatFs返回结果UINT BytesRead; // 实际读取的字节数UINT ImageLineSize;// 1. 打开BMP文件FatFsRes = f_open(&FileObj, FileName, FA_READ);if (FatFsRes != FR_OK) {printf("Error : file open failed.\n");return XST_FAILURE;}// 2. 读取BMP文件头BMPFileHeader FileHeader;FatFsRes = f_read(&FileObj, &FileHeader, sizeof(BMPFileHeader), &BytesRead);if (FatFsRes != FR_OK || BytesRead != sizeof(BMPFileHeader)) {printf("Error : bmp file header read failed.\n");f_close(&FileObj);return XST_FAILURE;}// 3. 检查文件类型是否为"BM"if (FileHeader.bfType != 0x4D42) {printf("Error : not a valid bmp file.\n");f_close(&FileObj);return XST_FAILURE;}// 4. 读取BMP信息头BMPInfoHeader InfoHeader;FatFsRes = f_read(&FileObj, &InfoHeader, sizeof(BMPInfoHeader), &BytesRead);if (FatFsRes != FR_OK || BytesRead != sizeof(BMPInfoHeader)) {printf("Error : bmp info header read failed.\n");f_close(&FileObj);return XST_FAILURE;}printf("BMP Image Info :\n");printf("\t\tImage Width\t\t= %lu pixels\n", InfoHeader.biWidth);printf("\t\tImage Height\t\t= %lu pixels\n", InfoHeader.biHeight);printf("\t\tImage BitDepth\t= %hu bits\n", InfoHeader.biBitCount);printf("\t\tImage Size\t\t= %lu bytes\n", InfoHeader.biSizeImage);// 5. 定位到像素数据开始位置FatFsRes = f_lseek(&FileObj, FileHeader.bfOffBits);if (FatFsRes != FR_OK) {printf("Error : seeking to pixel data failed.\n");f_close(&FileObj);return XST_FAILURE;}// 6. 读取像素数据到DDRImageLineSize = InfoHeader.biWidth * InfoHeader.biBitCount / 8;for (int i = InfoHeader.biHeight - 1; i >= 0; i--) {//FatFsRes = f_read(&FileObj, DdrAddr + i * ImageLineSize, ImageLineSize, &BytesRead);if (FatFsRes != FR_OK || BytesRead != ImageLineSize) {printf("Error : pixel data read failed.\n");f_close(&FileObj);return XST_FAILURE;}}// 7.刷新DCacheXil_DCacheFlushRange((INTPTR)DdrAddr, InfoHeader.biSizeImage);// 8. 关闭文件f_close(&FileObj);//return XST_SUCCESS;
}/*****************************************************************************/
4.2.3 main.c文件
代码如下所示:
/********************************************************************/#include "vdma/vdma_api.h"
#include "sd/sd_api.h"#include "xparameters.h"
#include "stdio.h"
#include "sleep.h"/********************************************************************/#define VDMA_DEVICE_ID XPAR_AXIVDMA_0_DEVICE_ID
#define MEMORY_BASEADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR#define IMAGE_WIDTH 1920
#define IMAGE_HEIGHT 1080/********************************************************************//********************************************************************/XAxiVdma VdmaInst;
FATFS FatFsInst;int FrameBufferAddr = (MEMORY_BASEADDR + 0x02000000);char* FileName = "TestBmp_1920x1080.bmp";
/********************************************************************/int main()
{//int Status;u8* VdmaBufferAddr = (u8*)FrameBufferAddr;// SD卡初始化Status = SdCardInit(&FatFsInst);if (Status == XST_FAILURE) {printf("Error : SD card initialization failed.\n");}else {printf("SD card initialization succeeded.\n");}// 从SD卡中读取BMP图片写入DDR中Status = ReadSdCardBmpToDDR(FileName, VdmaBufferAddr);if (Status == XST_FAILURE) {printf("Error : SD card read failed.\n");}else {printf("SD card read succeeded.\n");}// 启动VDMA读操作Status = run_vdma_frame_buffer(&VdmaInst, VDMA_DEVICE_ID, IMAGE_WIDTH, IMAGE_HEIGHT, FrameBufferAddr, 0, 0, ONLY_READ);if (Status == XST_FAILURE) {printf("Error : run vdma frame buffer failed.\n");}else {printf("Run vdma frame buffer succeeded.\n");}//while (1) {//sleep(10);printf("Stop vdma channel.\n");XAxiVdma_DmaStop(&VdmaInst, XAXIVDMA_READ);//sleep(5);printf("Start vdma channel.\n");XAxiVdma_DmaStart(&VdmaInst, XAXIVDMA_READ);}//return XST_SUCCESS;
}/*****************************************************************************/