[1].V3学院
现在FPGA板卡上面常用的存储设备是SD卡,也经常将BOOT文件下载到SD卡中启动。那么这篇文章我们将讲解使用API函数来进行SD卡的读写,当然使用纯FPGA写Verilog也是可以读写SD卡,遵循SPI协议,后面的文章我们会进行相应的介绍,这篇文章先来讲解简单的C语言访问SD卡。
工程描述:ZYNQ利用FAT文件系统对SD卡些一张图片。
本次实验所用到的软硬件环境如下:
1、VIVADO 2019.1
2、米联客MZ7015FA开发板
本片博客我们将利用开源的FAT文件系统架构,介绍及维护这个系统的网址如下:FAT。打开这个网址,我们便可以看到如下信息:
点开每一个函数都有详细的参数说明及例子:
同学们可以主要通过上面的例子进行相应的学习,了解每个函数的功能。这里注意上面的介绍非常详细,尤其是示例工程。
那么学习到这里的同学或许会问,我们明白了上面函数的作用,那么我们如何将上面的系统框架引用到ZYNQ中呢?因为我们直接写相应的FAT中的函数,ZYNQ肯定不会识别的,这里我们将给出详细的操作步骤。
首先右击相应工程的bsp文件,选择Board Support Package Setting
然后点击相应的xilffs
然后重新生成相应的bsp文件即可。接下来我们对常用的函数进行简单的介绍:
//挂载的函数
//The f_mount fucntion registers/unregisters filesystem object to the FatFs module.
FRESULT f_mount (
FATFS* fs, /* [IN] Filesystem object */
const TCHAR* path, /* [IN] Logical drive number */
BYTE opt /* [IN] Initialization option */
);
//The f_open function opens a file.
FRESULT f_open (
FIL* fp, /* [OUT] Pointer to the file object structure */
const TCHAR* path, /* [IN] File name */
BYTE mode /* [IN] Mode flags */
);
//The f_write writes data to a file.
FRESULT f_write (
FIL* fp, /* [IN] Pointer to the file object structure */
const void* buff, /* [IN] Pointer to the data to be written */
UINT btw, /* [IN] Number of bytes to write */
UINT* bw /* [OUT] Pointer to the variable to return number of bytes written */
);
//The f_read function reads data from a file.
FRESULT f_read (
FIL* fp, /* [IN] File object */
void* buff, /* [OUT] Buffer to store read data */
UINT btr, /* [IN] Number of bytes to read */
UINT* br /* [OUT] Number of bytes read */
);
//The f_sync function flushes the cached information of a writing file.
FRESULT f_sync (
FIL* fp /* [IN] File object */
);
//The f_close function closes an open file.
FRESULT f_close (
FIL* fp /* [IN] Pointer to the file object */
);
这里需要特别注意f_sync函数,是将
至于上面函数中每个参数的作用,同学们可以打开博客中上面的连接进行学习,上面的介绍非常详细。
bmp图像主要由下面结构组成:
1、文件头结构
2、信息头结构
3、颜色表
4、像素数据
对于bmp格式的24位真彩图,上面的颜色表信息为空,因为24位不需要颜色表的映射。至于每个结构里面具体的信息,我们给出相应的头文件,可以学习上面的注释。
#ifndef _BMP_IMG_H
#define _BMP_IMG_H
#include "xsdps.h"
#include "ff.h"
#endif
typedef unsigned short int WORD;
//typedef unsigned int DWORD;
typedef int LONGG;
typedef unsigned char BYTE;
/*********** *********** *********** *********** *********** *********** ***********
* 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()//取消自定义字节方式
/*********** *********** *********** *********** *********** *********** ***********
* definition :struct
* Description :调色板
*********** *********** *********** *********** *********** *********** ***********/
typedef struct tagRGBQUAD
{
BYTE rgbBlue;///蓝色的亮度(0-255)
BYTE rgbGreen;//绿色的亮度(0-255)
BYTE rgbRed;红色的亮度(0-255)
BYTE rgbReserved;///保留,必须为0
}RGBQUAD;
/*********** *********** *********** *********** *********** *********** ***********
* Function Name :printInfo
* Description :输出文件信息
*********** *********** *********** *********** *********** *********** ***********/
void printInfo(BITMAPFILEHEADER fileHeader,BITMAPINFOHEADER infoHeader);
/*********** *********** *********** *********** *********** *********** ***********
* Function Name :printInfo
* Description :输出画板信息
*********** *********** *********** *********** *********** *********** ***********/
void printPalette(RGBQUAD *rgbPalette,int sizeOfPalette);
//int ReadBmp(BITMAPFILEHEADER fileHeader,BITMAPINFOHEADER infoHeader,RGBQUAD *rgbPalette/*给它去别名一起变化*/,void *img[5000],char *FileName);
int SaveBmp(BITMAPFILEHEADER fileHeader,BITMAPINFOHEADER infoHeader,RGBQUAD *rgbPalette,u8 *img,char *FileName);
特别注意以下函数限制:
这是为了让结构体之间的成员按照字节递增的顺序排列,如果没有这句约束,结构体再内存中的排列有可能是跳跃的。
所谓ZYNQ写24位真彩图片到SD卡,其实就是先写文件头、再写信息头、最后写图像数据。详情请查看下面的代码进行学习。
因为我们全部的工作量都是在PS端设计的,所以我们这里不再浪费空间给出相应的PL端设计。所以这里直接给出相应的代码,代码说白了就是从示例工程中学习得来的。代码如下:
#include
#include "platform.h"
#include "xil_printf.h"
#include "ff.h"
#include "bmp_img.h"
int main()
{
BITMAPFILEHEADER filh;
BITMAPINFOHEADER infh;
filh.bfOffBits = 54;
filh.bfReserved1 =0;
filh.bfReserved2 =0;
filh.bfSize = 54 + 32*32*3;
filh.bfType = 0x4d42;
infh.biBitCount = 24;
infh.biClrImportant = 0;
infh.biClrUsed =0;
infh.biCompression =0;
infh.biHeight =32;
infh.biPlanes =1;
infh.biSize = 40;
infh.biSizeImage = 32*32*3;
infh.biWidth =32;
infh.biXPelsPerMeter =0;
infh.biYPelsPerMeter =0;
FATFS fs;
FIL fil;
u8 *databuf = (u8 *)0x2000000;
TCHAR *path ="0:/";
TCHAR *filename ="abc.bmp";
FRESULT res;
UINT write_byte_nums;
int r,c,i;
for(r=0;r<32;r++){
for(c=0;c<32;c++){
for(i=0;i<3;i++){
if(r<16){
databuf[r*32*3+c*3+i] = 255;
}
else{
databuf[r*32*3+c*3+i] = 0;
}
}
}
}
res = f_mount(&fs,path,0);
if(res != FR_OK){
return res;
}
res = f_open(&fil,filename,FA_CREATE_ALWAYS | FA_WRITE);
if(res != FR_OK){
return res;
}
res = f_write(&fil,&filh,sizeof(BITMAPFILEHEADER),&write_byte_nums);
if(res != FR_OK){
return res;
}
res = f_write(&fil,&infh,sizeof(BITMAPINFOHEADER),&write_byte_nums);
if(res != FR_OK){
return res;
}
res = f_write(&fil,databuf,32*32*3,&write_byte_nums);
if(res != FR_OK){
return res;
}
res = f_sync(&fil);
if(res != FR_OK){
return res;
}
f_close(&fil);
print("write 256 bytes to abc.bin \n\r");
return 0;
}
上面的代码特别简单,相信同学们可以学会,但是学这个的时候需要特别注意bmp图像的数据格式。
从上面的代码中我们可以看出,我们写了一副32*32的bmp图片到SD卡。然后将SD卡在电脑上读出,观察图片是否正确。
上图证明了我们实验的正确性。
创作不易,认为文章有帮助的同学们可以关注、点赞、转发支持。为行业贡献及其微小的一部分。对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群: