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