基於ZYNQ的SD卡的訪問

參考文獻

[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卡在電腦上讀出,觀察圖片是否正確。
在這裏插入圖片描述
上圖證明了我們實驗的正確性。

總結

創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章