使用在ZYNQ中有两个A9的arm核,在PS部分可以像单片机那样去访问一些常用的接口。并且Xilinx已经为这些接口的使用提供了库可以在SDK中直接使用。想要使用SD卡存储图片,首先需要在ZYNQ核中打开SD卡设置。
在ZYNQ核中,打开SD卡,然后导出bit文件到sdk中,接下来就可以在PS端来完成调用前面所介绍的函数,从而实现向SD卡中写入数据的操作。
Xilinx已经将FATFS进行了移植,在使用的时候只需要打开所支持的库即可。在创建好工程后点击BSP设置,就可以看到其中所支持的库,需要勾选xilffs。
在头文件中,需要将ff.h这个头文件进行引用,然后再头文件中需要使用到文件头和信息头的结构体。数据类型WORD等等其实都是基本数据类型的重定义。
/*********** *********** *********** *********** *********** *********** ***********
* definition :struct
* Description :位图文件头
*********** *********** *********** *********** *********** *********** ***********/
#pragma pack(1)/////////////////将结构体中成员按n字节对齐
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;////////////////文件类型,必须为BM
DWORD bfSize;///////////////指定文件大小,以字节为单位(3-6字节,低位在前)
WORD bfReserved1;///////////文件保留字,必须为0
WORD bfReserved2;///////////文件保留字,必须为0
DWORD bfOffBits;////////////从文件头到实际位图数据的偏移字节数(11-14字节,低位在前)
}BITMAPFILEHEADER;
/*********** *********** *********** *********** *********** *********** ***********
* definition :struct
* Description :位图信息头
*********** *********** *********** *********** *********** *********** ***********/
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;///////////////本结构所占用字节数,为40。注意:实际操作中则有44,这是字节补齐的原因
LONGG biWidth;///////////////位图的宽度,以像素为单位
LONGG biHeight;//////////////位图的高度,以像素为单位
WORD biPlanes;//////////////目标设备的级别,必须为1
WORD biBitCount;////////////每个像素所需的位数,1(双色),4(16色),8(256色)16(高彩色),24(真彩色)或32之一
DWORD biCompression;////////位图压缩类型,0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage;//////////位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位
LONGG biXPelsPerMeter;///////位图水平分辨率,每米像素数
LONGG biYPelsPerMeter;///////位图垂直分辨率,每米像素数
DWORD biClrUsed;////////////位图实际使用的颜色表中的颜色数,若该值为0,则使用颜色数为2的biBitCount次方
DWORD biClrImportant;///////位图显示过程中重要的颜色数,若该值为0,则所有的颜色都重要
}BITMAPINFOHEADER;
#pragma pack()//////////////////取消自定义字节方式
main函数中需要定义这两个结构体的对象,并且在main函数中对这两个结构体进行赋值。本次我做的是一个1024*768大小的图像。
//文件头结构体赋值
bmpFile_H.bfType = 0x4d42; // 文件类型为BMP
bmpFile_H.bfSize = 54 + 1024*768*3; // 文件大小存储1024*768大小的图像数据
bmpFile_H.bfReserved1 = 0;
bmpFile_H.bfReserved2 = 0;
bmpFile_H.bfOffBits = 54; //图像数据相较于文件头的偏移地址
//信息头结构体赋值
bmpInfo_H.biSize = 40; //信息头大小
bmpInfo_H.biWidth = 1024; //BMP图像宽
bmpInfo_H.biHeight = 768; //BMP图像高度
bmpInfo_H.biPlanes = 1; //目标设备级别
bmpInfo_H.biBitCount = 24; //像素为24位真彩色
bmpInfo_H.biCompression = 0; //不压缩
bmpInfo_H.biSizeImage = 1024 * 768 * 3; //位图的大小
bmpInfo_H.biXPelsPerMeter = 0;//水平分辨率
bmpInfo_H.biYPelsPerMeter = 0;//垂直分辨率
bmpInfo_H.biClrImportant = 0;//色彩权重
bmpInfo_H.biClrUsed = 0 ; //使用到的颜色
然后声明两个函数,一个函数用于向SD卡中写入数据,一个用于产生测试图像。向SD中写入数据的函数实现如下:
/*********** *********** *********** *********** *********** *********** ***********
*功能:保存图片
*parameter: @ bInfoHeader: BMP文件信息头
*parameter: @ bFileHeader:BMP文件头
*parameter: @ imageSrc :图像数据源
*parameter: @ fileName :图像要保存的文件
*return : 返回值判断图片是否被正确写入
*********** *********** *********** *********** *********** *********** ***********/
int writeSdCard(
BITMAPFILEHEADER * bFileHeader,
BITMAPINFOHEADER * bInfoHeader,
u8 * imageSrc,
char * fileName
)
{
FATFS fatFS; //FATFS 文件结构体对象
const char * path = "0:/";//逻辑分区的指针编号
FIL fil;
UINT numWriteBytes;
FRESULT fileOK;
fileOK = f_mount(&fatFS, path, 0); //挂载
fileOK = f_open(&fil,fileName, FA_CREATE_ALWAYS|FA_WRITE);//创建文件并对文件进行写入
fileOK = f_lseek(&fil, 0); //指针指向文件开始的位置
fileOK = f_write(&fil, bFileHeader, sizeof(BITMAPFILEHEADER), &numWriteBytes);//写入文件头
fileOK = f_write(&fil, bInfoHeader, sizeof(BITMAPINFOHEADER), &numWriteBytes);//写入信息头
fileOK = f_write(&fil, imageSrc , 1024*768*3 + 256, &numWriteBytes);//写入图像数据
fileOK = f_sync(&fil); //同步
fileOK = f_close(&fil);//关闭
if (fileOK != FR_OK )
{
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*********** *********** *********** *********** *********** *********** ***********
*功能:产生测试图像
*parameter: @ imageSrc 测试图像的指针
*********** *********** *********** *********** *********** *********** ***********/
void genTestImage(u8 * imageSrc)
{
for (int idxRow = 0; idxRow < 768; idxRow++)
{
for (int idxCol = 0; idxCol < 1024; idxCol++)
{
if ( idxCol >= 0 && idxCol < 341)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0x00;
}
else if ( idxCol >= 341 && idxCol < 682)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0x00;
}
else if ( idxCol >= 682 && idxCol < 1024)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0xFF;
}
}
}
}
将SD卡插入到开发板后,就可以运行程序,然后就可以将程序运行起来,程序运行结束后,可以将SD插入到电脑上看到SD卡中出现了一幅bmp的图像。
打开可以看到产生了测试的图像。虽然出现了图像,但是图像的与期望是不一样的,是相反的,图像彩条应该是RGB排列,但是现在得到的结果是BGR排列。这是与内部数据排列有关。
通过更改测试图像的数据后可以看到图像数据确实发生了变化,可以看到BMP图像的存储,可以看到是由左下角开始的。需要注意在SD卡中存储的数据是低位在前,高位在后,因此在程序中设计的想要的每个像素RGB排列变成了BGR排列。并且可以看到,在SD中存储的图片在显示的时候,第一行变成了最后一行。最后一行变成了第一行。
/*********** *********** *********** *********** *********** *********** ***********
*功能:产生测试图像
*parameter: @ imageSrc 测试图像的指针
*********** *********** *********** *********** *********** *********** ***********/
void genTestImage(u8 * imageSrc)
{
for (int idxRow = 0; idxRow < 768; idxRow++)
{
for (int idxCol = 0; idxCol < 1024; idxCol++)
{
if ( idxRow>=0 && idxRow <200 && idxCol >= 682 && idxCol < 1024)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0xFF;
}
else if ( idxCol >= 0 && idxCol < 341)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0x00;
}
else if ( idxCol >= 341 && idxCol < 682)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0x00;
}
else
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0xFF;
}
}
}
}
经过一番debug之后,最终解决了这些问题,显示的颜色顺序也就都正常了。
void genTestImage(u8 * imageSrc)
{
for (int idxRow = 0; idxRow < 768; idxRow++)
{
for (int idxCol = 0; idxCol < 1024; idxCol++)
{
if ( idxRow>=500 && idxRow <768 && idxCol >= 682 && idxCol < 1024)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0xFF;
}
else if ( idxCol >= 0 && idxCol < 341)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0xFF;
}
else if ( idxCol >= 341 && idxCol < 682)
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0x00;
}
else
{
*(imageSrc + (1024*idxRow + idxCol)*3) = 0xFF;
*(imageSrc + (1024*idxRow + idxCol)*3 + 1) = 0x00;
*(imageSrc + (1024*idxRow + idxCol)*3 + 2) = 0x00;
}
}
}
参考:V3学院尤老师的哦