學習內容
本文主要關于SD卡相關內容,然后使用SD卡進行TXT文本讀寫,并用串口打印出讀寫數據。
開發環境
vivado 18.3&SDK,PYNQ-Z2開發板。
SD卡簡介
SD卡(Secure Digital Card):安全數字卡,又叫安全數碼卡。有體積小,容量大傳輸速度快,支持熱插拔等特點。在ZYNQ開發板上這里是使用的是TF卡,也就是小卡(micro sd卡)又稱TF卡。
SD卡是在 MMC 卡( Multimedia Card,多媒體卡)的基礎上發展而來,主要增加了兩個特色:更高的安全性和更快的讀寫速度。SD卡的接口與MMC卡是兼容的,支持SD卡的接口大多支持MMC卡。下表為不同類型的 SD 卡采用的協議規范、容量等級及支持的文件系統。
SD卡類型協議規范容量等級磁盤格式SDSCSD1.0上限為2GBFAT12, FAT16SDHCSD2.02GB至32GBFAT32SDXCSD3.032GB至2TB( 2048GBexFAT
不同協議規范的 SD 卡有著不同速度等級的表示方法。在 SD1.0 規范中(現已不用),使用“ X”表示不同的速度等級;在 SD2.0 規范中,普通卡和高速卡的速率定義為Class2、Class4、Class6 和Class10 四個等級;SD3.0 規范(又稱為超高速卡)使用 UHS( Ultra High Speed)表示不同的速度等級。不同等級的讀寫速度和應用如下圖所示:
SD 卡共有 9 個引腳線, 共支持三種傳輸模式:SPI模式(獨立序列輸入和序列輸出),1位SD模式 (獨立指令和數據通道,獨有的傳輸格式), 4位SD模式 (使用額外的針腳以及某些重新設置的針腳。支持四位寬的并行傳輸)。具體的引腳功能定義如下表所示:
MicroSD 卡接口定義以及各引腳功能說明如下圖所示。
ZYNQ 內部集成了兩個 SD 卡控制器,并且 Xilinx SDK 的 standalone 已經移植好了 FATFS( SDK 軟件中叫做 xilffs)文件系統,因此在 SDK 中添加 xilffs 庫后, 就可以在程序中使用 FATFS 中的 API 函數來操作 SD 卡。
SD 卡控制器( SD/SDIO Controller)
SD/SDIO控制器與SDIO設備、SD存儲卡和MMC卡通信,最多有4條數據線。SD接口可以使用一條 (dat0)或四條(dat0- dat3)行進行數據傳輸。SDIO接口可以通過MIO多路復用到MIO引腳或通過PL中的EMIO進行lO引腳分配。
ZYNQ 中的 SD 卡控制器符合 SD2.0 協議規范, 接口兼容 eMMC、 MMC3.31、 SDIO2.0、 SD2.0、 SPI,支持 SDHC、 SDHS 器件。SD 卡控制器支持 SDMA(單操作 DMA)、 ADMA1( 4K 邊界限制 DMA)和ADMA2( 在 32 位系統中允許任何位置和任意大小)。SD/SDIO控制器由ARM處理器通過AHB總線訪問。該控制器還包括一個DMA單元與內部FIFO以滿足吞吐量要求。SD/SDIO控制器的框圖如下:
SD控制器使用兩個512字節深度的雙端口FIFO執行寫和讀操作。SD 控制器讀寫通道采用獨立的 512 字節深度的雙緩沖 FIFO 執行讀和寫操作。在寫操作時,處理器向 其中一個 FIFO 寫數據,將另一個 FIFO 的數據寫到 SD 總線;在讀操作時, SD 總線上的數據向其中一個FIFO 寫數據,處理器將數據從另一個 FIFO 讀出數據。SD 卡控制器通過雙緩沖機制以保證最大帶寬。
FATFS文件系統
負責管理和存儲文件信息的軟件機構稱為文件管理系統,簡稱文件系統。即在磁盤上組織文件的方法。常見的文件系統有FAT/FATFS(FATFS 是一個完全開源免費的 FAT 文件系統模塊)、NTFS(基于安全性的文件系統,是Windows NT采用的獨特的文件系統結構)、CDFS(CDFS是大部分光盤的文件系統)、exFAT(擴展性的文件系統)。FATFS是一個可以裁剪的文件系統,專門為小型的嵌入式系統而設計。它完全用標準 C語言編寫,結構清晰,代碼量小,文件系統和IO底層分開,所以具有良好的硬件平臺獨立性,可以很方便的移植到各種嵌入式處理器中,也很適合新手進行入門學習。支持最多10個邏輯盤符和兩級文件夾;可以支持FAT12、FAT16和FAT32,支持多個存儲媒介。FATFS 模塊的層次結構如下:
- 最頂層:應用層,使用者無需理會 FATFS 的內部結構和復雜的 FAT 協議,只需要調用 FATFS 模塊提供給用戶的一系列應用接口函數,如 f_open, f_read, f_write 和 f_close 等,就可以像在 PC 上讀/寫文件那樣簡單。
- 中間層 :FATFS 模塊,實現了 FAT 文件讀/寫協議。使用者一般不用修改,使用時將頭文件直接包含進去即可。
- 底層接口,包括存儲媒介讀/寫接口( disk I/O)和供給文件創建修改時間的實時時鐘。需要根據平臺和存儲介質編寫并移植代碼。關于文件系統的函數API使用可以通過下面這個網址進行學習入門:FATFS 學習網址Xilinx SDK 的standalone 已經移植好了 FATFS 文件系統,因此在 SDK 中添加 xilffs 庫后, 就可以在程序中使用 FATFS 中的 API 函數來操作 SD 卡。
系統框圖
本次工程只使用了PS端的資源,通過 Xilinx SDK 自帶的 FATFS 庫,完成對 SD卡中 TXT 文本讀寫的功能,并將讀寫測試結果通過串口打印出來。系統框圖如下:
硬件平臺搭建
新建工程,創建 block design。添加ZYNQ7 IP,對zynq進行初始化配置,勾選sd,uart資源,
設置BANK的電平,
取消勾選多余資源,點擊OK,完成硬件設計。如下圖:
然后我們進行generate output product 然后生成HDL封裝。這里沒有進行使用PL資源,也不需要進行綜合布局,在導出硬件時也不用包含bit流文件。
SDK軟件部分
打開SDK后,新建application project。選中工程右擊選中設置板載支持文件模式。
這里選擇xilffs模式,
點擊standalone下的xilffs,可以對文件系統進行配置,這里可以使能長文件名有效,改變勾選為true。
完成配置后點擊ok。
在main.c中輸入以下代碼:
#include "stdio.h"
#include "xparameters.h"
#include "ff.h"
#include "string.h"
#define FILE_NAME "vuko.txt"
char str_wr[100]= "this is a sd read and write test~";
char str_rd[100]="";
FATFS fs;
void sd_mount();
void sd_write_data(char wr_dat[], u32 wr_len);
void sd_read_data(char rd_dat[], u32 rd_len);
int main(){
u32 len;
sd_mount();
len=strlen(str_wr);
//寫數據
sd_write_data(str_wr,len);
//讀數據
sd_read_data(str_rd,len);
if(strcmp(str_rd,str_wr)==0){
printf("%s\n",str_rd);
printf("sd card test success!\n");
}
else
printf("sd card test fail!\n");
return0;
}
//掛載sd卡
void sd_mount(){
FRESULT status;
BYTE work[FF_MAX_SS];
//掛載sd卡,注冊文件系統對象
status=f_mount(&fs,"",1);
if(status != FR_OK){
printf("%d\n",status);
printf("It isn't FAT format\n");
f_mkfs("",FM_FAT32,0,work,sizeof work);
f_mount(&fs,"",1);
}
}
//寫數據
void sd_write_data(char wr_dat[], u32 wr_len){
FIL fil;
UINT bw;
//創建或者打開文件
f_open(&fil,FILE_NAME,FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
//移動讀寫指針
f_lseek(&fil, 0);
//寫數據
f_write(&fil,wr_dat,wr_len,&bw);
//關閉文件
f_close(&fil);
}
//讀數據
void sd_read_data(char rd_dat[], u32 rd_len){
FIL fil;
UINT br;
//創建或者打開文件
f_open(&fil,FILE_NAME,FA_READ);
//移動讀寫指針
f_lseek(&fil, 0);
//讀取數據
f_read(&fil,rd_dat,rd_len,&br);
//關閉文件
f_close(&fil);
}
整體代碼思路
該工程代碼主要實現三個函數,分別是掛載SD卡,讀取SD卡和寫入SD卡。在main函數中首先完成對SD卡的掛載,然后向指定文件內寫入的字符串數據,通過SD卡讀取函數把SD卡中指定文件的數據讀到數組中,完成數據的讀取后將寫入的字符串數據和讀取出來的字符串數據進行對比,對比一致后,用串口打印測試成功的標識。
部分代碼講解
對于具體的讀寫函數的使用,我們可以進行參考下面這個網址進行學習:FATFS 學習網址可以參考對應的讀寫函數的使用示例進行輔助開發設計。
對于寫入SD卡函數編寫:首先我們要進行創建或者打開文件,這里引入文件的結構體,使用f_open()
函數進行打開,將讀寫的指針移動到到指定位置,這里使用f_lseek(&fil, 0);
把光標移動到初始位置。然后使用寫入函數進行寫入數據f_write(&fil,wr_dat,wr_len,&bw);
完成寫入后,關閉文件f_close(&fil);
讀取SD卡函數和寫入的思路類似,對于掛載函數來說,使用status=f_mount(&fs,"",1);
注冊文件系統對象,如果讀取返回值不是FAT文件系統,則使用f_mkfs("",FM_FAT32,0,work,sizeof work);
把SD卡進行初始化。
運行結果
串口數據:
使用讀卡器讀取SD卡的文件數據:
Reference
- 正點原子ZYNQ開發視頻
- xilinx UG585