新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > STM32的FATFS文件系統(tǒng)移植筆記

STM32的FATFS文件系統(tǒng)移植筆記

作者: 時(shí)間:2016-11-26 來源:網(wǎng)絡(luò) 收藏
一、序言

經(jīng)常在網(wǎng)上、群里看到很多人問關(guān)于STM32的FATFS文件系統(tǒng)移植的問題,剛好自己最近也在調(diào)試這個(gè)程序,為了讓大家少走彎路,我把我的調(diào)試過程和方法也貢獻(xiàn)給大家。

二、FATFS簡(jiǎn)介
FatFs Module是一種完全免費(fèi)開源的FAT文件系統(tǒng)模塊,專門為小型的嵌入式系統(tǒng)而設(shè)計(jì)。它完全用標(biāo)準(zhǔn)C語(yǔ)言編寫,所以具有良好的硬件平臺(tái)獨(dú)立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列單片機(jī)上而只需做簡(jiǎn)單的修改。它支持FATl2、FATl6和FAT32,支持多個(gè)存儲(chǔ)媒介;有獨(dú)立的緩沖區(qū),可以對(duì)多個(gè)文件進(jìn)行讀/寫,并特別對(duì)8位單片機(jī)和16位單片機(jī)做了優(yōu)化。

三、移植準(zhǔn)備
1、FATFS源代碼的獲取,可以到官網(wǎng)下載:http://elm-chan.org/fsw/ff/00index_e.html最新版本是R0.09版本,我們就移植這個(gè)版本的。
2、解壓文件會(huì)得到兩個(gè)文件夾,一個(gè)是doc文件夾,這里是FATFS的一些使用文檔和說明,以后在文件編程的時(shí)候可以查看該文檔。另一個(gè)是src文件夾,里面就是我們所要的源文件。
3、建立一個(gè)STM32的工程,為方便調(diào)試,我們應(yīng)重載printf()底層函數(shù)實(shí)現(xiàn)串口打印輸出。可以參考已經(jīng)建立好的printf()打印輸出工程:http://www.viewtool.com/bbs/foru ... d=77&extra=page%3D1
四、開始移植
1、在已經(jīng)建立好的工程目錄User文件夾下新建兩個(gè)文件夾,F(xiàn)ATFS_V0.09和SPI_SD_Card,F(xiàn)ATFS_V0.09用于存放FATFS源文件,SPI_SD_Card用于存放SPI的驅(qū)動(dòng)文件。
2、如圖1將ff.c添加到工程文件夾中,并新建diskio.c文件,在diskio.c文件中實(shí)現(xiàn)五個(gè)函數(shù):

本文引用地址:http://butianyuan.cn/article/201611/321826.htm
  1. DSTATUS disk_initialize (BYTE);//SD卡的初始化
  2. DSTATUS disk_status (BYTE);//獲取SD卡的狀態(tài),這里可以不用管
  3. DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);//從SD卡讀取數(shù)據(jù)
  4. DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);//將數(shù)據(jù)寫入SD卡,若該文件系統(tǒng)為只讀文件系統(tǒng)則不用實(shí)現(xiàn)該函數(shù)
  5. DRESULT disk_ioctl (BYTE, BYTE, void*);//獲取SD卡文件系統(tǒng)相關(guān)信息
復(fù)制代碼



圖1
3、初步實(shí)現(xiàn)以上五個(gè)函數(shù)
FATFS初始化函數(shù):

  1. DSTATUS disk_initialize (
  2. BYTE drv /* Physical drive nmuber (0..) */
  3. )
  4. {
  5. switch (drv)
  6. {
  7. case 0 :
  8. return RES_OK;
  9. case 1 :
  10. return RES_OK;
  11. case 2 :
  12. return RES_OK;
  13. case 3 :
  14. return RES_OK;
  15. default:
  16. return STA_NOINIT;
  17. }
  18. }
復(fù)制代碼

FATFS狀態(tài)獲取函數(shù):

  1. DSTATUS disk_status (
  2. BYTE drv /* Physical drive nmuber (0..) */
  3. )
  4. {
  5. switch (drv)
  6. {
  7. case 0 :
  8. return RES_OK;
  9. case 1 :
  10. return RES_OK;
  11. case 2 :
  12. return RES_OK;
  13. default:
  14. return STA_NOINIT;
  15. }
  16. }
復(fù)制代碼

FATFS底層讀數(shù)據(jù)函數(shù):

  1. DRESULT disk_read (
  2. BYTE drv, /* Physical drive nmuber (0..) */
  3. BYTE *buff, /* Data buffer to store read data */
  4. DWORD sector, /* Sector address (LBA) */
  5. BYTE count /* Number of sectors to read (1..255) */
  6. )
  7. {
  8. if( !count )
  9. {
  10. return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯(cuò)誤 */
  11. }
  12. switch (drv)
  13. {
  14. case 0:
  15. if(count==1) /* 1個(gè)sector的讀操作 */
  16. {
  17. return RES_OK;
  18. }
  19. else /* 多個(gè)sector的讀操作 */
  20. {
  21. return RES_OK;
  22. }
  23. case 1:
  24. if(count==1) /* 1個(gè)sector的讀操作 */
  25. {
  26. return RES_OK;
  27. }
  28. else /* 多個(gè)sector的讀操作 */
  29. {
  30. return RES_OK;
  31. }
  32. default:
  33. return RES_ERROR;
  34. }
  35. }
復(fù)制代碼

FATFS底層寫數(shù)據(jù)函數(shù):

  1. DRESULT disk_write (
  2. BYTE drv, /* Physical drive nmuber (0..) */
  3. const BYTE *buff, /* Data to be written */
  4. DWORD sector, /* Sector address (LBA) */
  5. BYTE count /* Number of sectors to write (1..255) */
  6. )
  7. {
  8. if( !count )
  9. {
  10. return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯(cuò)誤 */
  11. }
  12. switch (drv)
  13. {
  14. case 0:
  15. if(count==1) /* 1個(gè)sector的寫操作 */
  16. {
  17. return RES_OK;
  18. }
  19. else /* 多個(gè)sector的寫操作 */
  20. {
  21. return RES_OK;
  22. }
  23. case 1:
  24. if(count==1) /* 1個(gè)sector的寫操作 */
  25. {
  26. return RES_OK;
  27. }
  28. else /* 多個(gè)sector的寫操作 */
  29. {
  30. return RES_OK;
  31. }
  32. default:return RES_ERROR;
  33. }
  34. }
復(fù)制代碼

FATFS磁盤控制函數(shù):

  1. DRESULT disk_ioctl (
  2. BYTE drv, /* Physical drive nmuber (0..) */
  3. BYTE ctrl, /* Control code */
  4. void *buff /* Buffer to send/receive control data */
  5. )
  6. {
  7. if (drv==0)
  8. {
  9. switch (ctrl)
  10. {
  11. case CTRL_SYNC :
  12. return RES_OK;
  13. case GET_SECTOR_COUNT :
  14. return RES_OK;
  15. case GET_BLOCK_SIZE :
  16. return RES_OK;
  17. case CTRL_POWER :
  18. break;
  19. case CTRL_LOCK :
  20. break;
  21. case CTRL_EJECT :
  22. break;
  23. /* MMC/SDC command */
  24. case MMC_GET_TYPE :
  25. break;
  26. case MMC_GET_CSD :
  27. break;
  28. case MMC_GET_CID :
  29. break;
  30. case MMC_GET_OCR :
  31. break;
  32. case MMC_GET_SDSTAT :
  33. break;
  34. }
  35. }else if(drv==1){
  36. switch (ctrl)
  37. {
  38. case CTRL_SYNC :
  39. return RES_OK;
  40. case GET_SECTOR_COUNT :
  41. return RES_OK;
  42. case GET_SECTOR_SIZE :
  43. return RES_OK;
  44. case GET_BLOCK_SIZE :
  45. return RES_OK;
  46. case CTRL_POWER :
  47. break;
  48. case CTRL_LOCK :
  49. break;
  50. case CTRL_EJECT :
  51. break;
  52. /* MMC/SDC command */
  53. case MMC_GET_TYPE :
  54. break;
  55. case MMC_GET_CSD :
  56. break;
  57. case MMC_GET_CID :
  58. break;
  59. case MMC_GET_OCR :
  60. break;
  61. case MMC_GET_SDSTAT :
  62. break;
  63. }
  64. }
  65. else{
  66. return RES_PARERR;
  67. }
  68. return RES_PARERR;
  69. }
復(fù)制代碼

以上函數(shù)都只是實(shí)現(xiàn)一個(gè)框架,并沒有做實(shí)際的事情,下一步就需要把操作SD卡的程序填充在這個(gè)框架里面。
4、實(shí)現(xiàn)disk_initialize()函數(shù)
該函數(shù)在掛載文件系統(tǒng)的時(shí)候會(huì)被調(diào)用,主要是實(shí)現(xiàn)讀寫SD卡前對(duì)SD卡進(jìn)行初始化,根據(jù)SD卡的傳輸協(xié)議,我們按照如下步驟初始化SD卡:
a、判斷SD卡是否插入,可以通過檢查SD卡卡座的CD腳電平進(jìn)行判斷,一般插入卡后該引腳會(huì)變成低電平。
b、稍微延時(shí)一段時(shí)間后發(fā)送至少74個(gè)時(shí)鐘給SD卡。
c、發(fā)送CMD0命令給SD卡,直到SD卡返回0x01為止,這里可以循環(huán)多次發(fā)送。
程序如下:

  1. /* Start send CMD0 till return 0x01 means in IDLE state */
  2. for(retry=0; retry<0xFFF; retry++)
  3. {
  4. r1 = MSD0_send_command(CMD0, 0, 0x95);
  5. if(r1 == 0x01)
  6. {
  7. retry = 0;
  8. break;
  9. }
  10. }
復(fù)制代碼

d、發(fā)送CMD8獲取卡的類型,不同類型的卡其初始化方式有所不同。
e、根據(jù)卡的類型對(duì)卡進(jìn)行初始化。具體初始化方式可以參考附件程序。
注:在初始化SD卡之前應(yīng)該初始化SPI接口和相關(guān)的管腳。
實(shí)現(xiàn)后的程序如下:

  1. DSTATUS disk_initialize (
  2. BYTE drv /* Physical drive nmuber (0..) */
  3. )
  4. {
  5. int Status;
  6. switch (drv)
  7. {
  8. case 0 :
  9. Status = MSD0_Init();
  10. if(Status==0){
  11. return RES_OK;
  12. }else{
  13. return STA_NOINIT;
  14. }
  15. case 1 :
  16. return RES_OK;
  17. case 2 :
  18. return RES_OK;
  19. case 3 :
  20. return RES_OK;
  21. default:
  22. return STA_NOINIT;
  23. }
  24. }
復(fù)制代碼

MSD0_Init()函數(shù)在SPI_MSD0_Driver.c文件中實(shí)現(xiàn)。
5、實(shí)現(xiàn)disk_read()函數(shù)
該函數(shù)是讀取SD卡扇區(qū)數(shù)據(jù)的函數(shù),根據(jù)SD卡數(shù)據(jù)傳輸協(xié)議可知有讀取單扇區(qū)和讀取多扇區(qū)兩種操作模式,為提高讀文件的速度應(yīng)該實(shí)現(xiàn)讀取多扇區(qū)函數(shù)。
實(shí)現(xiàn)后的程序如下:

  1. DRESULT disk_read (
  2. BYTE drv, /* Physical drive nmuber (0..) */
  3. BYTE *buff, /* Data buffer to store read data */
  4. DWORD sector, /* Sector address (LBA) */
  5. BYTE count /* Number of sectors to read (1..255) */
  6. )
  7. {
  8. int Status;
  9. if( !count )
  10. {
  11. return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯(cuò)誤 */
  12. }
  13. switch (drv)
  14. {
  15. case 0:
  16. if(count==1) /* 1個(gè)sector的讀操作 */
  17. {
  18. Status =MSD0_ReadSingleBlock( sector ,buff );
  19. if(Status == 0){
  20. return RES_OK;
  21. }else{
  22. return RES_ERROR;
  23. }
  24. }
  25. else /* 多個(gè)sector的讀操作 */
  26. {
  27. Status = MSD0_ReadMultiBlock( sector , buff ,count);
  28. if(Status == 0){
  29. return RES_OK;
  30. }else{
  31. return RES_ERROR;
  32. }
  33. }
  34. case 1:
  35. if(count==1) /* 1個(gè)sector的讀操作 */
  36. {
  37. return RES_OK;
  38. }
  39. else /* 多個(gè)sector的讀操作 */
  40. {
  41. return RES_OK;
  42. }
  43. default:
  44. return RES_ERROR;
  45. }
  46. }
復(fù)制代碼

MSD0_ReadSingleBlock()和MSD0_ReadMultiBlock()函數(shù)都是SD卡操作的底層函數(shù),我們?cè)赟PI_MSD0_Driver.c文件中實(shí)現(xiàn)。
6、實(shí)現(xiàn)disk_write()函數(shù)
該函數(shù)主要實(shí)現(xiàn)對(duì)SD卡進(jìn)行寫數(shù)據(jù)操作,和讀數(shù)據(jù)操作一樣也分單塊寫和多塊寫,建議實(shí)現(xiàn)多塊寫的方式,這樣可以提高寫數(shù)據(jù)速度。
實(shí)現(xiàn)后的程序如下:

  1. DRESULT disk_write (
  2. BYTE drv, /* Physical drive nmuber (0..) */
  3. const BYTE *buff, /* Data to be written */
  4. DWORD sector, /* Sector address (LBA) */
  5. BYTE count /* Number of sectors to write (1..255) */
  6. )
  7. {
  8. int Status;
  9. if( !count )
  10. {
  11. return RES_PARERR;/* count不能等于0,否則返回參數(shù)錯(cuò)誤 */
  12. }
  13. switch (drv)
  14. {
  15. case 0:
  16. if(count==1) /* 1個(gè)sector的寫操作 */
  17. {
  18. Status = MSD0_WriteSingleBlock( sector , (uint8_t *)(&buff[0]) );
  19. if(Status == 0){
  20. return RES_OK;
  21. }else{
  22. return RES_ERROR;
  23. }
  24. }
  25. else /* 多個(gè)sector的寫操作 */
  26. {
  27. Status = MSD0_WriteMultiBlock( sector , (uint8_t *)(&buff[0]) , count );
  28. if(Status == 0){
  29. return RES_OK;
  30. }else{
  31. return RES_ERROR;
  32. }
  33. }
  34. case 1:
  35. if(count==1) /* 1個(gè)sector的寫操作 */
  36. {
  37. return RES_OK;
  38. }
  39. else /* 多個(gè)sector的寫操作 */
  40. {
  41. return RES_OK;
  42. }
  43. default:return RES_ERROR;
  44. }
  45. }
    上一頁(yè) 1 2 下一頁(yè)

評(píng)論


技術(shù)專區(qū)

關(guān)閉