RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

FatFS文件系統(tǒng)在STM32F4上的移植和應用

CHANBAEK ? 來源:木南創(chuàng)智 ? 作者:尹家軍 ? 2022-12-13 17:26 ? 次閱讀

在實現如U盤文件讀寫,SD卡的文件讀寫等工作時,我們往往需要一個文件系統(tǒng)來支持我們的工作。特別在一些MCU應用中,文件系統(tǒng)的加入能明顯改善系統(tǒng)交互的友好性。在這一篇中,我們就來討論FatFS文件系統(tǒng)在STM32F4上的移植和應用。

1、準備工作

??在開始FatFS的移植之前我們需要做一些必要的準備工作。首先需要準備相應的硬件平臺,我們在這里使用的是STM32F407VET6的操作平臺。USB硬件相關的庫的移植工作也已完成。

??其次我們還需要準備FatFS的相關源碼,在這里我們使用最新的R0.14b版本,該文件可在網站下載。

??下載的源碼解壓后有兩個文件夾:document和source,其中document文件夾中是相關的文檔資料,與網站上的內容一樣,在移植時可以查看這些文檔來工作。Source文件夾中則是源碼相關的文件,主要包括:

??在上圖所示的一系列文件中,00readme.txt文件有對各個文件的介紹,我們查看其內容如下:

00readme.txt readme文件
00history.txt 版本記錄文件
ff.c FatFs模塊
ffconf.h FatFs模塊的配置文件
ff.h FatFs應用模塊的頭文件
diskio.h FatFs和磁盤IO模塊的頭文件
diskio.c 一個將磁盤IO函數附加到FatFS的實例
ffunicode.c Unicode編碼功能函數
ffsystem.c 可選的操作系統(tǒng)相關文件實例

??在這些文件中,ff.c和ff.h是核心文件。ffunicode.c是字符編碼,會根據配置文件的配置選擇編碼。ffsystem.c文件根據自己的需要決定。所以與具體的應用平臺相關的,并需要我們來實現的文件是配置文件ffconf.h和磁盤操作文件diskio.h與diskio.c,這幾個文件也是我們移植的重點。

2、實現移植

??我們已經完成了移植的準備工作,接下來就來實現面向大容量U盤的應用移植。前面我們已經說過,移植需要處理的文件是配置文件ffconf.h和磁盤操作文件diskio.h與diskio.c。

??關于配置文件ffconf.h其實它本身有一個實例,我們只需要根據需要修改配置就好。這里我們需要修改的配置參數包括:

??所支持的編碼方式配置參數FF_CODE_PAGE,這個關系到文件編碼的問題,我們將其配置為簡體中文支持。

??邏輯驅動器的數量配置參數FF_VOLUMES,FatFS可以同時應用于多個驅動器,所以我們需要根據實際情況配置驅動器的數量。

??時間戳配置參數FF_FS_NORTC,我們大多時候并不需要記錄時間戳,所以在這里我們將其關閉。

??余下就是實現磁盤IO操作的相關函數,在FatFS的幫助文檔中告訴了我們需要實現的函數有兩類:一類是磁盤設備控制相關的函數,主要是獲取設備狀態(tài)函數、初始化設備函數、讀取數據函數、寫入數據函數以及控制設備相關功能函數;二類是實時時鐘操作函數,主要是獲取當前時間函數。所以實現這6個函數就是移植的主要工作。

2.1、獲取設備狀態(tài)函數

??磁盤狀態(tài)檢測函數disk_status。用于檢測磁盤狀態(tài),在ff.c文件中會被調用。其函數原型如下:

??DSTATUS disk_status(BYTE drV);

??根據其原型定義以及我們USB大容量存儲設備的要求,我們可以實現磁盤狀態(tài)獲取函數如下:

/*用于USBH的狀態(tài)獲取函數*/
static DSTATUS USBH_status(BYTE lun)
{
 DRESULT res = RES_ERROR;
 
 if(USBH_MSC_UnitIsReady(&hUsbHostFS, lun))
 {
  res = RES_OK;
 }
 else
 {
  res = RES_ERROR;
 }
 
 return res;
}

2.2、初始化設備函數

