天天看点

MSP430、STM32、8051单片机fatfs 文件系统移植 W25Q128一、工具二、使用步骤总结

前言

嵌入式系统中我们常常对flash、SD卡、U盘等进行操作,但我们操作一般是直接操作物理地址,使用起来相对来说比较繁琐,也不能将我们自己写的数据导出到我们的电脑中,这时大名鼎鼎的文件系统fatfs就可以派上用场,fatfs是一小型的可裁剪免费文件系统,移植起来比较方便,移植完文件系统大大缩短开发周期,可以很方便的操作内存,废话不再多说,下面开始介绍移植文件系统步骤:

参考:

https://blog.csdn.net/qq_21475601/article/details/78032854

https://blog.csdn.net/Jun626/article/details/72954494

一、工具

文件系统源码fatfs10b,链接 https://download.csdn.net/download/qq_35257512/12803176是楼主已经移植好的文件系统,运行平台MSP430F5438 IAR工程

二、使用步骤

2.1.解压源码

MSP430、STM32、8051单片机fatfs 文件系统移植 W25Q128一、工具二、使用步骤总结

doc 文档主要是一些参考文档,使用说明、例程等

src文件夹主要是我们的文件系统源码 进入该目录

MSP430、STM32、8051单片机fatfs 文件系统移植 W25Q128一、工具二、使用步骤总结

diskio.c个diskio.h是和存储器读写控制相关的驱动接口,比如SPI_FLASH的读写函数接口,都要映射到这里面。必须的文件 

ff.h和ff.h是FATFS的核心文件,必须的文件

ffconf.h是FATFS的配置文件,用来裁剪FATFS,必须的文件

integer.h是FATFS所用到的数据类型定义,用以兼容不同字长CPU,必须的文件

option 目录又是什么呢,下面进入该目录看下

MSP430、STM32、8051单片机fatfs 文件系统移植 W25Q128一、工具二、使用步骤总结

cc936.c  /* CP936 (Simplified Chinese GBK)  

syscall.c  unicode.c            文件名支持长文件名是里面ff_malloc 等ha  函数会用到,需要添加到工程中,具体使用到什么可以不用管他    。    

2.1.将源码添加到我们的工程中

MSP430、STM32、8051单片机fatfs 文件系统移植 W25Q128一、工具二、使用步骤总结

2.1.1 修改ffconf.h文件

来裁剪我们的FATFS,通过宏开关来去掉不用的功能,来精简文件系统。想知道每个宏的功能,参考https://blog.csdn.net/xiayufeng520/article/details/8830157

/*---------------------------------------------------------------------------/
/  FatFs - FAT file system module configuration file  R0.10b (C)ChaN, 2014
/---------------------------------------------------------------------------*/

#ifndef _FFCONF
#define _FFCONF 29000    /* Revision ID */


/*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations
/---------------------------------------------------------------------------*/

#define    _FS_TINY        1    /* 0:Normal or 1:Tiny */    /*文件系统 0   1 微文件系统*/
/* When _FS_TINY is set to 1, it reduces memory consumption _MAX_SS bytes each
/  file object. For file data transfer, FatFs uses the common sector buffer in
/  the file system object (FATFS) instead of private sector buffer eliminated
/  from the file object (FIL). */


#define _FS_READONLY    0    /* 0:Read/Write or 1:Read only */  //0 文件可读可写  1 只读  裁剪
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/  writing functions, f_write(), f_sync(), f_unlink(), f_mkdir(), f_chmod(),
/  f_rename(), f_truncate() and useless f_getfree(). */


#define _FS_MINIMIZE    0    /* 0 to 3 */   //3个程度进行裁剪  3 裁剪函数最多  0 最少
/* The _FS_MINIMIZE option defines minimization level to remove API functions.
/
/   0: All basic functions are enabled.
/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
/      f_truncate() and f_rename() function are removed.
/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/   3: f_lseek() function is removed in addition to 2. */
#define    _USE_STRFUNC    1    /* 0:Disable or 1-2:Enable */
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define    _USE_MKFS        1    /* 0:Disable or 1:Enable */
/* To enable f_mkfs() function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */


#define    _USE_FASTSEEK    1    /* 0:Disable or 1:Enable */ //快速索引 0 取消 1支持
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */


#define _USE_LABEL        1    /* 0:Disable or 1:Enable */  //0  不支持盘符修改  1 支持盘符修改
/* To enable volume label functions, set _USE_LAVEL to 1 */
#define    _USE_FORWARD    0    /* 0:Disable or 1:Enable */ //f_forward函数的使能
/* To enable f_forward() function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/

#define _CODE_PAGE    932    //中文应该选择936
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/  Incorrect setting of the code page can cause a file open failure.
/
/   932  - Japanese Shift_JIS (DBCS, OEM, Windows)
/   936  - Simplified Chinese GBK (DBCS, OEM, Windows)
/   949  - Korean (DBCS, OEM, Windows)
/   950  - Traditional Chinese Big5 (DBCS, OEM, Windows)
/   1250 - Central Europe (Windows)
/   1251 - Cyrillic (Windows)
/   1252 - Latin 1 (Windows)
/   1253 - Greek (Windows)
/   1254 - Turkish (Windows)
/   1255 - Hebrew (Windows)
/   1256 - Arabic (Windows)
/   1257 - Baltic (Windows)
/   1258 - Vietnam (OEM, Windows)
/   437  - U.S. (OEM)
/   720  - Arabic (OEM)
/   737  - Greek (OEM)
/   775  - Baltic (OEM)
/   850  - Multilingual Latin 1 (OEM)
/   858  - Multilingual Latin 1 + Euro (OEM)
/   852  - Latin 2 (OEM)
/   855  - Cyrillic (OEM)
/   866  - Russian (OEM)
/   857  - Turkish (OEM)
/   862  - Hebrew (OEM)
/   874  - Thai (OEM, Windows)
/   1    - ASCII (Valid for only non-LFN configuration) */


#define    _USE_LFN    3        /* 0 to 3 */    //0 不支持长文件名    

#define    _MAX_LFN    32        /* Maximum LFN length to handle (12 to 255) */   //文件名长度 12 到255
/* The _USE_LFN option switches the LFN feature.
/
/   0: Disable LFN feature. _MAX_LFN has no effect. //1 2 3 长文件名 分配位置不同
/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/   2: Enable LFN with dynamic working buffer on the STACK.
/   3: Enable LFN with dynamic working buffer on the HEAP.
/
/  When enable LFN feature, Unicode handling functions ff_convert() and ff_wtoupper()
/  function must be added to the project.
/  The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. When use stack for the
/  working buffer, take care on stack overflow. When use heap memory for the working
/  buffer, memory management functions, ff_memalloc() and ff_memfree(), must be added
/  to the project. */


#define    _LFN_UNICODE    0    /* 0:ANSI/OEM or 1:Unicode */

 // FatFs API要切换字符编码形式为Union时,将LEN和LFN_UNICODE为1
/* To switch the character encoding on the FatFs API (TCHAR) to Unicode, enable LFN
/  feature and set _LFN_UNICODE to 1. This option affects behavior of string I/O
/  functions. This option must be 0 when LFN feature is not enabled. */


#define _STRF_ENCODE    0    /* 0:ANSI/OEM, 1:UTF-16LE, 2:UTF-16BE, 3:UTF-8 */
/* When Unicode API is enabled by _LFN_UNICODE option, this option selects the character
/  encoding on the file to be read/written via string I/O functions, f_gets(), f_putc(),
/  f_puts and f_printf(). This option has no effect when _LFN_UNICODE == 0. Note that
/  FatFs supports only BMP. */


#define _FS_RPATH        0    /* 0 to 2 */
/* The _FS_RPATH option configures relative path feature.
/
/   0: Disable relative path feature and remove related functions.
/   1: Enable relative path. f_chdrive() and f_chdir() function are available.
/   2: f_getcwd() function is available in addition to 1.
/
/  Note that output of the f_readdir() fnction is affected by this option. */


/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/

#define _VOLUMES    1   //逻辑桊使用数目
/* Number of volumes (logical drives) to be used. */


#define _STR_VOLUME_ID    0    /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */
#define _VOLUME_STRS    "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
/* When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/  number in the path name. _VOLUME_STRS defines the drive ID strings for each logical
/  drives. Number of items must be equal to _VOLUMES. Valid characters for the drive ID
/  strings are: 0-9 and A-Z. */


#define    _MULTI_PARTITION    0    /* 0:Single partition, 1:Enable multiple partition */   //0 单分区  1 多分区
/* By default(0), each logical drive number is bound to the same physical drive number
/  and only a FAT volume found on the physical drive is mounted. When it is set to 1,
/  each logical drive number is bound to arbitrary drive/partition listed in VolToPart[].
*/


