• 專注電子技術學習與研究
    當前位置:單片機教程網 >> STM32 >> 瀏覽文章

    FATfs 在STM32F107VC上的移植過程

    作者:佚名   來源:本站原創   點擊數:  更新時間:2014年08月18日   【字體:
    【文件系統將對文件的塊的操作轉換為對物理存儲器扇區的各種操作】
      FatFs是一個通用的文件系統模塊,以小的嵌入式系統的FAT文件系統。 FatFs的編程遵守的ANSI C格式語法標準,因此,它是具有獨立于硬件架構。 在不做任何改變就可以被移植到常用的微控制器中,如8051, PIC, AVR, SH, Z80, H8, ARM等。

    FatFs 特點
    分離緩沖的FAT結構和每一個文件,適合快速訪問多個文件。
    支持多個驅動器和分區。
    支持FAT12 , FAT16和FAT32 。
    支持8.3格式的文件名(LFN不支持)
    支持兩個分區規則: Fdisk和超級軟盤。
    優化8/16-bit微控制器。

    應用接口
    FatFs /微型FatFs模塊提供下列功能。
    f_mount – 登記或注銷一個工作領域
    f_open -打開或創建文件
    f_close – 關閉一個文件
    f_read – 讀文件
    f_write – 寫文件
    f_lseek -移動文件讀/寫指針
    f_truncate – 截斷文件
    f_sync – 刷新緩存的數據
    f_opendir – 打開一個目錄
    f_readdir – 閱讀目錄項目
    f_getfree -獲取免費集群
    f_stat – 獲取文件狀態
    f_mkdir – 創建一個目錄
    f_unlink – 刪除文件或目錄
    f_chmod – 更改屬性
    f_utime – 變更時間戳記
    f_rename -重命名/移動文件或目錄
    f_mkfs – 創建一個文件系統的驅動器
    f_forward -轉發文件數據流直接
    fgets – 讀一個字符串
    fputc – 寫一個字符
    fputs – 寫一個字符串
    fprintf – 寫格式化字串

    Disk I/O Interface

    disk_initialize -初始化的磁盤驅動器
    disk_status – 獲取磁盤狀態
    disk_read – 讀部門(星期日)
    disk_write – 收件部門(星期日)
    disk_ioctl – 控制裝置依賴功能
    get_fattime – 獲取當前時間

    一種易于移植和使用的文件系統FatFs Moule

    引 言

    隨著信息技術的發展,當今社會的信息量越來越大,以往由單片機構成的系統簡單地對存儲媒介按地址、按字節的讀/寫已經不滿足人們實際應用的需要,于是利用文件系統對存儲媒介進行管理成了今后單片機系統的一個發展方向。目前常用的文件系統主要有微軟的FATl2、FATl6、FAT32、NTFS,以及Linux系統下的EXT2、EXT3等。由于微軟Windows的廣泛應用,在當前的消費類電子產品中,用得最多的還是FAT文件系統,如U盤、MP3、MP4、數碼相機等,所以找到一款容易移植和使用、占用硬件資源相對較小而功能又強大的FAT開源文件系統,對于單片機系統設計者來說是很重要的。

    FatFs Module是一種完全免費開源的FAT文件系統模塊,專門為小型的嵌入式系統而設計。它完全用標準C語言編寫,所以具有良好的硬件平臺獨立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列單片機上而只需做簡單的修改。它支持FATl2、FATl6和FAT32,支持多個存儲媒介;有獨立的緩沖區,可以對多個文件進行讀/寫,并特別對8位單片機和16位單片機做了優化。FatFs Module有個簡化版本Tiny—FatFs,它跟完全版FatFs的不同之處主要有兩點:

    ①占用內存更少,只要1 KB RAM;

    ②1次僅支持1個存儲介。
     
     
    1:下載代碼fatfs_ff007c,添加到工程,并通過ff.h做相應配置, 我的配置如下
    #define _WORD_ACCESS 0
    #define _FS_READONLY 0
    #define _FS_MINIMIZE 0
    #define _FS_TINY 1
    ...【根據它的注釋進行配合即可】
    下圖就是工程中的結構:mmc_sd.c是自己實現的fatfs文件系統與SD卡驅動的銜接文件。
    2:移植fatfs前,系統需包含sd卡的驅動程序,至少需要實現下面幾個函數

    //SD卡的初始化函數
    SD_Init()
    //SD卡的卡寄存器讀取函數
    SD_GetCardInfo(&SDinfo);
    //SD卡讀取一個扇區的函數【在文件系統中是通過邏輯塊與物理塊管理文件,但文件系統對硬件設備操作的最小單元是扇區
    SD_ReadBlock(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t BlockSize);
    //SD卡讀取多個扇區的函數
    SD_ReadMultiBlocks
         (uint8_t* pBuffer, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
    //SD卡寫一個扇區的函數
    SD_WriteBlock(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t BlockSize)
    //SD卡寫多個扇區的函數
     SD_WriteMultiBlocks
     (uint8_t* pBuffer, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)

    3:fatfs與SD驅動的接口函數
    就是下面4個簡單的函數,實現了就可以了
    DSTATUS MMC_disk_initialize(void)
    DRESULT MMC_disk_read(BYTE *buff, DWORD sector, BYTE count)
    DRESULT  MMC_disk_write(const BYTE *buff, DWORD sector, BYTE count)
    DRESULT  MMC_disk_ioctl(BYTE ctrl, void *buff)
     
    disk_ioctl:
    DRESULT disk_ioctl (
    BYTE drv,
    BYTE ctrl,
    void *buff
    )
    CPU調用disk_ioctl函數執行ctrl指令對應的動作,這些指令一般都是通過底層flash驅動讀取flash存儲設備中的一些特殊寄存器(如SD卡中的OCR、CID、RCA等)。通過查找,可以發現在調用該函數前,主調函數先會調用disk_initialize,所以我們可以在disk_initialize中初始化SD接口,并將SD卡中的各個寄存器的值都讀取并存儲起來,以備disk_ioctl使用!disk_ioctl該函數網絡上有教材說可以直接返回0,那是不行的,因為很多地方用disk_ioctl來獲取SD卡的相關信息后,才做出正確的動作,否則出錯,比如f_mkfs:格式化操作等
    The RCA register is not available in SPI Mode. 
    OCR: 卡操作電壓寄存器 32位, 只讀,每隔0.1V占1位, 第31位卡上電過程是否完成
    CID: 卡身份識別寄存器 128bit,只讀, 廠家號,產品號,串號,生產日期
    SCR: 卡配置寄存器, 可寫的 64bit 是否用Security特性(LINUX不支持),以及數據位寬(1bit或4bit)
    RCA: 卡地址寄存器: 可寫的 16bit SD host和卡進行協商的一個地址,內核中會在代碼里面記錄這個地址,卡這      邊則寫到RCA寄存器
    CSD: 卡專有數據寄存器 部分可讀寫 128bit, 卡容量,最大傳輸速率,讀寫操作的最大電流、電壓,讀寫擦出塊的最大長度



     
    f_mount:通過文件系統管理一個存儲設備,需先在該設備上創建文件系統(先格式化創建文件系統f_mkfs),如果已經創建好了,只需通過f_mount掛載后即可使用。
    //////////////////////具體代碼的實現//////////////////////////////
    DSTATUS MMC_disk_initialize(void)
    {
        SD_Error err;
        if ((err = SD_Init()) != SD_RESPONSE_NO_ERROR) {
        return err;
    } else {
                //USART_SendString(USART2,"MMC_disk_initialize OK!\n");
    }
    SD_GetCardInfo(&SDinfo); 
    return RES_OK;
    }
     
    DRESULT MMC_disk_read(BYTE *buff, DWORD sector, BYTE count)
    {
    sector *= 512;
    if (count == 1) {
                SD_ReadBlock(buff,sector,512);
        count = 0;
    } else {
                SD_ReadMultiBlocks(buff,sector,512,count);
                count = 0;
    }
    return count?RES_ERROR:RES_OK; 
    }
     
    DRESULT  MMC_disk_write(const BYTE *buff, DWORD sector, BYTE count)
    {
            sector *= 512;
            if (count == 1) {
        SD_WriteBlock((BYTE *)buff,sector,512);
        count = 0;
    } else {
                SD_WriteMultiBlocks((BYTE *)buff,sector,512,count);
                count = 0;
    }
    return count?RES_ERROR:RES_OK; 
    }
    //可以搜索下下面的各個命令,只有其中的幾個被使用
    DRESULT  MMC_disk_ioctl(BYTE ctrl, void *buff)
    {
        DRESULT res;
    res = RES_ERROR;
        switch(ctrl) {
    case CTRL_SYNC:      
       res = RES_OK;
    break;
    case GET_SECTOR_COUNT:  
       *(DWORD *)buff = (DWORD)SDinfo.CardCapacity / 512;
       res = RES_OK;
       break;
        case GET_SECTOR_SIZE:  
       *(DWORD *)buff = 512;
    res = RES_OK;
       break;
    case GET_BLOCK_SIZE:  
       *(DWORD *)buff = (DWORD)SDinfo.CardBlockSize;
    res = RES_OK;
    break;
        case CTRL_POWER:  
       res = RES_OK;
       break;
    case CTRL_LOCK:
    res = RES_OK;
       break;
        case CTRL_EJECT:
       break;
    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;
    }
    return res;
    }
    /////////////////////應用層/////////////////////////
    應用層 通過串口顯示菜單,打開文件,讀寫文件,實現人機交互

    char * Menu[] = {
      "create new file: 1 \n",
      "create new  dir: 2 \n",
      "delete     file: 3 \n",
      "delete      dir: 4 \n",
      "open       file: 5 \n",
      "open        dir: 6 \n",
      "read       file: 7 \n",
      "write      file: 8 \n",
    };
     
    static  void  AppTaskUsartDisp(void )
    {
      char err;
      char *pString = NULL;
      pQ = OSQCreate(MsgQArray,20); 
      USART_SendString(USART2,"Usart2 is Ok!\n");
      USART_SendString(USART2,Menu[0]);
      USART_SendString(USART2,Menu[1]);
      USART_SendString(USART2,Menu[2]);
      USART_SendString(USART2,Menu[3]);
      USART_SendString(USART2,Menu[4]);
      USART_SendString(USART2,Menu[5]);
      USART_SendString(USART2,Menu[6]);
      USART_SendString(USART2,Menu[7]);
      while(DEF_TRUE) {
          pString = (char *)OSQPend(pQ,0,&err);
          USART_SendString(USART2,pString);
      }
    }
    void AppOpenfile (void)
    {
        u8 err;
    FATFS fs;
    FIL file;
    FRESULT res;
        char * pBoxData;
        pBoxData = (char *)OSMboxPend(pBox,0,&err);
    OSQPost(pQ,pBoxData);
    res = f_open(&file,pBoxData, FA_OPEN_EXISTING | FA_READ);
    if (res == FR_OK) {
            OSQPost(pQ,"\n OPen succed!\n");
    } else {
    OSQPost(pQ,"\n OPen failed!\n");
    }
    f_close(&file);
    }
    void AppCreatefile (void)
    {
        u8 err;
    FATFS fs;
    FIL file;
    FRESULT res;
        char * pBoxData;
        pBoxData = (char *)OSMboxPend(pBox,0,&err);
    OSQPost(pQ,pBoxData);
    res = f_open(&file,pBoxData, FA_CREATE_NEW | FA_READ);
    if (res == FR_OK) {
            OSQPost(pQ,"\n create succed!\n");
    } else {
    OSQPost(pQ,"\n create failed!\n");
    }
    f_close(&file);
    }
    char   fileData[30] = {0};
    void AppReadfile (void)
    {
        u8 err;
    FATFS fs;
    FIL file;
    FRESULT res;
        char * pBoxData;
    u32 br;
        pBoxData = (char *)OSMboxPend(pBox,0,&err);
    OSQPost(pQ,pBoxData);
    res = f_open(&file,pBoxData, FA_OPEN_EXISTING | FA_READ);
    if (res == FR_OK) {
            OSQPost(pQ,"\n OPen succed!\n");
    } else {
    OSQPost(pQ,"\n OPen failed!\n");
    }
    res = f_read(&file,fileData,20,&br);
    fileData[21] = '\0';
    if (res == FR_OK) {
            OSQPost(pQ,"Data:");
    OSQPost(pQ,fileData);
    } else {
    OSQPost(pQ,"\n read failed!\n");
    }
    f_close(&file);
    }
    void AppWritefile (void)
    {
        u8 err;
    u8 Len;
    FATFS fs;
    FIL file;
    FRESULT res;
        char * pBoxData;
    u32 br;
        pBoxData = (char *)OSMboxPend(pBox,0,&err);
    OSQPost(pQ,pBoxData);
    res = f_open(&file,pBoxData, FA_OPEN_EXISTING | FA_READ | FA_WRITE);
    if (res == FR_OK) {
            OSQPost(pQ,"\n OPen succed!\n");
    } else {
    OSQPost(pQ,"\n OPen failed!\n");
    }
    OSQPost(pQ,"Input:");
    pBoxData = (char *)OSMboxPend(pBox,0,&err);
    Len = strlen(pBoxData);
    res = f_write(&file,pBoxData,Len,&br);
    if (res == FR_OK) {
    OSQPost(pQ,"\n write OK!\n");
    } else {
    OSQPost(pQ,"\n write failed!\n");
    }
    f_close(&file);
    }
     
    static  void  AppTaskSdCard(void )
    {
        u8 err;
    char BoxData;
    FATFS fs;
    FRESULT res;
    FIL file;
    pBox = OSMboxCreate((void *)0);
    res = f_mount(0,&fs);
    OSQPost(pQ,"fatfs!\n");
        while (1) {
    BoxData = (char)OSMboxPend(pBox,0,&err);    
    switch (BoxData) {
    case '1'://create new file
       OSQPost(pQ,"new filename:");
    AppCreatefile();
       break;
    case '2':
       OSQPost(pQ,"2222!\n");
       break;
    case '3':
       OSQPost(pQ,"3333!\n");
       break;
    case '4':
       OSQPost(pQ,"f4444!\n");
       break;
    case '5': //Openfile  
       OSQPost(pQ,"filename:");
    AppOpenfile();
       break;
    case '6':
       OSQPost(pQ,"6666!\n");
       break;
    case '7': //read file:
       OSQPost(pQ,"filename:");
    AppReadfile();
       break;
    case '8': //write file
       OSQPost(pQ,"filename:\n");
              AppWritefile();
       break;
    default:
       OSQPost(pQ,"null!\n");
       break;
    }
    }
    }
     
     
    //返回的是 字符串的字符個數
    int GetStringFromFifo(sequeue *sq, datatype *buff)
    {
        int Count = 0;
    do {
       *buff = DeQueue(sq);
    if (*buff == NULL || *buff == ENDFLAG ) {
      break;
    }
    if (++Count <= BUFFERSIZE - 1) {
      buff ++;
    } while(1);
    *(buff++) = '\0';
    return Count;
    }
     
    datatype InputBuffer[BUFFERSIZE];
     
    static  void  AppTaskUsartInput (void *p_arg)
    {
       u8 tick=0 , Cnt = 0 ,err;
       NVIC_InitTypeDef  NVIC_InitStruct;
       USART_InitTypeDef USART_InitStructure;
       (void)p_arg;
       NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQChannel;
       NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
       NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
       NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
     
       USART_InitStructure.USART_BaudRate = 115200;
       USART_InitStructure.USART_WordLength = USART_WordLength_8b;
       USART_InitStructure.USART_StopBits = USART_StopBits_1;
       USART_InitStructure.USART_Parity = USART_Parity_No;
       USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
       USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
     
       NVIC_Init(&NVIC_InitStruct);
       STM_EVAL_COMInit(COM1, &USART_InitStructure);
       USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
     
       SetNull(&USART_FIFO);
       pSem = OSSemCreate(0);
         
       while(DEF_TRUE) {
            OSSemPend(pSem,0,&err);
    tick++;
            //OSTimeDlyHMSM(0,0,0,10);  
    Cnt = GetStringFromFifo(&USART_FIFO,InputBuffer);
    //OSQPost(pQ,InputBuffer);
    if (Cnt == 1) {
       OSMboxPost(pBox,(void *)InputBuffer[0]);
    } else {
       OSMboxPost(pBox,(void *)InputBuffer);        
    }  
    if(tick&0x01)
    {
       GPIO_SetBits(GPIOD,GPIO_Pin_2);
       GPIO_SetBits(GPIOD,GPIO_Pin_4);
    GPIO_ResetBits(GPIOD,GPIO_Pin_3);
    GPIO_ResetBits(GPIOD,GPIO_Pin_7);
    }
    else
    {
    GPIO_ResetBits(GPIOD,GPIO_Pin_2);
    GPIO_ResetBits(GPIOD,GPIO_Pin_4);
    GPIO_SetBits(GPIOD,GPIO_Pin_3);
    GPIO_SetBits(GPIOD,GPIO_Pin_7);
    }
       }
    }
    ///////////////測試/////////////////////
     
     
     
    關閉窗口

    相關文章

    亚洲一区二区制服在线|在绩专区欧美自拍日韩|青春娱乐网97超碰人人射|在线观看国产网址你懂的