??存儲媒介初始化函數disk_initialize。用于對磁盤設備進行初始化,在ff.c文件中會被調用。其函數原型如下:

??DSTATUS disk_initialize(BYTE drv);

??根據其原型定義以及我們USB大容量存儲設備的要求,我們可以實現磁盤驅動器初始化函數,但這里我們其實不需要,因為在USB HOST庫中已經完成了初始化,所以直接返回正確就可以了。

/*用于USBH的初始化函數*/
static DSTATUS USBH_initialize(BYTE lun)
{
  //USB HOST庫中已經完成了初始化
 return RES_OK;
}

2.3、讀取數據

??讀扇區(qū)函數disk_read。用于實現對磁盤數據的讀取,根據具體的磁盤IO編寫,在ff.c文件中會被調用。其函數原型如下:

??DRESULT disk_read(BYTE drv,BYTE*buff,DWORD sector,BYTE.count);

??根據其原型定義以及我們USB大容量存儲設備的要求,我們可以實現磁盤數據讀取函數如下:

/*用于USBH的讀扇區(qū)函數*/
static DRESULT USBH_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
 DRESULT res = RES_ERROR;
 MSC_LUNTypeDef info;
 
 if(USBH_MSC_Read(&hUsbHostFS, lun, sector, buff, count) == USBH_OK)
 {
  res = RES_OK;
 }
 else
 {
  USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info);
 
  switch (info.sense.asc)
  {
  case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
  case SCSI_ASC_MEDIUM_NOT_PRESENT:
  case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
   USBH_ErrLog ("USB Disk is not ready!");
   res = RES_NOTRDY;
   break;
 
  default:
   res = RES_ERROR;
   break;
  }
 }
 
 return res;
}

2.4、寫入數據

??寫扇區(qū)函數disk_write。用于實現對磁盤數據的寫入,根據具體的磁盤IO編寫,在ff.c文件中會被調用。其函數原型如下:

??DRESULT disk_write(BYTE drv,const BYTE*buff,DWORD sector,BYTE count);

??根據其原型定義以及我們USB大容量存儲設備的要求,我們可以實現磁盤數據寫入函數如下:

/*用于USBH的寫扇區(qū)函數*/
static DRESULT USBH_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
 DRESULT res = RES_ERROR;
 MSC_LUNTypeDef info;
 
 if(USBH_MSC_Write(&hUsbHostFS, lun, sector, (BYTE *)buff, count) == USBH_OK)
 {
  res = RES_OK;
 }
 else
 {
  USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info);
 
  switch (info.sense.asc)
  {
  case SCSI_ASC_WRITE_PROTECTED:
   USBH_ErrLog("USB Disk is Write protected!");
   res = RES_WRPRT;
   break;
 
  case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
  case SCSI_ASC_MEDIUM_NOT_PRESENT:
  case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
   USBH_ErrLog("USB Disk is not ready!");
   res = RES_NOTRDY;
   break;
 
  default:
   res = RES_ERROR;
   break;
  }
 }
 
 return res;
}

2.5、控制設備相關功能

??存儲媒介控制函數disk_ioctl。可以在此函數里編寫自己需要的功能代碼,比如獲得存儲媒介的大小、檢測存儲媒介的上電與否存儲媒介的扇區(qū)數等。如果是簡單的應用,也可以不用編寫。其函數原型如下:

??DRESULT disk_ioctl(BYTE drv,BYTE ctrl,VoiI*buff);

??根據其原型定義以及我們USB大容量存儲設備的要求,我們可以實現磁盤設備控制相關功能函數如下:

