FatFs文件系統


1、文件系統

  文件系統負責管理和存儲文件信息的軟件機構,在磁盤上組織文件的方法。

  對於 SPI Flash 芯片或者 SD 卡之類的大容量設備,我們需要一種高效的方式來管理它的存儲內容。這些管理方式即為文件系統,它是為了存儲和管理數據,而在存儲介質建立的一種組織結構,這些結構包括操作系統引導區、目錄和文件。 常見的 windows 下的文件系統格式包括 FAT32、 NTFS、 exFAT。 在使用文件系統前,要先對存儲介質進行格式化。格式化先擦除原來內容,在存儲介質上新建一個文件分配表和目錄。這樣,文件系統就可以記錄數據存放的物理地址,剩余空間。

  使用文件系統時, 數據都以文件的形式存儲。寫入新文件時,先在目錄中創建一個文件索引,它指示了文件存放的物理地址,再把數據存儲到該地址中。當需要讀取數據時,可以從目錄中找到該文件的索引,進而在相應的地址中讀取出數據。具體還涉及到邏輯地址、簇大小、不連續存儲等一系列輔助結構或處理過程。

  文件系統的存在使我們在存取數據時,不再是簡單地向某物理地址直接讀寫,而是要遵循它的讀寫格式。如經過邏輯轉換,一個完整的文件可能被分開成多段存儲到不連續的物理地址,使用目錄或鏈表的方式來獲知下一段的位置。SPI Flash 芯片驅動只完成了向物理地址寫入數據的工作,而根據文件系統格式的邏輯轉換部分則需要額外的代碼來完成。實質上,這個邏輯轉換部分可以理解為當我們需要寫入一段數據時,由它來求解向什么物理地址寫入數據、以什么格式寫入及寫入一些原始數據以外的信息(如目錄)。這個邏輯轉換部分代碼我們也習慣稱之為文件系統。

2、FatFs 文件系統簡介

  上面提到的邏輯轉換部分代碼(文件系統)即為FatFs 文件系統要點,文件系統龐大而復雜,它需要根據應用的文件系統格式而編寫,而且一般與驅動層分離開來,很方便移植,所以工程應用中一般是移植現成的文件系統源碼。

  常用的文件系統:FAT/FATFS(小型嵌入式系統)、  NTFS (WINDOWS)、CDFS(光盤)、exFAT(內存)。

  FatFs 是面向小型嵌入式系統的一種通用的 FAT 文件系統。它完全是由 AISI C 語言編寫並且完全獨立於底層的 I/O 介質。因此它可以很容易地不加修改地移植到其他的處理器當中,如 8051、 PIC、 AVR、 SH、 Z80、 H8、 ARM 等。 FatFs 支持 FAT12、 FAT16、FAT32 等格式利用文件系統的各種函數, 所以可以利用FatFs對 SPI Flash 芯片以“文件”格式進行讀寫操作。

  FATFS優點:免費開源,專門為小型嵌入式系統設計,c編寫,支持FAT12, FAT16 與 FAT32,支持多種存儲媒介,有獨立的緩沖區,可對多個文件進行讀寫,可裁剪的文件系統(極為重要)。

  FATFS的特點:

  • Windows兼容的FAT文件系統(支持FAT12/FAT16/FAT32)與平台無關,移植簡單
  • 代碼量少、效率高
  • 多種配置選項
  • 支持多卷(物理驅動器或分區, 最多10個卷)
  • 多個ANSI/OEM代碼頁包括DBCS
  • 支持長文件名、 ANSI/OEM 或Unicode
  • 支持RTOS
  • 支持多種扇區 大小
  • 只讀、最小化的API和I/O緩沖區等

  FatFs 文件系統的源碼可以從 fatfs 官網下載:http://elm-chan.org/fsw/ff/00index_e.html

3、FatFs 的目錄結構

  在移植 FatFs 文件系統到開發板之前,我們先要到 FatFs 的官網獲取源碼, 最新版本為R0.11a,官網有對 FatFs 做詳細的介紹,有興趣可以了解。

  解壓之后可看到里面有 doc 和src 這兩個文件夾。 doc 文件夾里面是一些使用幫助文檔; src 才是 FatFs 文件系統的源碼。

 

  3.1、doc文件夾  

