STM32的FATFS檔案系統移植筆記(轉…
經常在網上、群裡看到很多人問關於STM32的FATFS檔案系統移植的問題,剛好自己最近也在除錯這個程式,為了讓大家少走彎路,我把我的除錯過程和方法也貢獻給大家。
二、FATFS簡介
FatFs Module是一種完全免費開源的FAT檔案系統模組,專門為小型的嵌入式系統而設計。它完全用標準C語言編寫,所以具有良好的硬體平臺獨立性,可以移植 到8051、PIC、AVR、SH、Z80、H8、ARM等系列微控制器上而只需做簡單的修改。它支援FATl2、FATl6和FAT32,支援多個儲存媒 介;有獨立的緩衝區,可以對多個檔案進行讀/寫,並特別對8位微控制器和16位微控制器做了優化。
三、移植準備
1、FATFS原始碼的獲取,可以到官網下載:
2、解壓檔案會得到兩個資料夾,一個是doc資料夾,這裡是FATFS的一些使用文件和說明,以後在檔案程式設計的時候可以檢視該文件。另一個是src資料夾,裡面就是我們所要的原始檔。
3、建立一個STM32的工程,為方便除錯,我們應過載printf()底層函式實現串列埠列印輸出。可以參考已經建立好的printf()列印輸出工程:http://www.viewtool.com/bbs/foru ... d=77&extra=page=1
四、開始移植
1、在已經建立好的工程目錄User資料夾下新建兩個資料夾,FATFS_V0.09和SPI_SD_Card,FATFS_V0.09用於存放FATFS原始檔,SPI_SD_Card用於存放SPI的驅動檔案。
2、如圖1將ff.c新增到工程資料夾中,並新建diskio.c檔案,在diskio.c檔案中實現五個函式:
- DSTATUS disk_initialize (BYTE);//SD卡的初始化
- DSTATUS disk_status (BYTE);//獲取SD卡的狀態,這裡可以不用管
- DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);//從SD卡讀取資料
- DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);//將資料寫入SD卡,若該檔案系統為只讀檔案系統則不用實現該函式
-
DRESULT
disk_ioctl (BYTE, BYTE, void*);//獲取SD卡檔案系統相關資訊
圖1
3、初步實現以上五個函式
FATFS初始化函式:
- DSTATUS disk_initialize (
- BYTE drv
- )
- {
- switch (drv)
- {
- case 0 :
- return RES_OK;
- case 1 :
- return RES_OK;
- case 2 :
- return RES_OK;
- case 3 :
- return RES_OK;
- default:
- return STA_NOINIT;
- }
- }
FATFS狀態獲取函式:
- DSTATUS disk_status (
- BYTE drv
- )
- {
- switch (drv)
- {
- case 0 :
- return RES_OK;
- case 1 :
- return RES_OK;
- case 2 :
- return RES_OK;
- default:
- return STA_NOINIT;
- }
- }
FATFS底層讀資料函式:
- DRESULT disk_read (
- BYTE drv,
- BYTE *buff,
- DWORD sector,
- BYTE count
- )
- {
- if( !count )
- {
- return RES_PARERR;
- }
- switch (drv)
- {
- case 0:
- if(count==1)
- {
- return RES_OK;
- }
- else
- {
- return RES_OK;
- }
- case 1:
- if(count==1)
- {
- return RES_OK;
- }
- else
- {
- return RES_OK;
- }
- default:
- return RES_ERROR;
- }
- }
FATFS底層寫資料函式:
- DRESULT disk_write (
- BYTE drv,
- const BYTE *buff,
- DWORD sector,
- BYTE count
- )
- {
- if( !count )
- {
- return RES_PARERR;
- }
- switch (drv)
- {
- case 0:
- if(count==1)
- {
- return RES_OK;
- }
- else
- {
- return RES_OK;
- }
- case 1:
- if(count==1)
- {
- return RES_OK;
- }
- else
- {
- return RES_OK;
- }
- default:return RES_ERROR;
- }
- }
FATFS磁碟控制函式:
- DRESULT disk_ioctl (
- BYTE drv,
- BYTE ctrl,
- void *buff
- )
- {
- if (drv==0)
- {
- switch (ctrl)
- {
- case CTRL_SYNC :
- return RES_OK;
- case GET_SECTOR_COUNT :
- return RES_OK;
- case GET_BLOCK_SIZE :
- return RES_OK;
- case CTRL_POWER :
- break;
- case CTRL_LOCK :
- break;
- case CTRL_EJECT :
- break;
- case MMC_GET_TYPE :
- break;
- case MMC_GET_CSD :
- break;
- case MMC_GET_CID :
- break;
- case MMC_GET_OCR :
- break;
- case MMC_GET_SDSTAT :
- break;
- }
- }else if(drv==1){
- switch (ctrl)
- {
- case CTRL_SYNC :
- return RES_OK;
- case GET_SECTOR_COUNT :
- return RES_OK;
- case GET_SECTOR_SIZE :
- return RES_OK;
- case GET_BLOCK_SIZE :
- return RES_OK;
- case CTRL_POWER :
- break;
- case CTRL_LOCK :
- break;
- case CTRL_EJECT :
- break;
- case MMC_GET_TYPE :
- break;
- case MMC_GET_CSD :
- break;
- case MMC_GET_CID :
- break;
- case MMC_GET_OCR :
- break;
- case MMC_GET_SDSTAT :
- break;
- }
- }
- else{
- return RES_PARERR;
- }
- return RES_PARERR;
- }
以上函式都只是實現一個框架,並沒有做實際的事情,下一步就需要把操作SD卡的程式填充在這個框架裡面。
4、實現disk_initialize()函式
該函式在掛載檔案系統的時候會被呼叫,主要是實現讀寫SD卡前對SD卡進行初始化,根據SD卡的傳輸協議,我們按照如下步驟初始化SD卡:
a、判斷SD卡是否插入,可以通過檢查SD卡卡座的CD腳電平進行判斷,一般插入卡後該引腳會變成低電平。
b、稍微延時一段時間後傳送至少74個時鐘給SD卡。
c、傳送CMD0命令給SD卡,直到SD卡返回0x01為止,這裡可以迴圈多次傳送。
程式如下:
- for(retry=0; retry<0xFFF; retry++)
- {
- r1 = MSD0_send_command(CMD0, 0, 0x95);
- if(r1 == 0x01)
- {
- retry = 0;
- break;
- }
- }
d、傳送CMD8獲取卡的型別,不同型別的卡其初始化方式有所不同。
e、根據卡的型別對卡進行初始化。具體初始化方式可以參考附件程式。
注:在初始化SD卡之前應該初始化SPI介面和相關的管腳。
實現後的程式如下:
- DSTATUS disk_initialize (
- BYTE drv
- )
- {
- int Status;
- switch (drv)
- {
- case 0 :
- Status = MSD0_Init();
- if(Status==0){
- return RES_OK;
- }else{
- return STA_NOINIT;
- }
- case 1 :
- return RES_OK;
- case 2 :
- return RES_OK;
- case 3 :
- return RES_OK;
- default:
- return STA_NOINIT;
- }
- }
MSD0_Init()函式在SPI_MSD0_Driver.c檔案中實現。
5、實現disk_read()函式
該函式是讀取SD卡扇區資料的函式,根據SD卡資料傳輸協議可知有讀取單扇區和讀取多扇區兩種操作模式,為提高讀檔案的速度應該實現讀取多扇區函式。
實現後的程式如下:
- DRESULT disk_read (
- BYTE drv,
- BYTE *buff,
- DWORD sector,
- BYTE count
- )
- {
- int Status;
- if( !count )
- {
- return RES_PARERR;
- }
- switch (drv)
- {
- case 0:
- if(count==1)
- {
- Status = MSD0_ReadSingleBlock( sector ,buff );
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- else
- {
- Status = MSD0_ReadMultiBlock( sector , buff ,count);
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- case 1:
- if(count==1)
- {
- return RES_OK;
- }
- else
- {
- return RES_OK;
- }
- default:
- return RES_ERROR;
- }
- }
MSD0_ReadSingleBlock()和MSD0_ReadMultiBlock()函式都是SD卡操作的底層函式,我們在SPI_MSD0_Driver.c檔案中實現。
6、實現disk_write()函式
該函式主要實現對SD卡進行寫資料操作,和讀資料操作一樣也分單塊寫和多塊寫,建議實現多塊寫的方式,這樣可以提高寫資料速度。
實現後的程式如下:
- DRESULT disk_write (
- BYTE drv,
- const BYTE *buff,
- DWORD sector,
- BYTE count
- )
- {
- int Status;
- if( !count )
- {
- return RES_PARERR;
- }
- switch (drv)
- {
- case 0:
- if(count==1)
- {
- Status = MSD0_WriteSingleBlock( sector , (uint8_t *)(&buff[0]) );
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- else
- {
- Status = MSD0_WriteMultiBlock( sector , (uint8_t *)(&buff[0]) , count );
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- case 1:
- if(count==1)
- {
- return RES_OK;
- }
- else
- {
- return RES_OK;
- }
- default:return RES_ERROR;
- }
- }
MSD0_WriteSingleBlock()和MSD0_WriteMultiBlock()函式都是SD卡操作的底層函式,我們在SPI_MSD0_Driver.c檔案中實現。
7、實現disk_ioctl()函式
該函式在磁碟格式化、獲取檔案系統資訊等操作時會被呼叫。
實現後的程式如下:
- DRESULT disk_ioctl (
- BYTE drv,
- BYTE ctrl,
- void *buff
- )
- {
- if (drv==0)
- {
- MSD0_GetCardInfo(&SD0_CardInfo);
- switch (ctrl)
- {
- case CTRL_SYNC :
- return RES_OK;
- case GET_SECTOR_COUNT :
- *(DWORD*)buff = SD0_CardInfo.Capacity/SD0_CardInfo.BlockSize;
- return RES_OK;
- case GET_BLOCK_SIZE :
- *(WORD*)buff = SD0_CardInfo.BlockSize;
- return RES_OK;
- case CTRL_POWER :
- break;
- case CTRL_LOCK :
- break;
- case CTRL_EJECT :
- break;
- case MMC_GET_TYPE :
- break;
- case MMC_GET_CSD :
- break;
- case MMC_GET_CID :
- break;
- case MMC_GET_OCR :
- break;
- case MMC_GET_SDSTAT :
- break;
- }
- }else if(drv==1){
- switch (ctrl)
- {
- case CTRL_SYNC :
- return RES_OK;
- case GET_SECTOR_COUNT :
- return RES_OK;
- case GET_SECTOR_SIZE :
- return RES_OK;
- case GET_BLOCK_SIZE :
- return RES_OK;
- case CTRL_POWER :
- break;
- case CTRL_LOCK :
- break;
- case CTRL_EJECT :
- break;
- case MMC_GET_TYPE :
- break;
- case MMC_GET_CSD :
- break;
- case MMC_GET_CID :
- break;
- case MMC_GET_OCR :
- break;
- case MMC_GET_SDSTAT :
- break;
- }
- }
- else{
- return RES_PARERR;
- }
- return RES_PARERR;
- }
MSD0_GetCardInfo()函式也在SPI_MSD0_Driver.c檔案中實現,其中SD0_CardInfo為PMSD_CARDINFO型別的全域性變數,它在SPI_MSD0_Driver.h檔案中被定義。
8、到此diskio.c這個檔案中的所有函式就已經實現,下一步就是實現SPI_MSD0_Driver.c檔案中的相關函
數,SPI_MSD0_Driver.c檔案可以在網上下載,參考的程式比較多,本工程使用的這個檔案也是在網上下載並進行一定的修改過的。本檔案中函式
的實現方式可以參考原始碼。
五、檔案系統測試
1、測試寫檔案
測試程式碼如下:
- //寫檔案測試
- printf("write file test......\n\r");
- res = f_open(&fdst, "0:/test.txt", FA_CREATE_ALWAYS | FA_WRITE);
- if(res != FR_OK){
- printf("open file error : %d\n\r",res);
- }else{
- res = f_write(&fdst, textFileBuffer, sizeof(textFileBuffer), &bw);
- if(res == FR_OK){
- printf("write data ok! %d\n\r",bw);
- }else{
- printf("write data error : %d\n\r",res);
- }
- f_close(&fdst);
- }
注意:成功開啟檔案後一定要呼叫f_close()函式,否則資料無法寫入SD卡中。
2、測試讀檔案
- //讀檔案測試
- printf("read file test......\n\r");
- res = f_open(&fsrc, "0:/test.txt", FA_OPEN_EXISTING | FA_READ);
- if(res != FR_OK){
- printf("open file error : %d\n\r",res);
- }else{
- res = f_read(&fsrc, buffer, sizeof(textFileBuffer), &br);
- if(res==FR_OK){
- printf("read data num : %d\n\r",br);
- printf("%s\n\r",buffer);
- }else{
- printf("read file error : %d\n\r",res);
- }
- f_close(&fsrc);
- }
測試結果如圖2所示。
圖2
六、中文長檔名支援
1、要支援長檔名需要在ffconf.h檔案中修改兩個巨集定義。如下為我們修改後的巨集定義。
#define _CODE_PAGE 936
#define _USE_LFN 1
2、新增支援中文編碼的檔案
重新編譯會發現有如圖3的錯誤。原因是要支援中文檔名需要包含另外一個檔案cc936.c,該檔案在FATFS檔案系統原始碼的.\src\option 目錄下,將它新增到工程檔案目錄FATFS中。如圖4是我們新增檔案後的工程檔案結構,再次編譯就通過了。如圖5所示。我們發現增加這個檔案後代碼量增加 了很多,主要原因是這個檔案是我們支援中文所需要的中文編碼檔案。
圖3
圖4
圖5
3、再次下載到板子中執行,發現中文的長檔名顯示正常了。如圖6所示。
圖6
4、若不需要支援中文長檔名而只支援英文長檔名則可以將巨集定義做如下修改:
#define _CODE_PAGE 437
#define _USE_LFN 1
同時將ccsbcs.c新增到工程目錄中,這樣就可以減小很多大程式碼量。將程式下載板子後再次執行結果如圖7所示,可以看到可以支援英文的長檔名。
原帖地址:http://www.cnblogs.com/GL-BBL/archive/2012/08/20/2647347.html
相關推薦
STM32的FATFS檔案系統移植筆記(轉…
一、序言 經常在網上、群裡看到很多人問關於STM32的FATFS檔案系統移植的問題,剛好自己最近也在除錯這個程式,為了讓大家少走彎路,我把我的除錯過程和方法也貢獻給大家。 二、FATFS簡介 FatFs Module是一種完全免費開源的FAT檔案系統模組,專門為小型的嵌入式系統而設計。
嵌入式系統移植筆記(八) --製作rootfs
Linux核心啟動後,需要掛載根檔案系統。本章介紹檔案系統的製作過程,並且讓開發板通過網路遠端掛載nfs系統來驗證製作的rootfs。。 檔案系統格式 上面不同的檔案系統格式,有適合不同的應用場合。nfs rootfs,實際nfs是將伺服器端的目錄通過網路的形式共享出
嵌入式系統移植筆記(七) --第三方驅動移植(黑盒子移植)
由於嵌入式系統分層,應用層要想操作硬體需通過核心層。驅動對上提供系統呼叫函式,對下封裝了對底層硬體的一些基本操作。筆者是不瞭解驅動程式的編輯,所以本章是在已經有驅動程式(fs4412_led_drv.c)和對應的應用程式(fs4412_led_app.c),來實現黑盒子移植(
虛擬檔案系統學習筆記(1)
1 通過虛擬檔案系統,linux可以支援多種檔案系統型別; 2 虛擬檔案系統所隱含的思想是把表示很多不同種類檔案系統的共同資訊放入核心;其中用1個欄位或函式來支援所有支援具體檔案系統所提供的任何操作。 3 VFS支援的檔案系統可以分為3類:磁碟檔案系統、網路檔案系統及特
STM32的FATFS檔案系統移植筆記
一、序言 經常在網上、群裡看到很多人問關於STM32的FATFS檔案系統移植的問題,剛好自己最近也在除錯這個程式,為了讓大家少走彎路,我把我的除錯過程和方法也貢獻給大家。 二、FATFS簡介 FatFs Module是一種完全免費開源的FAT檔案系統模組,專
04-opencv移植-終極解決方案之buildroot檔案系統圖片測試(原創)
接前一篇《opencv移植–終極解決方案之buildroot編譯和核心配置(原創)》。 平臺:Exynos4412。 實驗平臺:iTOP-4412-精英版。 編譯平臺:Ubuntu12.04。 編譯器版本:arm-4.4.1,懶人直接用開發板自帶的。 buildroot版本:直接官網
轉一篇比較詳細介紹FatFs檔案系統移植的文章 FatFs檔案系統的移植
因為需要,又不想自己寫,所以就移植了一個檔案系統。 說下我的硬體和開發工具:接成 TRUE IDE 模式下的CF卡(也就是相當於一塊硬碟了),三星S3C2440的ARM9,開發工具是很老很老的D版的ADS1.2。
轉一篇比較詳細介紹FatFs檔案系統移植的文章
摘自:http://blog.163.com/[email protected]/blog/static/3278568820090710053782/ 補充一點,FatFs的作者寫了兩個,一個是正宗的FatFs,比較適合大的RAM的裝置,另一個是FatFs/
Python Click 學習筆記(轉)
col 輸出 小工具 方法 chm 好的 put name 回調 原文鏈接:Python Click 學習筆記 Click 是 Flask 的團隊 pallets 開發的優秀開源項目,它為命令行工具的開發封裝了大量方法,使開發者只需要專註於功能實現。恰好我最近在開發的一個小
Angular js 過濾器 筆記(轉自菜鳥教程)
per test 筆記 ring ood filter 子集 true 貨幣格式 1、uppercase,lowercase 大小寫轉換 {{ "lower cap string" | uppercase }} // 結果:LOWER CAP STRING {{ "TA
ES6重點--筆記(轉)
ava 例如 ring func arrow tps 新建 方程 document 最常用的ES6特性 let, const, class, extends, super, arrow functions, template string, destructuring, d
Unity3D之Mecanim動畫系統學習筆記(二):模型導入
leg character ... sdk ocs 物體 mat 版本 sset 我們要在Unity3D中使用上模型和動畫,需要經過下面幾個階段的制作,下面以一個人形的模型開發為準來介紹。 模型制作 模型建模(Modelling) 我們的美術在建模時一般會制作一個稱為
Unity3D之Mecanim動畫系統學習筆記(六):使用腳本控制動畫
ont nim 復制代碼 info rip esc enter machine images 控制人物動畫播放 這裏我重新弄了一個簡單的場景和新的Animator Controller來作為示例。 下面先看看Animator Controller的配置: 人物在站
Unity3D之Mecanim動畫系統學習筆記(五):Animator Controller
浮點 key 發現 菜單 融合 stat mon 好的 project 簡介 Animator Controller在Unity中是作為一種單獨的配置文件存在的文件類型,其後綴為controller,Animator Controller包含了以下幾種功能: 可以對
Unity3D之Mecanim動畫系統學習筆記(四):Animation State
大致 面板 輸入 jpg any 動畫播放 速度 nsf 顯示 動畫的設置 我們先看看Animation Clip的一些設置: Loop time:動畫是否循環播放。 下面出現了3個大致一樣的選項: Root Transform Rotation:表示為播放動畫
Perfmon - Windows 自帶系統監測工具(轉)
跟蹤 存取 內存使用情況 ota 點擊 for 等等 order 服務 本文轉自:http://blog.csdn.net/oscar999/article/details/7918385 一、 簡述 可以用於監視CPU使用率、內存使用率、硬盤讀寫速度、網絡速度等。 Per
3.2《深入理解計算機系統》筆記(二)內存和高速緩存的原理【插圖】
img sram 本質 text ddr rate too 是我 很大的 《深入計算機系統》筆記(一)主要是講解程序的構成、執行和控制。接下來就是運行了。我跳過了“處理器體系結構”和“優化程序性能”,這兩章的筆記繼續往後延遲! 《深入計算機系統》的一個很大的用處
深入理解磁盤文件系統之inode(轉)
連續 blog 通過 lan 內容 打開 剩余空間 最大 .html 一、inode是什麽? 理解inode,要從文件儲存說起。 文件儲存在硬盤上,硬盤的最小存儲單位叫做"扇區"(Sector)。每個扇區儲存512字節(相當於0.5KB)。 操作系統讀取硬盤的時候,不會
操作系統學習筆記(五) 頁面置換算法
進入 es2017 問題 簡單 .cn 討論 相同 一位 四種 操作系統將內存按照頁的進行管理,在需要的時候才把進程相應的部分調入內存。當產生缺頁中斷時,需要選擇一個頁面寫入。如果要換出的頁面在內存中被修改過,變成了“臟”頁面,那就需要先寫會到磁盤。頁面置換算法,就是要選出
MySQL性能優化的筆記(轉)
ora 在一起 PC 當我 spa delet CP xpl 打開 今天,數據庫的操作越來越成為整個應用的性能瓶頸了,這點對於Web應用尤其明顯。關於數據庫的性能,這並不只是DBA才需要擔心的事,而這更是我們程序員需要去關註的事情。當我們去設計數據庫表結構,對操作數據庫時(