/*USBH IO控制函數 */
static DRESULT USBH_ioctl(BYTE lun, BYTE cmd, void *buff)
{
 DRESULT res = RES_ERROR;
 MSC_LUNTypeDef info;
 
 switch (cmd)
 {
 /* Make sure that no pending write process */
 case CTRL_SYNC:
  res = RES_OK;
  break;
 
 /* Get number of sectors on the disk (DWORD) */
 case GET_SECTOR_COUNT :
  if(USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info) == USBH_OK)
  {
   *(DWORD*)buff = info.capacity.block_nbr;
   res = RES_OK;
  }
  else
  {
   res = RES_ERROR;
  }
  break;
 
 /* Get R/W sector size (WORD) */
 case GET_SECTOR_SIZE :
  if(USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info) == USBH_OK)
  {
   *(DWORD*)buff = info.capacity.block_size;
   res = RES_OK;
  }
  else
  {
   res = RES_ERROR;
  }
  break;
 
  /* Get erase block size in unit of sector (DWORD) */
 case GET_BLOCK_SIZE :
 
  if(USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info) == USBH_OK)
  {
   *(DWORD*)buff = info.capacity.block_size / USB_DEFAULT_BLOCK_SIZE;
   res = RES_OK;
  }
  else
  {
   res = RES_ERROR;
  }
  break;
 
 default:
  res = RES_PARERR;
 }
 
 return res;
}

2.6、獲取當前時間

??實時時鐘函數get_fattime。用于獲取當前時間,返回一個32位無符號整數,時鐘信息包含在這32位中。如果不使用時間戳,可以直接返回一個數,如0。其函數原型如下:

??DWORD get_fattime(Void);

??根據其原型定義以及我們USB大容量存儲設備的要求,我們可以實現磁盤狀態(tài)獲取函數如下:

/*讀取時鐘函數*/
DWORD get_fattime(void)
{
 
 return 0;
 
}

??完成上述6個程序的編寫,移植工作也就基本完成了。大家可能會發(fā)現,我們實現的函數名似乎與原型函數不一樣,主要是考慮方便在多個存儲設備同時存在時進行操作,我們在目標函數中調用我們實現的函數就可以了。

3、應用測試

??我們完成了FatFS的移植,現在來驗證移植的是否正確。為此,我們來編寫一個應用,向U盤中寫入數據到文件以及讀取文件的數據等。

/* USB HOST MSC操作函數,這部分功能根據需求設定 */
static void MSC_Application(void)
{
  FRESULT res;                      /* FatFs函數返回值 */
  uint32_t byteswritten, bytesread;           /* 文件讀寫的數量 */
  uint8_t wtext[] = "This is STM32 working with FatFs!"; /* 寫文件緩沖器 */
  uint8_t wtext2[] = "這是一個FatFs讀寫的例子!"; /* 寫文件緩沖器 */
  uint8_t wtext3[] = "這是一個向文件追加數據的測試!"; /* 寫文件緩沖器 */
  uint8_t rtext[100];                  /* 讀文件緩沖器 */
  
  /* 注冊文件系統(tǒng)對象到FatFs模塊 */
  if(f_mount(&USBHFatFS, (TCHAR const*)USBHPath, 0) != FR_OK)
  {
    /* 錯誤處理 */
    Error_Handler();
  }
  else
  {
    /* 打開一個文件 */
    if(f_open(&USBHFile, "STM32.TXT", FA_OPEN_EXISTING | FA_WRITE) != FR_OK) 
    {
      /* 錯誤處理 */
      Error_Handler();
    }
    else
    {
      res=f_lseek(&USBHFile,f_size(&USBHFile));  //將指針指向文件末
      //res=f_lseek(&USBHFile,100);  //將指針指向文件末
      /* 寫數據到文件 */
      res = f_write(&USBHFile, wtext, sizeof(wtext), (void *)&byteswritten);
      res = f_write(&USBHFile, "\\r\\n", sizeof("\\r\\n")-1, &byteswritten); 
      res = f_write(&USBHFile, wtext2, sizeof(wtext2), (void *)&byteswritten);
      res = f_write(&USBHFile, "\\r\\n", sizeof("\\r\\n")-1, &byteswritten);
      res = f_write(&USBHFile, wtext3, sizeof(wtext3), (void *)&byteswritten);
      res = f_write(&USBHFile, "\\r\\n", sizeof("\\r\\n")-1, &byteswritten);
      
      if((byteswritten == 0) || (res != FR_OK))
      {
        /* 錯誤處理 */
        Error_Handler();
      }
      else
      {
        /* 關閉文件 */
        f_close(&USBHFile);
        
        /* 打開文件讀 */
        if(f_open(&USBHFile, "STM32.TXT", FA_READ) != FR_OK)
        {
          /* 錯誤處理 */
          Error_Handler();
        }
        else
        {
          /* 從文件讀數據 */
          res = f_read(&USBHFile, rtext, sizeof(rtext), (void *)&bytesread);
          
          if((bytesread == 0) || (res != FR_OK))
          {
            /* 錯誤處理 */
            Error_Handler();
          }
          else
          {
            /* 關閉文件 */
            f_close(&USBHFile);
            
            /* 比較讀和寫的數據 */
            if((bytesread != byteswritten))
            {         
              /* 錯誤處理*/
              Error_Handler();
            }
            else
            {
              /* 無錯誤 */
              
            }
          }
        }
      }
    }
  }
  
  FATFS_UnLinkDriver(USBHPath);
}

??我們先在U盤上創(chuàng)建的文件,名為“STM32.TXT”,在上述源碼中,我們創(chuàng)建完文件后將其修改為打開與存在文件。創(chuàng)建的文件如下圖所示:

??向創(chuàng)建的STM32.TXT文件中寫入“This is STM32 working with FatFs!”,我們查看文件內容,結果如下:

??接著我們嘗試向已經存在的文件中追加內容。依然是STM32.TXT文件,我們操作完畢,查看其內容圖下:

??至此,我們完成了FatFS文件系統(tǒng)的移植與測試,從測試結果看,移植是正確的,至少在簡單應用下沒有發(fā)現問題。

4、移植小結

??在這篇中,我們移植了FatFS文件系統(tǒng),并進行了簡單的讀寫測試。從測試的結果來看,FatFS的一直是沒有問題的,至少驗證了在一般的讀寫操作方面是沒有問題的。

??在我們移植時,我們考慮到在同時有多種驅動器的情況下能夠方便的操作。我們定義的磁盤IO操作函數是需要根據實際硬件實現的,然后在系統(tǒng)指定的回調函數中調用我們編寫的磁盤IO函數。這樣就可以實現多個驅動器的操作,事實上FatFS給出的磁盤IO示例中也是這樣建議的。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • 移植
    +關注

    關注

    1

    文章

    379

    瀏覽量

    28124
  • 文件系統(tǒng)

    關注

    0

    文章

    284

    瀏覽量

    19904
  • STM32F4
    +關注

    關注

    3

    文章

    194

    瀏覽量

    28046
  • FATFS
    +關注

    關注

    0

    文章

    44

    瀏覽量

    18298