打開 doc 文件夾,可看到如下圖的文件目錄:

 

   其中 en 和 ja 這兩個文件夾里面是編譯好的 html 文檔,講的是 FATFS 里面各個函數的使用方法,這些函數都是封裝得非常好的函數,利用這些函數我們就可以操作 SPI Flash 芯片。這兩個文件夾的唯一區別就是 en 文件夾下的文檔是英文的, ja 文件夾下的是日文的。 img 文件夾包含 en 和 ja 文件夾下文件需要用到的圖片,還有四個名為 app.c 文件,內容都是 FatFs 具體應用例程。 00index_e.html 和00index_j.html 是一些關於 FATFS 的簡介,至於另外兩個文件可以不看。

  3.2、src文件夾

  打開 src 文件夾,可看到如下圖文件目錄:

  option 文件夾下是一些可選的外部 c 文件,包含了多語言支持需要用到的文件和轉換函數。

  00history.txt 介紹了 FatFs 的版本更新情況。
  00readme.txt 說明了當前目錄下 diskio.c 、 diskio.h、 ff.c、 ff.h、 integer.h 的功能。

  diskio.c 文件是 FatFs 移植最關鍵的文件,它為文件系統提供了最底層的訪問 SPI Flash芯片的方法, FatFs 有且僅有它需要用到與 SPI Flash 芯片相關的函數。
  diskio.h 定義了FatFs 用到的宏,以及 diskio.c 文件內與底層硬件接口相關的函數聲明。

  源碼文件功能簡介如下:

  integer.h:文件中包含了一些數值類型定義。
  diskio.c:包含底層存儲介質的操作函數,這些函數需要用戶自己實現,主要添加底層驅動函數。
  ff.c:FatFs 核心文件,文件管理的實現方法。該文件獨立於底層介質操作文件的函數,利用這些函數實現文件的讀寫。
  cc936.c:本文件在 option 目錄下,是簡體中文支持所需要添加的文件,包含了簡體中文的 GBK 和 Unicode 相互轉換功能函數。
  ffconf.h:這個頭文件包含了對 FatFs 功能配置的宏定義,通過修改這些宏定義就可以裁剪 FatFs 的功能。如需要支持簡體中文,需要把 ffconf.h 中的_CODE_PAGE的宏改成 936 並把上面的 cc936.c 文件加入到工程之中。

  建議閱讀這些源碼的順序為: integer.h --> diskio.c --> ff.c 。

  閱讀文件系統源碼 ff.c 文件需要一定的功底,建議讀者先閱讀 FAT32 的文件格式,再去分析 ff.c 文件。若僅為使用文件系統,則只需要理解 integer.h 及 diskio.c 文件並會調用ff.c 文件中的函數就可以了。

4、FatFs 程序結構圖

 

  用戶應用程序需要由用戶編寫,想實現什么功能就編寫什么的程序,一般我們只用到f_mount()、 f_open()、 f_write()、 f_read()就可以實現文件的讀寫操作。

  FatFs 組件是 FatFs 的主體,文件都在源碼 src 文件夾中,其中 ff.c、 ff.h、 integer.h 以及diskio.h 四個文件我們不需要改動,只需要修改 ffconf.h 和 diskio.c 兩個文件。

  底層設備輸入輸出要求實現存儲設備的讀寫操作函數、存儲設備信息獲取函數等等。

5、 FatFs 底層設備驅動函數

  FatFs 文件系統與底層介質的驅動分離開來,對底層介質的操作都要交給用戶去實現,它僅僅是提供了一個函數接口而已。下表 為 FatFs 移植時用戶必須支持的函數。通過表25-1 我們可以清晰知道很多函數是在一定條件下才需要添加的,只有前三個函數是必須添加的。我們完全可以根據實際需求選擇實現用到的函數。

  前三個函數是實現讀文件最基本需求。接下來三個函數是實現創建文件、修改文件需要的。為實現格式化功能,需要在 disk_ioctl 添加兩個獲取物理設備信息選項。我們一般只有實現前面六個函數就可以了,已經足夠滿足大部分功能。
  為支持簡體中文長文件名稱需要添加 ff_convert 和 ff_wtoupper 函數,實際這兩個已經在 cc936.c 文件中實現了,我們只要直接把 cc936.c 文件添加到工程中就可以了。

  后面六個函數一般都不用。如真有需要可以參考 syscall.c 文件(src\option 文件夾內)。 

  底層設備驅動函數是存放在 diskio.c 文件,我們的目的就是把 diskio.c 中的函數接口與SPI Flash 芯片驅動連接起來。總共有五個函數,分別為設備狀態獲取(disk_status)、設備初始化(disk_initialize)、扇區讀取(disk_read)、扇區寫入(disk_write)、其他控制(disk_ioctl)。

