STM32的FATFS文件系統(tǒng)移植筆記
經(jīng)常在網(wǎng)上、群里看到很多人問關(guān)于STM32的FATFS文件系統(tǒng)移植的問題,剛好自己最近也在調(diào)試這個程序,為了讓大家少走彎路,我把我的調(diào)試過程和方法也貢獻(xiàn)給大家。
二、FATFS簡介
FatFs Module是一種完全免費(fèi)開源的FAT文件系統(tǒng)模塊,專門為小型的嵌入式系統(tǒng)而設(shè)計。它完全用標(biāo)準(zhǔn)C語言編寫,所以具有良好的硬件平臺獨(dú)立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列單片機(jī)上而只需做簡單的修改。它支持FATl2、FATl6和FAT32,支持多個存儲媒介;有獨(dú)立的緩沖區(qū),可以對多個文件進(jìn)行讀/寫,并特別對8位單片機(jī)和16位單片機(jī)做了優(yōu)化。
三、移植準(zhǔn)備
1、FATFS源代碼的獲取,可以到官網(wǎng)下載:http://elm-chan.org/fsw/ff/00index_e.html最新版本是R0.09版本,我們就移植這個版本的。
2、解壓文件會得到兩個文件夾,一個是doc文件夾,這里是FATFS的一些使用文檔和說明,以后在文件編程的時候可以查看該文檔。另一個是src文件夾,里面就是我們所要的源文件。
3、建立一個STM32的工程,為方便調(diào)試,我們應(yīng)重載printf()底層函數(shù)實現(xiàn)串口打印輸出??梢詤⒖家呀?jīng)建立好的printf()打印輸出工程:http://www.viewtool.com/bbs/foru ... d=77&extra=page%3D1
四、開始移植
1、在已經(jīng)建立好的工程目錄User文件夾下新建兩個文件夾,F(xiàn)ATFS_V0.09和SPI_SD_Card,F(xiàn)ATFS_V0.09用于存放FATFS源文件,SPI_SD_Card用于存放SPI的驅(qū)動文件。
2、如圖1將ff.c添加到工程文件夾中,并新建diskio.c文件,在diskio.c文件中實現(xiàn)五個函數(shù):
- DSTATUS disk_initialize (BYTE);//SD卡的初始化
- DSTATUS disk_status (BYTE);//獲取SD卡的狀態(tài),這里可以不用管
- DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);//從SD卡讀取數(shù)據(jù)
- DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);//將數(shù)據(jù)寫入SD卡,若該文件系統(tǒng)為只讀文件系統(tǒng)則不用實現(xiàn)該函數(shù)
- DRESULT disk_ioctl (BYTE, BYTE, void*);//獲取SD卡文件系統(tǒng)相關(guān)信息
圖1
3、初步實現(xiàn)以上五個函數(shù)
FATFS初始化函數(shù):
- DSTATUS disk_initialize (
- BYTE drv /* Physical drive nmuber (0..) */
- )
- {
- 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狀態(tài)獲取函數(shù):
- DSTATUS disk_status (
- BYTE drv /* Physical drive nmuber (0..) */
- )
- {
- switch (drv)
- {
- case 0 :
- return RES_OK;
- case 1 :
- return RES_OK;
- case 2 :
- return RES_OK;
- default:
- return STA_NOINIT;
- }
- }
FATFS底層讀數(shù)據(jù)函數(shù):
- DRESULT disk_read (
- BYTE drv, /* Physical drive nmuber (0..) */
- BYTE *buff, /* Data buffer to store read data */
- DWORD sector, /* Sector address (LBA) */
- BYTE count /* Number of sectors to read (1..255) */
- )
- {
- if( !count )
- {
- return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯誤 */
- }
- switch (drv)
- {
- case 0:
- if(count==1) /* 1個sector的讀操作 */
- {
- return RES_OK;
- }
- else /* 多個sector的讀操作 */
- {
- return RES_OK;
- }
- case 1:
- if(count==1) /* 1個sector的讀操作 */
- {
- return RES_OK;
- }
- else /* 多個sector的讀操作 */
- {
- return RES_OK;
- }
- default:
- return RES_ERROR;
- }
- }
FATFS底層寫數(shù)據(jù)函數(shù):
- DRESULT disk_write (
- BYTE drv, /* Physical drive nmuber (0..) */
- const BYTE *buff, /* Data to be written */
- DWORD sector, /* Sector address (LBA) */
- BYTE count /* Number of sectors to write (1..255) */
- )
- {
- if( !count )
- {
- return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯誤 */
- }
- switch (drv)
- {
- case 0:
- if(count==1) /* 1個sector的寫操作 */
- {
- return RES_OK;
- }
- else /* 多個sector的寫操作 */
- {
- return RES_OK;
- }
- case 1:
- if(count==1) /* 1個sector的寫操作 */
- {
- return RES_OK;
- }
- else /* 多個sector的寫操作 */
- {
- return RES_OK;
- }
- default:return RES_ERROR;
- }
- }
FATFS磁盤控制函數(shù):
- DRESULT disk_ioctl (
- BYTE drv, /* Physical drive nmuber (0..) */
- BYTE ctrl, /* Control code */
- void *buff /* Buffer to send/receive control data */
- )
- {
- 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;
- /* MMC/SDC command */
- 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;
- /* MMC/SDC command */
- 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;
- }
以上函數(shù)都只是實現(xiàn)一個框架,并沒有做實際的事情,下一步就需要把操作SD卡的程序填充在這個框架里面。
4、實現(xiàn)disk_initialize()函數(shù)
該函數(shù)在掛載文件系統(tǒng)的時候會被調(diào)用,主要是實現(xiàn)讀寫SD卡前對SD卡進(jìn)行初始化,根據(jù)SD卡的傳輸協(xié)議,我們按照如下步驟初始化SD卡:
a、判斷SD卡是否插入,可以通過檢查SD卡卡座的CD腳電平進(jìn)行判斷,一般插入卡后該引腳會變成低電平。
b、稍微延時一段時間后發(fā)送至少74個時鐘給SD卡。
c、發(fā)送CMD0命令給SD卡,直到SD卡返回0x01為止,這里可以循環(huán)多次發(fā)送。
程序如下:
- /* Start send CMD0 till return 0x01 means in IDLE state */
- for(retry=0; retry<0xFFF; retry++)
- {
- r1 = MSD0_send_command(CMD0, 0, 0x95);
- if(r1 == 0x01)
- {
- retry = 0;
- break;
- }
- }
d、發(fā)送CMD8獲取卡的類型,不同類型的卡其初始化方式有所不同。
e、根據(jù)卡的類型對卡進(jìn)行初始化。具體初始化方式可以參考附件程序。
注:在初始化SD卡之前應(yīng)該初始化SPI接口和相關(guān)的管腳。
實現(xiàn)后的程序如下:
- DSTATUS disk_initialize (
- BYTE drv /* Physical drive nmuber (0..) */
- )
- {
- 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()函數(shù)在SPI_MSD0_Driver.c文件中實現(xiàn)。
5、實現(xiàn)disk_read()函數(shù)
該函數(shù)是讀取SD卡扇區(qū)數(shù)據(jù)的函數(shù),根據(jù)SD卡數(shù)據(jù)傳輸協(xié)議可知有讀取單扇區(qū)和讀取多扇區(qū)兩種操作模式,為提高讀文件的速度應(yīng)該實現(xiàn)讀取多扇區(qū)函數(shù)。
實現(xiàn)后的程序如下:
- DRESULT disk_read (
- BYTE drv, /* Physical drive nmuber (0..) */
- BYTE *buff, /* Data buffer to store read data */
- DWORD sector, /* Sector address (LBA) */
- BYTE count /* Number of sectors to read (1..255) */
- )
- {
- int Status;
- if( !count )
- {
- return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯誤 */
- }
- switch (drv)
- {
- case 0:
- if(count==1) /* 1個sector的讀操作 */
- {
- Status =MSD0_ReadSingleBlock( sector ,buff );
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- else /* 多個sector的讀操作 */
- {
- Status = MSD0_ReadMultiBlock( sector , buff ,count);
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- case 1:
- if(count==1) /* 1個sector的讀操作 */
- {
- return RES_OK;
- }
- else /* 多個sector的讀操作 */
- {
- return RES_OK;
- }
- default:
- return RES_ERROR;
- }
- }
MSD0_ReadSingleBlock()和MSD0_ReadMultiBlock()函數(shù)都是SD卡操作的底層函數(shù),我們在SPI_MSD0_Driver.c文件中實現(xiàn)。
6、實現(xiàn)disk_write()函數(shù)
該函數(shù)主要實現(xiàn)對SD卡進(jìn)行寫數(shù)據(jù)操作,和讀數(shù)據(jù)操作一樣也分單塊寫和多塊寫,建議實現(xiàn)多塊寫的方式,這樣可以提高寫數(shù)據(jù)速度。
實現(xiàn)后的程序如下:
- DRESULT disk_write (
- BYTE drv, /* Physical drive nmuber (0..) */
- const BYTE *buff, /* Data to be written */
- DWORD sector, /* Sector address (LBA) */
- BYTE count /* Number of sectors to write (1..255) */
- )
- {
- int Status;
- if( !count )
- {
- return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯誤 */
- }
- switch (drv)
- {
- case 0:
- if(count==1) /* 1個sector的寫操作 */
- {
- Status = MSD0_WriteSingleBlock( sector , (uint8_t *)(&buff[0]) );
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- else /* 多個sector的寫操作 */
- {
- Status = MSD0_WriteMultiBlock( sector , (uint8_t *)(&buff[0]) , count );
- if(Status == 0){
- return RES_OK;
- }else{
- return RES_ERROR;
- }
- }
- case 1:
- if(count==1) /* 1個sector的寫操作 */
- {
- return RES_OK;
- }
- else /* 多個sector的寫操作 */
- {
- return RES_OK;
- }
- default:return RES_ERROR;
- }
- }
相關(guān)推薦
技術(shù)專區(qū)
- FPGA
- DSP
- MCU
- 示波器
- 步進(jìn)電機(jī)
- Zigbee
- LabVIEW
- Arduino
- RFID
- NFC
- STM32
- Protel
- GPS
- MSP430
- Multisim
- 濾波器
- CAN總線
- 開關(guān)電源
- 單片機(jī)
- PCB
- USB
- ARM
- CPLD
- 連接器
- MEMS
- CMOS
- MIPS
- EMC
- EDA
- ROM
- 陀螺儀
- VHDL
- 比較器
- Verilog
- 穩(wěn)壓電源
- RAM
- AVR
- 傳感器
- 可控硅
- IGBT
- 嵌入式開發(fā)
- 逆變器
- Quartus
- RS-232
- Cyclone
- 電位器
- 電機(jī)控制
- 藍(lán)牙
- PLC
- PWM
- 汽車電子
- 轉(zhuǎn)換器
- 電源管理
- 信號放大器
評論