參考文獻
[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文件系統架構,介紹及維護這個系統的網址如下: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圖像數據格式
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端設計
因爲我們全部的工作量都是在PS端設計的,所以我們這裏不再浪費空間給出相應的PL端設計。所以這裏直接給出相應的代碼,代碼說白了就是從示例工程中學習得來的。代碼如下:
#include <stdio.h>
#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卡在電腦上讀出,觀察圖片是否正確。
上圖證明了我們實驗的正確性。
總結
創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣: