<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

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

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

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

          二、FATFS簡介
          FatFs Module是一種完全免費開源的FAT文件系統(tǒng)模塊,專門為小型的嵌入式系統(tǒng)而設(shè)計。它完全用標(biāo)準(zhǔn)C語言編寫,所以具有良好的硬件平臺獨立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列單片機(jī)上而只需做簡單的修改。它支持FATl2、FATl6和FAT32,支持多個存儲媒介;有獨立的緩沖區(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ù):

          本文引用地址:http://www.ex-cimer.com/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)則不用實現(xiàn)該函數(shù)
          5. DRESULT disk_ioctl (BYTE, BYTE, void*);//獲取SD卡文件系統(tǒng)相關(guān)信息
          復(fù)制代碼



          圖1
          3、初步實現(xiàn)以上五個函數(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ù)錯誤 */
          11. }
          12. switch (drv)
          13. {
          14. case 0:
          15. if(count==1) /* 1個sector的讀操作 */
          16. {
          17. return RES_OK;
          18. }
          19. else /* 多個sector的讀操作 */
          20. {
          21. return RES_OK;
          22. }
          23. case 1:
          24. if(count==1) /* 1個sector的讀操作 */
          25. {
          26. return RES_OK;
          27. }
          28. else /* 多個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ù)錯誤 */
          11. }
          12. switch (drv)
          13. {
          14. case 0:
          15. if(count==1) /* 1個sector的寫操作 */
          16. {
          17. return RES_OK;
          18. }
          19. else /* 多個sector的寫操作 */
          20. {
          21. return RES_OK;
          22. }
          23. case 1:
          24. if(count==1) /* 1個sector的寫操作 */
          25. {
          26. return RES_OK;
          27. }
          28. else /* 多個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ù)都只是實現(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ā)送。
          程序如下:

          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ù)卡的類型對卡進(jìn)行初始化。具體初始化方式可以參考附件程序。
          注:在初始化SD卡之前應(yīng)該初始化SPI接口和相關(guān)的管腳。
          實現(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文件中實現(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)后的程序如下:

          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ù)錯誤 */
          12. }
          13. switch (drv)
          14. {
          15. case 0:
          16. if(count==1) /* 1個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 /* 多個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個sector的讀操作 */
          36. {
          37. return RES_OK;
          38. }
          39. else /* 多個sector的讀操作 */
          40. {
          41. return RES_OK;
          42. }
          43. default:
          44. return RES_ERROR;
          45. }
          46. }
          復(fù)制代碼

          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)后的程序如下:

          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ù)錯誤 */
          12. }
          13. switch (drv)
          14. {
          15. case 0:
          16. if(count==1) /* 1個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 /* 多個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個sector的寫操作 */
          36. {
          37. return RES_OK;
          38. }
          39. else /* 多個sector的寫操作 */
          40. {
          41. return RES_OK;
          42. }
          43. default:return RES_ERROR;
          44. }
          45. }
            上一頁 1 2 下一頁

          評論


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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();