收藏 人收藏

    評論

    相關推薦

    基于STM32完成FATFS文件系統(tǒng)移植與運用

    這篇文章主要演示FATFS文件系統(tǒng)如何移植到自己的工程,并完成文件的讀寫。 因為SD卡采用的是SPI模擬時序,所以,其他單片機一樣可以照著移植
    的頭像 發(fā)表于 03-08 09:17 ?6055次閱讀
    基于<b class='flag-5'>STM32</b>完成<b class='flag-5'>FATFS</b><b class='flag-5'>文件系統(tǒng)</b><b class='flag-5'>移植</b>與運用

    STM32CubeMx入門教程(10):Fatfs文件系統(tǒng)的應用

    導語"fatfs是一個小型的文件系統(tǒng),小型的嵌入式系統(tǒng)中使用非常的廣泛,STM32CubeMx自帶該
    發(fā)表于 07-12 11:39 ?5342次閱讀
    <b class='flag-5'>STM32</b>CubeMx入門教程(10):<b class='flag-5'>Fatfs</b><b class='flag-5'>文件系統(tǒng)</b>的應用

    STM32+SD NAND(貼片SD卡)完成FATFS文件系統(tǒng)移植與測試

    這篇文章就手把手教大家,STM32完成FATFS文件系統(tǒng)移植;主控芯片采用
    的頭像 發(fā)表于 07-17 17:24 ?7549次閱讀
    <b class='flag-5'>STM32</b>+SD NAND(貼片SD卡)完成<b class='flag-5'>FATFS</b><b class='flag-5'>文件系統(tǒng)</b><b class='flag-5'>移植</b>與測試

    轉:STM32CubeMX系列教程18:文件系統(tǒng)FATFS

    :http://elm-chan.org/fsw/ff/00index_e.html結合STM32cubeMX軟件移植FATFS文件系統(tǒng)非常簡單。本章程序在上一章SDMMC工程的基礎
    發(fā)表于 07-06 16:57

    STM32ZET6移植文件系統(tǒng)FatFs

    STM32ZET6移植文件系統(tǒng)FatFs,以文件的形式存儲數據到flash中。并給出了恢復w2
    發(fā)表于 08-03 07:03

    FATFS文件系統(tǒng)如何移植工程

    STM32F103ZET6系統(tǒng)板、一個SPI接口的SD卡卡槽模塊、一張SD卡工程完整源碼下載地址這篇文章主要演示FATFS文件系統(tǒng)如何移植
    發(fā)表于 08-24 06:34

    什么是串行FLASH文件系統(tǒng)FatFs?如何在STM32F1移植?

    什么是串行FLASH文件系統(tǒng)FatFs?如何在STM32F1移植?
    發(fā)表于 10-08 09:31

    FatFs文件系統(tǒng)的原理是什么?如何對FATFS進行移植?

    FatFs文件系統(tǒng)的原理是什么?FatFs文件系統(tǒng)移植方法是什么?如何實現eMMC卡中文件的讀
    發(fā)表于 11-25 07:52

    如何在spi_flash移植建立fatfs文件系統(tǒng)

    文章目錄基于stm32f103系列MCU,spi_flash移植建立fatfs文件系統(tǒng)
    發(fā)表于 02-14 06:38

    stm32+sdio+fatfs文件系統(tǒng)_源碼分析

    stm32+sdio+fatfs文件系統(tǒng)介紹,通俗易懂。
    發(fā)表于 11-06 09:52 ?25次下載

    MSP430、STM32、8051單片機fatfs 文件系統(tǒng)移植 W25Q128

    MSP430、STM32、8051單片機fatfs 文件系統(tǒng)移植 W25Q128
    發(fā)表于 11-15 16:21 ?36次下載
    MSP430、<b class='flag-5'>STM32</b>、8051單片機<b class='flag-5'>fatfs</b> <b class='flag-5'>文件系統(tǒng)</b><b class='flag-5'>移植</b> W25Q128

    Fatfs文件系統(tǒng)移植

    Fatfs文件系統(tǒng)移植)一、文件系統(tǒng)介紹二、移植條件、說明1、FatFs模塊
    發(fā)表于 11-15 18:51 ?22次下載
    <b class='flag-5'>Fatfs</b>(<b class='flag-5'>文件系統(tǒng)</b>的<b class='flag-5'>移植</b>)

    文件系統(tǒng)FatFs文件系統(tǒng)嵌入式芯片LPC18XX移植

    文件系統(tǒng)FatFs文件系統(tǒng)嵌入式芯片LPC18XX移植
    發(fā)表于 12-04 10:51 ?12次下載
    【<b class='flag-5'>文件系統(tǒng)</b>】<b class='flag-5'>FatFs</b><b class='flag-5'>文件系統(tǒng)</b><b class='flag-5'>在</b>嵌入式芯片LPC18XX<b class='flag-5'>上</b>的<b class='flag-5'>移植</b>

    手把手教你flash移植fatfs文件系統(tǒng)(含實時操作系統(tǒng))

    文章目錄基于stm32f103系列MCU,spi_flash移植建立fatfs文件系統(tǒng)
    發(fā)表于 12-09 12:51 ?30次下載
    手把手教你<b class='flag-5'>在</b>flash<b class='flag-5'>上</b><b class='flag-5'>移植</b><b class='flag-5'>fatfs</b><b class='flag-5'>文件系統(tǒng)</b>(含實時操作<b class='flag-5'>系統(tǒng)</b>)

    文件系統(tǒng)FatFs移植

    FATFS是一個完全免費開源的FAT文件系統(tǒng)模塊,專門為小型的嵌入式系統(tǒng)而設計。它完全用標準C語言編寫,所以具有良好的硬件平臺獨立性,甚至可以移植到8位的單片機上而只需做簡單的修改。
    的頭像 發(fā)表于 03-01 14:38 ?1939次閱讀
    <b class='flag-5'>文件系統(tǒng)</b><b class='flag-5'>FatFs</b>的<b class='flag-5'>移植</b>
    RM新时代网站-首页