6、 FatFs測試

   6.1、Flash

  FatFs 屬於軟件組件,不需要附帶其他硬件電路。我們使用 SPI Flash 芯片作為物理存儲設備,其硬件電路在上一章已經做了分析,這里就直接使用。

  FatFs 移植步驟

  FatFs 組件文件添加到工程中,需要添加 ff.cdiskio.c cc936.c 三個文件,FatFs_test.c為用戶測試程序。 

  如果現在編譯工程,可以發現有兩個錯誤,一個是來自 diskio.c 文件,提示有一些頭文件沒找, diskio.c 文件內容是與底層設備輸入輸出接口函數文件,不同硬件設計驅動就不同,需要的文件也不同;另外一個錯誤來自 cc936.c 文件,提示該文件不是工程所必需的,這是因為 FatFs 默認使用日語,我們想要支持簡體中文需要修改 FatFs 的配置,即修改 ffconf.h 文件。至此,將 FatFs 添加到工程的框架已經操作完成,接下來要做的就是修改文件和 ffconf.h 文件。

  (1)、ffconf.h文件配置

  ffconf.h 文件是 FatFs 功能配置文件,我們可以對文件內容進行修改,使得 FatFs 更符合我們的要求。 ffconf.h 對每個配置選項都做了詳細的使用情況說明。

  下面只列出修改的配置,其他配置采用默認即可:

//ffconf.h
#define _USE_MKFS     1
#define _CODE_PAGE    936
#define _USE_LFN      2
#define _VOLUMES      2
#define _MIN_SS       512
#define _MAX_SS       4096

_USE_MKFS:格式化功能選擇,為使用 FatFs 格式化功能,需要把它設置為 1。
_CODE_PAGE:語言功能選擇,並要求把相關語言文件添加到工程宏。為支持簡體中文文件名需要使用“936”。
_USE_LFN:長文件名支持,默認不支持長文件名,這里配置為 2,支持長文件名,並指定使用棧空間為緩沖區。
_VOLUMES:指定物理設備數量,這里設置為 2,包括預留 SD 卡和 SPI Flash 芯片。
_MIN_SS、_MAX_SS:指定扇區大小的最小值和最大值。 SD 卡扇區大小一般都為 512 字節, SPI Flash 芯片扇區大小一般設置為 4096 字節,所以需要把_MAX_SS 改為 4096

   (2)、底層設備驅動函數

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2014        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "diskio.h"        /* FatFs lower layer API */
#include "ff.h"
#include "main.h"
//#include "usbdisk.h"    /* Example: Header file of existing USB MSD control module */
//#include "atadrive.h"    /* Example: Header file of existing ATA harddisk control module */
//#include "sdcard.h"        /* Example: Header file of existing MMC/SDC contorl module */


/*為每個設備定義一個物理編號*/
/* Definitions of physical drive number for each drive 每個驅動器的物理驅動器號的定義*/
#define ATA           0    /* Example: Map ATA harddisk to physical drive 0  將一個硬盤映射到物理驅動器0*/
#define MMC           1    /* Example: Map MMC card to physical drive 1      將MMC卡映射到物理驅動器1*/
#define USB           2    /* Example: Map USB to physical drive 2           將USB映射到物理驅動器2*/
#define SD           3    /* Example: Map SD to physical drive 3            將SD卡映射到物理驅動器3*/
#define Flash       4    /* Example: Map FLASH to physical drive 4         將Flash映射到物理驅動器4*/