#define    _MIN_SS         4096  // 一个扇区大小4096个字节
#define    _MAX_SS        4096
/* These options configure the range of sector size to be supported. (512, 1024, 2048 or
/  4096) Always set both 512 for most systems, all memory card and harddisk. But a larger
/  value may be required for on-board flash memory and some type of optical media.
/  When _MAX_SS is larger than _MIN_SS, FatFs is configured to variable sector size and
/  GET_SECTOR_SIZE command must be implemented to the disk_ioctl() function. */


#define    _USE_ERASE    1    /* 0:Disable or 1:Enable */   //是否使能擦除
/* To enable sector erase feature, set _USE_ERASE to 1. Also CTRL_ERASE_SECTOR command
/  should be added to the disk_ioctl() function. */
#define _FS_NOFSINFO    0    /* 0 to 3 */
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this option
/  and f_getfree() function at first time after volume mount will force a full FAT scan.
/  Bit 1 controls the last allocated cluster number as bit 0.
/
/  bit0=0: Use free cluster count in the FSINFO if available.
/  bit0=1: Do not trust free cluster count in the FSINFO.
/  bit1=0: Use last allocated cluster number in the FSINFO if available.
/  bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/

/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/

#define    _FS_LOCK    0    /* 0:Disable or >=1:Enable */

//使能文件锁功能,设置FS_LOCK为1或者更大

//定义的大小决定了多少文件能同时打开

/* To enable file lock control feature, set _FS_LOCK to non-zero value.
/  The value defines how many files/sub-directories can be opened simultaneously
/  with file lock control. This feature uses bss _FS_LOCK * 12 bytes. */


#define _FS_REENTRANT    0        /* 0:Disable or 1:Enable */
#define _FS_TIMEOUT        1000    /* Timeout period in unit of time tick */
#define    _SYNC_t            HANDLE    /* O/S dependent sync object type. e.g. HANDLE, OS_EVENT*, ID, SemaphoreHandle_t and etc.. */
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs module.
/
/   0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/   1: Enable re-entrancy. Also user provided synchronization handlers,
/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/      function must be added to the project.
*/
#define _WORD_ACCESS    0    /* 0 or 1 */
/* The _WORD_ACCESS option is an only platform dependent option. It defines
/  which access method is used to the word data on the FAT volume.
/
/   0: Byte-by-byte access. Always compatible with all platforms.
/   1: Word access. Do not choose this unless under both the following conditions.
/
/  * Address misaligned memory access is always allowed for ALL instructions.
/  * Byte order on the memory is little-endian.
/
/  If it is the case, _WORD_ACCESS can also be set to 1 to improve performance and
/  reduce code size. Following table shows an example of some processor types.
/
/   ARM7TDMI    0           ColdFire    0           V850E       0
/   Cortex-M3   0           Z80         0/1         V850ES      0/1
/   Cortex-M0   0           RX600(LE)   0/1         TLCS-870    0/1
/   AVR         0/1         RX600(BE)   0           TLCS-900    0/1
/   AVR32       0           RL78        0           R32C        0
/   PIC18       0/1         SH-2        0           M16C        0/1
/   PIC24       0           H8S         0           MSP430      0
/   PIC32       0           H8/300H     0           x86         0/1
*/
#endif /* _FFCONF */
           

2.1.2  修改diskio.c 来映射我们的存储器读写控制接口

/*-----------------------------------------------------------------------*/
/* 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 "W25q.h"
#define EX_FLASH        0
#define FLASH_SECTOR_SIZE  4096
#define FLASH_BLOCK_SIZE   1
#define FLASH_SECTOR_COUNT 1024
/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
    BYTE pdrv        /* Physical drive nmuber to identify the drive */
)
{

    return RES_OK; //直接返回OK即可
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
    BYTE pdrv                /* Physical drive nmuber to identify the drive */
)
{
    DSTATUS stat =0;

    switch (pdrv) {
  

    case EX_FLASH:
    
                W25QXX_Init();   //初始化操作
              
        return stat;
    }
    return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
    BYTE pdrv,        /* Physical drive nmuber to identify the drive */
    BYTE *buff,        /* Data buffer to store read data */
    DWORD sector,            /* Sector address in LBA */
    UINT count        /* Number of sectors to read */
)
{

    switch (pdrv) {

    case EX_FLASH :
          for(;count>0;count--)
              {
                      W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
                      sector++;
                      buff+=FLASH_SECTOR_SIZE;
              }

             return RES_OK;
    }

    return RES_PARERR;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if _USE_WRITE
DRESULT disk_write (
    BYTE pdrv,            /* Physical drive nmuber to identify the drive */
    const BYTE *buff,    /* Data to be written */
    DWORD sector,        /* Sector address in LBA */
    UINT count            /* Number of sectors to write */
)
{
    switch (pdrv) {
    case EX_FLASH :
                 for(;count>0;count--)
                {                                            
                        W25QXX_Write((uint8_t*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
                        sector++;
                        buff+=FLASH_SECTOR_SIZE;
                }
        return RES_OK;

    }

    return RES_PARERR;
}
#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

#if _USE_IOCTL
DRESULT disk_ioctl (
    BYTE pdrv,        /* Physical drive nmuber (0..) */
    BYTE cmd,        /* Control code */
    void *buff        /* Buffer to send/receive control data */
)
{
    DRESULT res;


    switch (pdrv) {
    case EX_FLASH :
            switch(cmd)
        {
            case CTRL_SYNC:
                res = RES_OK; 
                break;     
            case GET_SECTOR_SIZE:
                *(WORD*)buff = FLASH_SECTOR_SIZE;
                res = RES_OK;
                break;     
            case GET_BLOCK_SIZE:
                *(WORD*)buff = FLASH_BLOCK_SIZE;
                res = RES_OK;
                break;     
            case GET_SECTOR_COUNT:
                *(DWORD*)buff = FLASH_SECTOR_COUNT;
                res = RES_OK;
                break;
            default:
                res = RES_PARERR;
                break;
        }

    }

    return res;
}
#endif
/*
*获取时间
*/
DWORD get_fattime (void)
{                 
    return 0;
}               

3 测试文件系统

测试实利:

#if 1
FATFS fs;           /* Filesystem object */
FIL fil;            /* File object */
FRESULT res;        /* API result code */
UINT bw;            /* Bytes written */
BYTE mm[50];
UINT i;
uint16_t f_size;
#endif
#if 0
uint8_t w25qWrite[512] ={0x55};
uint8_t w25qRead[512] ={0};
#endif
#if 1
void fs_test(void)
{
        
    /* 挂载文件系统 */
    res = f_mount(&fs, "0:", 0);
    if (res)
    {
        
    }
    else
    {
        
    }   
#if  1        
    /* 格式化文件系统 */
    res = f_mkfs("0:", 0 ,4096);//"0:"是卷标,来自于 #define SPI_FLASH        0
    if (res)
    {
        
        return ;
    }
    else
    {
        
    } 
#endif    
        res = f_mount(&fs, "0:", 0);
    if (res)
    {
        
    }
    else
    {
        
    } 
    /* Create a file as new */
        res = f_open(&fil, "0:/test.txt", FA_CREATE_NEW|FA_WRITE|FA_READ);
    if (res)
    {
        
    }
    else
    {
        
    }
    /* Write a message */
    res = f_write(&fil, "Hello,World!", 12, &bw);
    
    if (bw == 12)
    {
        
    }
    else
    {
        
    }
    //res = f_size(&fil);
    
    memset(mm,0x0,50);
    f_lseek(&fil,0);
    f_size = f_read(&fil,mm,12,&i);
    if (res == FR_OK)
    {

    }
    else
    {
        
    }
    /* Close the file */
    f_close(&fil);
    /*卸载文件系统*/
    f_mount(0, "0:", 0);
}
#endif
int main(void)
{   
   
    W25QXX_Init();
    //系统主频初始化
    W25Q_Enable();
#if  0
    memset(w25qWrite,0x55,512);
    W25QXX_Write(w25qWrite,0x00,512);
    W25QXX_Read(w25qRead,0x00,512);
#endif    
    fs_test();
    while(1);
    
}           

总结

在移植的过程中也是遇到了很多问题,前期准备非常重要,准备工作全了,其他的也就很容易解决,flash  W25Q一个扇区是4K 对RAM要求至少是4K 空间大小缓存,如果对SD卡扇区512 字节,RAM 要求512字节做为缓存大小

移植之前,一定先要对flash 进行读写操作下,向flash 中写入4K字节,并读取出来做下对比

MSP430 读数据前要先写一个时钟,然后再读寄存器,这一点与STM32 存在点区别

如:

W25QXX_WriteByte(0xFF);

 Temp = USCI_B_SPI_receiveData(USCI_B3_BASE);

写数据时,调用完一个写函数,做一个时钟的延时,否则容易写入失败

  USCI_B_SPI_transmitData(USCI_B3_BASE, byte);

   __delay_cycles(1);   //延时1个时钟,否则写入失败