精华内容
下载资源
问答
  • FAT文件系统分为三层,如下图所示。 1.底层接口,包括存储媒介读/写接口(disk I/O)和供给文件创建修改时间的实时时钟,需要我们根据平台和存储介质编写移植代码。 2.中间层FATFS模块,实现了FAT 文件读/写协议。...

    一.介绍
    FAT文件系统分为三层,如下图所示。

    在这里插入图片描述
    1.底层接口,包括存储媒介读/写接口(disk I/O)和供给文件创建修改时间的实时时钟,需要我们根据平台和存储介质编写移植代码。
    2.中间层FATFS模块,实现了FAT 文件读/写协议。FATFS模块提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。
    3.最顶层是应用层,使用者无需理会FATFS的内部结构和复杂的FAT 协议,只需要调用FATFS模块提供给用户的一系列应用接口函数,如f_open,f_read,f_write 和f_close等,就可以像在PC 上读/写文件那样简单。
    二、移植
    1.从官网下载合适的版本的软件(http://elm-chan.org/fsw/ff/00index_e.html),本次使用FatFs R0.13b
    2.把代码合并到工程中,放到一个新建文件夹下。
    在这里插入图片描述

    3.我们需要为diskio. c文件下填充下列六个函数的操作代码
    disk_status-获取设备状态
    disk_initialize-初始化设备
    disk_read-读取数据
    disk_write-写入数据
    disk_ioctl-控制设备相关的功能
    get_fattime-获取当前时间
    (1)本次使SPI FLASH 为MX25L6406E,先添加其驱动调用的头文件。
    修改以下代码,根据使用Flash数据手册修改

    #define DEV_SPIFLASH		0	/* Example: Map SPI Flash to physical drive 0 */
    
    #define FLASH_SECTOR_SIZE 	(4*1024)   //扇区大小
    #define FLASH_BLOCK_SIZE	16                //一个块有多少扇区
    const unsigned short int FLASH_SECTOR_COUNT = 640; //2.5M,一个使用多少扇区用于FAT文件系统
    

    (2)状态函数

    DSTATUS disk_status (
    	BYTE pdrv		/* Physical drive nmuber to identify the drive */
    )
    {
    	DSTATUS stat;
    	int result;
    
    	switch (pdrv) {
            case DEV_SPIFLASH:return RES_OK;
    	}
    	return STA_NOINIT;
    }
    

    (3)初始化函数

    DSTATUS disk_initialize (
    	BYTE pdrv				/* Physical drive nmuber to identify the drive */
    )
    {
    	DSTATUS stat;
    	int result;
    
    	switch (pdrv) {
    	case DEV_SPIFLASH :
         MX25LXXHal_PinInit();//引脚初设化
         MX25LXXHal_SpiInit();//芯片初设化
    		return RES_OK;
    	}
    	return STA_NOINIT;
    }
    

    (4)读函数

    /*-----------------------------------------------------------------------*/
    /* 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,	/* Start sector in LBA */
    	UINT count		/* Number of sectors to read */
    )
    {
    	DRESULT res;
    	int result;
        int i = 0;
        
    	switch (pdrv) {
    	case DEV_SPIFLASH :
    		for(i = 0; i < count;i++)
    		{
    			MX25L1602_RD(sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE,buff);
    			sector++;
    			buff+=FLASH_SECTOR_SIZE;
    		}
    		return RES_OK;
    	}
    
    	return RES_PARERR;
    }
    

    (5)写函数

    DRESULT disk_write (
    	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
    	const BYTE *buff,	/* Data to be written */
    	DWORD sector,		/* Start sector in LBA */
    	UINT count			/* Number of sectors to write */
    )
    {
    	DRESULT res;
    	int result;
        unsigned int s;
    	switch (pdrv) {
    	case DEV_SPIFLASH :
            for(s = sector;s <= sector+count-1;s++)
    		{ 
                MX25L1602_Erase(s, s); // 先檫除扇区,再写入数据
            }
            //MX25L1602_Erase(sector, sector+count-1);
    		for(;count>0;count--)
    		{            
    			MX25L1602_WR(sector*FLASH_SECTOR_SIZE, (u8*)buff,FLASH_SECTOR_SIZE);
    			sector++;
    			buff+=FLASH_SECTOR_SIZE;
    		}
    		return RES_OK;
    	}
    
    	return RES_PARERR;
    }
    

    (6)磁盘控制函数

    DRESULT disk_ioctl (
    	BYTE pdrv,		/* Physical drive nmuber (0..) */
    	BYTE cmd,		/* Control code */
    	void *buff		/* Buffer to send/receive control data */
    )
    {
    	DRESULT res;
    	int result;
    
    	switch (pdrv) {
    	case DEV_SPIFLASH :
    	    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;
    }
    

    4.应用层的调用
    挂载文件系统后即可调用文件操作函数,写函数最好在开辟个缓存,累计到一个扇区大小的数据再存入文件系统,这样可以做好负载均衡,避免flash使用寿命缩短。

    /**
     * 文件系统挂载函数
     */
    int fatfs_fileSystemReset()
    {
        FRESULT res = 0;
        
        res = 1;
        if(res != 0)
        {   printf("mount fail\n");
            res = f_mkfs("0:", FM_FAT, 0, gFsWork, sizeof gFsWork);//在逻辑驱动器上创建FAT卷
            if(res == 0)
            {   printf("mkfs sus\n");
                res = f_mount (&sysFs,"0:",1);//先挂载才能使用
                if(res == 0)
                {   printf("mount susu2\n");
                    gFsInited = 1;
                    return 0;
                }
                else {
                     printf("mount fail2\n");
                    return -1;   }
            }
            else  {   printf("mkfs fail\n");
                return -1;  }
        }
        else
            gFsInited = 1;
        return 0;
    }
    

    5.总结
    FAT文件比较小巧,适合在相对资源没有那么丰富的芯片上使用,相对于直接对FLASH操作,使用文件系统大大简化编程的难度,操作起来更加方便。

    展开全文
  • 51单片机上移植FAT文件系统,可以成功读取FAT32文件系统的SD卡里面的文件.zip
  • 在stm8S208上移植FAT文件系统,实测OK可用,而且速度还可以
  • stm32F407 + FreeRTOS + FAT 文件系统移植

    千次阅读 2020-06-19 18:32:13
    文件目录 :FreeRTOSv10.2.1_191129\FreeRTOS-Labs\Source\FreeRTOS-Plus-FAT 整个拷贝到工程。 所需C文件:1.上图 ff_xx.c, (ff_locking.org 删除不需要)。 2.\portable\common\ff_ramdisk.c。 3.\portable\S.....

    FreeRTOS 版本: FreeRTOSv10.2.1

    HAL 版本:  Keil.STM32F4xx_DFP_HAL.2.13.0

    版本无所谓,只是记录下。

    文件目录 :FreeRTOSv10.2.1_191129\FreeRTOS-Labs\Source\FreeRTOS-Plus-FAT 整个拷贝到工程。

    所需C文件:1.上图  ff_xx.c, (ff_locking.org 删除不需要)。 2.\portable\common\ff_ramdisk.c。

    3.\portable\STM32F4xx\ff_sddisk.c 和 stm32f4xx_hal_sd.c(使用提供的 hal sd库文件,替换工程hal_sd文件,版本不同函数会不同,所以用提供的就行)。

    添加头文件目录:\include 、\portable\common、\portable\STM32F4xx。(inlcude目录下)

    文件添加完编译会提示:

    所以跟TCP移植一样,官方提供FreeRTOSFATConfigDefaults.h默认配置,新建FreeRTOSFATConfig.h 添加自己的配置。

    这些配置在官网介绍,都需要添加:

    https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Embedded_File_System_Configuration.html

    详细配置见链接

    (FreeRTOSFATConfig.h)     https://blog.csdn.net/wy212670/article/details/106859340

    配置文件完编译:

    会报错  ff_old_config_defines.h 文件 , 既然是old,不需要。去include目录删除,同时在ff_headers.h中删除头文件引用, 

    编译:(麻烦开始!!!)报很多错和警告。一个个修改。

    双击定位到 ff_stdio.h

    configNUM_THREAD_LOCAL_STORAGE_POINTERS   5  大于3就行。

    编译:

    把ff_dev_support.c文件屏蔽不编译。

    编译:很多结构体未定义。

    主要是头文件引用问题,ff_sddisk.c 和 stm32f4xx_hal_sd.c 最好都引用  #include "stm32f4xx_hal_sd.h",

    然后在ff_headers.h 中引用 #include "stm32f4xx_hal.h",这样就没问题了。

    编译:

    就剩7个错误。

    主要是SD模块函数开关没打开,在stm32f4xx_hal_sd.c 打开 HAL_SD_MODULE_ENABLED

    在FreeRTOSFATConfig.h中 定义就行了,#define HAL_SD_MODULE_ENABLED。

    编译:

    又是一堆警告和错误,不过都很明显,主要是调用了 stm32f4xx_ll_sdmmc.c MMC库文件函数名和参数不同。

    把stm32f4xx_hal_sd.c 中 SDIO_ConfigData 函数名 全部替换成 SDIO_ConfigData。

    把 SDIO_GetResponse(SDIO_RESPx)函数多加一个参数 SDIO_GetResponse(hsd->Instance, SDIO_RESPx),全部替换。

    编译:

    就剩一个错了。

    在ff_sddisk.c   回调函数用不到,实现一个空函数就行

    编译没有错了!!!

     

    就可以测试了,插上SD卡 , 打开串口。

    在main.c调用 FF_SDDiskInit("/"); 

    如果打印初始化失败,主要是SD卡 检测不到卡。

    可以屏蔽代码,ff_sddisk.c 中 prvSDMMCInit(),

    (不一定要屏蔽,自己检查代码和SD卡cd检查引脚,根据PCB,没用到CD线,就可以屏蔽)

    需要注意的是初始化SD卡 FF_SDDiskInit()-> prvSDMMCInit( 0 )->vGPIO_SD_Init() 函数中

    根据开发板SD卡 数据线是四线还是三线 初始化,我的是4线,打开 BUS_4BITS。

    还有在配置文件中 ,文件名长度要尽量小,我设置200最后ff_open() molloc卡死,改成50。

    #define ffconfigMAX_FILENAME                                        (49+1)

    最后编译,

     

    证明初始化成功,能读取卡信息,能挂载。能否读写还需要写代码测试。

    读写测试:

    ff_mkdir("/wy") 创建文件夹。

    ff_fopen( pcFileName, "w" )打开文件流(ff_fopen()未创建文件会自动创建文件)。

    ff_fwrite( pcRAMBuffer, fsRAM_BUFFER_SIZE, 1, pxFile )读取文件,具体参考官方介绍。

    代码:https://blog.csdn.net/wy212670/article/details/106941394

    创建文件夹成功,创建文件写入成功,读取文件成功。

    展开全文
  • 可以在神舟一号开发板上运行,但只是简单的移植
  • 硬盘 FAT 详细介绍,做文件系统移植的朋友可以看下
  • FAT32文件系统在STM32f103的移植,裸机移植,并不包含操作系统,还有一些移植的技巧和步骤。包括源码
  • 摘 要:介绍了TI公司出品的DSP芯片TMS320F206对基于FAT32文件系统的文件读写和管理技术以及其对IDE硬盘的读写技术,着重介绍了文件的读写部分并且给出了该系统的软件流程图,简要介绍了硬件接口部分和对IDE硬盘的...
  • 一、环境介绍 主控MCU: STM32F103ZET6 STM32程序开发IDE: keil5 STM32程序风格: 采用寄存器方式开发,注释齐全,执行效率高,方便移植 ...这篇文章主要演示FATFS文件系统如何移植到自己的工程,并完成文件的读写...

    一、环境介绍

    主控MCU: STM32F103ZET6 

    STM32程序开发IDE: keil5

    STM32程序风格:  采用寄存器方式开发,注释齐全,执行效率高,方便移植

    硬件包含:  一块STM32F103ZET6系统板、一个SPI接口的SD卡卡槽模块、一张SD卡

    工程完整源码下载地址:  https://download.csdn.net/download/xiaolong1126626497/19687693

     

    这篇文章主要演示FATFS文件系统如何移植到自己的工程,并完成文件的读写。

    因为SD卡采用的是SPI模拟时序,所以,其他单片机一样可以照着移植,代码都可以复制粘贴的。

     

     

     

    二、FATFS文件系统介绍

    2.1 FATFS简介

    FatFs 是一种完全免费开源的 FAT 文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准C 语言编写,所以具有良好的硬件平台独立性,可以移植到 8051、 PIC、 AVR、 SH、 Z80、 H8、 ARM 等系列单片机上而只需做简单的修改。它支持 FATl2、 FATl6 和 FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对 8 位单片机和 16 位单片机做了优化。

    2.2 特点

    1.  Windows兼容的FAT文件系统
    2. 不依赖于平台,易于移植
    3. 代码和工作区占用空间非常小
    4.  多种配置选项
    5. 多卷(物理驱动器和分区)
    6.  多ANSI/OEM代码页,包括DBCS
    7. 在ANSI/OEM或Unicode中长文件名的支持
    8. RTOS的支持
    9. 多扇区大小的支持
    10. 只读,最少API,I/O缓冲区等等

    2.3 移植性

    fatfs模块是ANSI C(C89)编写的。 没有平台的依赖, 编译器只要符合ANSI C标准就可以编译。

    fatf模块假设大小的字符/短/长8/16/32位和int是16或32位。 这些数据类型在integer.h文件中定义。这些数据类型在大多数的编译器中定义都符合要求。 如果现有的定义与编译器有任何冲突发生时,需要自己解决。

    2.4 源码下载

    下载地址:http://elm-chan.org/fsw/ff/00index_e.html

    FATFS有两个版本,一个大版本,一个小版本。小版本主要用于8位机(内存小)使用。

    下载图:

    2.5 FATFS源码文件介绍

    将下载的源码解压后可以得到两个文件夹: doc 和 src。 doc 里面主要是对 FATFS 的介绍(离线文档—英文和日文),而 src 里面才是我们需要的源码。

    其中,与平台无关的是:

    ffconf.h     FATFS配置文件

    ff.h        应用层头文件

    ff.c        应用层源文件

    diskio.h    硬件层头文件

    interger.h   数据类型定义头文件

    option     可选的外部功能(比如支持中文等)

    与平台相关的代码:

    diskio.c     底层接口文件(需要用户提供)

    FATFS 模块在移植的时候,我们一般只需要修改 2 个文件,即 ffconf.h 和 diskio.c。

    FATFS模块的所有配置项都是存放在 ffconf.h 里面,我们可以通过配置里面的一些选项,来满足自己的需求。

    FATFS最顶层是应用层,使用者无需理会 FATFS 的内部结构和复杂的 FAT 协议,只需要调用FATFS 模块提供给用户的一系列应用接口函数,如 f_open, f_read, f_write 和 f_close 等,就可以像在 PC 上读/写文件那样简单。

    中间层 FATFS 模块, 实现了 FAT 文件读/写协议。 FATFS 模块提供的是 ff.c 和 ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。

    需要我们编写移植代码的是 FATFS 模块提供的底层接口,它包括存储媒介读/写接口 ( disk、I/O) 和供给文件创建修改时间的实时时钟。

     

    三、 移植FATFS文件系统

    移植之前,首先得准备一个能正常编译的工程,并且工程里有SD卡的驱动代码,提供了读写扇区这些函数才能进行FATFS文件系统的正常移植。

    关于如何编写SD卡驱动,SD卡的时序介绍、命令介绍等知识点下篇文章再讲解。这篇文章重点是FATFS文件系统的移植过程。

    3.1  新建工程

    FATFS文件系统源码下载下来,解压之后,移植修改的步骤如下:

    打开KEIL工程,添加FATFS文件源码:

    加入.h文件主要是方便配。cc936.c 用于支持中文。

     

    3.2  修改diskio.c文件

    注释掉现在不需要的用到的文件,因为我们现在用的是SD卡,与USB,ATA,MMC卡没关系。

    并加入一个新的宏 :

    #define  SD  0

    定义SD卡的物理驱动器号为0。 

    修改 disk_status函数,该函数主要是用来获取磁盘状态。现在未用到,可以直接函数体内代码删除。

    修改截图:

    代码示例:

    #include "diskio.h"           /* fatf底层API */

    #include "sd.h"                      /* SD卡驱动头文件  */

    /* 定义每个驱动器的物理驱动器号*/

    #define SD    0

     

    /*-----------------------------------------------------------------------*/

    /* 获取设备(磁盘)状态                                                     */

    /*-----------------------------------------------------------------------*/

     

    DSTATUS disk_status (

            BYTE pdrv             /* 物理驱动识别 */

    )

    {

       return 0;  //该函数现在无需用到,直接返回0

    }

    修改disk_initialize函数,添加SD卡的初始化,其他不用到的代码直接删掉,该函数成功返回0,失败返回1。

    修改截图:

    代码示例:

    /*-----------------------------------------------------------------------*/

    /* 初始化磁盘驱动                                                        */

    /*-----------------------------------------------------------------------*/

     

    DSTATUS disk_initialize (

            BYTE pdrv                             /* 物理驱动识别 */

    )

    {

            DSTATUS stat;

            int result;

     

            switch (pdrv) {

            case SD :            //选择SD

                    stat=SD_Init();   //初始化SD-用户自己提供

            }

            if(stat)return STA_NOINIT;  //磁盘未初始化

            return 0; //初始化成功

    }

    修改disk_read函数,加入SD卡读任意扇区的函数(需要用户自己提供),其他不用到的选项可以删掉。

    修改代码如下:

    /*-----------------------------------------------------------------------*/

    /* 读扇区                                                                */

    /*-----------------------------------------------------------------------*/

    DRESULT disk_read (

            BYTE pdrv,            /* 物理驱动编号 - 范围0-9*/

            BYTE *buff,           /* 数据缓冲区存储读取数据 */

            DWORD sector,  /* 扇区地址*/

            UINT count             /* 需要读取的扇区数*/

    )

    {

            DRESULT res;

            int result;

            switch (pdrv) {

                    case SD:

                      res=SD_Read_Data((u8*)buff,sector,count);  //SD扇区函数--用户提供

                      return res; //在此处可以判错误

            }

            return RES_PARERR;  //无效参数

    }

    修改disk_write 函数,添加写扇区函数:

    代码:

    /*-----------------------------------------------------------------------*/

    /* 写扇区                                                                */

    /*-----------------------------------------------------------------------*/

     

    #if _USE_WRITE

    DRESULT disk_write (

            BYTE pdrv,                      /* 物理驱动号*/

            const BYTE *buff,        /* 要写入数据的首地址 */

            DWORD sector,                 /* 扇区地址 */

            UINT count                        /* 扇区数量*/

    )

    {

            DRESULT res;

            int result;

     

            switch (pdrv) {

                    case SD:

                            res=SD_Write_Data((u8*)buff,sector,count); //写入扇区

                      return res;

            }

            return RES_PARERR;  //无效参数

    }

    #endif

    修改disk_ioctl 函数,填充ioctl命令功能。这些功能是标准的命令,在diskio.h有定义。

    代码如下:

    /*-----------------------------------------------------------------------*/

    /* 其他函数                                              */

    /*-----------------------------------------------------------------------*/

     

    #if _USE_IOCTL

    DRESULT disk_ioctl (

            BYTE pdrv,            /* 物理驱动号 */

            BYTE cmd,               /* 控制码  */

            void *buff               /* 发送/接收数据缓冲区地址 */

    )

    {

            DRESULT res;

            int result;

     

            switch (pdrv) {

                    case SD:

                             switch(cmd)

                             {

                                     case CTRL_SYNC:      //等待写过程

                                             SD_CS(0);          //选中SD

                                             if(SD_Wait_Ready())result = RES_ERROR;/*等待卡准备好*/

                                         else res = RES_OK;     //成功

                                             SD_CS(1);            //释放SD

                            break;     

                                     

                             case GET_SECTOR_SIZE://获取扇区大小

                               *(DWORD*)buff = 512;

                            res = RES_OK;     //成功

                            break;     

                                     

                             case GET_BLOCK_SIZE:    //获取块大小

                                    *(WORD*)buff = 8;      //块大小(扇区为单位),一块等于8个扇区

                             res = RES_OK;

                             break;

                                     

                             case GET_SECTOR_COUNT: //获取总扇区数量

                            *(DWORD*)buff = SD_Get_Sector_Count();

                            res = RES_OK;

                            break;

                                     

                            default:  //命令错误

                            res = RES_PARERR;

                            break;

                             }

                    return res;

            }

            return RES_PARERR;  //返回状态

    }

    diskio.c 文件修改完整代码:

    /*-----------------------------------------------------------------------*/

    /* 低级别磁盘I / O模块框架fatf(C)ChaN)2014 

    *存储控制模块fatf模块定义了一个API      */

    /*-----------------------------------------------------------------------*/

     

    #include "diskio.h"           /* fatf底层API */

    #include "sd.h"                      /* SD卡驱动头文件  */

     

    /* 定义每个驱动器的物理驱动器号*/

    #define SD    0

     

    /*-----------------------------------------------------------------------*/

    /* 获取设备(磁盘)状态                                                     */

    /*-----------------------------------------------------------------------*/

     

    DSTATUS disk_status (

            BYTE pdrv             /* 物理驱动识别 */

    )

    {

       return 0;  //该函数现在无需用到,直接返回0

    }

     

     

     

    /*-----------------------------------------------------------------------*/

    /* 初始化磁盘驱动                                                        */

    /*-----------------------------------------------------------------------*/

     

    DSTATUS disk_initialize (

            BYTE pdrv                             /* 物理驱动识别 */

    )

    {

            DSTATUS stat;

            int result;

     

            switch (pdrv) {

            case SD :           //选择SD

                    stat=SD_Init();   //初始化SD-用户自己提供

            }

            if(stat)return STA_NOINIT;  //磁盘未初始化

            return 0; //初始化成功

    }

     

     

    /*-----------------------------------------------------------------------*/

    /* 读扇区                                                                */

    /*-----------------------------------------------------------------------*/

     

    DRESULT disk_read (

            BYTE pdrv,            /* 物理驱动编号 - 范围0-9*/

            BYTE *buff,           /* 数据缓冲区存储读取数据 */

            DWORD sector,      /* 扇区地址*/

            UINT count             /* 需要读取的扇区数*/

    )

    {

            DRESULT res;

            int result;

     

            switch (pdrv) {

                    case SD:

                            res=SD_Read_Data((u8*)buff,sector,count);  //SD扇区函数--用户提供

                      return res; //在此处可以判错误

            }

            return RES_PARERR;  //无效参数

    }

     

     

     

    /*-----------------------------------------------------------------------*/

    /* 写扇区                                                                */

    /*-----------------------------------------------------------------------*/

     

    #if _USE_WRITE

    DRESULT disk_write (

            BYTE pdrv,                      /* 物理驱动号*/

            const BYTE *buff, /* 要写入数据的首地址 */

            DWORD sector,                /* 扇区地址 */

            UINT count                       /* 扇区数量*/

    )

    {

            DRESULT res;

            int result;

     

            switch (pdrv) {

                    case SD:

                            res=SD_Write_Data((u8*)buff,sector,count); //写入扇区

                      return res;

            }

            return RES_PARERR;  //无效参数

    }

    #endif

     

     

    /*-----------------------------------------------------------------------*/

    /* 其他函数                                              */

    /*-----------------------------------------------------------------------*/

     

    #if _USE_IOCTL

    DRESULT disk_ioctl (

            BYTE pdrv,            /* 物理驱动号 */

            BYTE cmd,               /* 控制码  */

            void *buff               /* 发送/接收数据缓冲区地址 */

    )

    {

            DRESULT res;

            int result;

     

            switch (pdrv) {

                    case SD:

                             switch(cmd)

                             {

                                     case CTRL_SYNC:      //等待写过程

                                             SD_CS(0);          //选中SD

                                             if(SD_Wait_Ready())result = RES_ERROR;/*等待卡准备好*/

                                           else res = RES_OK;     //成功

                                              SD_CS(1);          //释放SD

                                 break;   

                                     

                                     case GET_SECTOR_SIZE://获取扇区大小

                                    *(DWORD*)buff = 512;

                            res = RES_OK;     //成功

                            break;     

                                     

                                     case GET_BLOCK_SIZE:  //获取块大小

                                    *(WORD*)buff = 8;      //块大小--一块等于8个扇区

                            res = RES_OK;

                            break;

                                     

                                     case GET_SECTOR_COUNT: //获取总扇区数量

                            *(DWORD*)buff = SD_Get_Sector_Count();

                            res = RES_OK;

                            break;

                                     

                                     default:  //命令错误

                            res = RES_PARERR;

                            break;

                             }

                    return res;

            }

            return RES_PARERR;  //返回状态

    }

    #endif

     

     

    //返回FATFS时间

    //获得时间 

    DWORD get_fattime (void)

    {     

            return (DWORD)(2017-1980)<<25|    //

                                                        7<<21|    //

                                                       27<<16|    //

                                       12<<11|    //

                                        13<<5|    //

                                           14;    //

    }

     

     

    /*

    Return Value

    Currnet local time is returned with packed into a DWORD value. The bit field is as follows:

    bit31:25

    Year origin from the 1980 (0..127)

    bit24:21

    Month (1..12)

    bit20:16

    Day of the month(1..31)

    bit15:11

    Hour (0..23)

    bit10:5

    Minute (0..59)

    bit4:0

    Second / 2 (0..29)

    */

     

    3.3 修改ffconf.h文件

    需要注意的一些宏配置:

    #define _CODE_PAGE  936   //采用中文GBK编码       (64)

    #define    _USE_LFN     3     //动态的堆上工作             93行)

    #define    _MAX_LFN   255   /*_USE_LFN选项开关LFN(长文件名)特性。

    #define _VOLUMES      1     /* 支持的磁盘数量(逻辑驱动器)。 */   (142行)

    #define    _MIN_SS                512                                  (165行)

    #define    _MAX_SS              512   /*这些选项配置支持扇区大小的范围。(512,1024, 4096*/ 

    #define _FS_NORTC         0    /*启用RTC时间功能*/   (202行)

    #define _NORTC_MON     1

    #define _NORTC_MDAY     1

    #define _NORTC_YEAR       2015 //年 

    /*需要实现:get_fattime()函数*/

     

    ffconf.h 文件源码(讲解):

    /*---------------------------------------------------------------------------/

    /  FatFs - FAT文件系统模块配置文件  R0.11a (C)ChaN, 2015

    /---------------------------------------------------------------------------*/

     

    #define _FFCONF 64180       /* 版本识别*/

     

    /*---------------------------------------------------------------------------/

    / 功能配置

    /---------------------------------------------------------------------------*/

     

    #define _FS_READONLY     0

    /* 这个选项开关只读配置。(0:/写或1:只读)   

    /只读配置删除编写API函数,f_write(),f_sync(),   

    / f_unlink(),f_mkdir(),f_chmod(),f_rename(),f_truncate(),f_getfree()   

    /写和可选的功能. */

     

     

    #define _FS_MINIMIZE        0

    /*此选项定义删除一些基本的API函数极小化水平。  

    /   

    / 0:所有基本功能都是激活的。  

    / 1:f_stat(),f_getfree(),f_unlink(),f_mkdir(),f_chmod(),f_utime(),   

    / f_truncate()f_rename()函数删除。  

    / 2:f_opendir(),f_readdir()f_closedir()中除了1。  

    / 3:f_lseek()函数删除除了2*/

     

     

    #define    _USE_STRFUNC  1

    /*这个选项开关字符串函数,f_gets(),f_putc(),f_puts()和 

    / f_printf()。  

    /   

    / 0:禁用字符串函数。  

    / 1:启用没有LF-CRLF转换。  

    / 2:启用LF-CRLF(回车换行)转换。*/

     

     

    #define _USE_FIND              0

    /*这个选项开关过滤目录读取特性和相关功能,   

    / f_findfirst()f_findnext()(0:禁用或1:启用)*/

     

     

    #define    _USE_MKFS         1

    /* 这个选项开关f_mkfs()函数。(0:禁用或1:启用) */

     

     

    #define    _USE_FASTSEEK 1

    /* 这个选项开关快速寻求功能。(0:禁用或1:启用) */

     

     

    #define _USE_LABEL           1

    /*   磁盘卷标这个选项开关功能,f_getlabel()f_setlabel()。  

    /(0:禁用或1:启用) */

     

     

    #define    _USE_FORWARD 0

    /*  这个选项开关f_forward()函数。(0:禁用或1:启用)   

    /启用它,_FS_TINY需要设置为1. */

     

     

    /*---------------------------------------------------------------------------/

    / 语言环境和名称空间配置

    /---------------------------------------------------------------------------*/

     

    #define _CODE_PAGE  936  //采用中文GBK编码

    /* 这个选项指定OEM代码页在目标系统上使用。  

    /不正确的代码页的设置会导致文件打开失败.

    /

    /   1   - ASCII (没有扩展字符。Non-LFN cfg。只有)

    /   437 - U.S.

    /   720 - 阿拉伯语

    /   737 - 希腊语;

    /   771 - 阿富汗

    /   775 - 波罗的海

    /   850 - 拉丁1

    /   852 - 拉丁2

    /   855 - 西里尔字母

    /   857 - 土耳其语

    /   860 - 葡萄牙语

    /   861 - 冰岛语

    /   862 - 希伯来人

    /   863 - 加拿大法语

    /   864 - 阿拉伯语

    /   865 - 日耳曼民族的

    /   866 - 俄语

    /   869 - 希腊 2

    /   932 - 日本人 (DBCS)

    /   936 - 简体中文(DBCS)

    /   949 - 韩国人 (DBCS)

    /   950 - 繁体中文(DBCS)

    */

     

     

    #define    _USE_LFN     3 //动态的堆上工作

    #define    _MAX_LFN   255

    /*_USE_LFN选项开关LFN(长文件名)特性。

    /

    / 0:禁用LFN特性。_MAX_LFN没有影响。  

    / 1:启用LFN BSS静态工作缓冲区。总是不是线程安全的。  

    / 2:启用LFN与动态缓冲栈上的工作。  

    / 3:使LFN与动态缓冲区在堆上工作。

    /

    当启用LFN(长文件名)特性,Unicode(选项/ unicode.c)必须处理功能  

    /被添加到项目中。LFN工作缓冲区占用(_MAX_LFN + 1)* 2字节。  

    /当使用堆栈缓冲区,照顾堆栈溢出。当使用堆  

    /工作缓冲区内存,内存管理功能,ff_memalloc()和  

    / ff_memfree(),必须添加到项目中。 */

     

     

    #define    _LFN_UNICODE   0

    /* 这个选项开关字符编码的API(0:ANSI / OEM1:Unicode)   

    路径名/使用Unicode字符串,并设置_LFN_UNICODE启用LFN特性  

    /1。这个选项也会影响行为的字符串的I / O功能。

    */

     

     

    #define _STRF_ENCODE     3

    /* _LFN(长文件名)_UNICODE1,这个选项选择文件的字符编码  

    /通过字符串读取/写入I /O功能,f_gets(),f_putc(),f_putsf_printf().

    /

    /  0: ANSI/OEM

    /  1: UTF-16LE

    /  2: UTF-16BE

    /  3: UTF-8

    /

    / _LFN_UNICODE = 0,该选项没有影响。*/

     

    #define _FS_RPATH     0

    /* 这个选项配置相对路径的功能。  /   

    / 0:禁用相对路径特性和删除相关功能。  

    / 1:启用相对路径特性。f_chdir()f_chdrive()是可用的。  

    / 2:f_getcwd()函数可用除了1。  /   

    /注意,目录项读通过f_readdir()这个选项。

    */

     

    /*---------------------------------------------------------------------------/

    / 驱动/卷配置

    /---------------------------------------------------------------------------*/

     

     

    #define _VOLUMES      1

    /* 支持的磁盘数量(逻辑驱动器) */

     

     

    #define _STR_VOLUME_ID 0

    #define _VOLUME_STRS        "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"

    /* STR_VOLUME_ID选项开关卷ID字符串功能。  

    /_STR_VOLUME_ID设置为1,也可以使用预先定义的字符串在路径名称/数量。

    为每个_VOLUME_STRS定义驱动ID字符串  

    /逻辑驱动器。条目的数量必须等于_VOLUMES。有效字符  

    /驱动ID字符串:a - z0 - 9*/

     

     

    #define    _MULTI_PARTITION  0

    /*  这个选项开关多分区的特性。在默认情况下(0),每个逻辑驱动器  

    /号绑定到相同的物理驱动器号  

    /物理驱动器将被安装。当启用分区特性(1),   

    /每个逻辑驱动器号是绑定到任意物理驱动器和分区  

    /中列出VolToPart[]。还f_fdisk()函数可用. */

     

     

    #define    _MIN_SS                512

    #define    _MAX_SS              512

    /*  这些选项配置支持扇区大小的范围。(512,1024,   

    / 20484096)总是为大多数系统设置两个512,卡和所有类型的内存  

    /硬盘。但是可能需要更大的值为车载闪存和一些  

    /类型的光学媒体。当_MAX_SS大于_MIN_SS,fatf配置  

    /变量扇区大小和GET_SECTOR_SIZE命令必须执行  disk_ioctl()函数. */

     

     

    #define    _USE_TRIM  0

    /* 这个选项开关ATA-TRIM特性。(0:禁用或1:启用)   

    /启用削减特性,也应该实现CTRL_TRIM命令  

    / disk_ioctl()函数。*/

     

     

    #define _FS_NOFSINFO       0

    /*   

    如果你需要知道正确的自由空间体积FAT32,设置一些0   

    /选项,f_getfree()函数在第一次后体积将迫使山  

    /全脂肪扫描。位1控制使用的集群数量分配。  /   

    / bit0 = 0:使用免费的集群计算FSINFO如果可用。  

    / bit0 = 1:不相信自由FSINFO集群计算。  

    / bit1 = 0:最后使用集群可用FSINFO如果数量分配。  

    / bit1 = 1:不相信最后分配FSINFO集群数量.

    */

     

     

     

    /*---------------------------------------------------------------------------/

    / 系统配置列表

    /---------------------------------------------------------------------------*/

     

    #define    _FS_TINY      0

    /* 这个选项开关小缓冲区配置。(0:正常或1:)   

    /小配置,文件对象的大小(FIL)_MAX_SS减少字节。而不是私人部门从文件对象,缓冲了  

    /公共部门缓冲文件系统中的对象(fatf)是用于该文件  

    /数据传输. */

     

     

    #define _FS_NORTC     0

    #define _NORTC_MON 1

    #define _NORTC_MDAY     1

    #define _NORTC_YEAR       2015 //

    /* _FS_NORTC选项开关时间戳的特性。如果系统没有/

     RTC函数或不需要有效的时间戳,_FS_NORTC 1设置为禁用/

     时间戳的特性。所有对象修改fatf将有一个固定的时间戳。/

      固定的时间定义为_NORTC_MON _NORTC_MDAY _NORTC_YEAR。  

     

    /当启用时间戳特性(_FS_NORTC = = 0),需要实现get_fattime()函数。  /

     添加到项目RTC读当前时间形式。_NORTC_MON,   /

    _NORTC_MDAY_NORTC_YEAR没有效果。  

    /这些选项没有影响只读配置(_FS_READONLY = = 1) */

     

     

    #define    _FS_LOCK     0

    /*  _FS_LOCK选项开关控制复制的文件打开的文件锁定功能  

    /和非法操作打开对象。这个选项_FS_READONLY时必须是0   

    /1。  /   

    / 0:禁用文件锁定功能。为了避免体积腐败、应用程序  

    /应该避免非法打开,删除和重命名的开放对象。  

    / > 0:启用文件锁定功能。值定义了多少文件/子目录  

    可以同时打开的/文件锁的控制之下。注意,这个文件独立于re-entrancy /锁功能。 */

     

     

     

    #define _FS_REENTRANT   0

    #define _FS_TIMEOUT         1000

    #define    _SYNC_t                 HANDLE

    /*  _FS_REENTRANT选项开关re-entrancy fatf(线程安全)   

    /模块本身。注意,不管这个选项,文件访问不同  

    /体积始终是凹角和音量控制功能,f_mount(),f_mkfs()   

    /f_fdisk()函数,总是不凹角。只有文件/目录的访问  

    /相同的体积是这个功能的控制。  

    /   

    / 0:禁用re-entrancy_FS_TIMEOUT_SYNC_t没有效果。  

    / 1:启用re-entrancy。还提供用户同步处理程序,   

    / ff_req_grant(),ff_rel_grant(),ff_del_syncobj()ff_cre_syncobj()   

    /函数,必须添加到项目中。样品中可用  

    /选项

    / syscall.c

    /

    /  _FS_TIMEOUT定义超时时间单位的滴答声。  

    / _SYNC_t定义了O

    / S依赖同步对象类型。例如处理、IDOS_EVENT *   

    / SemaphoreHandle_t. .O / S的头文件定义需要  

    /包括在ff.c的范围。 */

     

     

    #define _WORD_ACCESS    0

    /* _WORD_ACCESS选项是一个只有依赖于平台的选择。

    它定义了这个词/访问方法是用来体积上的数据。

    /

    / 0:逐字节的访问。总是兼容所有平台。  

    / 1:词的访问。不要选择这个,除非在下列条件。  

    /   

    / *地址对齐内存访问总是允许所有指令。  

    / *字节顺序的记忆是低位优先。  

    /   

    /如果是这样的情况,_WORD_ACCESS也可以减少代码的大小设置为1。  

    /下表显示允许设置某种类型的处理器。

    /

    /  ARM7TDMI   0   *2          ColdFire   0    *1         V850E      0    *2

    /  Cortex-M3  0   *3          Z80        0/1             V850ES     0/1

    /  Cortex-M0  0   *2          x86        0/1             TLCS-870   0/1

    /  AVR        0/1             RX600(LE)  0/1             TLCS-900   0/1

    /  AVR32      0   *1          RL78       0    *2         R32C       0    *2

    /  PIC18      0/1             SH-2       0    *1         M16C       0/1

    /  PIC24      0   *2          H8S        0    *1         MSP430     0    *2

    /  PIC32      0   *1          H8/300H    0    *1         8051       0/1

    /

     

    * 1:高位优先。  /

    * 2:不支持不连续的内存访问。  /

    * 3:一些编译器生成LDM(逻辑磁盘管理器 ) / STM mem_cpy(内存拷贝)函数。

    */

    3.4 实现动态内存分配函数与时间函数

    ff.h文件有动态内存的释放,动态内存申请,时间获取函数接口。

    在diskio.c文件实现函数功能:

    代码实现如下:

    //动态内存分配

    void* ff_memalloc (UINT msize)                      /* 分配内存块 */

    {

            return (void*)malloc(msize); //分配空间

    }

     

     

    //动态内存释放

    void ff_memfree (void* mblock)                       /* 空闲内存块 */

    {

            free(mblock);              //释放空间

    }

     

     

    //返回FATFS时间

    //获得时间 

    DWORD get_fattime (void)

    {     

            //Get_RTC_Timer(); //获取一次RTC时间

                    return (RTC_Timer.year-1980)<<25|   //

                              RTC_Timer.month<<21|  //

                           RTC_Timer.day<<16|    //

                           RTC_Timer.hour<<11|   //

                           RTC_Timer.minute<<5|  //

                           RTC_Timer.sec;        //

    }

     

    /*

    Return Value

    Currnet local time is returned with packed into a DWORD value. The bit field is as follows:

    bit31:25

    Year origin from the 1980 (0..127)

    bit24:21

    Month (1..12)

    bit20:16

    Day of the month(1..31)

    bit15:11

    Hour (0..23)

    bit10:5

    Minute (0..59)

    bit4:0

    Second / 2 (0..29)

    */

    3.5 修改堆栈空间

    完成了上述的修改,还需要修改堆栈空间,因为长文件支持需要占用堆空间。

    修改STM32启动文件如下:

    3.6 编译工程测试

    修改完毕之后,给开发板插上SD卡,调用API函数在SD卡创建一个文件,并写入数据,测试是否成功:

    #include "ff.h"

    FATFS fs;  // 用户定义的文件系统结构体

    FIL  file;  // 用户定义的文件系统结构体

    u8 buff[]="123 知识!!";

    int main(void)

    {

            u32 data;                //检测SD卡容量

            u8 i,res;

        LED_Init();              //LED灯初始化

        Delay_Init();

        KEY_Init();

        USART1_Init(72,115200);

        USART2_Init(36,115200);

        FLASH_Init();

              Set_Font_addr(); //字库地址初始化

              FSMC_SRAM_Init();

              LCD_Init();

              RTC_Init();     //RTC时钟初始化

              while(SD_Init())    //检测不到SD,SD相关硬件初始化

                    {

                            i=!i;

                            LCD_ShowString(60,150,200,16,16,"SD Card Error!  Please Check SD Card!!",0xf800);                                

                            Delay_ms(500);

                            LED1(i)//DS0闪烁

                    }

                   

           f_mount(&fs,"0",1);  // 注册工作区,驱动器号 0,初始化后其他函数可使用里面的参数

                    printf("注册工作区!\n");

                   

                    if(f_mkfs("0",0,4096))  //格式化SD

                    {

                            printf("格式化失败!!\n");

                    }

                    else

                    {

                            printf("格式化成功!!\n");

                    }

                    res = f_open(&file, "/file.c", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);

                    if(res==0)

                    {

                            printf("文件创建成功!!\n");

                    }

                    else

                    {

                            printf("文件创建失败!!\n");

                    }

                    res =f_write(&file,buff,strlen((const char*)buff),&data);

                    if(res==0)

                    {

                            printf("数据写入成功!!\n");

                    }

                    else

                    {

                            printf("数据写入失败!!\n");

                    }

                    printf("成功写入%d字节数据\n",data);

                    f_close(&file);  //关闭文件

                    //_FS_RPATH

                   

                    while(1)

                    {

                            Delay_ms(1000);

                            LED1(1);

                            Delay_ms(500);

                            LED1(0);

                    }

    }

     

     

    展开全文
  • RTT下spi flash+elm fat文件系统移植小记

    万次阅读 2013-08-24 23:32:39
    背景:MCU:STM32F207SPI flash: Winbond W25Q16BVOS: RTT V1.1.1bsp: STM32F20x1 将spi_core.c,spi_dev.c及spi.h三个文件加入工程spi_core.c,spi_dev.c这两个文件位于RTT\components\drivers\spi目录下,而spi.h头文件...

    背景:

    • MCU:STM32F207
    • SPI flash: Winbond W25Q16BV
    • OS: RTT V1.1.1
    • bsp: STM32F20x

    1 将spi_core.c,spi_dev.c及spi.h三个文件加入工程


    spi_core.c,spi_dev.c这两个文件位于RTT\components\drivers\spi目录下,而spi.h头文件位于RTT\\components\drivers\include\drivers目录下.

    可在MKD工程的Drivers组下将上面两个源文件加进行,并将spi.h头文件所在目录添加到工程的include path下.


    spi_core.c文件实现了spi的抽象操作,如注册spi总线(spi_bus),向SPI总线添加设备函数等.

    注: 这里将MCU的一路spi外设虚拟成spi总线,然后总线上可以挂很多spi设备(spi_device),很个spi_device有一个片选cs.

    spi总线和spi设备要在RTT中可以生效就必须先向RTT注册,因此就需要使用上面的注册SPI总线函数和向SPI总线中添加SPI设备.

    spi_core.c还包含了配置SPI函数,发送和接收等通信函数,占用和释放SPI总线函数及选择SPI设备函数.这些函数都是抽象出来的,反映出SPI总线上的一些常规操作.真正执行这些操作的过程并不在spi_core.c源文件中,实际上,这些操作信息都是通过注册SPI总线和向总线添加SPI设备时这些操作集就已经"注册"下来了,真正操作时是通过注册信息内的操作函数去实现,也可以说是一种回调操作.


    而spi_dev.c实现了SPI设备的一些抽象操作,比如读,写,打开,关闭,初始化等,当然当MCU操作SPI设备的时候,是需要通过SPI总线与SPI设备进行通信的,既然通信就必然会有SPI通信协议,但是通信协议并不在这里具体,spi_dev.c这里还只是SPI设备的抽象操作而已,它只是简单地调用spi_core.c源文件中的抽象通信而已,具体实现还是要靠上层通过SPI总线或SPI设备注册下来的信息而实现的.


    在确保了spi_core.c,spi_dev.c和spi.h这三个源文件在MDK工程内之后,接着往下走.

    2 添加stm32f20x_40x_spi.c及其对应头文件

    将stm32f20x_40x_spi.c添加到Drivers组内.这个stm32f20x_40x_spi.c要在realtouch源码工程里找来,在文件系统示例代码中有.

    在源文件在spi.h的基础上根据STM32F20x这款MCU的特点进行了进一步封装.这里修改的地方只有一处理:

    即在config函数内配置SPI最大时钟时可根据MCU的具体特性配置为:30000000;

    //#ifdef STM32F4XX
    //        stm32_spi_max_clock = 37500000;
    //#elif STM32F2XX
            stm32_spi_max_clock = 30000000;
    //#endif

    3 添加spi_flash_w25qxx.c进工程

    由于这里使用的FLASH是Winbond的W25Q16BV,所以以此文件命名,此源文件及其头文件可以在realtouch的源文件中找到.realtouch工程正好也是使用的此flash.

    顾名思义,此源文件正是针对w25q16这款芯片的特点来实现的,当然包含

    在这里,具体实现了SPI通信的参数,这些参数传递给stm32f20x_4-x_spi.c文件中定义的函数,然后再进一步传递给spi_core来进行通信,spi_core的通信过程又会回调回来.

    spi_flash_w25qxx.c还实现了read.write,open,close这些标准操作,这些函数就封装到一个结构体中通信注册函数注册到spi_core内部以供其回调所用.同时spi_flash_w25qxx.c还传递操作所必要的参数下去.

    4 初始化 spi flash

    接下来就是在RTT系统初始化时对SPI FLASH做些必要的初始化.

    如下:

    #ifdef RT_USING_SPI
        rt_hw_spi2_init();
    
    #ifdef RT_USING_DFS
        w25qxx_init("flash0", "spi20");
    #endif /* RT_USING_DFS */

    rt_hw_spi2_int()函数的作用是向RTT设备管理系统注册SPI2总线和向SPI2总线添加spi设备及其必要的IO管脚初始化. 这里仅仅只是注册设备而已.

    w25qxx_init的作用是将SPI2总线上的SPI设备spi20注册成FLASH设备,也就是说将之前的设备告诉RTT其实是FLASH存储设备,然后配上相关的SPI FLASH存储设备参数.

    在w25qxx_init函数内会读取spi flash的device id, 这里得根据自己所使用的具体FLASH进行修改.

    rt_hw_spi_init函数如下:

    这里PB12用作SPI FLASH的片选管脚.

    static void rt_hw_spi2_init(void)
    {
        /* register spi bus */
        {
            static struct stm32_spi_bus stm32_spi;
            GPIO_InitTypeDef GPIO_InitStructure;
    
            RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    
            GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
            GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
            GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
            /*!< SPI SCK pin configuration */
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
            GPIO_Init(GPIOB, &GPIO_InitStructure);
    
            /* Connect alternate function */
            GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
            GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
            GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
    
            stm32_spi_register(SPI2, &stm32_spi, "spi2");
        }
    
        /* attach cs */
        {
            static struct rt_spi_device spi_device;
            static struct stm32_spi_cs  spi_cs;
    
            GPIO_InitTypeDef GPIO_InitStructure;
    
            GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
            GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
            GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
            /* spi21: PB12 */
            spi_cs.GPIOx = GPIOB;
            spi_cs.GPIO_Pin = GPIO_Pin_12;
            RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    
            GPIO_InitStructure.GPIO_Pin = spi_cs.GPIO_Pin;
            GPIO_SetBits(spi_cs.GPIOx, spi_cs.GPIO_Pin);
            GPIO_Init(spi_cs.GPIOx, &GPIO_InitStructure);
    
            rt_spi_bus_attach_device(&spi_device, "spi20", "spi2", (void*)&spi_cs);
        }
    }
    注:在rt_config.h头文件中得将#define RT_USING_SPI宏打开.

    5 移植ELM FAT文件系统

    ELM FAT一般用不着移植,MDK工程中一般默认就有,如果没有就得自己添加了,一般包含6个C文件:

    ff.c,dfs_elm.c,dfs.c,dfs_file.c,dfs_fs.c,dfs_posix.c,这些源文件在RTT\components\dfs目录下可以找到,一般不需要修改.

    但是在rtconfig.h头文件中针对ELM需要做些修改,如下:

    /* SECTION: device filesystem */
    #define RT_USING_DFS 
    #define RT_USING_DFS_ELMFAT
    #define RT_DFS_ELM_REENTRANT
    #define RT_DFS_ELM_WORD_ACCESS
    #define RT_DFS_ELM_DRIVES			1
    #define RT_DFS_ELM_USE_LFN			0 //这里一般设置为0,不使用长文件名,否则需要加入另外的源文件才能编译通过
    #define RT_DFS_ELM_MAX_LFN			255
    #define RT_DFS_ELM_MAX_SECTOR_SIZE  4096     //这里一定要与实际的spi flash一个扇区所包含的字节数相符,太小了会出现内存非法覆盖的情况
    
    /* the max number of mounted filesystem */
    #define DFS_FILESYSTEMS_MAX			2
    /* the max number of opened files 		*/
    #define DFS_FD_MAX					4

    此时附上MDK工程示图如下:


    6  初始化文件系统及挂载文件系统

    /* Filesystem Initialization */
    #ifdef RT_USING_DFS
    	{
    		/* init the device filesystem */
    		dfs_init();
    
    #ifdef RT_USING_DFS_ELMFAT
    		/* init the elm chan FatFs filesystam*/
    		elm_init();
    
    		/* mount sd card fat partition 1 as root directory */
    		if (dfs_mount("flash0", "/", "elm", 0, 0) == 0)
    		{
    			rt_kprintf("flash0 mount to /.\n");
    		}
    		else
    			rt_kprintf("flash0 mount to / failed.\n");
    #endif
    	}
    #endif


    7 格式化spi flash

    烧录进MCU,首次时SPI FLASH是未格式化的,因此会挂载出错,此时可以在finish下使用mkfs来格式化FLASH,然后使用mkdir来创建一个目录,再使用ls指令来查看创建的目录是否存在,如果存在,则说明正常了.如下图:


    通过这一步就说明SPI FLASH能正常工作了.

    下面通过代码来测试.

    8 通过代码来测试打开读写文件系统

    在工程中加入如下测试代码:

    {
            //文件系统测试代码
            int fd=0;
    
            fd =open("/myfile.txt",DFS_O_CREAT|DFS_O_RDWR,0);
            if(fd <0)
            {
                rt_kprintf("open file failed!\r\n");
            }
            else
            {
                int count =write(fd,"123456",7);
                char buf[10];
    
                close(fd);
                fd =0;
    
    
                rt_thread_delay(50);
                rt_memset(buf,0,10);
                fd =open("/myfile.txt",DFS_O_RDONLY,0);
                if(read(fd,buf,7))
                {
                    rt_kprintf("read=%s\r\n",buf);
                }
                else
                {
                    rt_kprintf("read file err!\r\n");
                }
    
            }
        }

    结果如下:

    写进myfile.txt文件中的内容又可以原样读出来.

    也可以通过ls指令再次查看/目录下的内容:



    这样就验证了文件系统完全可以正常工作了.


    完!




    展开全文
  • 1,磁盘分区 ...FATFS 是一个完全免费开源的 FAT 文件系统模块,专门为小型的嵌入式系统而设计。它完 全用标准 C 语言编写,所以具有良好的硬件平台独立性,可以移植到 8051、PIC、AVR、SH、 Z80、H8、AR
  • sysbios fat文件系统制作工具和方法
  • 文章目录FAT文件系统介绍以及FatFs的移植1、FAT文件系统介绍1.1 MBR分区1.1.1 MBR分区结构1.1.2 MBR的DPT分区表解析1.2 GPT分区1.2.1 GPT分区结构1.2.2 GPT各分区结构介绍1.3 FAT文件系统分析1.3.1 FAT简介1.3.2 DBR...
  • 嵌入式FAT32文件系统设计与实现--振南znFAT上下全册
  • 嵌入式FAT文件系统免费源码下载-- 本版本代码完全兼容FAT16/FAT32文件系统总共两种格式,兼容长文件名, 兼容文字编码GB2312/UNICODE汉字编码(文件名完全支持中文), 实现了支持子目录,实现了支持文件的读取,...
  • 嵌入式FAT文件系统免费源码下载 本版本代码完全兼容FAT16/FAT32文件系统总共两种格式,兼容长文件名, 兼容文字编码GB2312/UNICODE汉字编码(文件名完全支持中文), 实现了支持子目录,实现了支持文件的读取,写入...
  • 移植c语言Fat文件系统Fat文件系统可以设计操作,比周立功的要很多
  • 振南znFAT--嵌入式FAT32文件系统设计与实现(上下册)
  • 里面有两个FAT源码模块,有说明英文的文档。其中的一个介绍如下: Features •Very small RAM consumption (44 bytes work area + certain stack). •Very small code size (2K-4K bytes). •Supports FAT32....
  • FAT快速版--嵌入式FAT文件系统免费源码下载 本代码完全兼容FAT16/FAT32文件系统共计两种格式,支持长文件名, 文件名完全支持中文,中文支持需要UNICODE/GB2312码表(需占用190KB的ROM),只支持英文的可不用码表,...
  • stm32f10x 用spi方式移植fat32文件系统(支持32G以上的sdcard)
  • FAT文件系统搞明白、把fatfs源代码分析清楚,是为了什么?只是爱好?只是想知道别人设计思想?这样的目的当然也是可以的,通过这些学习,学习能力和分析问题的能力肯定是有提升的。但是,如果能把学习的东西转化成...
  • FAT精减版(专业嵌入式应用版本)--嵌入式FAT文件系统免费源码下载 本代码完全兼容FAT16/FAT32文件系统共计两种格式,支持长文件名, 文件名完全支持中文,中文支持需要UNICODE/GB2312码表(需占用190KB的ROM),只支持...
  • FAT32文件系统介绍

    千次阅读 2020-12-13 23:06:42
    FAT32文件系统(一)为什么要有文件系统(二)FAT32文件系统组成(三)分步介绍各部分(1) 首先介绍一下MBR(2)DBR介绍(3)FAT表介绍(4) 数据区 (一)为什么要有文件系统 文件系统是操作系统用于明确存储设备或分区上...
  • 经常在网上、群里看到很多人问关于STM32的FATFS文件系统移植的问题,刚好自己最近也在调试这个程序,为了让大家少走弯路,我把我的调试过程和方法也贡献给大家。 二、FATFS简介 FatFs Module是一种完全免费开源的FAT...
  • FatFs 是用于小型嵌入式系统的通用 FAT/exFAT 文件系统模块。FatFs 模块是按照 ANSI C (C89) 编写的,与磁盘 I/O 层完全分离。因此它独立于平台。它可以集成到资源有限的小型微控制器中,例如 8051、PIC、AVR、ARM、...
  • FAT及FATFS资料合集FAT32简单教材文件系统详解FATFS浅谈FAT32中文版: FAT32中文版.pdf FAT32文件系统详解.pdf FAT32简单教材.pdf FatFs使用说明—基于SmartARMCortexM3-1700.pdf ...FAT文件系统的组织结构.pdf
  • 记一次fatfs文件系统移植问题 (1)问题描述: 由于在SD卡读写实验时,将SD卡第0个扇区写入内容并清除扇区,导致SD卡中的Fatfs信息丢失。用读卡器在电脑上用WINHEX格式化工具,将SD卡重新格式化为Fat32格式,但是在STM...
  • 嵌入式FAT文件系统

    2011-03-16 13:28:45
    不依赖于操作系统的FAT文件系统,方便移植。 包括FAT16和FAT32
  • 基于51单片机的SD卡fat32文件系统,znfat原创。已测试,文件读取效率比较快。 解压后根据你的sd卡的端口修改之后下载到单片机就可以用了。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,660
精华内容 2,664
关键字:

fat文件系统移植