/*-----------------------------------------------------------------------*/
/* Get Drive Status  獲取設備狀態                                       */
/*-----------------------------------------------------------------------*/
/*BYTE pdrv    :Physical drive nmuber to identify the drive 設備物理編號,通過物理驅動器編號來識別驅動器*/
DSTATUS disk_status (BYTE pdrv)
{
    DSTATUS status = STA_NOINIT & 0x00;
    //int result;

    switch(pdrv) 
    {
        case ATA:
            //result = ATA_disk_status();//獲取設備狀態
            break;

        case MMC:
            //result = MMC_disk_status();
            break;

        case USB:
            //result = USB_disk_status();
            break;

        case SD:
            //result = SD_disk_status();
            break;

        case Flash :
            //result = FLASH_disk_status();
            //SPI Flash狀態檢測:讀取SPI Flash 設備ID
            if(FLASH_ID == FLASH_Read_Jedec_ID())          //設備ID讀取結果正確
            {
                status = STA_NOINIT & 0x00;   
            }
            else    //設備ID讀取結果錯誤
            {      
                status = STA_NOINIT;
            }
            break;

        default:
            status = STA_NOINIT;
            break;
    }

    return status;
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive  設備初始化                                                        */
/*-----------------------------------------------------------------------*/
/*BYTE pdrv    :Physical drive nmuber to identify the drive 設備物理編號,通過物理驅動器編號來識別驅動器*/
DSTATUS disk_initialize(BYTE pdrv)
{
    DSTATUS status = STA_NOINIT & 0x00;
    //int result;

    switch(pdrv)
    {
        case ATA:
            //result = ATA_disk_initialize();//設備初始化 
            break;

        case MMC:
            //result = MMC_disk_initialize();
            break;

        case USB:
            //result = USB_disk_initialize();
            break;

        case SD:
            //result = SD_disk_initialize();
            break;

        case Flash:
            //result = FLASH_disk_initialize();
            SPI_1_Config_Init();
            int i=500;
            while(--i);                
            Flash_PowerOn_Mode();    //喚醒Flash     
            status = disk_status(Flash);  //獲取SPI Flash芯片狀態
            break;

        default:
            status = STA_NOINIT;
            break;
    }

    return status;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)   讀扇區:讀取扇區內容到指定存儲區                                                    */
/*-----------------------------------------------------------------------*/
/*BYTE pdrv:Physical drive nmuber to identify the drive 設備物理編號(0...)*/
/*BYTE *buff:Data buffer to store read data 數據緩存區*/
/*DWORD sector:Sector address in LBA 扇區首地址*/
/*UINT count:Number of sectors to read 扇區個數(1...128)*/
DRESULT disk_read(BYTE pdrv,BYTE *buff,    DWORD sector,UINT count)
{
    DRESULT status = STA_NOINIT & 0x00;
    //int result;

    switch (pdrv) 
    {
        case ATA:
            //result = ATA_disk_read(buff, sector, count);//讀取扇區內容到指定存儲區  
            break;

        case MMC:
            //result = MMC_disk_read(buff, sector, count);
            break;

        case USB:
            //result = USB_disk_read(buff, sector, count);
            break;

        case SD:
            //result = DS_disk_read(buff, sector, count);
            break;

        case Flash:
            //result = FLASH_disk_read(buff, sector, count);
            
            /*開發板使用的 SPI Flash 芯片型號為 W25Q128FV,每個扇區大小為 4096 個字節(4KB),總共有 16M 字節空間,為兼
            容后面實驗程序,我們只將后部分 10MB 空間分配給 FatFs 使用,前部分 6MB 空間用於其他實驗需要,即 FatFs 是從
            6MB 空間開始,為實現這個效果需要將所有的讀寫地址都偏移 1536 個扇區空間。    
            對於 SPI Flash 芯片,主要是使用 SPI_FLASH_BufferRead()實現在指定地址讀取指定長度的數據,它接收三個參數,
            第一個參數為指定數據存放地址指針。第二個參數為指定數據讀取地址,這里使用左移運算符,左移12位實際是乘以4096,
            這與每個扇區大小是息息相關的。第三個參數為讀取數據個數,也是需要使用左移運算符。*/

            sector = sector + 1536; //扇區偏移6MB,外部Flash文件系統空間放在SPI Flash后面10MB空間
            FLASH_Read_Buffer(sector <<12, count<<12,buff);
            status = RES_OK;
            break;

        default:
            status = RES_PARERR;
            break;                   
    }

    return status;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)  寫扇區:將數據寫入指定扇區空間上                                                         */
/*-----------------------------------------------------------------------*/
/*BYTE pdrv: Physical drive nmuber to identify the drive 設備物理編號(0...)*/
/*const BYTE *buff: Data to be written 寫入數據的緩存區*/
/*DWORD sector: Sector address in LBA 扇區首地址*/
/*UINT count: Number of sectors to write 扇區個數(1...128)*/
#if _USE_WRITE
DRESULT disk_write(BYTE pdrv,const BYTE *buff,DWORD sector,UINT count)
{
    DRESULT status = STA_NOINIT & 0x00;
    uint32_t write_addr; 
    //int result;
    
    if(!count)  //扇區個數為0
    {
        status = STA_NOINIT;
        return status;        
    }



    switch (pdrv) 
    {
        case ATA:
            //result = ATA_disk_write(buff, sector, count);//將數據寫入指定扇區空間上  
            break;

        case MMC:
            //result = MMC_disk_write(buff, sector, count);
            break;

        case USB:
            //result = USB_disk_write(buff, sector, count);
            break;

        case SD:
            //result = SD_disk_write(buff, sector, count);
            break;

        case Flash:
            //result = FLASH_disk_write(buff, sector, count);
            /*扇區偏移6MB,外部Flash文件系統空間放在Flash后面10MB空間 */
            sector = sector + 1536;    
            write_addr = sector<<12;  
            FLASH_Erase_Sector(write_addr);    //寫入數據前先擦除    
            FLASH_Write_Buffer(write_addr,count<<12,(uint8_t *)buff);    
            status = RES_OK;
            break;

        default:
            status = STA_NOINIT;
            break;  
    }

    return status;
}
#endif



/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions  其他控制                                                 */
/*-----------------------------------------------------------------------*/
/*BYTE pdrv:Physical drive nmuber (0..) 設備物理編號 */
/*BYTE cmd:Control code 控制指令,包括發出同步信號、獲取扇區數目、獲取扇區大小、獲取擦除塊數量等等指令*/
/*void *buff:Buffer to send/receive control data 寫入或者讀取數據地址指針*/
#if _USE_IOCTL
DRESULT disk_ioctl (BYTE pdrv,BYTE cmd,void *buff)
{
    DRESULT status = STA_NOINIT & 0x00;
    int result;

    switch (pdrv)
    {
        case ATA:
            break;

        case MMC:
            break;

        case USB:
            break;

        case SD:
            break;

        case Flash:
            switch (cmd) 
            {        
                case GET_SECTOR_COUNT:    //扇區數量:2560*4096/1024/1024=10(MB)
                    *(DWORD * )buff = 2560;        
                    break;

                case GET_SECTOR_SIZE :    //扇區大小 
                    *(WORD * )buff = 4096;
                    break;

                case GET_BLOCK_SIZE :     //同時擦除扇區個數
                    *(DWORD * )buff = 1;
                    break;

                default:
                    status = STA_NOINIT;
                    break;                                 
            }                    
            break;

        default:
            status = STA_NOINIT;
            break;
    }

    return status;
}
#endif


/*
get_fattime 函數用於獲取當前時間戳,在 ff.c 文件中被調用。 FatFs 在文件創建、被修改時會記錄時間,這里我們直接使用賦值方法
設定時間戳。為更好的記錄時間,可以使用控制器 RTC 功能,具體要求返回值格式為:
        bit31:25 ——從 1980 至今是多少年,范圍是 (0..127) ;
        bit24:21 ——月份,范圍為 (1..12) ;
        bit20:16 ——該月份中的第幾日,范圍為(1..31) ;
        bit15:11——時,范圍為 (0..23);
        bit10:5 ——分,范圍為 (0..59);
        bit4:0 ——秒/ 2,范圍為 (0..29) 
*/
__weak DWORD get_fattime(void) 
{
    //返回當前時間戳
    return      (     (DWORD)(2015 - 1980) << 25)        //Year 2015 
                |     ((DWORD)1 << 21)                //Month 1
                |     ((DWORD)1 << 16)                //Mday 1
                |     ((DWORD)0 << 11)                //Hour 0
                |     ((DWORD)0 << 5)                      //Min 0
                |     ((DWORD)0 >> 1);                //Sec 0
}

  FatFs 的第一步工作就是使用 f_mount 函數掛載工作區。 f_mount 函數有三個形參,第一個參數是指向 FATFS 變量指針,如果賦值為 NULL 可以取消物理設備掛載。第二個參 數為邏輯設備編號,使用設備根路徑表示,與物理設備編號掛鈎,在代碼中我們定義 SPI Flash 芯片物理編號為 1,所以這里使用“1:”。第三個參數可選 0 或 1, 1 表示立即掛載, 0 表示不立即掛載,延遲掛載。 f_mount 函數會返回一個 FRESULT 類型值,指示運行情況。

FRESULT f_mount (
    FATFS* fs,            /* Pointer to the file system object (NULL:unmount)*/
    const TCHAR* path,    /* Logical drive number to be mounted/unmounted */
    BYTE opt            /* 0:Do not mount (delayed mount), 1:Mount immediately */
)

  如果 f_mount 函數返回值為 FR_NO_FILESYSTEM,說明沒有 FAT 文件系統,比如新出廠的 SPI Flash 芯片就沒有 FAT 文件系統。我們就必須對物理設備進行格式化處理。使用 f_mkfs 函數可以實現格式化操作。 f_mkfs 函數有三個形參,第一個參數為邏輯設備編號;第二參數可選 0 或者 1, 0 表示設備為一般硬盤, 1 表示設備為軟盤。第三個參數指定扇區大小,如果為 0,表示通過代碼中 disk_ioctl 函數獲取。格式化成功后需要先取消掛載原來設備,再重新掛載設備。

FRESULT f_mkfs (
    const TCHAR* path,    /* Logical drive number */
    BYTE sfd,            /* Partitioning rule 0:FDISK, 1:SFD */
    UINT au                /* Size of allocation unit in unit of byte or sector */
)

 

  在設備正常掛載后,就可以進行文件讀寫操作了。使用文件之前,必須使用 f_open 函數打開文件,不再使用文件必須使用 f_close 函數關閉文件,這個跟電腦端操作文件步驟類似。 f_open 函數有三個形參,第一個參數為文件對象指針。第二參數為目標文件,包含絕對路徑的文件名稱和后綴名。第三個參數為訪問文件模式選擇,可以是打開已經存在的文件模式、讀模式、寫模式、新建模式、總是新建模式等的或運行結果。比如對於寫測試,使用 FA_CREATE_ALWAYS 和 FA_WRITE 組合模式,就是總是新建文件並進行寫模式。f_close 函數用於不再對文件進行讀寫操作關閉文件, f_close 函數只要一個形參,為文件對象指針。 f_close 函數運行可以確保緩沖區完全寫入到文件內。

FRESULT f_open (
    FIL* fp,            /* Pointer to the blank file object */
    const TCHAR* path,    /* Pointer to the file name */
    BYTE mode            /* Access mode and file open mode flags */
)
FRESULT f_close (
    FIL *fp        /* Pointer to the file object to be closed */
)

  成功打開文件之后就可以使用 f_write 函數和 f_read 函數對文件進行寫操作和讀操作。這兩個函數用到的參數是一致的,只不過一個是數據寫入,一個是數據讀取。 f_write 函數第一個形參為文件對象指針,使用與 f_open 函數一致即可。第二個參數為待寫入數據的首地址,對於 f_read 函數就是用來存放讀出數據的首地址。第三個參數為寫入數據的字節數,對於 f_read 函數就是欲讀取數據的字節數。第四個參數為 32 位無符號整形指針,這里使用fnum 變量地址賦值給它,在運行讀寫操作函數后, fnum 變量指示成功讀取或者寫入的字節個數。

FRESULT f_write (
    FIL* fp,            /* Pointer to the file object */
    const void *buff,    /* Pointer to the data to be written */
    UINT btw,            /* Number of bytes to write */
    UINT* bw            /* Pointer to number of bytes written */
)
FRESULT f_read (
    FIL* fp,         /* Pointer to the file object */
    void* buff,        /* Pointer to data buffer */
    UINT btr,        /* Number of bytes to read */
    UINT* br        /* Pointer to number of bytes read */
)

  最后,不再使用文件系統時,使用 f_mount 函數取消掛載。

   注意:使用文件系統時,引腳初始化需要放在系統中


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM