第十二章SD卡讀寫TXT文本實驗
SD存儲卡是一種基于半導體快閃記憶器的記憶設備。它具有體積小、傳輸速度快、支持熱插拔等優點,在便攜式裝置領域得到了廣泛的應用,如手機、多媒體播放器等。本章我們將使用ZYNQ開發板學習如何對SD卡(這里特指Micro SD卡,即TF卡)進行TXT文本的讀寫操作。
本章包括以下幾個部分:
11.1簡介
1.2實驗任務
1.3硬件設計
1.4軟件設計
1.5下載驗證
簡介
我們開發板上的SD卡接口為小卡的設計,可以連接Micro SD卡(也叫TF卡)sd卡寫保護原理,在介紹TF卡之前,我們先來介紹一下較大的一種存儲卡,即SD卡。
SD卡介紹
SD卡的英文全稱是 Card,即安全數字卡(又叫安全數碼卡),是在MMC卡( Card,多媒體卡)的基礎上發展而來,主要增加了兩個特色:更高的安全性和更快的讀寫速度。SD卡和MMC卡的長度和寬度都是32mm x 24mm,不同的是,SD卡的厚度為2.1mm,而MMC卡的厚度為1.4mm,SD卡比MMC卡略厚,以容納更大容量的存貯單元,同時SD卡比MMC卡觸點引腳要多,且在側面多了一個寫保護開關。SD卡與MMC卡保持著向上兼容,也就是說,MMC卡可以被新的SD設備存取,兼容性則取決于應用軟件,但SD卡卻不可以被MMC設備存取。SD卡和MMC卡可通過卡片上面的標注進行區分,如下圖左側圖片上面標注為“”字母樣式的為MMC卡,右側圖片上面標注為“SD”字母樣式的為SD卡。
圖 12.1.1 MMC外觀圖(左)和SD卡外觀圖(右)
上圖中右側圖片的SD卡實際上為SDHC卡,SD卡從存儲容量上分為3個級別,分別為:SD卡、SDHC卡( High ,高容量安全數字卡)和SDXC卡(SD ,容量擴大化的安全存儲卡)。SD卡在MMC卡的基礎上發展而來,使用FAT12/FAT16文件系統,SD卡采用SD1.0協議規范,該協議規定了SD卡的最大存儲容量為2GB;SDHC卡是大容量存儲SD卡,使用FAT32文件系統,SDHC卡采用SD2.0協議規范,該協議規定了SDHC卡的存儲容量范圍為2GB至32GB;SDXC卡是新提出的標準,不同于SD卡和SDHC卡使用的FAT文件系統,SDXC卡使用exFAT文件系統,即擴展FAT文件系統。SDXC卡采用SD3.0協議規范,該協議規定了SDXC卡的存儲容量范圍為32GB至2TB(),一般用于中高端單反相機和高清攝像機。
下表為不同類型的SD卡采用的協議規范、容量等級及支持的文件系統。
表 12.1.1 SD卡的類型、協議規范、容量等級及支持的文件系統
SD卡類型 協議規范 容量等級 支持文件系統
SD SD1.0 SDHC SD2.0 2GB至32GB FAT32
SDXC SD3.0 32GB至2TB() exFAT
不同協議規范的SD卡有著不同速度等級的表示方法。在SD1.0協議規范中(現在用的較少)sd卡寫保護原理,使用“X”表示不同的速度等級;在SD2.0協議規范中,使用表示不同的速度等級;SD3.0協議規范使用UHS(Ultra High Speed)表示不同的速度等級。SD2.0規范中對SD卡的速度等級劃分為普通卡(、、)和高速卡();SD3.0規范對SD卡的速度等級劃分為UHS速度等級1和3。不同等級的讀寫速度和應用如下圖所示。
圖 12.1.2 SD卡不同速度等級表示法
SD卡共有9個引腳線,可工作在SDIO模式或者SPI模式。在SDIO模式下,共用到CLK、CMD、DAT[3:0]六根信號線;在SPI模式下,共用到CS([3])、CLK()、MISO([0])、MOSI()四根信號線。SD卡接口定義以及各引腳功能說明如圖 12.1.3所示。
圖 12.1.3 SD卡接口定義以及各引腳功能說明
市面上除標準SD卡外,還有Micro SD卡(原名TF卡),是一種極細小的快閃存儲器卡,是由(閃迪)公司發明,主要用于移動手機。卡插入適配器()可以轉換成SD卡,其操作時序和SD卡是一樣的。卡接口定義以及各引腳功能說明如圖 12.1.4所示。
圖 12.1.4 卡接口定義以及各引腳功能說明
標準SD卡2.0版本中,工作時鐘頻率可以達到50Mhz,在SDIO模式下采用4位數據位寬,理論上可以達到()的傳輸速率;在SPI模式下采用1位數據位寬,理論上可以達到的傳輸速率。因此SD卡在SDIO模式下的傳輸速率更快,同時其操作時序也更復雜。值得一提的是,ZYNQ內部集成了兩個SD卡控制器,并且 SDK的已經移植好了FATFS(SDK軟件中叫做)文件系統,因此在SDK中添加庫后,就可以在程序中使用FATFS中的API函數來操作SD卡。
SD卡控制器(SD/SDIO )
ZYNQ中的SD卡控制器符合SD2.0協議規范,接口兼容eMMC、MMC3.31、SDIO2.0、SD2.0、SPI,支持SDHC、SDHS器件。SD卡控制器支持SDMA(單操作DMA)、ADMA1(4K邊界限制DMA)和ADMA2(在32位系統中允許任何位置和任意大小)。ARM處理器通過AHB總線訪問SD卡控制器,SD控制器采用讀和寫通道各自雙緩沖FIFO的機制提高吞吐帶寬。其內部框圖如下圖所示:
圖 12.1.5 SD卡控制器內部框圖
SD控制器讀寫通道采用獨立的512字節深度的雙緩沖FIFO執行讀和寫操作。在寫操作時,處理器向其中一個FIFO寫數據,將另一個FIFO的數據寫到SD總線;在讀操作時,SD總線上的數據向其中一個FIFO寫數據,處理器將數據從另一個FIFO讀出數據。SD卡控制器通過雙緩沖機制以保證最大帶寬。
FATFS文件系統
FATFS是一個完全開源免費的FAT文件系統模塊,專門為小型的嵌入式系統而設計。它完全用標準C語言編寫,所以具有良好的硬件平臺獨立性,可以很方便的移植到各種嵌入式處理器中。 SDK的已經移植好了FATFS文件系統,因此在SDK中添加庫后,就可以在程序中使用FATFS中的API函數來操作SD卡。
FATFS的特點如下:
1、結構清晰,代碼量少,文件系統和IO底層分開,特別適合新手入門學習;
2、支持最多10個邏輯盤符和兩級文件夾;
3、支持FAT12/FAT16和FAT32文件系統;
4、支持長文件名稱。
FATFS的這些特點,加上開源、免費的原則,使得FATFS的應用非常廣泛。FATFS模塊的層次結構如圖 12.1.6所示:
圖 12.1.6 FATFS層次結構圖
最頂層是應用層,使用者無需理會FATFS的內部結構和復雜的FAT協議,只需要調用FATFS 模塊提供給用戶的一系列應用接口函數,如,,和等,就可以像在 PC上讀/寫文件那樣簡單。
中間層FATFS模塊,實現了FAT文件讀/寫協議。FATFS模塊提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用時將頭文件直接包含進去即可。
FATFS模塊提供的底層接口,它包括存儲媒介讀/寫接口(disk I/O)和供給文件創建修改時間的實時時鐘。
關于FATFS源碼以及API函數的介紹,大家可以在:這個網站上查看。
實驗任務
本章的實驗任務是通過 SDK自帶的FATFS庫,完成對TF卡中TXT文本讀寫的功能,并將讀寫測試結果通過串口打印出來。
硬件設計
我們的領航者ZYNQ開發板上面有一個SD卡接口,可以連接Micor SD卡(TF卡),原理圖如下圖所示:
圖 12.3.1 Micro SD卡原理圖
圖 12.3.1中的U8()是一個電平轉換芯片,實現了1.8V和3.3V電平轉換的功能。由于TF卡引腳連接到ZYNQ的,的IO電平為1.8V,而TF的IO電平是3.3V,因此這里添加一個電平轉換芯片,用來轉換IO的電平。值得注意的是,TF卡的CD信號連接到了PS的MIO 10引腳,MIO 10引腳位于ZYNQ的,IO電平為3.3V。SD_CD信號是TF卡檢測信號,用于標志開發板是否連接了TF卡。
從實驗任務我們可以畫出如下的系統框圖,DDR3中存放和運行程序、SD卡控制器驅動TF卡,UART實現串口通信。
圖 12.3.2 系統框圖
由系統框圖可知,本次實驗在ZYNQ嵌入式最小系統的基礎上,添加了SD卡控制器,用于驅動TF卡。需要說明的是,TF卡連接的是PS的MIO端口,因此本次實驗沒有用到PL的資源。
這里簡單介紹下ZYNQ PS的配置界面,如圖 8.3.2所示。配置界面選擇的是UART0 MIO14..MIO15和SD0 MIO40..MIO45。
圖 12.3.3 外設IO配置界面
需要注意的是,TF卡的引腳連接到ZYNQ的Bank 1端口(),Bank 1的IO電壓為1.8V,因此在MIO的配置界面將Bank1的電壓改為“ 1.8V”。如圖 12.3.4圖 12.1.4所示:
圖 12.3.4 MIO配置界面
圖 12.3.4中勾選了CD信號,CD信號用于指示當前開發板有沒有連接TF卡,這里勾選中CD信號,并將引腳分配至MIO 10。
嵌入式系統最終搭建的框圖如圖 12.3.5所示。
圖 12.3.5 嵌入式系統框圖界面
軟件設計
在硬件設計的最后,我們打開了SDK開發環境。
在菜單欄中選擇File->New-> ,新建一個SDK應用工程。
在彈出的界面中工程名命名為,點擊“NEXT”,選擇“Empty ”,點擊“”按鈕完成SDK應用工程的創建。
接下來添加FATFS庫。需要注意的是,先關閉.mss的界面(如圖 12.4.1所示),再添加FATFS庫,否則有可能導致FATFS庫添加失敗。
圖 12.4.1 關閉.mss
.mss界面關閉后,右擊,選擇“Board ”。如圖 12.4.2所示:
圖 12.4.2 打開板級支持包設置
在彈出的界面中勾選“”,即為FATFS庫,如圖 12.4.3所示:
圖 12.4.3 勾選
勾選后,會在左側的一欄出現,點擊。可以看到的默認設置為false,即不使能。用于設置是否使能長文件名以及文件名的小寫字母,這里將設置為true,點擊“OK”按鈕完成設置。如圖 12.4.4所示:
圖 12.4.4 使能
設置完成后,在→→一欄下,會多出FATFS的庫函數。如圖 12.4.5所示:
圖 12.4.5 庫函數
添加完FATFS庫之后,對TF卡的操作會簡單很多,我們只需要在程序中調用FATFS的庫函數即可。
接下來新建一個源文件。在/src目錄上右鍵,選擇New-> File,在彈出的對話框中 file一欄我們輸入文件名“main.c”,然后點擊“”。
我們在新建的main.c文件中輸入以下代碼:
1 # ".h"
2 # ".h"
3 # "ff.h"
4 # ".h"
5
6 # "ZDYZ.txt" //定義文件名
7
8 const char [30] = ""; //定義文本內容
9 FATFS fatfs; //文件系統
10
11//初始化文件系統
12int ()
13{
14 ;
15 TCHAR *Path = "0:/";
16 BYTE work[];
17
18 //注冊一個工作區(掛載分區文件系統)
19 //在使用任何其它文件函數之前,必須使用函數為每個使用卷注冊一個工作區
20 = (&fatfs, Path, 1);//掛載SD卡
21 if ( != FR_OK) {
22 (" is not FAT ; FAT\r\n");
23 //格式化SD卡
24 = (Path, , 0, work, work);
25 if ( != FR_OK) {
26 (" to FATfs\r\n");
27 -1;
28 }
29 //格式化之后,重新掛載SD卡
30 = (&fatfs, Path, 1);
31 if ( != FR_OK) {
32 (" to mount FATfs\r\n");
33 -1;
34 }
35 }
36 0;
37}
38
39//掛載SD(TF)卡
40int ()
41{
42 ;
43 //初始化文件系統(掛載SD卡,如果掛載不成功,則格式化SD卡)
44 = ();
45 if(){
46 ("ERROR: %d!\n",);
47 ;
48 }
49 ;
50}
51
52//SD卡寫數據
53int (char *,u32 ,u32 )
54{
55 FIL fil; //文件對象
56 UINT bw; //函數返回已寫入的字節數
57
58 //打開一個文件,如果不存在,則創建一個文件
59 (&fil,, | );
60 //移動打開的文件對象的文件讀/寫指針 0:指向文件開頭
61 (&fil, 0);
62 //向文件中寫入數據
63 (&fil,(void*) ,,&bw);
64 //關閉文件
65 (&fil);
66 0;
67}
68
69//SD卡讀數據
70int (char *,u32 ,u32 )
71{
72 FIL fil; //文件對象
73 UINT br; //函數返回已讀出的字節數
74
75 //打開一個只讀的文件
76 (&fil,,);
77 //移動打開的文件對象的文件讀/寫指針 0:指向文件開頭
78 (&fil,0);
79 //從SD卡中讀出數據
80 (&fil,(void*),,&br);
81 //關閉文件
82 (&fil);
83 0;
84}
85
86//main函數
87int main()
88{
89 int ,len;
90 char [30] = "";
91
92 = (); //掛載SD卡
93 if( != ){
94 (" to open SD card!\n");
95 0;
96 }
97 else
98 (" to open SD card!\n");
99
100 len = (); //計算字符串長度
101 //SD卡寫數據
102 (,(u32),len);
103 //SD卡讀數據
104 (,(u32),len);
105
106 //比較寫入的字符串和讀出的字符串是否相等
107 if ((, ) == 0)
108 (" is equal to ,SD card test !\n");
109 else
110 (" is not equal to ,SD card test !\n");
111
112 0;
113 }
復制代碼
在main函數中,實現的功能是向TF卡中讀寫TXT文本,并比較寫入的數據和讀出的數據是否一致。程序首先調用()函數掛載TF卡,接下來根據待寫入字符串的長度,通過()函數和()函數對TF卡中的TXT文本進行寫入和讀出,然后比較寫入和讀出的值,并打印比較的結果值,如代碼中第86行至第113行所示。
()函數實現的功能是掛載TF卡,并返回掛載的結果。()函數里通過調用()函數實現對TF卡的掛載,如果掛載不成功,則格式化TF卡,并重新掛載TF卡。在使用任何其它文件系統函數之前,必須先對TF卡進行掛載,()函數如代碼中第39至第50行所示,()函數如代碼中第12至第37行所示。需要注意的是,掛載函數同樣會對硬件進行檢查,如果未插入TF卡,會導致SD卡掛載失敗。
()函數在TF卡中打開一個文本,并寫入程序開頭定義的字符數組“”。寫入之前,先通過函數打開一個文件名為“ZDYZ.txt”的文件,如果不存在,則在TF卡中創建該文件。隨后通過函數移動已打開文件對象的讀寫指針,為0則代表移動到文件的開頭位置。接下來通過函數向打開的文件中寫入數據,寫完之后則通過函數關閉該文件。如代碼的第52行至67行代碼所示。
()函數從TF卡的TXT文本中讀出數據。TF卡的讀操作和寫操作類似,讀數據的函數為函數,如代碼中第69行至第84行代碼所示。
下載驗證
首先我們將下載器與領航者底板上的JTAG接口連接,下載器另外一端與電腦連接。然后使用Mini USB連接線將開發板左側的接口與電腦連接,用于串口通信。接下來插入TF卡(TF卡插槽位于開發板背面)。最后連接開發板的電源,并打開電源開關。領航者開發板連接TF卡的正面圖和背面圖如圖 12.5.1和圖 12.5.2所示:
圖 12.5.1 開發板連接TF卡正面圖
圖 12.5.2 開發板連接TF卡背面圖
在SDK軟件下方的SDK 窗口中點擊右上角的加號設置并連接串口。然后在應用工程上右擊,選擇“Run As”,然后選擇第一項“1 on ( )”。
軟件程序下載完成后,在下方的SDK 中可以看到應用程序打印的信息,如下圖所示:
圖 12.5.3 打印SD卡讀寫測試結果
由上圖可知,顯示寫入的字符和讀出的字符一致,說明TF卡讀寫測試成功。
接下來從開發板的卡槽中取出TF卡,通過連接讀卡器來插入電腦的USB接口,此時可以看到TF中的文件內容如所示。
圖 12.5.4 創建的TXT文本
打開“ZDYZ.txt”文本,可以看到文本的內容,如下圖所示:
圖 12.5.5 TXT文本內容
TXT文本的內容為“”字符串,和串口中打印的字符串一致,說明本次實驗在領航者ZYNQ開發板上面下載驗證成功。